refactor(core): 统一参数命名 - worldId/sceneId 改为 worldName/sceneName (#225)

* refactor(core): 统一参数命名 - worldId/sceneId 改为 worldName/sceneName

* test(core): 更新测试用例以匹配新的错误消息

* refactor(core): 提高代码覆盖率 - 添加参数验证和测试
This commit is contained in:
YHH
2025-11-15 00:20:17 +08:00
committed by GitHub
parent af49870084
commit eac660b1a0
6 changed files with 116 additions and 84 deletions

View File

@@ -136,9 +136,13 @@ export class World {
/** /**
* 创建并添加Scene到World * 创建并添加Scene到World
*/ */
public createScene<T extends IScene>(sceneId: string, sceneInstance?: T): T { public createScene<T extends IScene>(sceneName: string, sceneInstance?: T): T {
if (this._scenes.has(sceneId)) { if (!sceneName || typeof sceneName !== 'string' || sceneName.trim() === '') {
throw new Error(`Scene ID '${sceneId}' 已存在于World '${this.name}' 中`); throw new Error('Scene name不能为空');
}
if (this._scenes.has(sceneName)) {
throw new Error(`Scene name '${sceneName}' 已存在于World '${this.name}' 中`);
} }
if (this._scenes.size >= this._config.maxScenes!) { if (this._scenes.size >= this._config.maxScenes!) {
@@ -157,13 +161,13 @@ export class World {
// 设置Scene的标识 // 设置Scene的标识
if ('id' in scene) { if ('id' in scene) {
(scene as any).id = sceneId; (scene as any).id = sceneName;
} }
if ('name' in scene && !scene.name) { if ('name' in scene && !scene.name) {
scene.name = sceneId; scene.name = sceneName;
} }
this._scenes.set(sceneId, scene); this._scenes.set(sceneName, scene);
// 初始化Scene // 初始化Scene
scene.initialize(); scene.initialize();
@@ -174,30 +178,30 @@ export class World {
/** /**
* 移除Scene * 移除Scene
*/ */
public removeScene(sceneId: string): boolean { public removeScene(sceneName: string): boolean {
const scene = this._scenes.get(sceneId); const scene = this._scenes.get(sceneName);
if (!scene) { if (!scene) {
return false; return false;
} }
// 如果Scene正在运行先停止它 // 如果Scene正在运行先停止它
if (this._activeScenes.has(sceneId)) { if (this._activeScenes.has(sceneName)) {
this.setSceneActive(sceneId, false); this.setSceneActive(sceneName, false);
} }
// 清理Scene资源 // 清理Scene资源
scene.end(); scene.end();
this._scenes.delete(sceneId); this._scenes.delete(sceneName);
logger.info(`从World '${this.name}' 中移除Scene: ${sceneId}`); logger.info(`从World '${this.name}' 中移除Scene: ${sceneName}`);
return true; return true;
} }
/** /**
* 获取Scene * 获取Scene
*/ */
public getScene<T extends IScene>(sceneId: string): T | null { public getScene<T extends IScene>(sceneName: string): T | null {
return this._scenes.get(sceneId) as T || null; return this._scenes.get(sceneName) as T || null;
} }
/** /**
@@ -218,9 +222,9 @@ export class World {
* 移除所有Scene * 移除所有Scene
*/ */
public removeAllScenes(): void { public removeAllScenes(): void {
const sceneIds = Array.from(this._scenes.keys()); const sceneNames = Array.from(this._scenes.keys());
for (const sceneId of sceneIds) { for (const sceneName of sceneNames) {
this.removeScene(sceneId); this.removeScene(sceneName);
} }
logger.info(`从World '${this.name}' 中移除所有Scene`); logger.info(`从World '${this.name}' 中移除所有Scene`);
} }
@@ -228,32 +232,32 @@ export class World {
/** /**
* 设置Scene激活状态 * 设置Scene激活状态
*/ */
public setSceneActive(sceneId: string, active: boolean): void { public setSceneActive(sceneName: string, active: boolean): void {
const scene = this._scenes.get(sceneId); const scene = this._scenes.get(sceneName);
if (!scene) { if (!scene) {
logger.warn(`Scene '${sceneId}' 不存在于World '${this.name}' 中`); logger.warn(`Scene '${sceneName}' 不存在于World '${this.name}' 中`);
return; return;
} }
if (active) { if (active) {
this._activeScenes.add(sceneId); this._activeScenes.add(sceneName);
// 启动Scene // 启动Scene
if (scene.begin) { if (scene.begin) {
scene.begin(); scene.begin();
} }
logger.debug(`在World '${this.name}' 中激活Scene: ${sceneId}`); logger.debug(`在World '${this.name}' 中激活Scene: ${sceneName}`);
} else { } else {
this._activeScenes.delete(sceneId); this._activeScenes.delete(sceneName);
// 可选择性地停止Scene或者让它继续运行但不更新 // 可选择性地停止Scene或者让它继续运行但不更新
logger.debug(`在World '${this.name}' 中停用Scene: ${sceneId}`); logger.debug(`在World '${this.name}' 中停用Scene: ${sceneName}`);
} }
} }
/** /**
* 检查Scene是否激活 * 检查Scene是否激活
*/ */
public isSceneActive(sceneId: string): boolean { public isSceneActive(sceneName: string): boolean {
return this._activeScenes.has(sceneId); return this._activeScenes.has(sceneName);
} }
/** /**
@@ -344,8 +348,8 @@ export class World {
} }
// 停止所有Scene // 停止所有Scene
for (const sceneId of this._activeScenes) { for (const sceneName of this._activeScenes) {
this.setSceneActive(sceneId, false); this.setSceneActive(sceneName, false);
} }
// 重置所有全局System // 重置所有全局System
@@ -386,8 +390,8 @@ export class World {
} }
// 更新所有激活的Scene // 更新所有激活的Scene
for (const sceneId of this._activeScenes) { for (const sceneName of this._activeScenes) {
const scene = this._scenes.get(sceneId); const scene = this._scenes.get(sceneName);
if (scene && scene.update) { if (scene && scene.update) {
scene.update(); scene.update();
} }
@@ -409,9 +413,9 @@ export class World {
this.stop(); this.stop();
// 销毁所有Scene // 销毁所有Scene
const sceneIds = Array.from(this._scenes.keys()); const sceneNames = Array.from(this._scenes.keys());
for (const sceneId of sceneIds) { for (const sceneName of sceneNames) {
this.removeScene(sceneId); this.removeScene(sceneName);
} }
// 清理全局System // 清理全局System
@@ -445,10 +449,10 @@ export class World {
globalSystemCount: this._globalSystems.length, globalSystemCount: this._globalSystems.length,
createdAt: this._createdAt, createdAt: this._createdAt,
config: { ...this._config }, config: { ...this._config },
scenes: Array.from(this._scenes.keys()).map((sceneId) => ({ scenes: Array.from(this._scenes.keys()).map((sceneName) => ({
id: sceneId, id: sceneName,
isActive: this._activeScenes.has(sceneId), isActive: this._activeScenes.has(sceneName),
name: this._scenes.get(sceneId)?.name || sceneId name: this._scenes.get(sceneName)?.name || sceneName
})) }))
}; };
} }
@@ -490,8 +494,8 @@ export class World {
const currentTime = Date.now(); const currentTime = Date.now();
const cleanupThreshold = 5 * 60 * 1000; // 5分钟 const cleanupThreshold = 5 * 60 * 1000; // 5分钟
for (const [sceneId, scene] of this._scenes) { for (const [sceneName, scene] of this._scenes) {
if (!this._activeScenes.has(sceneId) && if (!this._activeScenes.has(sceneName) &&
scene.entities && scene.entities &&
scene.entities.count === 0 && scene.entities.count === 0 &&
(currentTime - this._createdAt) > cleanupThreshold) { (currentTime - this._createdAt) > cleanupThreshold) {
@@ -506,20 +510,20 @@ export class World {
* 执行清理操作 * 执行清理操作
*/ */
private cleanup(): void { private cleanup(): void {
const sceneIds = Array.from(this._scenes.keys()); const sceneNames = Array.from(this._scenes.keys());
const currentTime = Date.now(); const currentTime = Date.now();
const cleanupThreshold = 5 * 60 * 1000; // 5分钟 const cleanupThreshold = 5 * 60 * 1000; // 5分钟
for (const sceneId of sceneIds) { for (const sceneName of sceneNames) {
const scene = this._scenes.get(sceneId); const scene = this._scenes.get(sceneName);
if (scene && if (scene &&
!this._activeScenes.has(sceneId) && !this._activeScenes.has(sceneName) &&
scene.entities && scene.entities &&
scene.entities.count === 0 && scene.entities.count === 0 &&
(currentTime - this._createdAt) > cleanupThreshold) { (currentTime - this._createdAt) > cleanupThreshold) {
this.removeScene(sceneId); this.removeScene(sceneName);
logger.debug(`自动清理空Scene: ${sceneId} from World ${this.name}`); logger.debug(`自动清理空Scene: ${sceneName} from World ${this.name}`);
} }
} }
} }

View File

@@ -92,13 +92,13 @@ export class WorldManager implements IService {
/** /**
* 创建新World * 创建新World
*/ */
public createWorld(worldId: string, config?: IWorldConfig): World { public createWorld(worldName: string, config?: IWorldConfig): World {
if (!worldId || typeof worldId !== 'string' || worldId.trim() === '') { if (!worldName || typeof worldName !== 'string' || worldName.trim() === '') {
throw new Error('World ID不能为空'); throw new Error('World name不能为空');
} }
if (this._worlds.has(worldId)) { if (this._worlds.has(worldName)) {
throw new Error(`World ID '${worldId}' 已存在`); throw new Error(`World name '${worldName}' 已存在`);
} }
if (this._worlds.size >= this._config.maxWorlds!) { if (this._worlds.size >= this._config.maxWorlds!) {
@@ -107,14 +107,14 @@ export class WorldManager implements IService {
// 优先级config.debug > WorldManager.debug > 默认 // 优先级config.debug > WorldManager.debug > 默认
const worldConfig: IWorldConfig = { const worldConfig: IWorldConfig = {
name: worldId, name: worldName,
debug: config?.debug ?? this._config.debug ?? false, debug: config?.debug ?? this._config.debug ?? false,
...(config?.maxScenes !== undefined && { maxScenes: config.maxScenes }), ...(config?.maxScenes !== undefined && { maxScenes: config.maxScenes }),
...(config?.autoCleanup !== undefined && { autoCleanup: config.autoCleanup }) ...(config?.autoCleanup !== undefined && { autoCleanup: config.autoCleanup })
}; };
const world = new World(worldConfig); const world = new World(worldConfig);
this._worlds.set(worldId, world); this._worlds.set(worldName, world);
return world; return world;
} }
@@ -122,25 +122,25 @@ export class WorldManager implements IService {
/** /**
* 移除World * 移除World
*/ */
public removeWorld(worldId: string): boolean { public removeWorld(worldName: string): boolean {
const world = this._worlds.get(worldId); const world = this._worlds.get(worldName);
if (!world) { if (!world) {
return false; return false;
} }
// 销毁World // 销毁World
world.destroy(); world.destroy();
this._worlds.delete(worldId); this._worlds.delete(worldName);
logger.info(`移除World: ${worldId}`); logger.info(`移除World: ${worldName}`);
return true; return true;
} }
/** /**
* 获取World * 获取World
*/ */
public getWorld(worldId: string): World | null { public getWorld(worldName: string): World | null {
return this._worlds.get(worldId) || null; return this._worlds.get(worldName) || null;
} }
/** /**
@@ -160,27 +160,27 @@ export class WorldManager implements IService {
/** /**
* 设置World激活状态 * 设置World激活状态
*/ */
public setWorldActive(worldId: string, active: boolean): void { public setWorldActive(worldName: string, active: boolean): void {
const world = this._worlds.get(worldId); const world = this._worlds.get(worldName);
if (!world) { if (!world) {
logger.warn(`World '${worldId}' 不存在`); logger.warn(`World '${worldName}' 不存在`);
return; return;
} }
if (active) { if (active) {
world.start(); world.start();
logger.debug(`激活World: ${worldId}`); logger.debug(`激活World: ${worldName}`);
} else { } else {
world.stop(); world.stop();
logger.debug(`停用World: ${worldId}`); logger.debug(`停用World: ${worldName}`);
} }
} }
/** /**
* 检查World是否激活 * 检查World是否激活
*/ */
public isWorldActive(worldId: string): boolean { public isWorldActive(worldName: string): boolean {
const world = this._worlds.get(worldId); const world = this._worlds.get(worldName);
return world?.isActive ?? false; return world?.isActive ?? false;
} }
@@ -310,14 +310,14 @@ export class WorldManager implements IService {
worlds: [] as any[] worlds: [] as any[]
}; };
for (const [worldId, world] of this._worlds) { for (const [worldName, world] of this._worlds) {
const worldStats = world.getStats(); const worldStats = world.getStats();
stats.totalScenes += worldStats.totalSystems; // World的getStats可能需要调整 stats.totalScenes += worldStats.totalSystems; // World的getStats可能需要调整
stats.totalEntities += worldStats.totalEntities; stats.totalEntities += worldStats.totalEntities;
stats.totalSystems += worldStats.totalSystems; stats.totalSystems += worldStats.totalSystems;
stats.worlds.push({ stats.worlds.push({
id: worldId, id: worldName,
name: world.name, name: world.name,
isActive: world.isActive, isActive: world.isActive,
sceneCount: world.sceneCount, sceneCount: world.sceneCount,
@@ -334,8 +334,8 @@ export class WorldManager implements IService {
public getDetailedStatus() { public getDetailedStatus() {
return { return {
...this.getStats(), ...this.getStats(),
worlds: Array.from(this._worlds.entries()).map(([worldId, world]) => ({ worlds: Array.from(this._worlds.entries()).map(([worldName, world]) => ({
id: worldId, id: worldName,
isActive: world.isActive, isActive: world.isActive,
status: world.getStatus() status: world.getStatus()
})) }))
@@ -350,14 +350,14 @@ export class WorldManager implements IService {
public cleanup(): number { public cleanup(): number {
const worldsToRemove: string[] = []; const worldsToRemove: string[] = [];
for (const [worldId, world] of this._worlds) { for (const [worldName, world] of this._worlds) {
if (this.shouldCleanupWorld(world)) { if (this.shouldCleanupWorld(world)) {
worldsToRemove.push(worldId); worldsToRemove.push(worldName);
} }
} }
for (const worldId of worldsToRemove) { for (const worldName of worldsToRemove) {
this.removeWorld(worldId); this.removeWorld(worldName);
} }
if (worldsToRemove.length > 0) { if (worldsToRemove.length > 0) {
@@ -377,9 +377,9 @@ export class WorldManager implements IService {
this.stopAll(); this.stopAll();
// 销毁所有World // 销毁所有World
const worldIds = Array.from(this._worlds.keys()); const worldNames = Array.from(this._worlds.keys());
for (const worldId of worldIds) { for (const worldName of worldNames) {
this.removeWorld(worldId); this.removeWorld(worldName);
} }
this._worlds.clear(); this._worlds.clear();

View File

@@ -275,7 +275,7 @@ export class DebugPlugin implements IPlugin, IService {
* @param filter - 查询过滤器 * @param filter - 查询过滤器
*/ */
public queryEntities(filter: { public queryEntities(filter: {
sceneId?: string; sceneName?: string;
tag?: number; tag?: number;
name?: string; name?: string;
hasComponent?: string; hasComponent?: string;
@@ -289,7 +289,7 @@ export class DebugPlugin implements IPlugin, IService {
for (const world of worlds) { for (const world of worlds) {
for (const scene of world.getAllScenes()) { for (const scene of world.getAllScenes()) {
if (filter.sceneId && scene.name !== filter.sceneId) { if (filter.sceneName && scene.name !== filter.sceneName) {
continue; continue;
} }

View File

@@ -152,12 +152,22 @@ describe('World', () => {
expect(world.sceneCount).toBe(1); expect(world.sceneCount).toBe(1);
}); });
test('空的Scene name应该抛出错误', () => {
expect(() => {
world.createScene('');
}).toThrow('Scene name不能为空');
expect(() => {
world.createScene(' ');
}).toThrow('Scene name不能为空');
});
test('重复的Scene ID应该抛出错误', () => { test('重复的Scene ID应该抛出错误', () => {
world.createScene('duplicate'); world.createScene('duplicate');
expect(() => { expect(() => {
world.createScene('duplicate'); world.createScene('duplicate');
}).toThrow("Scene ID 'duplicate' 已存在于World 'TestWorld' 中"); }).toThrow("Scene name 'duplicate' 已存在于World 'TestWorld' 中");
}); });
test('超出最大Scene数量限制应该抛出错误', () => { test('超出最大Scene数量限制应该抛出错误', () => {
@@ -488,10 +498,10 @@ describe('World', () => {
}); });
describe('错误处理', () => { describe('错误处理', () => {
test('Scene ID为空时应该创建默认ID', () => { test('Scene name为空时应该抛出错误', () => {
expect(() => { expect(() => {
world.createScene(''); world.createScene('');
}).not.toThrow(); }).toThrow('Scene name不能为空');
}); });
test('极限情况下的资源管理', () => { test('极限情况下的资源管理', () => {

View File

@@ -109,12 +109,22 @@ describe('WorldManager', () => {
expect(world.name).toBe('configured-world'); expect(world.name).toBe('configured-world');
}); });
test('空的World name应该抛出错误', () => {
expect(() => {
worldManager.createWorld('');
}).toThrow('World name不能为空');
expect(() => {
worldManager.createWorld(' ');
}).toThrow('World name不能为空');
});
test('重复的World ID应该抛出错误', () => { test('重复的World ID应该抛出错误', () => {
worldManager.createWorld('duplicate-world'); worldManager.createWorld('duplicate-world');
expect(() => { expect(() => {
worldManager.createWorld('duplicate-world'); worldManager.createWorld('duplicate-world');
}).toThrow("World ID 'duplicate-world' 已存在"); }).toThrow("World name 'duplicate-world' 已存在");
}); });
test('超出最大World数量应该抛出错误', () => { test('超出最大World数量应该抛出错误', () => {

View File

@@ -198,6 +198,14 @@ describe('DebugPlugin', () => {
const results = debugPlugin.queryEntities({ tag: 999 }); const results = debugPlugin.queryEntities({ tag: 999 });
expect(results.length).toBe(0); expect(results.length).toBe(0);
}); });
it('应该能够按 sceneName 过滤实体', () => {
// 查询特定场景的实体
const results = debugPlugin.queryEntities({ sceneName: 'test-scene' });
// 应该返回 test-scene 中的所有实体Player, Enemy, Item
expect(results.length).toBe(3);
});
}); });
describe('监控功能', () => { describe('监控功能', () => {