Merge remote-tracking branch 'origin/master' into issue-94-响应式查询(Reactive_Query_System)/_Event-driven_Query
This commit is contained in:
@@ -14,6 +14,18 @@
|
|||||||
- **JSON格式**:人类可读,便于调试和编辑
|
- **JSON格式**:人类可读,便于调试和编辑
|
||||||
- **Binary格式**:使用MessagePack,体积更小,性能更高
|
- **Binary格式**:使用MessagePack,体积更小,性能更高
|
||||||
|
|
||||||
|
> **📢 v2.2.2 重要变更**
|
||||||
|
>
|
||||||
|
> 从 v2.2.2 开始,二进制序列化格式返回 `Uint8Array` 而非 Node.js 的 `Buffer`,以确保浏览器兼容性:
|
||||||
|
> - `serialize({ format: 'binary' })` 返回 `string | Uint8Array`(原为 `string | Buffer`)
|
||||||
|
> - `deserialize(data)` 接收 `string | Uint8Array`(原为 `string | Buffer`)
|
||||||
|
> - `applyIncremental(data)` 接收 `IncrementalSnapshot | string | Uint8Array`(原为包含 `Buffer`)
|
||||||
|
>
|
||||||
|
> **迁移影响**:
|
||||||
|
> - ✅ **运行时兼容**:Node.js 的 `Buffer` 继承自 `Uint8Array`,现有代码可直接运行
|
||||||
|
> - ⚠️ **类型检查**:如果你的 TypeScript 代码中显式使用了 `Buffer` 类型,需要改为 `Uint8Array`
|
||||||
|
> - ✅ **浏览器支持**:`Uint8Array` 是标准 JavaScript 类型,所有现代浏览器都支持
|
||||||
|
|
||||||
## 全量序列化
|
## 全量序列化
|
||||||
|
|
||||||
### 基础用法
|
### 基础用法
|
||||||
@@ -63,6 +75,7 @@ const binaryData = scene.serialize({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 保存为文件(Node.js环境)
|
// 保存为文件(Node.js环境)
|
||||||
|
// 注意:binaryData 是 Uint8Array 类型,Node.js 的 fs 可以直接写入
|
||||||
fs.writeFileSync('save.bin', binaryData);
|
fs.writeFileSync('save.bin', binaryData);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -285,7 +298,7 @@ otherScene.applyIncremental(incremental);
|
|||||||
const jsonData = IncrementalSerializer.serializeIncremental(incremental, { format: 'json' });
|
const jsonData = IncrementalSerializer.serializeIncremental(incremental, { format: 'json' });
|
||||||
otherScene.applyIncremental(jsonData);
|
otherScene.applyIncremental(jsonData);
|
||||||
|
|
||||||
// 从二进制Buffer应用
|
// 从二进制Uint8Array应用
|
||||||
const binaryData = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
|
const binaryData = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
|
||||||
otherScene.applyIncremental(binaryData);
|
otherScene.applyIncremental(binaryData);
|
||||||
```
|
```
|
||||||
@@ -552,9 +565,9 @@ class NetworkSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private receiveIncremental(data: ArrayBuffer): void {
|
private receiveIncremental(data: ArrayBuffer): void {
|
||||||
// 直接应用二进制数据
|
// 直接应用二进制数据(ArrayBuffer 转 Uint8Array)
|
||||||
const buffer = Buffer.from(data);
|
const uint8Array = new Uint8Array(data);
|
||||||
this.scene.applyIncremental(buffer);
|
this.scene.applyIncremental(uint8Array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -790,7 +803,7 @@ class LargeDataComponent extends Component {
|
|||||||
|
|
||||||
- [`Scene.createIncrementalSnapshot()`](/api/classes/Scene#createincrementalsnapshot) - 创建基础快照
|
- [`Scene.createIncrementalSnapshot()`](/api/classes/Scene#createincrementalsnapshot) - 创建基础快照
|
||||||
- [`Scene.serializeIncremental()`](/api/classes/Scene#serializeincremental) - 获取增量变更
|
- [`Scene.serializeIncremental()`](/api/classes/Scene#serializeincremental) - 获取增量变更
|
||||||
- [`Scene.applyIncremental()`](/api/classes/Scene#applyincremental) - 应用增量变更(支持IncrementalSnapshot对象、JSON字符串或二进制Buffer)
|
- [`Scene.applyIncremental()`](/api/classes/Scene#applyincremental) - 应用增量变更(支持IncrementalSnapshot对象、JSON字符串或二进制Uint8Array)
|
||||||
- [`Scene.updateIncrementalSnapshot()`](/api/classes/Scene#updateincrementalsnapshot) - 更新快照基准
|
- [`Scene.updateIncrementalSnapshot()`](/api/classes/Scene#updateincrementalsnapshot) - 更新快照基准
|
||||||
- [`Scene.clearIncrementalSnapshot()`](/api/classes/Scene#clearincrementalsnapshot) - 清除快照
|
- [`Scene.clearIncrementalSnapshot()`](/api/classes/Scene#clearincrementalsnapshot) - 清除快照
|
||||||
- [`Scene.hasIncrementalSnapshot()`](/api/classes/Scene#hasincrementalsnapshot) - 检查是否有快照
|
- [`Scene.hasIncrementalSnapshot()`](/api/classes/Scene#hasincrementalsnapshot) - 检查是否有快照
|
||||||
|
|||||||
53
package-lock.json
generated
53
package-lock.json
generated
@@ -3559,6 +3559,15 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@msgpack/msgpack": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "0.2.4",
|
"version": "0.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz",
|
||||||
@@ -5220,16 +5229,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/msgpack-lite": {
|
|
||||||
"version": "0.1.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/msgpack-lite/-/msgpack-lite-0.1.11.tgz",
|
|
||||||
"integrity": "sha512-cdCZS/gw+jIN22I4SUZUFf1ZZfVv5JM1//Br/MuZcI373sxiy3eSSoiyLu0oz+BPatTbGGGBO5jrcvd0siCdTQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/multer": {
|
"node_modules/@types/multer": {
|
||||||
"version": "1.4.13",
|
"version": "1.4.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.13.tgz",
|
||||||
@@ -7715,12 +7714,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/event-lite": {
|
|
||||||
"version": "0.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.3.tgz",
|
|
||||||
"integrity": "sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/eventemitter3": {
|
"node_modules/eventemitter3": {
|
||||||
"version": "4.0.7",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
@@ -8672,6 +8665,7 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -8861,12 +8855,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/int64-buffer": {
|
|
||||||
"version": "0.1.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.1.10.tgz",
|
|
||||||
"integrity": "sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/ip-address": {
|
"node_modules/ip-address": {
|
||||||
"version": "9.0.5",
|
"version": "9.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
|
||||||
@@ -9138,6 +9126,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/isexe": {
|
"node_modules/isexe": {
|
||||||
@@ -11543,21 +11532,6 @@
|
|||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/msgpack-lite": {
|
|
||||||
"version": "0.1.26",
|
|
||||||
"resolved": "https://registry.npmjs.org/msgpack-lite/-/msgpack-lite-0.1.26.tgz",
|
|
||||||
"integrity": "sha512-SZ2IxeqZ1oRFGo0xFGbvBJWMp3yLIY9rlIJyxy8CGrwZn1f0ZK4r6jV/AM1r0FZMDUkWkglOk/eeKIL9g77Nxw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"event-lite": "^0.1.1",
|
|
||||||
"ieee754": "^1.1.8",
|
|
||||||
"int64-buffer": "^0.1.9",
|
|
||||||
"isarray": "^1.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"msgpack": "bin/msgpack"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/multimatch": {
|
"node_modules/multimatch": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz",
|
||||||
@@ -15556,10 +15530,10 @@
|
|||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@esengine/ecs-framework",
|
"name": "@esengine/ecs-framework",
|
||||||
"version": "2.2.1",
|
"version": "2.2.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"msgpack-lite": "^0.1.26",
|
"@msgpack/msgpack": "^3.0.0",
|
||||||
"tslib": "^2.8.1"
|
"tslib": "^2.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -15572,7 +15546,6 @@
|
|||||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/msgpack-lite": "^0.1.11",
|
|
||||||
"@types/node": "^20.19.17",
|
"@types/node": "^20.19.17",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@esengine/ecs-framework",
|
"name": "@esengine/ecs-framework",
|
||||||
"version": "2.2.1",
|
"version": "2.2.3",
|
||||||
"description": "用于Laya、Cocos Creator等JavaScript游戏引擎的高性能ECS框架",
|
"description": "用于Laya、Cocos Creator等JavaScript游戏引擎的高性能ECS框架",
|
||||||
"main": "bin/index.js",
|
"main": "bin/index.js",
|
||||||
"types": "bin/index.d.ts",
|
"types": "bin/index.d.ts",
|
||||||
@@ -58,7 +58,6 @@
|
|||||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/msgpack-lite": "^0.1.11",
|
|
||||||
"@types/node": "^20.19.17",
|
"@types/node": "^20.19.17",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
@@ -78,7 +77,7 @@
|
|||||||
"directory": "packages/core"
|
"directory": "packages/core"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"msgpack-lite": "^0.1.26",
|
"@msgpack/msgpack": "^3.0.0",
|
||||||
"tslib": "^2.8.1"
|
"tslib": "^2.8.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { ServiceContainer } from './Core/ServiceContainer';
|
|||||||
import { PluginManager } from './Core/PluginManager';
|
import { PluginManager } from './Core/PluginManager';
|
||||||
import { IPlugin } from './Core/Plugin';
|
import { IPlugin } from './Core/Plugin';
|
||||||
import { WorldManager } from './ECS/WorldManager';
|
import { WorldManager } from './ECS/WorldManager';
|
||||||
import { registerInjectable } from './Core/DI';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 游戏引擎核心类
|
* 游戏引擎核心类
|
||||||
@@ -178,14 +177,9 @@ export class Core {
|
|||||||
this._poolManager = new PoolManager();
|
this._poolManager = new PoolManager();
|
||||||
this._serviceContainer.registerInstance(PoolManager, this._poolManager);
|
this._serviceContainer.registerInstance(PoolManager, this._poolManager);
|
||||||
|
|
||||||
// 使用依赖注入自动注册WorldManager和SceneManager
|
// 初始化场景管理器
|
||||||
// WorldManager会在构造时创建默认World
|
this._sceneManager = new SceneManager();
|
||||||
registerInjectable(this._serviceContainer, WorldManager);
|
this._serviceContainer.registerInstance(SceneManager, this._sceneManager);
|
||||||
this._worldManager = this._serviceContainer.resolve(WorldManager);
|
|
||||||
|
|
||||||
// SceneManager会通过@Inject自动获取WorldManager
|
|
||||||
registerInjectable(this._serviceContainer, SceneManager);
|
|
||||||
this._sceneManager = this._serviceContainer.resolve(SceneManager);
|
|
||||||
|
|
||||||
// 设置场景切换回调,通知调试管理器
|
// 设置场景切换回调,通知调试管理器
|
||||||
this._sceneManager.setSceneChangedCallback(() => {
|
this._sceneManager.setSceneChangedCallback(() => {
|
||||||
@@ -194,6 +188,10 @@ export class Core {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 初始化World管理器
|
||||||
|
this._worldManager = new WorldManager();
|
||||||
|
this._serviceContainer.registerInstance(WorldManager, this._worldManager);
|
||||||
|
|
||||||
// 初始化插件管理器
|
// 初始化插件管理器
|
||||||
this._pluginManager = new PluginManager();
|
this._pluginManager = new PluginManager();
|
||||||
this._pluginManager.initialize(this, this._serviceContainer);
|
this._pluginManager.initialize(this, this._serviceContainer);
|
||||||
@@ -647,7 +645,7 @@ export class Core {
|
|||||||
this._performanceMonitor.updateFPS(Time.deltaTime);
|
this._performanceMonitor.updateFPS(Time.deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新所有@Updatable服务(包括TimerManager, WorldManager, SceneManager等)
|
// 更新所有可更新的服务
|
||||||
const servicesStartTime = this._performanceMonitor.startMonitoring('Services.update');
|
const servicesStartTime = this._performanceMonitor.startMonitoring('Services.update');
|
||||||
this._serviceContainer.updateAll(deltaTime);
|
this._serviceContainer.updateAll(deltaTime);
|
||||||
this._performanceMonitor.endMonitoring('Services.update', servicesStartTime, this._serviceContainer.getUpdatableCount());
|
this._performanceMonitor.endMonitoring('Services.update', servicesStartTime, this._serviceContainer.getUpdatableCount());
|
||||||
@@ -655,6 +653,12 @@ export class Core {
|
|||||||
// 更新对象池管理器
|
// 更新对象池管理器
|
||||||
this._poolManager.update();
|
this._poolManager.update();
|
||||||
|
|
||||||
|
// 更新默认场景(通过 SceneManager)
|
||||||
|
this._sceneManager.update();
|
||||||
|
|
||||||
|
// 更新额外的 WorldManager
|
||||||
|
this._worldManager.updateAll();
|
||||||
|
|
||||||
// 更新调试管理器(基于FPS的数据发送)
|
// 更新调试管理器(基于FPS的数据发送)
|
||||||
if (this._debugManager) {
|
if (this._debugManager) {
|
||||||
this._debugManager.onFrameUpdate(deltaTime);
|
this._debugManager.onFrameUpdate(deltaTime);
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ export interface InjectableMetadata {
|
|||||||
* 依赖列表
|
* 依赖列表
|
||||||
*/
|
*/
|
||||||
dependencies: Array<ServiceType<any> | string | symbol>;
|
dependencies: Array<ServiceType<any> | string | symbol>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 属性注入映射
|
||||||
|
* key: 属性名, value: 服务类型
|
||||||
|
*/
|
||||||
|
properties?: Map<string | symbol, ServiceType<any>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,10 +83,12 @@ export interface UpdatableMetadata {
|
|||||||
*/
|
*/
|
||||||
export function Injectable(): ClassDecorator {
|
export function Injectable(): ClassDecorator {
|
||||||
return function <T extends Function>(target: T): T {
|
return function <T extends Function>(target: T): T {
|
||||||
// 标记为可注入
|
const existing = injectableMetadata.get(target);
|
||||||
|
|
||||||
injectableMetadata.set(target, {
|
injectableMetadata.set(target, {
|
||||||
injectable: true,
|
injectable: true,
|
||||||
dependencies: []
|
dependencies: [],
|
||||||
|
properties: existing?.properties
|
||||||
});
|
});
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
@@ -142,20 +150,7 @@ export function Updatable(priority: number = 0): ClassDecorator {
|
|||||||
*
|
*
|
||||||
* 标记构造函数参数需要注入的服务类型
|
* 标记构造函数参数需要注入的服务类型
|
||||||
*
|
*
|
||||||
* @param serviceType 服务类型标识符(类、字符串或Symbol)
|
* @param serviceType 服务类型标识符
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```typescript
|
|
||||||
* @Injectable()
|
|
||||||
* class MySystem extends EntitySystem {
|
|
||||||
* constructor(
|
|
||||||
* @Inject(TimeService) private timeService: TimeService,
|
|
||||||
* @Inject(PhysicsService) private physics: PhysicsService
|
|
||||||
* ) {
|
|
||||||
* super();
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
*/
|
||||||
export function Inject(serviceType: ServiceType<any> | string | symbol): ParameterDecorator {
|
export function Inject(serviceType: ServiceType<any> | string | symbol): ParameterDecorator {
|
||||||
return function (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) {
|
return function (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) {
|
||||||
@@ -171,6 +166,35 @@ export function Inject(serviceType: ServiceType<any> | string | symbol): Paramet
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @InjectProperty() 装饰器
|
||||||
|
*
|
||||||
|
* 通过属性装饰器注入依赖
|
||||||
|
*
|
||||||
|
* 注入时机:在构造函数执行后、onInitialize() 调用前完成
|
||||||
|
*
|
||||||
|
* @param serviceType 服务类型
|
||||||
|
*/
|
||||||
|
export function InjectProperty(serviceType: ServiceType<any>): PropertyDecorator {
|
||||||
|
return function (target: any, propertyKey: string | symbol) {
|
||||||
|
let metadata = injectableMetadata.get(target.constructor);
|
||||||
|
|
||||||
|
if (!metadata) {
|
||||||
|
metadata = {
|
||||||
|
injectable: true,
|
||||||
|
dependencies: []
|
||||||
|
};
|
||||||
|
injectableMetadata.set(target.constructor, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metadata.properties) {
|
||||||
|
metadata.properties = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.properties.set(propertyKey, serviceType);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查类是否标记为可注入
|
* 检查类是否标记为可注入
|
||||||
*
|
*
|
||||||
@@ -252,6 +276,29 @@ export function createInstance<T>(
|
|||||||
return new constructor(...dependencies);
|
return new constructor(...dependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为实例注入属性依赖
|
||||||
|
*
|
||||||
|
* @param instance 目标实例
|
||||||
|
* @param container 服务容器
|
||||||
|
*/
|
||||||
|
export function injectProperties<T>(instance: T, container: ServiceContainer): void {
|
||||||
|
const constructor = (instance as any).constructor;
|
||||||
|
const metadata = getInjectableMetadata(constructor);
|
||||||
|
|
||||||
|
if (!metadata?.properties || metadata.properties.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [propertyKey, serviceType] of metadata.properties) {
|
||||||
|
const service = container.resolve(serviceType);
|
||||||
|
|
||||||
|
if (service !== null) {
|
||||||
|
(instance as any)[propertyKey] = service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查类是否标记为可更新
|
* 检查类是否标记为可更新
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
export {
|
export {
|
||||||
Injectable,
|
Injectable,
|
||||||
Inject,
|
Inject,
|
||||||
|
InjectProperty,
|
||||||
Updatable,
|
Updatable,
|
||||||
isInjectable,
|
isInjectable,
|
||||||
getInjectableMetadata,
|
getInjectableMetadata,
|
||||||
@@ -14,6 +15,7 @@ export {
|
|||||||
isUpdatable,
|
isUpdatable,
|
||||||
getUpdatableMetadata,
|
getUpdatableMetadata,
|
||||||
createInstance,
|
createInstance,
|
||||||
|
injectProperties,
|
||||||
registerInjectable
|
registerInjectable
|
||||||
} from './Decorators';
|
} from './Decorators';
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOpt
|
|||||||
import { ComponentPoolManager } from './Core/ComponentPool';
|
import { ComponentPoolManager } from './Core/ComponentPool';
|
||||||
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
|
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
|
||||||
import { ServiceContainer, type ServiceType } from '../Core/ServiceContainer';
|
import { ServiceContainer, type ServiceType } from '../Core/ServiceContainer';
|
||||||
import { createInstance, isInjectable } from '../Core/DI';
|
import { createInstance, isInjectable, injectProperties } from '../Core/DI';
|
||||||
import { isUpdatable, getUpdatableMetadata } from '../Core/DI/Decorators';
|
import { isUpdatable, getUpdatableMetadata } from '../Core/DI/Decorators';
|
||||||
import { createLogger } from '../Utils/Logger';
|
import { createLogger } from '../Utils/Logger';
|
||||||
|
|
||||||
@@ -578,6 +578,8 @@ export class Scene implements IScene {
|
|||||||
|
|
||||||
this._services.registerInstance(constructor, system);
|
this._services.registerInstance(constructor, system);
|
||||||
|
|
||||||
|
injectProperties(system, this._services);
|
||||||
|
|
||||||
system.initialize();
|
system.initialize();
|
||||||
|
|
||||||
return system;
|
return system;
|
||||||
@@ -742,10 +744,10 @@ export class Scene implements IScene {
|
|||||||
/**
|
/**
|
||||||
* 序列化场景
|
* 序列化场景
|
||||||
*
|
*
|
||||||
* 将场景及其所有实体、组件序列化为JSON字符串或二进制Buffer
|
* 将场景及其所有实体、组件序列化为JSON字符串或二进制Uint8Array
|
||||||
*
|
*
|
||||||
* @param options 序列化选项
|
* @param options 序列化选项
|
||||||
* @returns 序列化后的数据(JSON字符串或二进制Buffer)
|
* @returns 序列化后的数据(JSON字符串或二进制Uint8Array)
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
@@ -761,7 +763,7 @@ export class Scene implements IScene {
|
|||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
public serialize(options?: SceneSerializationOptions): string | Buffer {
|
public serialize(options?: SceneSerializationOptions): string | Uint8Array {
|
||||||
return SceneSerializer.serialize(this, options);
|
return SceneSerializer.serialize(this, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,7 +772,7 @@ export class Scene implements IScene {
|
|||||||
*
|
*
|
||||||
* 从序列化数据恢复场景状态
|
* 从序列化数据恢复场景状态
|
||||||
*
|
*
|
||||||
* @param saveData 序列化的数据(JSON字符串或二进制Buffer)
|
* @param saveData 序列化的数据(JSON字符串或二进制Uint8Array)
|
||||||
* @param options 反序列化选项
|
* @param options 反序列化选项
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@@ -786,7 +788,7 @@ export class Scene implements IScene {
|
|||||||
* });
|
* });
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
public deserialize(saveData: string | Buffer, options?: SceneDeserializationOptions): void {
|
public deserialize(saveData: string | Uint8Array, options?: SceneDeserializationOptions): void {
|
||||||
SceneSerializer.deserialize(this, saveData, options);
|
SceneSerializer.deserialize(this, saveData, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,7 +860,7 @@ export class Scene implements IScene {
|
|||||||
/**
|
/**
|
||||||
* 应用增量变更到场景
|
* 应用增量变更到场景
|
||||||
*
|
*
|
||||||
* @param incremental 增量快照数据(IncrementalSnapshot对象、JSON字符串或二进制Buffer)
|
* @param incremental 增量快照数据(IncrementalSnapshot对象、JSON字符串或二进制Uint8Array)
|
||||||
* @param componentRegistry 组件类型注册表(可选,默认使用全局注册表)
|
* @param componentRegistry 组件类型注册表(可选,默认使用全局注册表)
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@@ -870,21 +872,20 @@ export class Scene implements IScene {
|
|||||||
* const jsonData = IncrementalSerializer.serializeIncremental(snapshot, { format: 'json' });
|
* const jsonData = IncrementalSerializer.serializeIncremental(snapshot, { format: 'json' });
|
||||||
* scene.applyIncremental(jsonData);
|
* scene.applyIncremental(jsonData);
|
||||||
*
|
*
|
||||||
* // 从二进制Buffer应用
|
* // 从二进制Uint8Array应用
|
||||||
* const binaryData = IncrementalSerializer.serializeIncremental(snapshot, { format: 'binary' });
|
* const binaryData = IncrementalSerializer.serializeIncremental(snapshot, { format: 'binary' });
|
||||||
* scene.applyIncremental(binaryData);
|
* scene.applyIncremental(binaryData);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
public applyIncremental(
|
public applyIncremental(
|
||||||
incremental: IncrementalSnapshot | string | Buffer,
|
incremental: IncrementalSnapshot | string | Uint8Array,
|
||||||
componentRegistry?: Map<string, any>
|
componentRegistry?: Map<string, any>
|
||||||
): void {
|
): void {
|
||||||
const isSerializedData = typeof incremental === 'string' ||
|
const isSerializedData = typeof incremental === 'string' ||
|
||||||
(typeof Buffer !== 'undefined' && Buffer.isBuffer(incremental)) ||
|
|
||||||
incremental instanceof Uint8Array;
|
incremental instanceof Uint8Array;
|
||||||
|
|
||||||
const snapshot = isSerializedData
|
const snapshot = isSerializedData
|
||||||
? IncrementalSerializer.deserializeIncremental(incremental as string | Buffer)
|
? IncrementalSerializer.deserializeIncremental(incremental as string | Uint8Array)
|
||||||
: incremental as IncrementalSnapshot;
|
: incremental as IncrementalSnapshot;
|
||||||
|
|
||||||
const registry = componentRegistry || ComponentRegistry.getAllComponentNames() as Map<string, any>;
|
const registry = componentRegistry || ComponentRegistry.getAllComponentNames() as Map<string, any>;
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ import { ECSFluentAPI, createECSAPI } from './Core/FluentAPI';
|
|||||||
import { Time } from '../Utils/Time';
|
import { Time } from '../Utils/Time';
|
||||||
import { createLogger } from '../Utils/Logger';
|
import { createLogger } from '../Utils/Logger';
|
||||||
import type { IService } from '../Core/ServiceContainer';
|
import type { IService } from '../Core/ServiceContainer';
|
||||||
import type { IUpdatable } from '../Types/IUpdatable';
|
|
||||||
import { World } from './World';
|
import { World } from './World';
|
||||||
import { WorldManager } from './WorldManager';
|
|
||||||
import { Injectable, Inject, Updatable } from '../Core/DI';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单场景管理器
|
* 单场景管理器
|
||||||
@@ -21,13 +18,15 @@ import { Injectable, Inject, Updatable } from '../Core/DI';
|
|||||||
* - 简单直观的API
|
* - 简单直观的API
|
||||||
* - 支持延迟场景切换
|
* - 支持延迟场景切换
|
||||||
* - 自动管理ECS API
|
* - 自动管理ECS API
|
||||||
* - 通过依赖注入获取WorldManager的默认World
|
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
* // 初始化Core
|
* // 初始化Core
|
||||||
* Core.create({ debug: true });
|
* Core.create({ debug: true });
|
||||||
*
|
*
|
||||||
|
* // 创建场景管理器
|
||||||
|
* const sceneManager = new SceneManager();
|
||||||
|
*
|
||||||
* // 设置场景
|
* // 设置场景
|
||||||
* class GameScene extends Scene {
|
* class GameScene extends Scene {
|
||||||
* initialize() {
|
* initialize() {
|
||||||
@@ -36,22 +35,21 @@ import { Injectable, Inject, Updatable } from '../Core/DI';
|
|||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* Core.setScene(new GameScene());
|
* sceneManager.setScene(new GameScene());
|
||||||
*
|
*
|
||||||
* // 游戏循环
|
* // 游戏循环
|
||||||
* function gameLoop(deltaTime: number) {
|
* function gameLoop(deltaTime: number) {
|
||||||
* Core.update(deltaTime); // 自动更新所有服务(包括SceneManager)
|
* Core.update(deltaTime); // 更新全局服务
|
||||||
|
* sceneManager.update(); // 更新场景
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* // 延迟切换场景(下一帧生效)
|
* // 延迟切换场景(下一帧生效)
|
||||||
* Core.loadScene(new MenuScene());
|
* sceneManager.loadScene(new MenuScene());
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
export class SceneManager implements IService {
|
||||||
@Updatable(10)
|
|
||||||
export class SceneManager implements IService, IUpdatable {
|
|
||||||
/**
|
/**
|
||||||
* 内部默认World(从WorldManager获取)
|
* 内部默认World
|
||||||
*/
|
*/
|
||||||
private _defaultWorld: World;
|
private _defaultWorld: World;
|
||||||
|
|
||||||
@@ -80,18 +78,9 @@ export class SceneManager implements IService, IUpdatable {
|
|||||||
*/
|
*/
|
||||||
private static readonly DEFAULT_SCENE_ID = '__main__';
|
private static readonly DEFAULT_SCENE_ID = '__main__';
|
||||||
|
|
||||||
/**
|
constructor() {
|
||||||
* 构造函数
|
this._defaultWorld = new World({ name: '__default__' });
|
||||||
*
|
this._defaultWorld.start();
|
||||||
* WorldManager通过依赖注入自动传入
|
|
||||||
*
|
|
||||||
* @param worldManager WorldManager实例,用于获取默认World
|
|
||||||
*/
|
|
||||||
constructor(
|
|
||||||
@Inject(WorldManager) worldManager: WorldManager
|
|
||||||
) {
|
|
||||||
// 使用WorldManager管理的默认World
|
|
||||||
this._defaultWorld = worldManager.getDefaultWorld();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { Component } from '../Component';
|
|||||||
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
|
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
|
||||||
import { SerializedEntity } from './EntitySerializer';
|
import { SerializedEntity } from './EntitySerializer';
|
||||||
import { ComponentType } from '../Core/ComponentStorage';
|
import { ComponentType } from '../Core/ComponentStorage';
|
||||||
import * as msgpack from 'msgpack-lite';
|
import { encode, decode } from '@msgpack/msgpack';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 变更操作类型
|
* 变更操作类型
|
||||||
@@ -609,7 +609,7 @@ export class IncrementalSerializer {
|
|||||||
*
|
*
|
||||||
* @param incremental 增量快照
|
* @param incremental 增量快照
|
||||||
* @param options 序列化选项
|
* @param options 序列化选项
|
||||||
* @returns 序列化后的数据(JSON字符串或二进制Buffer)
|
* @returns 序列化后的数据(JSON字符串或二进制Uint8Array)
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
@@ -631,7 +631,7 @@ export class IncrementalSerializer {
|
|||||||
public static serializeIncremental(
|
public static serializeIncremental(
|
||||||
incremental: IncrementalSnapshot,
|
incremental: IncrementalSnapshot,
|
||||||
options?: { format?: IncrementalSerializationFormat; pretty?: boolean }
|
options?: { format?: IncrementalSerializationFormat; pretty?: boolean }
|
||||||
): string | Buffer {
|
): string | Uint8Array {
|
||||||
const opts = {
|
const opts = {
|
||||||
format: 'json' as IncrementalSerializationFormat,
|
format: 'json' as IncrementalSerializationFormat,
|
||||||
pretty: false,
|
pretty: false,
|
||||||
@@ -639,7 +639,7 @@ export class IncrementalSerializer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (opts.format === 'binary') {
|
if (opts.format === 'binary') {
|
||||||
return msgpack.encode(incremental);
|
return encode(incremental);
|
||||||
} else {
|
} else {
|
||||||
return opts.pretty
|
return opts.pretty
|
||||||
? JSON.stringify(incremental, null, 2)
|
? JSON.stringify(incremental, null, 2)
|
||||||
@@ -650,7 +650,7 @@ export class IncrementalSerializer {
|
|||||||
/**
|
/**
|
||||||
* 反序列化增量快照
|
* 反序列化增量快照
|
||||||
*
|
*
|
||||||
* @param data 序列化的数据(JSON字符串或二进制Buffer)
|
* @param data 序列化的数据(JSON字符串或二进制Uint8Array)
|
||||||
* @returns 增量快照
|
* @returns 增量快照
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@@ -662,13 +662,13 @@ export class IncrementalSerializer {
|
|||||||
* const snapshot = IncrementalSerializer.deserializeIncremental(buffer);
|
* const snapshot = IncrementalSerializer.deserializeIncremental(buffer);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
public static deserializeIncremental(data: string | Buffer): IncrementalSnapshot {
|
public static deserializeIncremental(data: string | Uint8Array): IncrementalSnapshot {
|
||||||
if (typeof data === 'string') {
|
if (typeof data === 'string') {
|
||||||
// JSON格式
|
// JSON格式
|
||||||
return JSON.parse(data);
|
return JSON.parse(data);
|
||||||
} else {
|
} else {
|
||||||
// 二进制格式(MessagePack)
|
// 二进制格式(MessagePack)
|
||||||
return msgpack.decode(data);
|
return decode(data) as IncrementalSnapshot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
|
|||||||
import { EntitySerializer, SerializedEntity } from './EntitySerializer';
|
import { EntitySerializer, SerializedEntity } from './EntitySerializer';
|
||||||
import { getComponentTypeName } from '../Decorators';
|
import { getComponentTypeName } from '../Decorators';
|
||||||
import { getSerializationMetadata } from './SerializationDecorators';
|
import { getSerializationMetadata } from './SerializationDecorators';
|
||||||
import * as msgpack from 'msgpack-lite';
|
import { encode, decode } from '@msgpack/msgpack';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 场景序列化格式
|
* 场景序列化格式
|
||||||
@@ -154,9 +154,9 @@ export class SceneSerializer {
|
|||||||
*
|
*
|
||||||
* @param scene 要序列化的场景
|
* @param scene 要序列化的场景
|
||||||
* @param options 序列化选项
|
* @param options 序列化选项
|
||||||
* @returns 序列化后的数据(JSON字符串或二进制Buffer)
|
* @returns 序列化后的数据(JSON字符串或二进制Uint8Array)
|
||||||
*/
|
*/
|
||||||
public static serialize(scene: IScene, options?: SceneSerializationOptions): string | Buffer {
|
public static serialize(scene: IScene, options?: SceneSerializationOptions): string | Uint8Array {
|
||||||
const opts: SceneSerializationOptions = {
|
const opts: SceneSerializationOptions = {
|
||||||
systems: false,
|
systems: false,
|
||||||
format: 'json',
|
format: 'json',
|
||||||
@@ -207,7 +207,7 @@ export class SceneSerializer {
|
|||||||
: JSON.stringify(serializedScene);
|
: JSON.stringify(serializedScene);
|
||||||
} else {
|
} else {
|
||||||
// 二进制格式(使用 MessagePack)
|
// 二进制格式(使用 MessagePack)
|
||||||
return msgpack.encode(serializedScene);
|
return encode(serializedScene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,12 +215,12 @@ export class SceneSerializer {
|
|||||||
* 反序列化场景
|
* 反序列化场景
|
||||||
*
|
*
|
||||||
* @param scene 目标场景
|
* @param scene 目标场景
|
||||||
* @param saveData 序列化的数据(JSON字符串或二进制Buffer)
|
* @param saveData 序列化的数据(JSON字符串或二进制Uint8Array)
|
||||||
* @param options 反序列化选项
|
* @param options 反序列化选项
|
||||||
*/
|
*/
|
||||||
public static deserialize(
|
public static deserialize(
|
||||||
scene: IScene,
|
scene: IScene,
|
||||||
saveData: string | Buffer,
|
saveData: string | Uint8Array,
|
||||||
options?: SceneDeserializationOptions
|
options?: SceneDeserializationOptions
|
||||||
): void {
|
): void {
|
||||||
const opts: SceneDeserializationOptions = {
|
const opts: SceneDeserializationOptions = {
|
||||||
@@ -237,7 +237,7 @@ export class SceneSerializer {
|
|||||||
serializedScene = JSON.parse(saveData);
|
serializedScene = JSON.parse(saveData);
|
||||||
} else {
|
} else {
|
||||||
// 二进制格式(MessagePack)
|
// 二进制格式(MessagePack)
|
||||||
serializedScene = msgpack.decode(saveData);
|
serializedScene = decode(saveData) as SerializedScene;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Failed to parse save data: ${error}`);
|
throw new Error(`Failed to parse save data: ${error}`);
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { World, IWorldConfig } from './World';
|
import { World, IWorldConfig } from './World';
|
||||||
import { createLogger } from '../Utils/Logger';
|
import { createLogger } from '../Utils/Logger';
|
||||||
import type { IService } from '../Core/ServiceContainer';
|
import type { IService } from '../Core/ServiceContainer';
|
||||||
import type { IUpdatable } from '../Types/IUpdatable';
|
|
||||||
import { Injectable, Updatable } from '../Core/DI';
|
|
||||||
|
|
||||||
const logger = createLogger('WorldManager');
|
const logger = createLogger('WorldManager');
|
||||||
|
|
||||||
@@ -29,13 +27,6 @@ export interface IWorldManagerConfig {
|
|||||||
* 是否启用调试模式
|
* 是否启用调试模式
|
||||||
*/
|
*/
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否创建默认World(默认true)
|
|
||||||
*
|
|
||||||
* 当通过Core使用时应该为true,直接使用WorldManager时可设为false
|
|
||||||
*/
|
|
||||||
createDefaultWorld?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,18 +57,12 @@ export interface IWorldManagerConfig {
|
|||||||
*
|
*
|
||||||
* // 游戏循环
|
* // 游戏循环
|
||||||
* function gameLoop(deltaTime: number) {
|
* function gameLoop(deltaTime: number) {
|
||||||
* Core.update(deltaTime); // 自动更新所有@Updatable服务(包括WorldManager)
|
* Core.update(deltaTime);
|
||||||
|
* worldManager.updateAll(); // 更新所有活跃World
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
export class WorldManager implements IService {
|
||||||
@Updatable(5)
|
|
||||||
export class WorldManager implements IService, IUpdatable {
|
|
||||||
/**
|
|
||||||
* 默认World的ID
|
|
||||||
*/
|
|
||||||
public static readonly DEFAULT_WORLD_ID = '__default__';
|
|
||||||
|
|
||||||
private readonly _config: IWorldManagerConfig;
|
private readonly _config: IWorldManagerConfig;
|
||||||
private readonly _worlds: Map<string, World> = new Map();
|
private readonly _worlds: Map<string, World> = new Map();
|
||||||
private readonly _activeWorlds: Set<string> = new Set();
|
private readonly _activeWorlds: Set<string> = new Set();
|
||||||
@@ -90,26 +75,16 @@ export class WorldManager implements IService, IUpdatable {
|
|||||||
autoCleanup: true,
|
autoCleanup: true,
|
||||||
cleanupInterval: 30000, // 30秒
|
cleanupInterval: 30000, // 30秒
|
||||||
debug: false,
|
debug: false,
|
||||||
createDefaultWorld: true, // 默认创建
|
|
||||||
...config
|
...config
|
||||||
};
|
};
|
||||||
|
|
||||||
// 默认启动运行状态
|
// 默认启动运行状态
|
||||||
this._isRunning = true;
|
this._isRunning = true;
|
||||||
|
|
||||||
// 如果配置要求,创建并注册默认World
|
|
||||||
if (this._config.createDefaultWorld) {
|
|
||||||
const defaultWorld = new World({ name: WorldManager.DEFAULT_WORLD_ID });
|
|
||||||
this._worlds.set(WorldManager.DEFAULT_WORLD_ID, defaultWorld);
|
|
||||||
this._activeWorlds.add(WorldManager.DEFAULT_WORLD_ID);
|
|
||||||
defaultWorld.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info('WorldManager已初始化', {
|
logger.info('WorldManager已初始化', {
|
||||||
maxWorlds: this._config.maxWorlds,
|
maxWorlds: this._config.maxWorlds,
|
||||||
autoCleanup: this._config.autoCleanup,
|
autoCleanup: this._config.autoCleanup,
|
||||||
cleanupInterval: this._config.cleanupInterval,
|
cleanupInterval: this._config.cleanupInterval
|
||||||
defaultWorldCreated: this._config.createDefaultWorld
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.startCleanupTimer();
|
this.startCleanupTimer();
|
||||||
@@ -117,22 +92,6 @@ export class WorldManager implements IService, IUpdatable {
|
|||||||
|
|
||||||
// ===== World管理 =====
|
// ===== World管理 =====
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取默认World
|
|
||||||
*
|
|
||||||
* 默认World由WorldManager自动创建,供SceneManager使用。
|
|
||||||
* 此方法主要供SceneManager内部使用。
|
|
||||||
*
|
|
||||||
* @returns 默认World实例
|
|
||||||
*/
|
|
||||||
public getDefaultWorld(): World {
|
|
||||||
const defaultWorld = this._worlds.get(WorldManager.DEFAULT_WORLD_ID);
|
|
||||||
if (!defaultWorld) {
|
|
||||||
throw new Error('默认World不存在,这不应该发生');
|
|
||||||
}
|
|
||||||
return defaultWorld;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建新World
|
* 创建新World
|
||||||
*/
|
*/
|
||||||
@@ -164,16 +123,8 @@ export class WorldManager implements IService, IUpdatable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除World
|
* 移除World
|
||||||
*
|
|
||||||
* 注意:默认World不能被删除
|
|
||||||
*/
|
*/
|
||||||
public removeWorld(worldId: string): boolean {
|
public removeWorld(worldId: string): boolean {
|
||||||
// 防止删除默认World
|
|
||||||
if (worldId === WorldManager.DEFAULT_WORLD_ID) {
|
|
||||||
logger.warn('无法删除默认World');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const world = this._worlds.get(worldId);
|
const world = this._worlds.get(worldId);
|
||||||
if (!world) {
|
if (!world) {
|
||||||
return false;
|
return false;
|
||||||
@@ -246,12 +197,18 @@ export class WorldManager implements IService, IUpdatable {
|
|||||||
/**
|
/**
|
||||||
* 更新所有活跃的World
|
* 更新所有活跃的World
|
||||||
*
|
*
|
||||||
* 此方法由ServiceContainer自动调用(@Updatable装饰器)
|
* 应该在每帧的游戏循环中调用。
|
||||||
* 会自动更新所有活跃World的全局系统和场景。
|
* 会自动更新所有活跃World的全局系统和场景。
|
||||||
*
|
*
|
||||||
* @param deltaTime 帧时间间隔(未使用,保留用于接口兼容)
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* function gameLoop(deltaTime: number) {
|
||||||
|
* Core.update(deltaTime); // 更新全局服务
|
||||||
|
* worldManager.updateAll(); // 更新所有World
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
public update(deltaTime?: number): void {
|
public updateAll(): void {
|
||||||
if (!this._isRunning) return;
|
if (!this._isRunning) return;
|
||||||
|
|
||||||
for (const worldId of this._activeWorlds) {
|
for (const worldId of this._activeWorlds) {
|
||||||
|
|||||||
@@ -47,6 +47,13 @@ class NetworkGlobalSystem implements IGlobalSystem {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* World与Core集成测试
|
* World与Core集成测试
|
||||||
|
*
|
||||||
|
* 注意:v3.0重构后,Core不再直接管理Scene/World
|
||||||
|
* - 场景管理由 SceneManager 负责
|
||||||
|
* - 多世界管理由 WorldManager 负责
|
||||||
|
* - Core 仅负责全局服务(Timer、Performance等)
|
||||||
|
*
|
||||||
|
* 大部分旧的集成测试已移至 SceneManager.test.ts 和 WorldManager.test.ts
|
||||||
*/
|
*/
|
||||||
describe('World与Core集成测试', () => {
|
describe('World与Core集成测试', () => {
|
||||||
let worldManager: WorldManager;
|
let worldManager: WorldManager;
|
||||||
@@ -60,10 +67,8 @@ describe('World与Core集成测试', () => {
|
|||||||
Core.create({ debug: false });
|
Core.create({ debug: false });
|
||||||
|
|
||||||
// WorldManager和SceneManager不再是单例
|
// WorldManager和SceneManager不再是单例
|
||||||
// SceneManager需要WorldManager的默认World,所以必须创建
|
worldManager = new WorldManager();
|
||||||
worldManager = new WorldManager({ createDefaultWorld: true });
|
sceneManager = new SceneManager();
|
||||||
// SceneManager需要WorldManager实例
|
|
||||||
sceneManager = new SceneManager(worldManager);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -104,8 +109,7 @@ describe('World与Core集成测试', () => {
|
|||||||
const world1 = worldManager.createWorld('world1');
|
const world1 = worldManager.createWorld('world1');
|
||||||
const world2 = worldManager.createWorld('world2');
|
const world2 = worldManager.createWorld('world2');
|
||||||
|
|
||||||
// worldManager已包含默认World,所以总数是3
|
expect(worldManager.worldCount).toBe(2);
|
||||||
expect(worldManager.worldCount).toBe(3);
|
|
||||||
expect(worldManager.getWorld('world1')).toBe(world1);
|
expect(worldManager.getWorld('world1')).toBe(world1);
|
||||||
expect(worldManager.getWorld('world2')).toBe(world2);
|
expect(worldManager.getWorld('world2')).toBe(world2);
|
||||||
});
|
});
|
||||||
@@ -133,7 +137,7 @@ describe('World与Core集成测试', () => {
|
|||||||
|
|
||||||
// 游戏循环
|
// 游戏循环
|
||||||
Core.update(0.016); // 更新全局服务
|
Core.update(0.016); // 更新全局服务
|
||||||
worldManager.update(); // 更新所有World
|
worldManager.updateAll(); // 更新所有World
|
||||||
|
|
||||||
expect(world.isActive).toBe(true);
|
expect(world.isActive).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -146,7 +150,7 @@ describe('World与Core集成测试', () => {
|
|||||||
worldManager.setWorldActive('test-world', true);
|
worldManager.setWorldActive('test-world', true);
|
||||||
|
|
||||||
// 更新World
|
// 更新World
|
||||||
worldManager.update();
|
worldManager.updateAll();
|
||||||
|
|
||||||
expect(globalSystem.syncCount).toBeGreaterThan(0);
|
expect(globalSystem.syncCount).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
@@ -154,8 +158,8 @@ describe('World与Core集成测试', () => {
|
|||||||
|
|
||||||
describe('隔离性测试', () => {
|
describe('隔离性测试', () => {
|
||||||
test('多个WorldManager实例应该完全隔离', () => {
|
test('多个WorldManager实例应该完全隔离', () => {
|
||||||
const manager1 = new WorldManager({ createDefaultWorld: false });
|
const manager1 = new WorldManager();
|
||||||
const manager2 = new WorldManager({ createDefaultWorld: false });
|
const manager2 = new WorldManager();
|
||||||
|
|
||||||
manager1.createWorld('world1');
|
manager1.createWorld('world1');
|
||||||
manager2.createWorld('world2');
|
manager2.createWorld('world2');
|
||||||
@@ -171,10 +175,8 @@ describe('World与Core集成测试', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('多个SceneManager实例应该完全隔离', () => {
|
test('多个SceneManager实例应该完全隔离', () => {
|
||||||
const wm1 = new WorldManager({ createDefaultWorld: true });
|
const sm1 = new SceneManager();
|
||||||
const wm2 = new WorldManager({ createDefaultWorld: true });
|
const sm2 = new SceneManager();
|
||||||
const sm1 = new SceneManager(wm1);
|
|
||||||
const sm2 = new SceneManager(wm2);
|
|
||||||
|
|
||||||
const scene1 = new Scene();
|
const scene1 = new Scene();
|
||||||
const scene2 = new Scene();
|
const scene2 = new Scene();
|
||||||
@@ -188,8 +190,6 @@ describe('World与Core集成测试', () => {
|
|||||||
// 清理
|
// 清理
|
||||||
sm1.destroy();
|
sm1.destroy();
|
||||||
sm2.destroy();
|
sm2.destroy();
|
||||||
wm1.destroy();
|
|
||||||
wm2.destroy();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { EntitySystem } from '../../src/ECS/Systems/EntitySystem';
|
|||||||
import { Entity } from '../../src/ECS/Entity';
|
import { Entity } from '../../src/ECS/Entity';
|
||||||
import { Component } from '../../src/ECS/Component';
|
import { Component } from '../../src/ECS/Component';
|
||||||
import { Matcher } from '../../src/ECS/Utils/Matcher';
|
import { Matcher } from '../../src/ECS/Utils/Matcher';
|
||||||
import { Injectable, Inject } from '../../src/Core/DI';
|
import { Injectable, Inject, InjectProperty } from '../../src/Core/DI';
|
||||||
import { Core } from '../../src/Core';
|
import { Core } from '../../src/Core';
|
||||||
import type { IService } from '../../src/Core/ServiceContainer';
|
import type { IService } from '../../src/Core/ServiceContainer';
|
||||||
import { ECSSystem } from '../../src/ECS/Decorators';
|
import { ECSSystem } from '../../src/ECS/Decorators';
|
||||||
@@ -423,4 +423,170 @@ describe('EntitySystem - 依赖注入测试', () => {
|
|||||||
expect(transform.y).toBeCloseTo(0.8, 1);
|
expect(transform.y).toBeCloseTo(0.8, 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('属性注入 @InjectProperty', () => {
|
||||||
|
test('应该支持单个属性注入', () => {
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('Config')
|
||||||
|
class GameConfig extends EntitySystem implements IService {
|
||||||
|
public bulletDamage = 10;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('Combat')
|
||||||
|
class CombatSystem extends EntitySystem implements IService {
|
||||||
|
@InjectProperty(GameConfig)
|
||||||
|
gameConfig!: GameConfig;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty().all(Health));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override onInitialize(): void {
|
||||||
|
expect(this.gameConfig).toBeInstanceOf(GameConfig);
|
||||||
|
expect(this.gameConfig.bulletDamage).toBe(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.addEntityProcessor(GameConfig);
|
||||||
|
scene.addEntityProcessor(CombatSystem);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该支持多个属性注入', () => {
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('Time')
|
||||||
|
class TimeService extends EntitySystem implements IService {
|
||||||
|
public deltaTime = 0.016;
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('Collision')
|
||||||
|
class CollisionSystem extends EntitySystem implements IService {
|
||||||
|
public checkCount = 0;
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('Physics')
|
||||||
|
class PhysicsSystem extends EntitySystem implements IService {
|
||||||
|
@InjectProperty(TimeService)
|
||||||
|
time!: TimeService;
|
||||||
|
|
||||||
|
@InjectProperty(CollisionSystem)
|
||||||
|
collision!: CollisionSystem;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override onInitialize(): void {
|
||||||
|
expect(this.time).toBeInstanceOf(TimeService);
|
||||||
|
expect(this.collision).toBeInstanceOf(CollisionSystem);
|
||||||
|
expect(this.time.deltaTime).toBe(0.016);
|
||||||
|
}
|
||||||
|
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.registerSystems([TimeService, CollisionSystem, PhysicsSystem]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('属性注入应该在onInitialize之前完成', () => {
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('Service')
|
||||||
|
class TestService extends EntitySystem implements IService {
|
||||||
|
public value = 42;
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('Consumer')
|
||||||
|
class ConsumerSystem extends EntitySystem implements IService {
|
||||||
|
@InjectProperty(TestService)
|
||||||
|
service!: TestService;
|
||||||
|
|
||||||
|
private initializeValue = 0;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override onInitialize(): void {
|
||||||
|
this.initializeValue = this.service.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getInitializeValue(): number {
|
||||||
|
return this.initializeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.addEntityProcessor(TestService);
|
||||||
|
const consumer = scene.addEntityProcessor(ConsumerSystem);
|
||||||
|
|
||||||
|
expect(consumer.getInitializeValue()).toBe(42);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('属性注入可以与构造函数注入混合使用', () => {
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('A')
|
||||||
|
class ServiceA extends EntitySystem implements IService {
|
||||||
|
public valueA = 'A';
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('B')
|
||||||
|
class ServiceB extends EntitySystem implements IService {
|
||||||
|
public valueB = 'B';
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@ECSSystem('Mixed')
|
||||||
|
class MixedSystem extends EntitySystem implements IService {
|
||||||
|
@InjectProperty(ServiceB)
|
||||||
|
serviceB!: ServiceB;
|
||||||
|
|
||||||
|
constructor(@Inject(ServiceA) public serviceA: ServiceA) {
|
||||||
|
super(Matcher.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override onInitialize(): void {
|
||||||
|
expect(this.serviceA).toBeInstanceOf(ServiceA);
|
||||||
|
expect(this.serviceB).toBeInstanceOf(ServiceB);
|
||||||
|
expect(this.serviceA.valueA).toBe('A');
|
||||||
|
expect(this.serviceB.valueB).toBe('B');
|
||||||
|
}
|
||||||
|
|
||||||
|
override dispose() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.registerSystems([ServiceA, ServiceB, MixedSystem]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -464,7 +464,7 @@ describe('Incremental Serialization System', () => {
|
|||||||
const incremental = scene.serializeIncremental();
|
const incremental = scene.serializeIncremental();
|
||||||
const binary = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
|
const binary = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
|
||||||
|
|
||||||
expect(Buffer.isBuffer(binary)).toBe(true);
|
expect(binary instanceof Uint8Array).toBe(true);
|
||||||
|
|
||||||
const deserialized = IncrementalSerializer.deserializeIncremental(binary);
|
const deserialized = IncrementalSerializer.deserializeIncremental(binary);
|
||||||
expect(deserialized.version).toBe(incremental.version);
|
expect(deserialized.version).toBe(incremental.version);
|
||||||
|
|||||||
@@ -557,14 +557,14 @@ describe('ECS Serialization System', () => {
|
|||||||
// 二进制序列化
|
// 二进制序列化
|
||||||
const binaryData = scene1.serialize({ format: 'binary' });
|
const binaryData = scene1.serialize({ format: 'binary' });
|
||||||
|
|
||||||
// 验证是Buffer类型
|
// 验证是Uint8Array类型
|
||||||
expect(Buffer.isBuffer(binaryData)).toBe(true);
|
expect(binaryData instanceof Uint8Array).toBe(true);
|
||||||
|
|
||||||
// JSON序列化对比
|
// JSON序列化对比
|
||||||
const jsonData = scene1.serialize({ format: 'json', pretty: false });
|
const jsonData = scene1.serialize({ format: 'json', pretty: false });
|
||||||
|
|
||||||
// 二进制应该更小
|
// 二进制应该更小
|
||||||
const binarySize = (binaryData as Buffer).length;
|
const binarySize = (binaryData as Uint8Array).length;
|
||||||
const jsonSize = (jsonData as string).length;
|
const jsonSize = (jsonData as string).length;
|
||||||
console.log(`Binary size: ${binarySize} bytes, JSON size: ${jsonSize} bytes`);
|
console.log(`Binary size: ${binarySize} bytes, JSON size: ${jsonSize} bytes`);
|
||||||
expect(binarySize).toBeLessThan(jsonSize);
|
expect(binarySize).toBeLessThan(jsonSize);
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ describe('WorldManager', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// WorldManager不再是单例,直接创建新实例
|
// WorldManager不再是单例,直接创建新实例
|
||||||
// 测试时不创建默认World
|
worldManager = new WorldManager();
|
||||||
worldManager = new WorldManager({ createDefaultWorld: false });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -60,8 +59,8 @@ describe('WorldManager', () => {
|
|||||||
|
|
||||||
describe('实例化', () => {
|
describe('实例化', () => {
|
||||||
test('可以创建多个独立的WorldManager实例', () => {
|
test('可以创建多个独立的WorldManager实例', () => {
|
||||||
const manager1 = new WorldManager({ createDefaultWorld: false });
|
const manager1 = new WorldManager();
|
||||||
const manager2 = new WorldManager({ createDefaultWorld: false });
|
const manager2 = new WorldManager();
|
||||||
|
|
||||||
expect(manager1).not.toBe(manager2);
|
expect(manager1).not.toBe(manager2);
|
||||||
|
|
||||||
@@ -77,8 +76,7 @@ describe('WorldManager', () => {
|
|||||||
const config: IWorldManagerConfig = {
|
const config: IWorldManagerConfig = {
|
||||||
maxWorlds: 10,
|
maxWorlds: 10,
|
||||||
autoCleanup: true,
|
autoCleanup: true,
|
||||||
debug: false,
|
debug: false
|
||||||
createDefaultWorld: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const instance = new WorldManager(config);
|
const instance = new WorldManager(config);
|
||||||
@@ -123,7 +121,7 @@ describe('WorldManager', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('超出最大World数量应该抛出错误', () => {
|
test('超出最大World数量应该抛出错误', () => {
|
||||||
const limitedManager = new WorldManager({ maxWorlds: 2, createDefaultWorld: false });
|
const limitedManager = new WorldManager({ maxWorlds: 2 });
|
||||||
|
|
||||||
limitedManager.createWorld('world1');
|
limitedManager.createWorld('world1');
|
||||||
limitedManager.createWorld('world2');
|
limitedManager.createWorld('world2');
|
||||||
@@ -430,8 +428,7 @@ describe('WorldManager', () => {
|
|||||||
const invalidConfig: IWorldManagerConfig = {
|
const invalidConfig: IWorldManagerConfig = {
|
||||||
maxWorlds: -1,
|
maxWorlds: -1,
|
||||||
autoCleanup: true,
|
autoCleanup: true,
|
||||||
debug: true,
|
debug: true
|
||||||
createDefaultWorld: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const manager = new WorldManager(invalidConfig);
|
const manager = new WorldManager(invalidConfig);
|
||||||
@@ -445,8 +442,7 @@ describe('WorldManager', () => {
|
|||||||
const config: IWorldManagerConfig = {
|
const config: IWorldManagerConfig = {
|
||||||
maxWorlds: 3,
|
maxWorlds: 3,
|
||||||
autoCleanup: true,
|
autoCleanup: true,
|
||||||
debug: true,
|
debug: true
|
||||||
createDefaultWorld: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const manager = new WorldManager(config);
|
const manager = new WorldManager(config);
|
||||||
|
|||||||
Reference in New Issue
Block a user