feat: 纹理路径稳定 ID 与架构改进 (#305)

* feat(asset-system): 实现路径稳定 ID 生成器

使用 FNV-1a hash 算法为纹理生成稳定的运行时 ID:
- 新增 _pathIdCache 静态缓存,跨 Play/Stop 循环保持稳定
- 新增 getStableIdForPath() 方法,相同路径永远返回相同 ID
- 修改 loadTextureForComponent/loadTextureByGuid 使用稳定 ID
- clearTextureMappings() 不再清除 _pathIdCache

这解决了 Play/Stop 后纹理 ID 失效的根本问题。

* fix(runtime-core): 移除 Play/Stop 循环中的 clearTextureMappings 调用

使用路径稳定 ID 后,不再需要在快照保存/恢复时清除纹理缓存:
- saveSceneSnapshot() 移除 clearTextureMappings() 调用
- restoreSceneSnapshot() 移除 clearTextureMappings() 调用
- 组件保存的 textureId 在 Play/Stop 后仍然有效

* fix(editor-core): 修复场景切换时的资源泄漏

在 openScene() 加载新场景前先卸载旧场景资源:
- 调用 sceneResourceManager.unloadSceneResources() 释放旧资源
- 使用引用计数机制,仅卸载不再被引用的资源
- 路径稳定 ID 缓存不受影响,保持 ID 稳定性

* fix(runtime-core): 修复 PluginManager 组件注册类型错误

将 ComponentRegistry 类改为 GlobalComponentRegistry 实例:
- registerComponents() 期望 IComponentRegistry 接口实例
- GlobalComponentRegistry 是 ComponentRegistry 的全局实例

* refactor(core): 提取 IComponentRegistry 接口

将组件注册表抽象为接口,支持场景级组件注册:
- 新增 IComponentRegistry 接口定义
- Scene 持有独立的 componentRegistry 实例
- 支持从 GlobalComponentRegistry 克隆
- 各系统支持传入自定义注册表

* refactor(engine-core): 改进插件服务注册机制

- 更新 IComponentRegistry 类型引用
- 优化 PluginServiceRegistry 服务管理

* refactor(modules): 适配新的组件注册接口

更新各模块 RuntimeModule 使用 IComponentRegistry 接口:
- audio, behavior-tree, camera
- sprite, tilemap, world-streaming

* fix(physics-rapier2d): 修复物理插件组件注册

- PhysicsEditorPlugin 添加 runtimeModule 引用
- 适配 IComponentRegistry 接口
- 修复物理组件在场景加载时未注册的问题

* feat(editor-core): 添加 UserCodeService 就绪信号机制

- 新增 waitForReady()/signalReady() API
- 支持等待用户脚本编译完成
- 解决场景加载时组件未注册的时序问题

* fix(editor-app): 在编译完成后调用 signalReady()

确保用户脚本编译完成后发出就绪信号:
- 编译成功后调用 userCodeService.signalReady()
- 编译失败也要发出信号,避免阻塞场景加载

* feat(editor-core): 改进编辑器核心服务

- EntityStoreService 添加调试日志
- AssetRegistryService 优化资产注册
- PluginManager 改进插件管理
- IFileAPI 添加 getFileMtime 接口

* feat(engine): 改进 Rust 纹理管理器

- 支持任意 ID 的纹理加载(非递增)
- 添加纹理状态追踪 API
- 优化纹理缓存清理机制
- 更新 TypeScript 绑定

* feat(ui): 添加场景切换和文本闪烁组件

新增组件:
- SceneLoadTriggerComponent: 场景切换触发器
- TextBlinkComponent: 文本闪烁效果

新增系统:
- SceneLoadTriggerSystem: 处理场景切换逻辑
- TextBlinkSystem: 处理文本闪烁动画

其他改进:
- UIRuntimeModule 适配新组件注册接口
- UI 渲染系统优化

* feat(editor-app): 添加外部文件修改检测

- 新增 ExternalModificationDialog 组件
- TauriFileAPI 支持 getFileMtime
- 场景文件被外部修改时提示用户

* feat(editor-app): 添加渲染调试面板

- 新增 RenderDebugService 和调试面板 UI
- App/ContentBrowser 添加调试日志
- TitleBar/Viewport 优化
- DialogManager 改进

* refactor(editor-app): 编辑器服务和组件优化

- EngineService 改进引擎集成
- EditorEngineSync 同步优化
- AssetFileInspector 改进
- VectorFieldEditors 优化
- InstantiatePrefabCommand 改进

* feat(i18n): 更新国际化翻译

- 添加新功能相关翻译
- 更新中文、英文、西班牙文

* feat(tauri): 添加文件修改时间查询命令

- 新增 get_file_mtime 命令
- 支持检测文件外部修改

* refactor(particle): 粒子系统改进

- 适配新的组件注册接口
- ParticleSystem 优化
- 添加单元测试

* refactor(platform): 平台适配层优化

- BrowserRuntime 改进
- 新增 RuntimeSceneManager 服务
- 导出优化

* refactor(asset-system-editor): 资产元数据改进

- AssetMetaFile 优化
- 导出调整

* fix(asset-system): 移除未使用的 TextureLoader 导入

* fix(tests): 更新测试以使用 GlobalComponentRegistry 实例

修复多个测试文件以适配 ComponentRegistry 从静态类变为实例类的变更:
- ComponentStorage.test.ts: 使用 GlobalComponentRegistry.reset()
- EntitySerializer.test.ts: 使用 GlobalComponentRegistry 实例
- IncrementalSerialization.test.ts: 使用 GlobalComponentRegistry 实例
- SceneSerializer.test.ts: 使用 GlobalComponentRegistry 实例
- ComponentRegistry.extended.test.ts: 使用 GlobalComponentRegistry,同时注册到 scene.componentRegistry
- SystemTypes.test.ts: 在 Scene 创建前注册组件
- QuerySystem.test.ts: mockScene 添加 componentRegistry
This commit is contained in:
YHH
2025-12-16 12:46:14 +08:00
committed by GitHub
parent d834ca5e77
commit ed8f6e283b
107 changed files with 7399 additions and 847 deletions

View File

@@ -1,19 +1,19 @@
import { Component } from '../../../src/ECS/Component';
import { ComponentRegistry } from '../../../src/ECS/Core/ComponentStorage/ComponentRegistry';
import { GlobalComponentRegistry } from '../../../src/ECS/Core/ComponentStorage/ComponentRegistry';
import { Entity } from '../../../src/ECS/Entity';
import { Scene } from '../../../src/ECS/Scene';
describe('ComponentRegistry Extended - 64+ 组件支持', () => {
// 组件类缓存
// 组件类缓存 | Component class cache
const componentClassCache = new Map<number, any>();
beforeEach(() => {
ComponentRegistry.reset();
GlobalComponentRegistry.reset();
componentClassCache.clear();
});
afterEach(() => {
ComponentRegistry.reset();
GlobalComponentRegistry.reset();
componentClassCache.clear();
});
@@ -39,11 +39,11 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
// 注册 100 个组件类型
for (let i = 0; i < 100; i++) {
const ComponentClass = createTestComponent(i);
const bitIndex = ComponentRegistry.register(ComponentClass);
const bitIndex = GlobalComponentRegistry.register(ComponentClass);
componentTypes.push(ComponentClass);
expect(bitIndex).toBe(i);
expect(ComponentRegistry.isRegistered(ComponentClass)).toBe(true);
expect(GlobalComponentRegistry.isRegistered(ComponentClass)).toBe(true);
}
expect(componentTypes.length).toBe(100);
@@ -53,14 +53,14 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
// 注册 80 个组件
for (let i = 0; i < 80; i++) {
const ComponentClass = createTestComponent(i);
ComponentRegistry.register(ComponentClass);
GlobalComponentRegistry.register(ComponentClass);
}
// 验证第 70 个组件的位掩码
const Component70 = createTestComponent(70);
ComponentRegistry.register(Component70);
GlobalComponentRegistry.register(Component70);
const bitMask = ComponentRegistry.getBitMask(Component70);
const bitMask = GlobalComponentRegistry.getBitMask(Component70);
expect(bitMask).toBeDefined();
expect(bitMask.segments).toBeDefined(); // 应该有扩展段
expect(bitMask.segments!.length).toBeGreaterThan(0);
@@ -70,11 +70,11 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
// 注册 1500 个组件验证无限制
for (let i = 0; i < 1500; i++) {
const ComponentClass = createTestComponent(i);
const bitIndex = ComponentRegistry.register(ComponentClass);
const bitIndex = GlobalComponentRegistry.register(ComponentClass);
expect(bitIndex).toBe(i);
}
expect(ComponentRegistry.getRegisteredCount()).toBe(1500);
expect(GlobalComponentRegistry.getRegisteredCount()).toBe(1500);
});
});
@@ -92,10 +92,13 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
const componentTypes: any[] = [];
const components: any[] = [];
// 添加 80 个组件
// 添加 80 个组件 | Add 80 components
// 需要同时注册到 GlobalComponentRegistryArchetypeSystem 使用)和 Scene registry
// Need to register to both GlobalComponentRegistry (used by ArchetypeSystem) and Scene registry
for (let i = 0; i < 80; i++) {
const ComponentClass = createTestComponent(i);
ComponentRegistry.register(ComponentClass);
GlobalComponentRegistry.register(ComponentClass);
scene.componentRegistry.register(ComponentClass);
componentTypes.push(ComponentClass);
const component = new ComponentClass();
@@ -115,32 +118,35 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
});
it('应该能够正确检查超过 64 个组件的存在性', () => {
// 添加组件 0-79
// 添加组件 0-79 | Add components 0-79
for (let i = 0; i < 80; i++) {
const ComponentClass = createTestComponent(i);
ComponentRegistry.register(ComponentClass);
GlobalComponentRegistry.register(ComponentClass);
scene.componentRegistry.register(ComponentClass);
entity.addComponent(new ComponentClass());
}
// 验证 hasComponent 对所有组件都工作
// 验证 hasComponent 对所有组件都工作 | Verify hasComponent works for all
for (let i = 0; i < 80; i++) {
const ComponentClass = createTestComponent(i);
expect(entity.hasComponent(ComponentClass)).toBe(true);
}
// 验证不存在的组件
// 验证不存在的组件 | Verify non-existent component
const NonExistentComponent = createTestComponent(999);
ComponentRegistry.register(NonExistentComponent);
GlobalComponentRegistry.register(NonExistentComponent);
scene.componentRegistry.register(NonExistentComponent);
expect(entity.hasComponent(NonExistentComponent)).toBe(false);
});
it('应该能够移除超过 64 索引的组件', () => {
const componentTypes: any[] = [];
// 添加 80 个组件
// 添加 80 个组件 | Add 80 components
for (let i = 0; i < 80; i++) {
const ComponentClass = createTestComponent(i);
ComponentRegistry.register(ComponentClass);
GlobalComponentRegistry.register(ComponentClass);
scene.componentRegistry.register(ComponentClass);
componentTypes.push(ComponentClass);
entity.addComponent(new ComponentClass());
}
@@ -162,10 +168,11 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
});
it('应该能够正确遍历超过 64 个组件', () => {
// 添加 80 个组件
// 添加 80 个组件 | Add 80 components
for (let i = 0; i < 80; i++) {
const ComponentClass = createTestComponent(i);
ComponentRegistry.register(ComponentClass);
GlobalComponentRegistry.register(ComponentClass);
scene.componentRegistry.register(ComponentClass);
entity.addComponent(new ComponentClass());
}
@@ -182,29 +189,29 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
describe('热更新模式', () => {
it('默认应该禁用热更新模式', () => {
expect(ComponentRegistry.isHotReloadEnabled()).toBe(false);
expect(GlobalComponentRegistry.isHotReloadEnabled()).toBe(false);
});
it('应该能够启用和禁用热更新模式', () => {
expect(ComponentRegistry.isHotReloadEnabled()).toBe(false);
expect(GlobalComponentRegistry.isHotReloadEnabled()).toBe(false);
ComponentRegistry.enableHotReload();
expect(ComponentRegistry.isHotReloadEnabled()).toBe(true);
GlobalComponentRegistry.enableHotReload();
expect(GlobalComponentRegistry.isHotReloadEnabled()).toBe(true);
ComponentRegistry.disableHotReload();
expect(ComponentRegistry.isHotReloadEnabled()).toBe(false);
GlobalComponentRegistry.disableHotReload();
expect(GlobalComponentRegistry.isHotReloadEnabled()).toBe(false);
});
it('reset 应该重置热更新模式为禁用', () => {
ComponentRegistry.enableHotReload();
expect(ComponentRegistry.isHotReloadEnabled()).toBe(true);
GlobalComponentRegistry.enableHotReload();
expect(GlobalComponentRegistry.isHotReloadEnabled()).toBe(true);
ComponentRegistry.reset();
expect(ComponentRegistry.isHotReloadEnabled()).toBe(false);
GlobalComponentRegistry.reset();
expect(GlobalComponentRegistry.isHotReloadEnabled()).toBe(false);
});
it('启用热更新时应该替换同名组件类', () => {
ComponentRegistry.enableHotReload();
GlobalComponentRegistry.enableHotReload();
// 模拟热更新场景:两个不同的类但有相同的 constructor.name
// Simulate hot reload: two different classes with same constructor.name
@@ -229,20 +236,20 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
expect(TestComponentV1.name).toBe(TestComponentV2.name);
expect(TestComponentV1).not.toBe(TestComponentV2);
const index1 = ComponentRegistry.register(TestComponentV1);
const index2 = ComponentRegistry.register(TestComponentV2);
const index1 = GlobalComponentRegistry.register(TestComponentV1);
const index2 = GlobalComponentRegistry.register(TestComponentV2);
// 应该复用相同的 bitIndex
expect(index1).toBe(index2);
// 新类应该替换旧类
expect(ComponentRegistry.isRegistered(TestComponentV2)).toBe(true);
expect(ComponentRegistry.isRegistered(TestComponentV1)).toBe(false);
expect(GlobalComponentRegistry.isRegistered(TestComponentV2)).toBe(true);
expect(GlobalComponentRegistry.isRegistered(TestComponentV1)).toBe(false);
});
it('禁用热更新时不应该替换同名组件类', () => {
// 确保热更新被禁用
ComponentRegistry.disableHotReload();
GlobalComponentRegistry.disableHotReload();
// 创建两个同名组件
// Create two classes with same constructor.name
@@ -265,15 +272,15 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
expect(TestCompA.name).toBe(TestCompB.name);
expect(TestCompA).not.toBe(TestCompB);
const index1 = ComponentRegistry.register(TestCompA);
const index2 = ComponentRegistry.register(TestCompB);
const index1 = GlobalComponentRegistry.register(TestCompA);
const index2 = GlobalComponentRegistry.register(TestCompB);
// 应该分配不同的 bitIndex因为热更新被禁用
expect(index2).toBe(index1 + 1);
// 两个类都应该被注册
expect(ComponentRegistry.isRegistered(TestCompA)).toBe(true);
expect(ComponentRegistry.isRegistered(TestCompB)).toBe(true);
expect(GlobalComponentRegistry.isRegistered(TestCompA)).toBe(true);
expect(GlobalComponentRegistry.isRegistered(TestCompB)).toBe(true);
});
});
@@ -282,14 +289,15 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
const scene = new Scene();
const entity = scene.createEntity('TestEntity');
// 注册 65 个组件(跨越 64 位边界)
// 注册 65 个组件(跨越 64 位边界)| Register 65 components (crossing 64-bit boundary)
for (let i = 0; i < 65; i++) {
const ComponentClass = createTestComponent(i);
ComponentRegistry.register(ComponentClass);
GlobalComponentRegistry.register(ComponentClass);
scene.componentRegistry.register(ComponentClass);
entity.addComponent(new ComponentClass());
}
// 验证第 63, 64, 65 个组件
// 验证第 63, 64, 65 个组件 | Verify components 63, 64
const Component63 = createTestComponent(63);
const Component64 = createTestComponent(64);
@@ -301,25 +309,27 @@ describe('ComponentRegistry Extended - 64+ 组件支持', () => {
const scene = new Scene();
const entity = scene.createEntity('TestEntity');
// 添加 80 个组件
// 添加 80 个组件 | Add 80 components
for (let i = 0; i < 80; i++) {
const ComponentClass = createTestComponent(i);
ComponentRegistry.register(ComponentClass);
GlobalComponentRegistry.register(ComponentClass);
scene.componentRegistry.register(ComponentClass);
entity.addComponent(new ComponentClass());
}
// 强制重建缓存(通过访问 components
// 强制重建缓存(通过访问 components| Force cache rebuild
const components1 = entity.components;
expect(components1.length).toBe(80);
// 添加更多组件
// 添加更多组件 | Add more components
for (let i = 80; i < 90; i++) {
const ComponentClass = createTestComponent(i);
ComponentRegistry.register(ComponentClass);
GlobalComponentRegistry.register(ComponentClass);
scene.componentRegistry.register(ComponentClass);
entity.addComponent(new ComponentClass());
}
// 重新获取组件数组(应该重建缓存)
// 重新获取组件数组(应该重建缓存)| Re-get component array (should rebuild cache)
const components2 = entity.components;
expect(components2.length).toBe(90);
});

View File

@@ -1,7 +1,10 @@
import { ComponentRegistry, ComponentStorage, ComponentStorageManager } from '../../../src/ECS/Core/ComponentStorage';
import { ComponentRegistry, GlobalComponentRegistry, ComponentStorage, ComponentStorageManager } from '../../../src/ECS/Core/ComponentStorage';
import { Component } from '../../../src/ECS/Component';
import { BitMask64Utils } from '../../../src/ECS/Utils/BigIntCompatibility';
// 为测试创建独立的注册表实例 | Create isolated registry instance for tests
let testRegistry: ComponentRegistry;
// 测试组件类(默认使用原始存储)
class TestComponent extends Component {
public value: number;
@@ -51,89 +54,88 @@ class HealthComponent extends Component {
describe('ComponentRegistry - 组件注册表测试', () => {
beforeEach(() => {
// 重置注册表状态
(ComponentRegistry as any).componentTypes = new Map<Function, number>();
(ComponentRegistry as any).nextBitIndex = 0;
// 每个测试创建新的注册表实例 | Create new registry instance for each test
testRegistry = new ComponentRegistry();
});
describe('组件注册功能', () => {
test('应该能够注册组件类型', () => {
const bitIndex = ComponentRegistry.register(TestComponent);
const bitIndex = testRegistry.register(TestComponent);
expect(bitIndex).toBe(0);
expect(ComponentRegistry.isRegistered(TestComponent)).toBe(true);
expect(testRegistry.isRegistered(TestComponent)).toBe(true);
});
test('重复注册相同组件应该返回相同的位索引', () => {
const bitIndex1 = ComponentRegistry.register(TestComponent);
const bitIndex2 = ComponentRegistry.register(TestComponent);
const bitIndex1 = testRegistry.register(TestComponent);
const bitIndex2 = testRegistry.register(TestComponent);
expect(bitIndex1).toBe(bitIndex2);
expect(bitIndex1).toBe(0);
});
test('应该能够注册多个组件类型', () => {
const bitIndex1 = ComponentRegistry.register(TestComponent);
const bitIndex2 = ComponentRegistry.register(PositionComponent);
const bitIndex3 = ComponentRegistry.register(VelocityComponent);
const bitIndex1 = testRegistry.register(TestComponent);
const bitIndex2 = testRegistry.register(PositionComponent);
const bitIndex3 = testRegistry.register(VelocityComponent);
expect(bitIndex1).toBe(0);
expect(bitIndex2).toBe(1);
expect(bitIndex3).toBe(2);
});
test('应该能够检查组件是否已注册', () => {
expect(ComponentRegistry.isRegistered(TestComponent)).toBe(false);
ComponentRegistry.register(TestComponent);
expect(ComponentRegistry.isRegistered(TestComponent)).toBe(true);
expect(testRegistry.isRegistered(TestComponent)).toBe(false);
testRegistry.register(TestComponent);
expect(testRegistry.isRegistered(TestComponent)).toBe(true);
});
});
describe('位掩码功能', () => {
test('应该能够获取组件的位掩码', () => {
ComponentRegistry.register(TestComponent);
ComponentRegistry.register(PositionComponent);
const mask1 = ComponentRegistry.getBitMask(TestComponent);
const mask2 = ComponentRegistry.getBitMask(PositionComponent);
testRegistry.register(TestComponent);
testRegistry.register(PositionComponent);
const mask1 = testRegistry.getBitMask(TestComponent);
const mask2 = testRegistry.getBitMask(PositionComponent);
expect(BitMask64Utils.getBit(mask1,0)).toBe(true); // 2^0
expect(BitMask64Utils.getBit(mask2,1)).toBe(true); // 2^1
});
test('应该能够获取组件的位索引', () => {
ComponentRegistry.register(TestComponent);
ComponentRegistry.register(PositionComponent);
const index1 = ComponentRegistry.getBitIndex(TestComponent);
const index2 = ComponentRegistry.getBitIndex(PositionComponent);
testRegistry.register(TestComponent);
testRegistry.register(PositionComponent);
const index1 = testRegistry.getBitIndex(TestComponent);
const index2 = testRegistry.getBitIndex(PositionComponent);
expect(index1).toBe(0);
expect(index2).toBe(1);
});
test('获取未注册组件的位掩码应该抛出错误', () => {
expect(() => {
ComponentRegistry.getBitMask(TestComponent);
testRegistry.getBitMask(TestComponent);
}).toThrow('Component type TestComponent is not registered');
});
test('获取未注册组件的位索引应该抛出错误', () => {
expect(() => {
ComponentRegistry.getBitIndex(TestComponent);
testRegistry.getBitIndex(TestComponent);
}).toThrow('Component type TestComponent is not registered');
});
});
describe('注册表管理', () => {
test('应该能够获取所有已注册的组件类型', () => {
ComponentRegistry.register(TestComponent);
ComponentRegistry.register(PositionComponent);
const allTypes = ComponentRegistry.getAllRegisteredTypes();
testRegistry.register(TestComponent);
testRegistry.register(PositionComponent);
const allTypes = testRegistry.getAllRegisteredTypes();
expect(allTypes.size).toBe(2);
expect(allTypes.has(TestComponent)).toBe(true);
expect(allTypes.has(PositionComponent)).toBe(true);
@@ -142,12 +144,12 @@ describe('ComponentRegistry - 组件注册表测试', () => {
});
test('返回的注册表副本不应该影响原始数据', () => {
ComponentRegistry.register(TestComponent);
const allTypes = ComponentRegistry.getAllRegisteredTypes();
testRegistry.register(TestComponent);
const allTypes = testRegistry.getAllRegisteredTypes();
allTypes.set(PositionComponent, 999);
expect(ComponentRegistry.isRegistered(PositionComponent)).toBe(false);
expect(testRegistry.isRegistered(PositionComponent)).toBe(false);
});
});
});
@@ -156,10 +158,9 @@ describe('ComponentStorage - 组件存储器测试', () => {
let storage: ComponentStorage<TestComponent>;
beforeEach(() => {
// 重置注册表
(ComponentRegistry as any).componentTypes = new Map<Function, number>();
(ComponentRegistry as any).nextBitIndex = 0;
// 每个测试创建新的注册表实例 | Create new registry instance for each test
testRegistry = new ComponentRegistry();
storage = new ComponentStorage(TestComponent);
});
@@ -358,10 +359,9 @@ describe('ComponentStorageManager - 组件存储管理器测试', () => {
let manager: ComponentStorageManager;
beforeEach(() => {
// 重置注册表
(ComponentRegistry as any).componentTypes = new Map<Function, number>();
(ComponentRegistry as any).nextBitIndex = 0;
// 重置全局注册表 | Reset global registry
GlobalComponentRegistry.reset();
manager = new ComponentStorageManager();
});
@@ -455,10 +455,10 @@ describe('ComponentStorageManager - 组件存储管理器测试', () => {
describe('位掩码功能', () => {
test('应该能够获取实体的组件位掩码', () => {
// 确保组件已注册
ComponentRegistry.register(TestComponent);
ComponentRegistry.register(PositionComponent);
ComponentRegistry.register(VelocityComponent);
// 确保组件已注册 | Ensure components are registered
GlobalComponentRegistry.register(TestComponent);
GlobalComponentRegistry.register(PositionComponent);
GlobalComponentRegistry.register(VelocityComponent);
manager.addComponent(1, new TestComponent(100));
manager.addComponent(1, new PositionComponent(10, 20));
@@ -475,8 +475,8 @@ describe('ComponentStorageManager - 组件存储管理器测试', () => {
});
test('添加和移除组件应该更新掩码', () => {
ComponentRegistry.register(TestComponent);
ComponentRegistry.register(PositionComponent);
GlobalComponentRegistry.register(TestComponent);
GlobalComponentRegistry.register(PositionComponent);
manager.addComponent(1, new TestComponent(100));
let mask = manager.getComponentMask(1);

View File

@@ -894,10 +894,12 @@ describe('QuerySystem - 查询系统测试', () => {
const independentQuerySystem = new QuerySystem();
const testEntity = scene.createEntity('ArchetypeTestEntity');
// 模拟Scene环境保留componentStorageManager
// 模拟Scene环境保留componentStorageManager和componentRegistry
// Mock Scene environment (keep componentStorageManager and componentRegistry)
const mockScene = {
querySystem: independentQuerySystem,
componentStorageManager: scene.componentStorageManager,
componentRegistry: scene.componentRegistry,
clearSystemEntityCaches: jest.fn()
};
testEntity.scene = mockScene as any;
@@ -938,10 +940,12 @@ describe('QuerySystem - 查询系统测试', () => {
const independentQuerySystem = new QuerySystem();
const testEntity = scene.createEntity('RemoveAllTestEntity');
// 模拟Scene环境保留componentStorageManager
// 模拟Scene环境保留componentStorageManager和componentRegistry
// Mock Scene environment (keep componentStorageManager and componentRegistry)
const mockScene = {
querySystem: independentQuerySystem,
componentStorageManager: scene.componentStorageManager,
componentRegistry: scene.componentRegistry,
clearSystemEntityCaches: jest.fn()
};
testEntity.scene = mockScene as any;

View File

@@ -5,7 +5,7 @@ import { Component } from '../../../src/ECS/Component';
import { HierarchySystem } from '../../../src/ECS/Systems/HierarchySystem';
import { HierarchyComponent } from '../../../src/ECS/Components/HierarchyComponent';
import { ECSComponent } from '../../../src/ECS/Decorators';
import { ComponentRegistry, ComponentType } from '../../../src/ECS/Core/ComponentStorage';
import { GlobalComponentRegistry, ComponentType } from '../../../src/ECS/Core/ComponentStorage';
import { Serializable, Serialize } from '../../../src/ECS/Serialization';
@ECSComponent('EntitySerTest_Position')
@@ -40,16 +40,18 @@ describe('EntitySerializer', () => {
let componentRegistry: Map<string, ComponentType>;
beforeEach(() => {
ComponentRegistry.reset();
ComponentRegistry.register(PositionComponent);
ComponentRegistry.register(VelocityComponent);
ComponentRegistry.register(HierarchyComponent);
// 重置全局注册表 | Reset global registry
GlobalComponentRegistry.reset();
GlobalComponentRegistry.register(PositionComponent);
GlobalComponentRegistry.register(VelocityComponent);
GlobalComponentRegistry.register(HierarchyComponent);
scene = new Scene({ name: 'EntitySerializerTestScene' });
hierarchySystem = new HierarchySystem();
scene.addSystem(hierarchySystem);
componentRegistry = ComponentRegistry.getAllComponentNames() as Map<string, ComponentType>;
componentRegistry = GlobalComponentRegistry.getAllComponentNames() as Map<string, ComponentType>;
});
afterEach(() => {

View File

@@ -12,7 +12,7 @@ import {
ChangeOperation
} from '../../../src/ECS/Serialization';
import { ECSComponent } from '../../../src/ECS/Decorators';
import { ComponentRegistry } from '../../../src/ECS/Core/ComponentStorage';
import { GlobalComponentRegistry } from '../../../src/ECS/Core/ComponentStorage';
// 测试组件定义
@ECSComponent('IncTest_Position')
@@ -56,12 +56,14 @@ describe('Incremental Serialization System', () => {
beforeEach(() => {
IncrementalSerializer.resetVersion();
ComponentRegistry.reset();
// 重新注册测试组件
ComponentRegistry.register(PositionComponent);
ComponentRegistry.register(VelocityComponent);
ComponentRegistry.register(HealthComponent);
// 重置全局注册表 | Reset global registry
GlobalComponentRegistry.reset();
// 重新注册测试组件 | Re-register test components
GlobalComponentRegistry.register(PositionComponent);
GlobalComponentRegistry.register(VelocityComponent);
GlobalComponentRegistry.register(HealthComponent);
scene = new Scene({ name: 'IncrementalTestScene' });
});

View File

@@ -4,7 +4,7 @@ import { Component } from '../../../src/ECS/Component';
import { HierarchySystem } from '../../../src/ECS/Systems/HierarchySystem';
import { HierarchyComponent } from '../../../src/ECS/Components/HierarchyComponent';
import { ECSComponent } from '../../../src/ECS/Decorators';
import { ComponentRegistry, ComponentType } from '../../../src/ECS/Core/ComponentStorage';
import { GlobalComponentRegistry, ComponentType } from '../../../src/ECS/Core/ComponentStorage';
import { Serializable, Serialize } from '../../../src/ECS/Serialization';
@ECSComponent('SceneSerTest_Position')
@@ -40,7 +40,7 @@ describe('SceneSerializer', () => {
beforeEach(() => {
scene = new Scene({ name: 'SceneSerializerTestScene' });
componentRegistry = ComponentRegistry.getAllComponentNames() as Map<string, ComponentType>;
componentRegistry = GlobalComponentRegistry.getAllComponentNames() as Map<string, ComponentType>;
});
afterEach(() => {

View File

@@ -4,7 +4,7 @@ import { IntervalSystem } from '../../../src/ECS/Systems/IntervalSystem';
import { ProcessingSystem } from '../../../src/ECS/Systems/ProcessingSystem';
import { Entity } from '../../../src/ECS/Entity';
import { Component } from '../../../src/ECS/Component';
import { ComponentRegistry } from '../../../src/ECS/Core/ComponentStorage';
import { GlobalComponentRegistry } from '../../../src/ECS/Core/ComponentStorage';
import { Time } from '../../../src/Utils/Time';
import { Matcher } from '../../../src/ECS/Utils/Matcher';
import { Core } from '../../../src/Core';
@@ -85,13 +85,15 @@ describe('System Types - 系统类型测试', () => {
beforeEach(() => {
Core.create();
// 注册测试组件类型 | Register test component types
// 必须在创建 Scene 之前注册,因为 Scene 会克隆 GlobalComponentRegistry
// Must register before Scene creation, as Scene clones GlobalComponentRegistry
GlobalComponentRegistry.register(TestComponent);
GlobalComponentRegistry.register(AnotherComponent);
scene = new Scene();
entity = scene.createEntity('TestEntity');
// 重置时间系统
Time.update(0.016);
// 注册测试组件类型
ComponentRegistry.register(TestComponent);
ComponentRegistry.register(AnotherComponent);
});
describe('PassiveSystem - 被动系统', () => {