fix: 修复场景反序列化时子实体丢失的问题
在场景反序列化过程中,子实体虽然保持了父子引用关系, 但未被添加到 Scene 的实体集合和查询系统中,导致查询时子实体"丢失"。
This commit is contained in:
@@ -275,15 +275,38 @@ export class SceneSerializer {
|
|||||||
|
|
||||||
// 将实体添加到场景
|
// 将实体添加到场景
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
scene.addEntity(entity);
|
scene.addEntity(entity, true);
|
||||||
|
this.addChildrenRecursively(entity, scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 统一清理缓存(批量操作完成后)
|
||||||
|
scene.querySystem.clearCache();
|
||||||
|
scene.clearSystemEntityCaches();
|
||||||
|
|
||||||
// 反序列化场景自定义数据
|
// 反序列化场景自定义数据
|
||||||
if (serializedScene.sceneData) {
|
if (serializedScene.sceneData) {
|
||||||
this.deserializeSceneData(serializedScene.sceneData, scene.sceneData);
|
this.deserializeSceneData(serializedScene.sceneData, scene.sceneData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归添加实体的所有子实体到场景
|
||||||
|
*
|
||||||
|
* 修复反序列化时子实体丢失的问题:
|
||||||
|
* EntitySerializer.deserialize会提前设置子实体的scene引用,
|
||||||
|
* 导致Entity.addChild的条件判断(!child.scene)跳过scene.addEntity调用。
|
||||||
|
* 因此需要在SceneSerializer中统一递归添加所有子实体。
|
||||||
|
*
|
||||||
|
* @param entity 父实体
|
||||||
|
* @param scene 目标场景
|
||||||
|
*/
|
||||||
|
private static addChildrenRecursively(entity: Entity, scene: IScene): void {
|
||||||
|
for (const child of entity.children) {
|
||||||
|
scene.addEntity(child, true); // 延迟缓存清理
|
||||||
|
this.addChildrenRecursively(child, scene); // 递归处理子实体的子实体
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化场景自定义数据
|
* 序列化场景自定义数据
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* 父子实体序列化和反序列化测试
|
||||||
|
*
|
||||||
|
* 测试场景序列化和反序列化时父子实体关系的正确性
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Scene } from '../../../src';
|
||||||
|
|
||||||
|
describe('父子实体序列化测试', () => {
|
||||||
|
let scene: Scene;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
scene = new Scene({ name: 'TestScene' });
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
scene.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该正确反序列化父子实体层次结构', () => {
|
||||||
|
// 创建父实体
|
||||||
|
const parent = scene.createEntity('parent');
|
||||||
|
parent.tag = 100;
|
||||||
|
|
||||||
|
// 创建2个子实体
|
||||||
|
const child1 = scene.createEntity('child1');
|
||||||
|
child1.tag = 200;
|
||||||
|
parent.addChild(child1);
|
||||||
|
|
||||||
|
const child2 = scene.createEntity('child2');
|
||||||
|
child2.tag = 200;
|
||||||
|
parent.addChild(child2);
|
||||||
|
|
||||||
|
// 创建1个顶层实体(对照组)
|
||||||
|
const topLevel = scene.createEntity('topLevel');
|
||||||
|
topLevel.tag = 200;
|
||||||
|
|
||||||
|
// 验证序列化前的状态
|
||||||
|
expect(scene.querySystem.queryAll().entities.length).toBe(4);
|
||||||
|
expect(scene.findEntitiesByTag(100).length).toBe(1);
|
||||||
|
expect(scene.findEntitiesByTag(200).length).toBe(3);
|
||||||
|
|
||||||
|
// 序列化
|
||||||
|
const serialized = scene.serialize({ format: 'json' });
|
||||||
|
|
||||||
|
// 创建新场景并反序列化
|
||||||
|
const scene2 = new Scene({ name: 'LoadTestScene' });
|
||||||
|
scene2.deserialize(serialized as string, {
|
||||||
|
strategy: 'replace',
|
||||||
|
preserveIds: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 验证所有实体都被正确恢复
|
||||||
|
const allEntities = scene2.querySystem.queryAll().entities;
|
||||||
|
expect(allEntities.length).toBe(4);
|
||||||
|
expect(scene2.findEntitiesByTag(100).length).toBe(1);
|
||||||
|
expect(scene2.findEntitiesByTag(200).length).toBe(3);
|
||||||
|
|
||||||
|
// 验证父子关系正确恢复
|
||||||
|
const restoredParent = scene2.findEntity('parent');
|
||||||
|
expect(restoredParent).not.toBeNull();
|
||||||
|
expect(restoredParent!.children.length).toBe(2);
|
||||||
|
|
||||||
|
const restoredChild1 = scene2.findEntity('child1');
|
||||||
|
const restoredChild2 = scene2.findEntity('child2');
|
||||||
|
expect(restoredChild1).not.toBeNull();
|
||||||
|
expect(restoredChild2).not.toBeNull();
|
||||||
|
expect(restoredChild1!.parent).toBe(restoredParent);
|
||||||
|
expect(restoredChild2!.parent).toBe(restoredParent);
|
||||||
|
|
||||||
|
scene2.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('应该正确反序列化多层级实体层次结构', () => {
|
||||||
|
// 创建多层级实体结构:grandparent -> parent -> child
|
||||||
|
const grandparent = scene.createEntity('grandparent');
|
||||||
|
grandparent.tag = 1;
|
||||||
|
|
||||||
|
const parent = scene.createEntity('parent');
|
||||||
|
parent.tag = 2;
|
||||||
|
grandparent.addChild(parent);
|
||||||
|
|
||||||
|
const child = scene.createEntity('child');
|
||||||
|
child.tag = 3;
|
||||||
|
parent.addChild(child);
|
||||||
|
|
||||||
|
expect(scene.querySystem.queryAll().entities.length).toBe(3);
|
||||||
|
|
||||||
|
// 序列化
|
||||||
|
const serialized = scene.serialize({ format: 'json' });
|
||||||
|
|
||||||
|
// 创建新场景并反序列化
|
||||||
|
const scene2 = new Scene({ name: 'LoadTestScene' });
|
||||||
|
scene2.deserialize(serialized as string, {
|
||||||
|
strategy: 'replace',
|
||||||
|
preserveIds: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 验证多层级结构正确恢复
|
||||||
|
expect(scene2.querySystem.queryAll().entities.length).toBe(3);
|
||||||
|
|
||||||
|
const restoredGrandparent = scene2.findEntity('grandparent');
|
||||||
|
const restoredParent = scene2.findEntity('parent');
|
||||||
|
const restoredChild = scene2.findEntity('child');
|
||||||
|
|
||||||
|
expect(restoredGrandparent).not.toBeNull();
|
||||||
|
expect(restoredParent).not.toBeNull();
|
||||||
|
expect(restoredChild).not.toBeNull();
|
||||||
|
|
||||||
|
expect(restoredParent!.parent).toBe(restoredGrandparent);
|
||||||
|
expect(restoredChild!.parent).toBe(restoredParent);
|
||||||
|
expect(restoredGrandparent!.children.length).toBe(1);
|
||||||
|
expect(restoredParent!.children.length).toBe(1);
|
||||||
|
|
||||||
|
scene2.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user