/** * 实体序列化器 * * 负责实体的序列化和反序列化操作 */ import { Entity } from '../Entity'; import { Component } from '../Component'; import { ComponentType } from '../Core/ComponentStorage'; import { ComponentSerializer, SerializedComponent } from './ComponentSerializer'; import { IScene } from '../IScene'; /** * 序列化后的实体数据 */ export interface SerializedEntity { /** * 实体ID */ id: number; /** * 实体名称 */ name: string; /** * 实体标签 */ tag: number; /** * 激活状态 */ active: boolean; /** * 启用状态 */ enabled: boolean; /** * 更新顺序 */ updateOrder: number; /** * 组件列表 */ components: SerializedComponent[]; /** * 子实体列表 */ children: SerializedEntity[]; /** * 父实体ID(如果有) */ parentId?: number; } /** * 实体序列化器类 */ export class EntitySerializer { /** * 序列化单个实体 * * @param entity 要序列化的实体 * @param includeChildren 是否包含子实体(默认true) * @returns 序列化后的实体数据 */ public static serialize(entity: Entity, includeChildren: boolean = true): SerializedEntity { const serializedComponents = ComponentSerializer.serializeComponents( Array.from(entity.components) ); const serializedEntity: SerializedEntity = { id: entity.id, name: entity.name, tag: entity.tag, active: entity.active, enabled: entity.enabled, updateOrder: entity.updateOrder, components: serializedComponents, children: [] }; // 序列化父实体引用 if (entity.parent) { serializedEntity.parentId = entity.parent.id; } // 序列化子实体 if (includeChildren) { for (const child of entity.children) { serializedEntity.children.push(this.serialize(child, true)); } } return serializedEntity; } /** * 反序列化实体 * * @param serializedEntity 序列化的实体数据 * @param componentRegistry 组件类型注册表 * @param idGenerator 实体ID生成器(用于生成新ID或保持原ID) * @param preserveIds 是否保持原始ID(默认false) * @param scene 目标场景(可选,用于设置entity.scene以支持添加组件) * @returns 反序列化后的实体 */ public static deserialize( serializedEntity: SerializedEntity, componentRegistry: Map, idGenerator: () => number, preserveIds: boolean = false, scene?: IScene ): Entity { // 创建实体(使用原始ID或新生成的ID) const entityId = preserveIds ? serializedEntity.id : idGenerator(); const entity = new Entity(serializedEntity.name, entityId); // 如果提供了scene,先设置entity.scene以支持添加组件 if (scene) { entity.scene = scene; } // 恢复实体属性 entity.tag = serializedEntity.tag; entity.active = serializedEntity.active; entity.enabled = serializedEntity.enabled; entity.updateOrder = serializedEntity.updateOrder; // 反序列化组件 const components = ComponentSerializer.deserializeComponents( serializedEntity.components, componentRegistry ); for (const component of components) { entity.addComponent(component); } // 反序列化子实体 for (const childData of serializedEntity.children) { const childEntity = this.deserialize( childData, componentRegistry, idGenerator, preserveIds, scene ); entity.addChild(childEntity); } return entity; } /** * 批量序列化实体 * * @param entities 实体数组 * @param includeChildren 是否包含子实体 * @returns 序列化后的实体数据数组 */ public static serializeEntities( entities: Entity[], includeChildren: boolean = true ): SerializedEntity[] { const result: SerializedEntity[] = []; for (const entity of entities) { // 只序列化顶层实体(没有父实体的实体) // 子实体会在父实体序列化时一并处理 if (!entity.parent || !includeChildren) { result.push(this.serialize(entity, includeChildren)); } } return result; } /** * 批量反序列化实体 * * @param serializedEntities 序列化的实体数据数组 * @param componentRegistry 组件类型注册表 * @param idGenerator 实体ID生成器 * @param preserveIds 是否保持原始ID * @param scene 目标场景(可选,用于设置entity.scene以支持添加组件) * @returns 反序列化后的实体数组 */ public static deserializeEntities( serializedEntities: SerializedEntity[], componentRegistry: Map, idGenerator: () => number, preserveIds: boolean = false, scene?: IScene ): Entity[] { const result: Entity[] = []; for (const serialized of serializedEntities) { const entity = this.deserialize( serialized, componentRegistry, idGenerator, preserveIds, scene ); result.push(entity); } return result; } /** * 创建实体的深拷贝 * * @param entity 要拷贝的实体 * @param componentRegistry 组件类型注册表 * @param idGenerator ID生成器 * @returns 拷贝后的新实体 */ public static clone( entity: Entity, componentRegistry: Map, idGenerator: () => number ): Entity { const serialized = this.serialize(entity, true); return this.deserialize(serialized, componentRegistry, idGenerator, false); } }