新增world概念(多world管理多scene概念)现在支持多个world多个scene同时更新
This commit is contained in:
589
packages/core/tests/ECS/Core/WorldCoreIntegration.test.ts
Normal file
589
packages/core/tests/ECS/Core/WorldCoreIntegration.test.ts
Normal file
@@ -0,0 +1,589 @@
|
||||
import { Core } from '../../../src/Core';
|
||||
import { Scene } from '../../../src/ECS/Scene';
|
||||
import { World, IGlobalSystem } from '../../../src/ECS/World';
|
||||
import { WorldManager } from '../../../src/ECS/WorldManager';
|
||||
import { EntitySystem } from '../../../src/ECS/Systems/EntitySystem';
|
||||
import { Component } from '../../../src/ECS/Component';
|
||||
import { Matcher } from '../../../src/ECS/Utils/Matcher';
|
||||
import { Entity } from '../../../src/ECS/Entity';
|
||||
|
||||
// 测试用组件
|
||||
class TestComponent extends Component {
|
||||
public value: number = 0;
|
||||
|
||||
constructor(value: number = 0) {
|
||||
super();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class NetworkComponent extends Component {
|
||||
public playerId: string;
|
||||
|
||||
constructor(playerId: string) {
|
||||
super();
|
||||
this.playerId = playerId;
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.playerId = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用系统
|
||||
class TestGlobalSystem extends EntitySystem {
|
||||
public processedEntities: Entity[] = [];
|
||||
public updateCount: number = 0;
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty().all(TestComponent));
|
||||
}
|
||||
|
||||
protected override process(entities: Entity[]): void {
|
||||
this.processedEntities = [...entities];
|
||||
this.updateCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 正确的全局系统实现
|
||||
class NetworkSyncGlobalSystem implements IGlobalSystem {
|
||||
public readonly name = 'NetworkSyncSystem';
|
||||
public updateCount: number = 0;
|
||||
|
||||
public initialize(): void {
|
||||
// 初始化网络连接等
|
||||
}
|
||||
|
||||
public update(): void {
|
||||
this.updateCount++;
|
||||
// 同步网络数据等全局逻辑
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.updateCount = 0;
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
// 清理网络连接等
|
||||
}
|
||||
}
|
||||
|
||||
// Scene级别的EntitySystem(正确的用法)
|
||||
class NetworkSyncSystem extends EntitySystem {
|
||||
public syncCount: number = 0;
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty().all(NetworkComponent));
|
||||
}
|
||||
|
||||
protected override process(entities: Entity[]): void {
|
||||
this.syncCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// World级别的网络同步全局系统
|
||||
class NetworkGlobalSystem implements IGlobalSystem {
|
||||
public readonly name = 'NetworkGlobalSystem';
|
||||
public syncCount: number = 0;
|
||||
|
||||
public initialize(): void {
|
||||
// 初始化网络连接
|
||||
}
|
||||
|
||||
public update(): void {
|
||||
this.syncCount++;
|
||||
// 全局网络同步逻辑
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.syncCount = 0;
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
// 清理网络连接
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用Scene
|
||||
class TestScene extends Scene {
|
||||
public updateCallCount: number = 0;
|
||||
|
||||
public override update(): void {
|
||||
super.update();
|
||||
this.updateCallCount++;
|
||||
}
|
||||
}
|
||||
|
||||
describe('World与Core集成测试', () => {
|
||||
beforeEach(() => {
|
||||
// 重置Core和WorldManager
|
||||
if ((Core as any)._instance) {
|
||||
(Core as any)._instance = null;
|
||||
}
|
||||
WorldManager['_instance'] = null;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// 清理资源
|
||||
if ((Core as any)._instance) {
|
||||
const worldManager = Core.getWorldManager?.();
|
||||
if (worldManager) {
|
||||
const worldIds = worldManager.getWorldIds();
|
||||
worldIds.forEach(id => {
|
||||
worldManager.removeWorld(id);
|
||||
});
|
||||
}
|
||||
(Core as any)._instance = null;
|
||||
}
|
||||
WorldManager['_instance'] = null;
|
||||
});
|
||||
|
||||
describe('融合设计基础功能', () => {
|
||||
test('单Scene模式应该保持向后兼容', () => {
|
||||
Core.create({ debug: false });
|
||||
|
||||
// 传统单Scene用法
|
||||
const scene = new Scene();
|
||||
scene.name = 'TestScene';
|
||||
|
||||
Core.setScene(scene);
|
||||
|
||||
const retrievedScene = Core.getScene();
|
||||
expect(retrievedScene).toBe(scene);
|
||||
expect(retrievedScene?.name).toBe('TestScene');
|
||||
});
|
||||
|
||||
test('启用WorldManager后应该支持多World功能', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
expect(worldManager).toBeDefined();
|
||||
|
||||
const world = worldManager.createWorld('TestWorld');
|
||||
expect(world).toBeDefined();
|
||||
expect(world.name).toBe('TestWorld');
|
||||
});
|
||||
|
||||
test('getWorldManager应该自动创建WorldManager', () => {
|
||||
Core.create({ debug: false });
|
||||
|
||||
// 获取WorldManager会自动创建实例
|
||||
const worldManager = Core.getWorldManager();
|
||||
expect(worldManager).toBeDefined();
|
||||
|
||||
// 多次获取应该返回同一个实例
|
||||
const worldManager2 = Core.getWorldManager();
|
||||
expect(worldManager2).toBe(worldManager);
|
||||
});
|
||||
|
||||
test('单Scene模式下Core.update应该正常工作', () => {
|
||||
Core.create({ debug: false });
|
||||
|
||||
const scene = new TestScene();
|
||||
Core.setScene(scene);
|
||||
|
||||
// 模拟更新
|
||||
Core.update(0.016);
|
||||
|
||||
expect(scene.updateCallCount).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('默认World机制', () => {
|
||||
test('设置Scene应该自动创建默认World', () => {
|
||||
Core.create({ debug: false });
|
||||
|
||||
const scene = new Scene();
|
||||
Core.setScene(scene);
|
||||
|
||||
// 启用WorldManager后应该能看到默认World
|
||||
Core.enableWorldManager();
|
||||
const worldManager = Core.getWorldManager();
|
||||
|
||||
expect(worldManager.getWorld('__default__')).toBeDefined();
|
||||
|
||||
const defaultWorld = worldManager.getWorld('__default__');
|
||||
expect(defaultWorld).toBeDefined();
|
||||
expect(defaultWorld?.getScene('__main__')).toBe(scene);
|
||||
});
|
||||
|
||||
test('默认World的Scene应该正确激活', () => {
|
||||
Core.create({ debug: false });
|
||||
|
||||
const scene = new Scene();
|
||||
Core.setScene(scene);
|
||||
|
||||
Core.enableWorldManager();
|
||||
const worldManager = Core.getWorldManager();
|
||||
const defaultWorld = worldManager.getWorld('__default__');
|
||||
|
||||
expect(defaultWorld?.isSceneActive('__main__')).toBe(true);
|
||||
});
|
||||
|
||||
test('替换默认Scene应该正确处理', () => {
|
||||
Core.create({ debug: false });
|
||||
|
||||
const scene1 = new Scene();
|
||||
scene1.name = 'Scene1';
|
||||
Core.setScene(scene1);
|
||||
|
||||
const scene2 = new Scene();
|
||||
scene2.name = 'Scene2';
|
||||
Core.setScene(scene2);
|
||||
|
||||
const currentScene = Core.getScene();
|
||||
expect(currentScene).toBe(scene2);
|
||||
expect(currentScene?.name).toBe('Scene2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('多World更新机制', () => {
|
||||
test('Core.update应该更新所有活跃World', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
|
||||
// 创建多个World
|
||||
const world1 = worldManager.createWorld('World1');
|
||||
const world2 = worldManager.createWorld('World2');
|
||||
const world3 = worldManager.createWorld('World3');
|
||||
|
||||
// 为每个World创建Scene和System
|
||||
const scene1 = world1.createScene('scene1', new TestScene());
|
||||
const scene2 = world2.createScene('scene2', new TestScene());
|
||||
const scene3 = world3.createScene('scene3', new TestScene());
|
||||
|
||||
// 启动部分World
|
||||
worldManager.setWorldActive('World1', true);
|
||||
worldManager.setWorldActive('World2', true);
|
||||
// world3保持未启动
|
||||
|
||||
world1.setSceneActive('scene1', true);
|
||||
world2.setSceneActive('scene2', true);
|
||||
|
||||
// 执行更新
|
||||
Core.update(0.016);
|
||||
|
||||
// 检查只有激活的World被更新
|
||||
expect(scene1.updateCallCount).toBeGreaterThan(0);
|
||||
expect(scene2.updateCallCount).toBeGreaterThan(0);
|
||||
expect(scene3.updateCallCount).toBe(0);
|
||||
});
|
||||
|
||||
test('全局系统应该在Scene更新前执行', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
const world = worldManager.createWorld('TestWorld');
|
||||
|
||||
// 添加正确设计的全局系统(业务逻辑系统,不是EntitySystem)
|
||||
const globalSystem = new NetworkSyncGlobalSystem();
|
||||
world.addGlobalSystem(globalSystem);
|
||||
|
||||
// 创建Scene
|
||||
const scene = world.createScene('testScene');
|
||||
|
||||
worldManager.setWorldActive('TestWorld', true);
|
||||
world.setSceneActive('testScene', true);
|
||||
|
||||
// 执行更新
|
||||
Core.update(0.016);
|
||||
|
||||
// 验证全局System被正确更新
|
||||
expect(globalSystem.updateCount).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('多房间游戏服务器场景', () => {
|
||||
test('多个游戏房间应该独立运行', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
|
||||
// 创建两个游戏房间
|
||||
const room1 = worldManager.createWorld('Room_001');
|
||||
const room2 = worldManager.createWorld('Room_002');
|
||||
|
||||
// 为每个房间设置Scene
|
||||
const gameScene1 = room1.createScene('game');
|
||||
const gameScene2 = room2.createScene('game');
|
||||
|
||||
// 为每个房间添加全局网络系统
|
||||
const netSystem1 = new NetworkGlobalSystem();
|
||||
const netSystem2 = new NetworkGlobalSystem();
|
||||
|
||||
room1.addGlobalSystem(netSystem1);
|
||||
room2.addGlobalSystem(netSystem2);
|
||||
|
||||
// 在每个房间创建玩家
|
||||
const player1 = gameScene1.createEntity('Player1');
|
||||
player1.addComponent(new NetworkComponent('player_123'));
|
||||
|
||||
const player2 = gameScene2.createEntity('Player2');
|
||||
player2.addComponent(new NetworkComponent('player_456'));
|
||||
|
||||
// 启动房间
|
||||
worldManager.setWorldActive('Room_001', true);
|
||||
worldManager.setWorldActive('Room_002', true);
|
||||
room1.setSceneActive('game', true);
|
||||
room2.setSceneActive('game', true);
|
||||
|
||||
// 模拟游戏循环
|
||||
for (let i = 0; i < 5; i++) {
|
||||
Core.update(0.016);
|
||||
}
|
||||
|
||||
// 验证每个房间独立运行
|
||||
expect(netSystem1.syncCount).toBeGreaterThan(0);
|
||||
expect(netSystem2.syncCount).toBeGreaterThan(0);
|
||||
expect(room1.getActiveSceneCount()).toBe(1);
|
||||
expect(room2.getActiveSceneCount()).toBe(1);
|
||||
});
|
||||
|
||||
test('房间销毁应该完全清理资源', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
|
||||
// 创建房间
|
||||
const room = worldManager.createWorld('TempRoom');
|
||||
const scene = room.createScene('game');
|
||||
|
||||
// 添加内容
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const entity = scene.createEntity(`Entity${i}`);
|
||||
entity.addComponent(new TestComponent(i));
|
||||
}
|
||||
|
||||
room.addGlobalSystem(new NetworkSyncGlobalSystem());
|
||||
worldManager.setWorldActive('TempRoom', true);
|
||||
room.setSceneActive('game', true);
|
||||
|
||||
// 验证房间正常运行
|
||||
Core.update(0.016);
|
||||
|
||||
const beforeDestroy = worldManager.getStats();
|
||||
expect(beforeDestroy.totalWorlds).toBe(1);
|
||||
expect(beforeDestroy.activeWorlds).toBe(1);
|
||||
|
||||
// 销毁房间
|
||||
worldManager.removeWorld('TempRoom');
|
||||
|
||||
const afterDestroy = worldManager.getStats();
|
||||
expect(afterDestroy.totalWorlds).toBe(0);
|
||||
expect(afterDestroy.activeWorlds).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('客户端多层Scene架构', () => {
|
||||
test('分层Scene应该同时运行', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
const clientWorld = worldManager.createWorld('ClientWorld');
|
||||
|
||||
// 创建不同层的Scene
|
||||
const gameplayScene = clientWorld.createScene('gameplay', new TestScene());
|
||||
const uiScene = clientWorld.createScene('ui', new TestScene());
|
||||
const effectsScene = clientWorld.createScene('effects', new TestScene());
|
||||
|
||||
// 启动世界并激活所有Scene
|
||||
worldManager.setWorldActive('ClientWorld', true);
|
||||
clientWorld.setSceneActive('gameplay', true);
|
||||
clientWorld.setSceneActive('ui', true);
|
||||
clientWorld.setSceneActive('effects', true);
|
||||
|
||||
// 执行更新
|
||||
Core.update(0.016);
|
||||
|
||||
// 验证所有Scene都被更新
|
||||
expect(gameplayScene.updateCallCount).toBeGreaterThan(0);
|
||||
expect(uiScene.updateCallCount).toBeGreaterThan(0);
|
||||
expect(effectsScene.updateCallCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('Scene的动态激活和停用', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
const world = worldManager.createWorld('DynamicWorld');
|
||||
|
||||
const gameScene = world.createScene('game', new TestScene());
|
||||
const menuScene = world.createScene('menu', new TestScene());
|
||||
|
||||
worldManager.setWorldActive('DynamicWorld', true);
|
||||
|
||||
// 初始状态:只有游戏Scene激活
|
||||
world.setSceneActive('game', true);
|
||||
world.setSceneActive('menu', false);
|
||||
|
||||
Core.update(0.016);
|
||||
|
||||
const gameCount1 = gameScene.updateCallCount;
|
||||
const menuCount1 = menuScene.updateCallCount;
|
||||
|
||||
// 切换到菜单
|
||||
world.setSceneActive('game', false);
|
||||
world.setSceneActive('menu', true);
|
||||
|
||||
Core.update(0.016);
|
||||
|
||||
const gameCount2 = gameScene.updateCallCount;
|
||||
const menuCount2 = menuScene.updateCallCount;
|
||||
|
||||
// 验证Scene状态切换
|
||||
expect(gameCount2).toBe(gameCount1); // 游戏Scene停止更新
|
||||
expect(menuCount2).toBeGreaterThan(menuCount1); // 菜单Scene开始更新
|
||||
});
|
||||
});
|
||||
|
||||
describe('性能和稳定性', () => {
|
||||
test('大量World和Scene应该稳定运行', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
const worldCount = 20;
|
||||
const scenePerWorld = 3;
|
||||
|
||||
// 创建大量World和Scene
|
||||
for (let i = 0; i < worldCount; i++) {
|
||||
const world = worldManager.createWorld(`World${i}`);
|
||||
|
||||
for (let j = 0; j < scenePerWorld; j++) {
|
||||
const scene = world.createScene(`Scene${j}`, new TestScene());
|
||||
|
||||
// 添加一些实体
|
||||
for (let k = 0; k < 5; k++) {
|
||||
const entity = scene.createEntity(`Entity${k}`);
|
||||
entity.addComponent(new TestComponent(k));
|
||||
}
|
||||
|
||||
world.setSceneActive(`Scene${j}`, true);
|
||||
}
|
||||
|
||||
worldManager.setWorldActive(`World${i}`, true);
|
||||
}
|
||||
|
||||
// 验证所有资源创建成功
|
||||
expect(worldManager.getWorldIds()).toHaveLength(worldCount);
|
||||
expect(worldManager.getActiveWorlds()).toHaveLength(worldCount);
|
||||
|
||||
// 执行多次更新测试稳定性
|
||||
for (let i = 0; i < 10; i++) {
|
||||
expect(() => {
|
||||
Core.update(0.016);
|
||||
}).not.toThrow();
|
||||
}
|
||||
|
||||
// 验证更新正常工作
|
||||
const activeWorlds = worldManager.getActiveWorlds();
|
||||
activeWorlds.forEach(world => {
|
||||
const scenes = world.getAllScenes();
|
||||
scenes.forEach(scene => {
|
||||
if (scene instanceof TestScene && world.isSceneActive(scene.name)) {
|
||||
expect(scene.updateCallCount).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('频繁的World创建和销毁应该不影响性能', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
|
||||
// 频繁创建和销毁World
|
||||
for (let cycle = 0; cycle < 10; cycle++) {
|
||||
// 创建批次World
|
||||
const worldIds: string[] = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const worldId = `Cycle${cycle}_World${i}`;
|
||||
worldIds.push(worldId);
|
||||
|
||||
const world = worldManager.createWorld(worldId);
|
||||
const scene = world.createScene('test');
|
||||
scene.createEntity('entity');
|
||||
|
||||
worldManager.setWorldActive(worldId, true);
|
||||
world.setSceneActive('test', true);
|
||||
}
|
||||
|
||||
// 更新一次
|
||||
Core.update(0.016);
|
||||
|
||||
// 销毁批次World
|
||||
worldIds.forEach(id => {
|
||||
worldManager.removeWorld(id);
|
||||
});
|
||||
|
||||
// 验证清理完成
|
||||
expect(worldManager.getWorldIds()).toHaveLength(0);
|
||||
expect(worldManager.getActiveWorlds()).toHaveLength(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('错误处理和边界情况', () => {
|
||||
test('Core未初始化时操作应该抛出合适错误', () => {
|
||||
// getScene 会返回 null 而不是抛出错误
|
||||
expect(Core.getScene()).toBeNull();
|
||||
|
||||
expect(() => {
|
||||
Core.setScene(new Scene());
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
test('在World销毁后继续操作应该安全', () => {
|
||||
Core.create({ debug: false });
|
||||
Core.enableWorldManager();
|
||||
|
||||
const worldManager = Core.getWorldManager();
|
||||
const world = worldManager.createWorld('DestroyTest');
|
||||
|
||||
worldManager.setWorldActive('DestroyTest', true);
|
||||
worldManager.removeWorld('DestroyTest');
|
||||
|
||||
// 对已销毁的World进行操作应该不会崩溃
|
||||
expect(() => {
|
||||
world.updateGlobalSystems();
|
||||
world.updateScenes();
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
test('混合使用单Scene和多World模式', () => {
|
||||
Core.create({ debug: false });
|
||||
|
||||
// 直接启用WorldManager(避免先使用单Scene创建限制性配置)
|
||||
const worldManager = Core.getWorldManager();
|
||||
|
||||
// 然后使用单Scene模式
|
||||
const singleScene = new Scene();
|
||||
Core.setScene(singleScene);
|
||||
|
||||
// 验证默认World被创建
|
||||
expect(worldManager.getWorld('__default__')).toBeDefined();
|
||||
|
||||
// 创建额外的World
|
||||
const extraWorld = worldManager.createWorld('ExtraWorld');
|
||||
worldManager.setWorldActive('ExtraWorld', true);
|
||||
|
||||
// 两种模式应该能共存
|
||||
expect(() => {
|
||||
Core.update(0.016);
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
466
packages/core/tests/ECS/World.test.ts
Normal file
466
packages/core/tests/ECS/World.test.ts
Normal file
@@ -0,0 +1,466 @@
|
||||
import { World, IWorldConfig, IGlobalSystem } from '../../src/ECS/World';
|
||||
import { Scene } from '../../src/ECS/Scene';
|
||||
import { EntitySystem } from '../../src/ECS/Systems/EntitySystem';
|
||||
import { Entity } from '../../src/ECS/Entity';
|
||||
import { Component } from '../../src/ECS/Component';
|
||||
import { Matcher } from '../../src/ECS/Utils/Matcher';
|
||||
|
||||
// 测试用组件
|
||||
class TestComponent extends Component {
|
||||
public value: number = 0;
|
||||
|
||||
constructor(value: number = 0) {
|
||||
super();
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
class PlayerComponent extends Component {
|
||||
public playerId: string;
|
||||
|
||||
constructor(playerId: string) {
|
||||
super();
|
||||
this.playerId = playerId;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用全局系统
|
||||
class TestGlobalSystem implements IGlobalSystem {
|
||||
public readonly name = 'TestGlobalSystem';
|
||||
public updateCount: number = 0;
|
||||
|
||||
public initialize(): void {
|
||||
// 初始化逻辑
|
||||
}
|
||||
|
||||
public update(): void {
|
||||
this.updateCount++;
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.updateCount = 0;
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
// 销毁逻辑
|
||||
}
|
||||
}
|
||||
|
||||
class TestSceneSystem extends EntitySystem {
|
||||
public updateCount = 0;
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty().all(PlayerComponent));
|
||||
}
|
||||
|
||||
protected override process(): void {
|
||||
this.updateCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用Scene
|
||||
class TestScene extends Scene {
|
||||
public initializeCalled = false;
|
||||
public beginCalled = false;
|
||||
public endCalled = false;
|
||||
|
||||
public override initialize(): void {
|
||||
this.initializeCalled = true;
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
public override begin(): void {
|
||||
this.beginCalled = true;
|
||||
super.begin();
|
||||
}
|
||||
|
||||
public override end(): void {
|
||||
this.endCalled = true;
|
||||
super.end();
|
||||
}
|
||||
}
|
||||
|
||||
describe('World', () => {
|
||||
let world: World;
|
||||
|
||||
beforeEach(() => {
|
||||
world = new World({ name: 'TestWorld' });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (world) {
|
||||
world.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
describe('基础功能', () => {
|
||||
test('创建World时应该设置正确的配置', () => {
|
||||
const config: IWorldConfig = {
|
||||
name: 'GameWorld',
|
||||
debug: true,
|
||||
maxScenes: 5,
|
||||
autoCleanup: false
|
||||
};
|
||||
|
||||
const testWorld = new World(config);
|
||||
|
||||
expect(testWorld.name).toBe('GameWorld');
|
||||
expect(testWorld.sceneCount).toBe(0);
|
||||
expect(testWorld.isActive).toBe(false);
|
||||
expect(testWorld.createdAt).toBeGreaterThan(0);
|
||||
|
||||
testWorld.destroy();
|
||||
});
|
||||
|
||||
test('默认配置应该正确', () => {
|
||||
const defaultWorld = new World();
|
||||
|
||||
expect(defaultWorld.name).toBe('World');
|
||||
expect(defaultWorld.sceneCount).toBe(0);
|
||||
expect(defaultWorld.isActive).toBe(false);
|
||||
|
||||
defaultWorld.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Scene管理', () => {
|
||||
test('创建Scene应该成功', () => {
|
||||
const scene = world.createScene('test-scene');
|
||||
|
||||
expect(scene).toBeDefined();
|
||||
expect(world.sceneCount).toBe(1);
|
||||
expect(world.getSceneIds()).toContain('test-scene');
|
||||
});
|
||||
|
||||
test('创建Scene时传入自定义Scene实例', () => {
|
||||
const customScene = new TestScene();
|
||||
const scene = world.createScene('custom-scene', customScene);
|
||||
|
||||
expect(scene).toBe(customScene);
|
||||
expect(scene.initializeCalled).toBe(true);
|
||||
expect(world.sceneCount).toBe(1);
|
||||
});
|
||||
|
||||
test('重复的Scene ID应该抛出错误', () => {
|
||||
world.createScene('duplicate');
|
||||
|
||||
expect(() => {
|
||||
world.createScene('duplicate');
|
||||
}).toThrow("Scene ID 'duplicate' 已存在于World 'TestWorld' 中");
|
||||
});
|
||||
|
||||
test('超出最大Scene数量限制应该抛出错误', () => {
|
||||
const limitedWorld = new World({ maxScenes: 2 });
|
||||
|
||||
limitedWorld.createScene('scene1');
|
||||
limitedWorld.createScene('scene2');
|
||||
|
||||
expect(() => {
|
||||
limitedWorld.createScene('scene3');
|
||||
}).toThrow("World 'World' 已达到最大Scene数量限制: 2");
|
||||
|
||||
limitedWorld.destroy();
|
||||
});
|
||||
|
||||
test('获取Scene应该正确', () => {
|
||||
const scene = world.createScene('get-test');
|
||||
const retrievedScene = world.getScene('get-test');
|
||||
|
||||
expect(retrievedScene).toBe(scene);
|
||||
});
|
||||
|
||||
test('获取不存在的Scene应该返回null', () => {
|
||||
const scene = world.getScene('non-existent');
|
||||
expect(scene).toBeNull();
|
||||
});
|
||||
|
||||
test('移除Scene应该正确清理', () => {
|
||||
const testScene = new TestScene();
|
||||
world.createScene('remove-test', testScene);
|
||||
world.setSceneActive('remove-test', true);
|
||||
|
||||
const removed = world.removeScene('remove-test');
|
||||
|
||||
expect(removed).toBe(true);
|
||||
expect(world.sceneCount).toBe(0);
|
||||
expect(world.getScene('remove-test')).toBeNull();
|
||||
expect(testScene.endCalled).toBe(true);
|
||||
});
|
||||
|
||||
test('移除不存在的Scene应该返回false', () => {
|
||||
const removed = world.removeScene('non-existent');
|
||||
expect(removed).toBe(false);
|
||||
});
|
||||
|
||||
test('获取所有Scene应该正确', () => {
|
||||
const scene1 = world.createScene('scene1');
|
||||
const scene2 = world.createScene('scene2');
|
||||
|
||||
const allScenes = world.getAllScenes();
|
||||
|
||||
expect(allScenes).toHaveLength(2);
|
||||
expect(allScenes).toContain(scene1);
|
||||
expect(allScenes).toContain(scene2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Scene激活管理', () => {
|
||||
test('激活Scene应该正确', () => {
|
||||
const testScene = new TestScene();
|
||||
world.createScene('active-test', testScene);
|
||||
|
||||
world.setSceneActive('active-test', true);
|
||||
|
||||
expect(world.isSceneActive('active-test')).toBe(true);
|
||||
expect(world.getActiveSceneCount()).toBe(1);
|
||||
expect(testScene.beginCalled).toBe(true);
|
||||
});
|
||||
|
||||
test('停用Scene应该正确', () => {
|
||||
world.createScene('deactive-test');
|
||||
world.setSceneActive('deactive-test', true);
|
||||
|
||||
world.setSceneActive('deactive-test', false);
|
||||
|
||||
expect(world.isSceneActive('deactive-test')).toBe(false);
|
||||
expect(world.getActiveSceneCount()).toBe(0);
|
||||
});
|
||||
|
||||
test('激活不存在的Scene应该记录警告', () => {
|
||||
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
|
||||
|
||||
world.setSceneActive('non-existent', true);
|
||||
|
||||
// 注意:这里需要检查具体的日志实现,可能需要调整
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('全局System管理', () => {
|
||||
test('添加全局System应该成功', () => {
|
||||
const globalSystem = new TestGlobalSystem();
|
||||
|
||||
const addedSystem = world.addGlobalSystem(globalSystem);
|
||||
|
||||
expect(addedSystem).toBe(globalSystem);
|
||||
expect(world.getGlobalSystem(TestGlobalSystem)).toBe(globalSystem);
|
||||
});
|
||||
|
||||
test('重复添加相同System应该返回原System', () => {
|
||||
const globalSystem = new TestGlobalSystem();
|
||||
|
||||
const firstAdd = world.addGlobalSystem(globalSystem);
|
||||
const secondAdd = world.addGlobalSystem(globalSystem);
|
||||
|
||||
expect(firstAdd).toBe(secondAdd);
|
||||
expect(firstAdd).toBe(globalSystem);
|
||||
});
|
||||
|
||||
test('移除全局System应该成功', () => {
|
||||
const globalSystem = new TestGlobalSystem();
|
||||
world.addGlobalSystem(globalSystem);
|
||||
|
||||
const removed = world.removeGlobalSystem(globalSystem);
|
||||
|
||||
expect(removed).toBe(true);
|
||||
expect(world.getGlobalSystem(TestGlobalSystem)).toBeNull();
|
||||
});
|
||||
|
||||
test('移除不存在的System应该返回false', () => {
|
||||
const globalSystem = new TestGlobalSystem();
|
||||
|
||||
const removed = world.removeGlobalSystem(globalSystem);
|
||||
|
||||
expect(removed).toBe(false);
|
||||
});
|
||||
|
||||
test('获取不存在的System类型应该返回null', () => {
|
||||
const system = world.getGlobalSystem(TestGlobalSystem);
|
||||
expect(system).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('World生命周期', () => {
|
||||
test('启动World应该正确', () => {
|
||||
const globalSystem = new TestGlobalSystem();
|
||||
world.addGlobalSystem(globalSystem);
|
||||
|
||||
world.start();
|
||||
|
||||
expect(world.isActive).toBe(true);
|
||||
});
|
||||
|
||||
test('重复启动World应该无效果', () => {
|
||||
world.start();
|
||||
const firstActive = world.isActive;
|
||||
|
||||
world.start();
|
||||
|
||||
expect(world.isActive).toBe(firstActive);
|
||||
});
|
||||
|
||||
test('停止World应该停用所有Scene', () => {
|
||||
const testScene = new TestScene();
|
||||
world.createScene('stop-test', testScene);
|
||||
world.setSceneActive('stop-test', true);
|
||||
world.start();
|
||||
|
||||
world.stop();
|
||||
|
||||
expect(world.isActive).toBe(false);
|
||||
expect(world.isSceneActive('stop-test')).toBe(false);
|
||||
});
|
||||
|
||||
test('销毁World应该清理所有资源', () => {
|
||||
const testScene = new TestScene();
|
||||
const globalSystem = new TestGlobalSystem();
|
||||
|
||||
world.createScene('destroy-test', testScene);
|
||||
world.addGlobalSystem(globalSystem);
|
||||
world.start();
|
||||
|
||||
world.destroy();
|
||||
|
||||
expect(world.sceneCount).toBe(0);
|
||||
expect(world.isActive).toBe(false);
|
||||
expect(testScene.endCalled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('更新逻辑', () => {
|
||||
test('updateGlobalSystems应该更新全局系统', () => {
|
||||
const globalSystem = new TestGlobalSystem();
|
||||
world.addGlobalSystem(globalSystem);
|
||||
world.start();
|
||||
|
||||
// 创建测试Scene
|
||||
const scene = world.createScene('update-test');
|
||||
world.setSceneActive('update-test', true);
|
||||
|
||||
// 直接测试全局系统更新
|
||||
world.updateGlobalSystems();
|
||||
|
||||
// 验证全局System被正确调用
|
||||
expect(globalSystem.updateCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('未激活的World不应该更新', () => {
|
||||
const globalSystem = new TestGlobalSystem();
|
||||
world.addGlobalSystem(globalSystem);
|
||||
// 不启动World
|
||||
|
||||
world.updateGlobalSystems();
|
||||
|
||||
expect(globalSystem.updateCount).toBe(0);
|
||||
});
|
||||
|
||||
test('updateScenes应该更新激活的Scene', () => {
|
||||
const scene1 = world.createScene('scene1');
|
||||
const scene2 = world.createScene('scene2');
|
||||
|
||||
scene1.addEntityProcessor(new TestSceneSystem());
|
||||
scene2.addEntityProcessor(new TestSceneSystem());
|
||||
|
||||
world.start();
|
||||
world.setSceneActive('scene1', true);
|
||||
// scene2保持未激活
|
||||
|
||||
world.updateScenes();
|
||||
|
||||
// 这里需要根据具体的Scene更新实现来验证
|
||||
// 由于Scene.update()的具体实现可能不同,这里主要测试调用不出错
|
||||
expect(() => world.updateScenes()).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('状态和统计', () => {
|
||||
test('获取World状态应该正确', () => {
|
||||
world.createScene('status-scene1');
|
||||
world.createScene('status-scene2');
|
||||
world.setSceneActive('status-scene1', true);
|
||||
world.addGlobalSystem(new TestGlobalSystem());
|
||||
world.start();
|
||||
|
||||
const status = world.getStatus();
|
||||
|
||||
expect(status.name).toBe('TestWorld');
|
||||
expect(status.isActive).toBe(true);
|
||||
expect(status.sceneCount).toBe(2);
|
||||
expect(status.activeSceneCount).toBe(1);
|
||||
expect(status.globalSystemCount).toBe(1);
|
||||
expect(status.createdAt).toBeGreaterThan(0);
|
||||
expect(status.scenes).toHaveLength(2);
|
||||
|
||||
const activeScene = status.scenes.find(s => s.id === 'status-scene1');
|
||||
expect(activeScene?.isActive).toBe(true);
|
||||
|
||||
const inactiveScene = status.scenes.find(s => s.id === 'status-scene2');
|
||||
expect(inactiveScene?.isActive).toBe(false);
|
||||
});
|
||||
|
||||
test('获取World统计应该包含基本信息', () => {
|
||||
world.addGlobalSystem(new TestGlobalSystem());
|
||||
|
||||
const scene = world.createScene('stats-scene');
|
||||
const entity = scene.createEntity('stats-entity');
|
||||
entity.addComponent(new TestComponent());
|
||||
|
||||
const stats = world.getStats();
|
||||
|
||||
expect(stats).toHaveProperty('totalEntities');
|
||||
expect(stats).toHaveProperty('totalSystems');
|
||||
expect(stats).toHaveProperty('memoryUsage');
|
||||
expect(stats).toHaveProperty('performance');
|
||||
expect(stats.totalSystems).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('自动清理功能', () => {
|
||||
test('自动清理应该移除空闲Scene', async () => {
|
||||
// 创建一个启用自动清理的World
|
||||
const autoCleanWorld = new World({
|
||||
name: 'AutoCleanWorld',
|
||||
autoCleanup: true,
|
||||
maxScenes: 10
|
||||
});
|
||||
|
||||
// 创建一个空Scene
|
||||
autoCleanWorld.createScene('empty-scene');
|
||||
autoCleanWorld.start();
|
||||
|
||||
// 手动触发清理检查
|
||||
autoCleanWorld.updateScenes();
|
||||
|
||||
// 由于清理策略基于时间,这里主要测试不会出错
|
||||
expect(() => autoCleanWorld.updateScenes()).not.toThrow();
|
||||
|
||||
autoCleanWorld.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('错误处理', () => {
|
||||
test('Scene ID为空时应该创建默认ID', () => {
|
||||
expect(() => {
|
||||
world.createScene('');
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
test('极限情况下的资源管理', () => {
|
||||
// 创建大量Scene
|
||||
for (let i = 0; i < 5; i++) {
|
||||
world.createScene(`scene_${i}`);
|
||||
world.setSceneActive(`scene_${i}`, true);
|
||||
}
|
||||
|
||||
// 添加多个全局System
|
||||
for (let i = 0; i < 3; i++) {
|
||||
world.addGlobalSystem(new TestGlobalSystem());
|
||||
}
|
||||
|
||||
world.start();
|
||||
|
||||
// 测试批量清理
|
||||
expect(() => world.destroy()).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
464
packages/core/tests/ECS/WorldManager.test.ts
Normal file
464
packages/core/tests/ECS/WorldManager.test.ts
Normal file
@@ -0,0 +1,464 @@
|
||||
import { WorldManager, IWorldManagerConfig } from '../../src/ECS/WorldManager';
|
||||
import { World, IWorldConfig } from '../../src/ECS/World';
|
||||
import { Scene } from '../../src/ECS/Scene';
|
||||
import { EntitySystem } from '../../src/ECS/Systems/EntitySystem';
|
||||
import { Component } from '../../src/ECS/Component';
|
||||
import { Matcher } from '../../src/ECS/Utils/Matcher';
|
||||
|
||||
// 测试用组件
|
||||
class TestComponent extends Component {
|
||||
public value: number = 0;
|
||||
|
||||
constructor(value: number = 0) {
|
||||
super();
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用全局系统
|
||||
class TestGlobalSystem {
|
||||
public readonly name = 'TestGlobalSystem';
|
||||
public updateCount: number = 0;
|
||||
|
||||
public initialize(): void {
|
||||
// 初始化
|
||||
}
|
||||
|
||||
public update(): void {
|
||||
this.updateCount++;
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.updateCount = 0;
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
// 销毁
|
||||
}
|
||||
}
|
||||
|
||||
describe('WorldManager', () => {
|
||||
let worldManager: WorldManager;
|
||||
|
||||
beforeEach(() => {
|
||||
// 重置单例
|
||||
WorldManager['_instance'] = null;
|
||||
worldManager = WorldManager.getInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// 清理所有World
|
||||
if (worldManager) {
|
||||
const worldIds = worldManager.getWorldIds();
|
||||
worldIds.forEach(id => {
|
||||
worldManager.removeWorld(id);
|
||||
});
|
||||
// 清理定时器
|
||||
worldManager.destroy();
|
||||
}
|
||||
WorldManager['_instance'] = null;
|
||||
});
|
||||
|
||||
describe('单例模式', () => {
|
||||
test('获取实例应该返回相同的实例', () => {
|
||||
const instance1 = WorldManager.getInstance();
|
||||
const instance2 = WorldManager.getInstance();
|
||||
|
||||
expect(instance1).toBe(instance2);
|
||||
});
|
||||
|
||||
test('使用配置创建实例应该正确', () => {
|
||||
WorldManager['_instance'] = null;
|
||||
|
||||
const config: IWorldManagerConfig = {
|
||||
maxWorlds: 10,
|
||||
autoCleanup: true,
|
||||
debug: false
|
||||
};
|
||||
|
||||
const instance = WorldManager.getInstance(config);
|
||||
|
||||
expect(instance).toBeDefined();
|
||||
expect(instance).toBe(WorldManager.getInstance());
|
||||
});
|
||||
});
|
||||
|
||||
describe('World管理', () => {
|
||||
test('创建World应该成功', () => {
|
||||
const world = worldManager.createWorld('test-world');
|
||||
|
||||
expect(world).toBeDefined();
|
||||
expect(world.name).toBe('test-world');
|
||||
expect(worldManager.getWorld('test-world')).toBeDefined();
|
||||
expect(worldManager.getWorldIds()).toContain('test-world');
|
||||
});
|
||||
|
||||
test('创建World时传入配置应该正确', () => {
|
||||
const worldConfig: IWorldConfig = {
|
||||
name: 'ConfiguredWorld',
|
||||
debug: true,
|
||||
maxScenes: 5,
|
||||
autoCleanup: false
|
||||
};
|
||||
|
||||
const world = worldManager.createWorld('configured-world', worldConfig);
|
||||
|
||||
expect(world.name).toBe('ConfiguredWorld');
|
||||
});
|
||||
|
||||
test('重复的World ID应该抛出错误', () => {
|
||||
worldManager.createWorld('duplicate-world');
|
||||
|
||||
expect(() => {
|
||||
worldManager.createWorld('duplicate-world');
|
||||
}).toThrow("World ID 'duplicate-world' 已存在");
|
||||
});
|
||||
|
||||
test('超出最大World数量应该抛出错误', () => {
|
||||
WorldManager['_instance'] = null;
|
||||
const limitedManager = WorldManager.getInstance({ maxWorlds: 2 });
|
||||
|
||||
limitedManager.createWorld('world1');
|
||||
limitedManager.createWorld('world2');
|
||||
|
||||
expect(() => {
|
||||
limitedManager.createWorld('world3');
|
||||
}).toThrow("已达到最大World数量限制: 2");
|
||||
|
||||
// 清理
|
||||
limitedManager.removeWorld('world1');
|
||||
limitedManager.removeWorld('world2');
|
||||
});
|
||||
|
||||
test('获取World应该正确', () => {
|
||||
const world = worldManager.createWorld('get-world');
|
||||
const retrievedWorld = worldManager.getWorld('get-world');
|
||||
|
||||
expect(retrievedWorld).toBe(world);
|
||||
});
|
||||
|
||||
test('获取不存在的World应该返回null', () => {
|
||||
const world = worldManager.getWorld('non-existent');
|
||||
expect(world).toBeNull();
|
||||
});
|
||||
|
||||
test('检查World存在性应该正确', () => {
|
||||
expect(worldManager.getWorld('non-existent')).toBeNull();
|
||||
|
||||
worldManager.createWorld('exists');
|
||||
expect(worldManager.getWorld('exists')).toBeDefined();
|
||||
});
|
||||
|
||||
test('销毁World应该正确清理', () => {
|
||||
const world = worldManager.createWorld('destroy-world');
|
||||
world.start();
|
||||
|
||||
const destroyed = worldManager.removeWorld('destroy-world');
|
||||
|
||||
expect(destroyed).toBe(true);
|
||||
expect(worldManager.getWorld('destroy-world')).toBeNull();
|
||||
});
|
||||
|
||||
test('销毁不存在的World应该返回false', () => {
|
||||
const destroyed = worldManager.removeWorld('non-existent');
|
||||
expect(destroyed).toBe(false);
|
||||
});
|
||||
|
||||
test('获取所有World ID应该正确', () => {
|
||||
worldManager.createWorld('world1');
|
||||
worldManager.createWorld('world2');
|
||||
worldManager.createWorld('world3');
|
||||
|
||||
const worldIds = worldManager.getWorldIds();
|
||||
|
||||
expect(worldIds).toHaveLength(3);
|
||||
expect(worldIds).toContain('world1');
|
||||
expect(worldIds).toContain('world2');
|
||||
expect(worldIds).toContain('world3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('活跃World管理', () => {
|
||||
test('启动World应该加入活跃列表', () => {
|
||||
const world = worldManager.createWorld('active-world');
|
||||
|
||||
worldManager.setWorldActive('active-world', true);
|
||||
|
||||
const activeWorlds = worldManager.getActiveWorlds();
|
||||
expect(activeWorlds).toHaveLength(1);
|
||||
expect(activeWorlds[0]).toBe(world);
|
||||
});
|
||||
|
||||
test('停止World应该从活跃列表移除', () => {
|
||||
const world = worldManager.createWorld('inactive-world');
|
||||
worldManager.setWorldActive('inactive-world', true);
|
||||
|
||||
worldManager.setWorldActive('inactive-world', false);
|
||||
|
||||
const activeWorlds = worldManager.getActiveWorlds();
|
||||
expect(activeWorlds).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('销毁激活的World应该从活跃列表移除', () => {
|
||||
const world = worldManager.createWorld('destroy-active');
|
||||
worldManager.setWorldActive('destroy-active', true);
|
||||
|
||||
worldManager.removeWorld('destroy-active');
|
||||
|
||||
const activeWorlds = worldManager.getActiveWorlds();
|
||||
expect(activeWorlds).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('多个World的激活状态应该独立管理', () => {
|
||||
const world1 = worldManager.createWorld('world1');
|
||||
const world2 = worldManager.createWorld('world2');
|
||||
const world3 = worldManager.createWorld('world3');
|
||||
|
||||
worldManager.setWorldActive('world1', true);
|
||||
worldManager.setWorldActive('world3', true);
|
||||
// world2 保持未启动
|
||||
|
||||
const activeWorlds = worldManager.getActiveWorlds();
|
||||
|
||||
expect(activeWorlds).toHaveLength(2);
|
||||
expect(activeWorlds).toContain(world1);
|
||||
expect(activeWorlds).toContain(world3);
|
||||
expect(activeWorlds).not.toContain(world2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('统计和监控', () => {
|
||||
test('获取WorldManager状态应该正确', () => {
|
||||
worldManager.createWorld('status-world1');
|
||||
const world2 = worldManager.createWorld('status-world2');
|
||||
worldManager.setWorldActive('status-world2', true);
|
||||
|
||||
const status = worldManager.getStats();
|
||||
|
||||
expect(status.totalWorlds).toBe(2);
|
||||
expect(status.activeWorlds).toBe(1);
|
||||
expect(status.config.maxWorlds).toBeGreaterThan(0);
|
||||
expect(status.memoryUsage).toBeGreaterThanOrEqual(0);
|
||||
expect(status.isRunning).toBeDefined();
|
||||
});
|
||||
|
||||
test('获取所有World统计应该包含详细信息', () => {
|
||||
const world1 = worldManager.createWorld('stats-world1');
|
||||
const world2 = worldManager.createWorld('stats-world2');
|
||||
|
||||
// 为world1添加一些内容
|
||||
const scene1 = world1.createScene('scene1');
|
||||
scene1.createEntity('entity1');
|
||||
worldManager.setWorldActive('stats-world1', true);
|
||||
|
||||
// world2保持空
|
||||
|
||||
const allStats = worldManager.getDetailedStatus().worlds;
|
||||
|
||||
expect(allStats).toHaveLength(2);
|
||||
|
||||
const world1Stats = allStats.find(stat => stat.id === 'stats-world1');
|
||||
const world2Stats = allStats.find(stat => stat.id === 'stats-world2');
|
||||
|
||||
expect(world1Stats).toBeDefined();
|
||||
expect(world2Stats).toBeDefined();
|
||||
expect(world1Stats?.isActive).toBe(true);
|
||||
expect(world2Stats?.isActive).toBe(false);
|
||||
});
|
||||
|
||||
test('空WorldManager的统计应该正确', () => {
|
||||
const status = worldManager.getStats();
|
||||
const allStats = worldManager.getDetailedStatus().worlds;
|
||||
|
||||
expect(status.totalWorlds).toBe(0);
|
||||
expect(status.activeWorlds).toBe(0);
|
||||
expect(allStats).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('清理功能', () => {
|
||||
test('清理空闲World应该移除符合条件的World', () => {
|
||||
// 创建一个空的World
|
||||
const emptyWorld = worldManager.createWorld('empty-world');
|
||||
|
||||
// 创建一个有内容的World
|
||||
const fullWorld = worldManager.createWorld('full-world');
|
||||
const scene = fullWorld.createScene('scene');
|
||||
scene.createEntity('entity');
|
||||
fullWorld.start();
|
||||
|
||||
// 执行清理
|
||||
const cleanedCount = worldManager.cleanup();
|
||||
|
||||
// 由于清理逻辑可能基于时间或其他条件,这里主要测试不会出错
|
||||
expect(cleanedCount).toBeGreaterThanOrEqual(0);
|
||||
expect(() => worldManager.cleanup()).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('World更新协调', () => {
|
||||
test('更新所有活跃World应该正确', () => {
|
||||
const world1 = worldManager.createWorld('update-world1');
|
||||
const world2 = worldManager.createWorld('update-world2');
|
||||
const world3 = worldManager.createWorld('update-world3');
|
||||
|
||||
// 添加一些内容到World中
|
||||
const scene1 = world1.createScene('scene1');
|
||||
const scene2 = world2.createScene('scene2');
|
||||
|
||||
scene1.createEntity('entity1');
|
||||
scene2.createEntity('entity2');
|
||||
|
||||
// 启动部分World
|
||||
worldManager.setWorldActive('update-world1', true);
|
||||
worldManager.setWorldActive('update-world2', true);
|
||||
// world3保持未启动
|
||||
|
||||
// 手动调用更新(通常由Core.update()调用)
|
||||
const activeWorlds = worldManager.getActiveWorlds();
|
||||
|
||||
expect(() => {
|
||||
activeWorlds.forEach(world => {
|
||||
world.updateGlobalSystems();
|
||||
world.updateScenes();
|
||||
});
|
||||
}).not.toThrow();
|
||||
|
||||
expect(activeWorlds).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('边界情况和错误处理', () => {
|
||||
test('World ID为空字符串应该抛出错误', () => {
|
||||
expect(() => {
|
||||
worldManager.createWorld('');
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
test('World ID为null或undefined应该抛出错误', () => {
|
||||
expect(() => {
|
||||
worldManager.createWorld(null as any);
|
||||
}).toThrow();
|
||||
|
||||
expect(() => {
|
||||
worldManager.createWorld(undefined as any);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
test('极限情况下的大量World管理', () => {
|
||||
const worldCount = 50;
|
||||
const worldIds: string[] = [];
|
||||
|
||||
// 创建大量World
|
||||
for (let i = 0; i < worldCount; i++) {
|
||||
const worldId = `mass-world-${i}`;
|
||||
worldIds.push(worldId);
|
||||
|
||||
expect(() => {
|
||||
worldManager.createWorld(worldId);
|
||||
}).not.toThrow();
|
||||
}
|
||||
|
||||
expect(worldManager.getWorldIds()).toHaveLength(worldCount);
|
||||
|
||||
// 启动一半的World
|
||||
for (let i = 0; i < worldCount / 2; i++) {
|
||||
worldManager.setWorldActive(worldIds[i], true);
|
||||
}
|
||||
|
||||
expect(worldManager.getActiveWorlds()).toHaveLength(worldCount / 2);
|
||||
|
||||
// 批量清理
|
||||
worldIds.forEach(id => {
|
||||
expect(() => {
|
||||
worldManager.removeWorld(id);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
expect(worldManager.getWorldIds()).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('销毁后获取World应该返回null', () => {
|
||||
worldManager.createWorld('temp-world');
|
||||
worldManager.removeWorld('temp-world');
|
||||
|
||||
expect(worldManager.getWorld('temp-world')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('内存管理', () => {
|
||||
test('销毁所有World后内存应该被释放', () => {
|
||||
// 创建多个World并添加内容
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const world = worldManager.createWorld(`memory-world-${i}`);
|
||||
const scene = world.createScene('scene');
|
||||
|
||||
// 添加一些实体和系统
|
||||
for (let j = 0; j < 5; j++) {
|
||||
const entity = scene.createEntity(`entity-${j}`);
|
||||
entity.addComponent(new TestComponent(j));
|
||||
}
|
||||
|
||||
world.addGlobalSystem(new TestGlobalSystem());
|
||||
worldManager.setWorldActive(`memory-world-${i}`, true);
|
||||
}
|
||||
|
||||
const beforeCleanup = worldManager.getStats();
|
||||
expect(beforeCleanup.totalWorlds).toBe(10);
|
||||
expect(beforeCleanup.activeWorlds).toBe(10);
|
||||
|
||||
// 清理所有World
|
||||
const worldIds = worldManager.getWorldIds();
|
||||
worldIds.forEach(id => {
|
||||
worldManager.removeWorld(id);
|
||||
});
|
||||
|
||||
const afterCleanup = worldManager.getStats();
|
||||
expect(afterCleanup.totalWorlds).toBe(0);
|
||||
expect(afterCleanup.activeWorlds).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('配置验证', () => {
|
||||
test('无效的maxWorlds配置应该使用默认值', () => {
|
||||
WorldManager['_instance'] = null;
|
||||
|
||||
const invalidConfig: IWorldManagerConfig = {
|
||||
maxWorlds: -1,
|
||||
autoCleanup: true,
|
||||
debug: true
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
WorldManager.getInstance(invalidConfig);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
test('配置更新应该影响后续操作', () => {
|
||||
WorldManager['_instance'] = null;
|
||||
|
||||
const config: IWorldManagerConfig = {
|
||||
maxWorlds: 3,
|
||||
autoCleanup: true,
|
||||
debug: true
|
||||
};
|
||||
|
||||
const manager = WorldManager.getInstance(config);
|
||||
|
||||
// 创建到限制数量的World
|
||||
manager.createWorld('world1');
|
||||
manager.createWorld('world2');
|
||||
manager.createWorld('world3');
|
||||
|
||||
// 第四个应该失败
|
||||
expect(() => {
|
||||
manager.createWorld('world4');
|
||||
}).toThrow();
|
||||
|
||||
// 清理
|
||||
manager.removeWorld('world1');
|
||||
manager.removeWorld('world2');
|
||||
manager.removeWorld('world3');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user