feat(core): 为 World 添加独立的服务容器 (#222)
* feat(core): 为 World 添加独立的服务容器 * test(core): 为 World 服务容器添加完整测试覆盖
This commit is contained in:
@@ -44,7 +44,13 @@ class MyService implements IService {
|
||||
|
||||
### 访问服务容器
|
||||
|
||||
Core 类内置了服务容器,可以通过 `Core.services` 访问:
|
||||
ECS Framework 提供了三级服务容器:
|
||||
|
||||
> **版本说明**:World 服务容器功能在 v2.2.13+ 版本中可用
|
||||
|
||||
#### Core 级别服务容器
|
||||
|
||||
应用程序全局服务容器,可以通过 `Core.services` 访问:
|
||||
|
||||
```typescript
|
||||
import { Core } from '@esengine/ecs-framework';
|
||||
@@ -52,10 +58,53 @@ import { Core } from '@esengine/ecs-framework';
|
||||
// 初始化Core
|
||||
Core.create({ debug: true });
|
||||
|
||||
// 访问服务容器
|
||||
// 访问全局服务容器
|
||||
const container = Core.services;
|
||||
```
|
||||
|
||||
#### World 级别服务容器
|
||||
|
||||
每个 World 拥有独立的服务容器,用于管理 World 范围内的服务:
|
||||
|
||||
```typescript
|
||||
import { World } from '@esengine/ecs-framework';
|
||||
|
||||
// 创建 World
|
||||
const world = new World({ name: 'GameWorld' });
|
||||
|
||||
// 访问 World 级别的服务容器
|
||||
const worldContainer = world.services;
|
||||
|
||||
// 注册 World 级别的服务
|
||||
world.services.registerSingleton(RoomManager);
|
||||
```
|
||||
|
||||
#### Scene 级别服务容器
|
||||
|
||||
每个 Scene 拥有独立的服务容器,用于管理 Scene 范围内的服务:
|
||||
|
||||
```typescript
|
||||
// 访问 Scene 级别的服务容器
|
||||
const sceneContainer = scene.services;
|
||||
|
||||
// 注册 Scene 级别的服务
|
||||
scene.services.registerSingleton(PhysicsSystem);
|
||||
```
|
||||
|
||||
#### 服务容器层级
|
||||
|
||||
```
|
||||
Core.services (应用程序全局)
|
||||
└─ World.services (World 级别)
|
||||
└─ Scene.services (Scene 级别)
|
||||
```
|
||||
|
||||
不同级别的服务容器是独立的,服务不会自动向上或向下查找。选择合适的容器级别:
|
||||
|
||||
- **Core.services**: 应用程序级别的全局服务(配置、插件管理器等)
|
||||
- **World.services**: World 级别的服务(房间管理器、多人游戏状态等)
|
||||
- **Scene.services**: Scene 级别的服务(ECS 系统、场景特定逻辑等)
|
||||
|
||||
### 注册服务
|
||||
|
||||
#### 注册单例服务
|
||||
|
||||
@@ -2,6 +2,7 @@ import { IScene } from './IScene';
|
||||
import { Scene } from './Scene';
|
||||
import { createLogger } from '../Utils/Logger';
|
||||
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
|
||||
import { ServiceContainer } from '../Core/ServiceContainer';
|
||||
|
||||
const logger = createLogger('World');
|
||||
|
||||
@@ -65,6 +66,13 @@ export interface IWorldConfig {
|
||||
* World类 - ECS世界管理器
|
||||
*
|
||||
* World是Scene的容器,每个World可以管理多个Scene。
|
||||
* World拥有独立的服务容器,用于管理World级别的全局服务。
|
||||
*
|
||||
* 服务容器层级:
|
||||
* - Core.services: 应用程序全局服务
|
||||
* - World.services: World级别服务(每个World独立)
|
||||
* - Scene.services: Scene级别服务(每个Scene独立)
|
||||
*
|
||||
* 这种设计允许创建独立的游戏世界,如:
|
||||
* - 游戏房间(每个房间一个World)
|
||||
* - 不同的游戏模式
|
||||
@@ -75,10 +83,16 @@ export interface IWorldConfig {
|
||||
* // 创建游戏房间的World
|
||||
* const roomWorld = new World({ name: 'Room_001' });
|
||||
*
|
||||
* // 注册World级别的服务
|
||||
* roomWorld.services.registerSingleton(RoomManager);
|
||||
*
|
||||
* // 在World中创建Scene
|
||||
* const gameScene = roomWorld.createScene('game', new Scene());
|
||||
* const uiScene = roomWorld.createScene('ui', new Scene());
|
||||
*
|
||||
* // 在Scene中使用World级别的服务
|
||||
* const roomManager = roomWorld.services.resolve(RoomManager);
|
||||
*
|
||||
* // 更新整个World
|
||||
* roomWorld.update(deltaTime);
|
||||
* ```
|
||||
@@ -89,6 +103,7 @@ export class World {
|
||||
private readonly _scenes: Map<string, IScene> = new Map();
|
||||
private readonly _activeScenes: Set<string> = new Set();
|
||||
private readonly _globalSystems: IGlobalSystem[] = [];
|
||||
private readonly _services: ServiceContainer;
|
||||
private _isActive: boolean = false;
|
||||
private _createdAt: number;
|
||||
|
||||
@@ -103,6 +118,17 @@ export class World {
|
||||
|
||||
this.name = this._config.name!;
|
||||
this._createdAt = Date.now();
|
||||
this._services = new ServiceContainer();
|
||||
}
|
||||
|
||||
// ===== 服务容器 =====
|
||||
|
||||
/**
|
||||
* World级别的服务容器
|
||||
* 用于管理World范围内的全局服务
|
||||
*/
|
||||
public get services(): ServiceContainer {
|
||||
return this._services;
|
||||
}
|
||||
|
||||
// ===== Scene管理 =====
|
||||
@@ -398,6 +424,9 @@ export class World {
|
||||
}
|
||||
this._globalSystems.length = 0;
|
||||
|
||||
// 清空服务容器
|
||||
this._services.clear();
|
||||
|
||||
this._scenes.clear();
|
||||
this._activeScenes.clear();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ 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';
|
||||
import { IService } from '../../src/Core/ServiceContainer';
|
||||
|
||||
// 测试用组件
|
||||
class TestComponent extends Component {
|
||||
@@ -48,16 +49,26 @@ class TestGlobalSystem implements IGlobalSystem {
|
||||
|
||||
class TestSceneSystem extends EntitySystem {
|
||||
public updateCount = 0;
|
||||
|
||||
|
||||
constructor() {
|
||||
super(Matcher.empty().all(PlayerComponent));
|
||||
}
|
||||
|
||||
|
||||
protected override process(): void {
|
||||
this.updateCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用服务
|
||||
class TestWorldService implements IService {
|
||||
public disposed = false;
|
||||
public value = 'test';
|
||||
|
||||
dispose(): void {
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用Scene
|
||||
class TestScene extends Scene {
|
||||
public initializeCalled = false;
|
||||
@@ -438,27 +449,65 @@ describe('World', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('服务容器', () => {
|
||||
test('应该能访问World级别的服务容器', () => {
|
||||
const services = world.services;
|
||||
|
||||
expect(services).toBeDefined();
|
||||
expect(services).toHaveProperty('registerSingleton');
|
||||
expect(services).toHaveProperty('resolve');
|
||||
});
|
||||
|
||||
test('应该能在World服务容器中注册和解析服务', () => {
|
||||
world.services.registerSingleton(TestWorldService);
|
||||
|
||||
const service = world.services.resolve(TestWorldService);
|
||||
|
||||
expect(service).toBeDefined();
|
||||
expect(service.value).toBe('test');
|
||||
expect(service.disposed).toBe(false);
|
||||
});
|
||||
|
||||
test('World销毁时应该清理服务容器中的服务', () => {
|
||||
const service = new TestWorldService();
|
||||
world.services.registerInstance(TestWorldService, service);
|
||||
|
||||
world.destroy();
|
||||
|
||||
expect(service.disposed).toBe(true);
|
||||
});
|
||||
|
||||
test('World服务容器应该独立于Scene服务容器', () => {
|
||||
const scene = world.createScene('test-scene');
|
||||
|
||||
world.services.registerSingleton(TestWorldService);
|
||||
|
||||
expect(world.services.isRegistered(TestWorldService)).toBe(true);
|
||||
expect(scene.services.isRegistered(TestWorldService)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user