新增world概念(多world管理多scene概念)现在支持多个world多个scene同时更新

This commit is contained in:
YHH
2025-08-20 17:48:31 +08:00
parent 69616bbddc
commit a44251cc55
15 changed files with 3539 additions and 783 deletions

View 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();
});
});
});

View 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();
});
});
});

View 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');
});
});
});