场景自定义序列化支持

This commit is contained in:
YHH
2025-10-08 18:34:15 +08:00
parent c631290049
commit 06b3f92007
11 changed files with 2610 additions and 4 deletions

View File

@@ -0,0 +1,336 @@
/**
* 组件序列化器
*
* 负责组件的序列化和反序列化操作
*/
import { Component } from '../Component';
import { ComponentType } from '../Core/ComponentStorage';
import { getComponentTypeName } from '../Decorators';
import {
getSerializationMetadata,
isSerializable,
SerializationMetadata
} from './SerializationDecorators';
/**
* 序列化后的组件数据
*/
export interface SerializedComponent {
/**
* 组件类型名称
*/
type: string;
/**
* 序列化版本
*/
version: number;
/**
* 组件数据
*/
data: Record<string, any>;
}
/**
* 组件序列化器类
*/
export class ComponentSerializer {
/**
* 序列化单个组件
*
* @param component 要序列化的组件实例
* @returns 序列化后的组件数据如果组件不可序列化则返回null
*/
public static serialize(component: Component): SerializedComponent | null {
const metadata = getSerializationMetadata(component);
if (!metadata) {
// 组件没有使用@Serializable装饰器不可序列化
return null;
}
const componentType = component.constructor as ComponentType;
const typeName = metadata.options.typeId || getComponentTypeName(componentType);
const data: Record<string, any> = {};
// 序列化标记的字段
for (const [fieldName, options] of metadata.fields) {
const fieldKey = typeof fieldName === 'symbol' ? fieldName.toString() : fieldName;
const value = (component as any)[fieldName];
// 跳过忽略的字段
if (metadata.ignoredFields.has(fieldName)) {
continue;
}
// 使用自定义序列化器或默认序列化
const serializedValue = options.serializer
? options.serializer(value)
: this.serializeValue(value);
// 使用别名或原始字段名
const key = options.alias || fieldKey;
data[key] = serializedValue;
}
return {
type: typeName,
version: metadata.options.version,
data
};
}
/**
* 反序列化组件
*
* @param serializedData 序列化的组件数据
* @param componentRegistry 组件类型注册表 (类型名 -> 构造函数)
* @returns 反序列化后的组件实例如果失败则返回null
*/
public static deserialize(
serializedData: SerializedComponent,
componentRegistry: Map<string, ComponentType>
): Component | null {
const componentClass = componentRegistry.get(serializedData.type);
if (!componentClass) {
console.warn(`未找到组件类型: ${serializedData.type}`);
return null;
}
const metadata = getSerializationMetadata(componentClass);
if (!metadata) {
console.warn(`组件 ${serializedData.type} 不可序列化`);
return null;
}
// 创建组件实例
const component = new componentClass();
// 反序列化字段
for (const [fieldName, options] of metadata.fields) {
const fieldKey = typeof fieldName === 'symbol' ? fieldName.toString() : fieldName;
const key = options.alias || fieldKey;
const serializedValue = serializedData.data[key];
if (serializedValue === undefined) {
continue; // 字段不存在于序列化数据中
}
// 使用自定义反序列化器或默认反序列化
const value = options.deserializer
? options.deserializer(serializedValue)
: this.deserializeValue(serializedValue);
(component as any)[fieldName] = value;
}
return component;
}
/**
* 批量序列化组件
*
* @param components 组件数组
* @returns 序列化后的组件数据数组
*/
public static serializeComponents(components: Component[]): SerializedComponent[] {
const result: SerializedComponent[] = [];
for (const component of components) {
const serialized = this.serialize(component);
if (serialized) {
result.push(serialized);
}
}
return result;
}
/**
* 批量反序列化组件
*
* @param serializedComponents 序列化的组件数据数组
* @param componentRegistry 组件类型注册表
* @returns 反序列化后的组件数组
*/
public static deserializeComponents(
serializedComponents: SerializedComponent[],
componentRegistry: Map<string, ComponentType>
): Component[] {
const result: Component[] = [];
for (const serialized of serializedComponents) {
const component = this.deserialize(serialized, componentRegistry);
if (component) {
result.push(component);
}
}
return result;
}
/**
* 默认值序列化
*
* 处理基本类型、数组、对象等的序列化
*/
private static serializeValue(value: any): any {
if (value === null || value === undefined) {
return value;
}
// 基本类型
const type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
return value;
}
// 日期
if (value instanceof Date) {
return {
__type: 'Date',
value: value.toISOString()
};
}
// 数组
if (Array.isArray(value)) {
return value.map(item => this.serializeValue(item));
}
// Map (如果没有使用@SerializeMap装饰器)
if (value instanceof Map) {
return {
__type: 'Map',
value: Array.from(value.entries())
};
}
// Set
if (value instanceof Set) {
return {
__type: 'Set',
value: Array.from(value)
};
}
// 普通对象
if (type === 'object') {
const result: Record<string, any> = {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
result[key] = this.serializeValue(value[key]);
}
}
return result;
}
// 其他类型(函数等)不序列化
return undefined;
}
/**
* 默认值反序列化
*/
private static deserializeValue(value: any): any {
if (value === null || value === undefined) {
return value;
}
// 基本类型直接返回
const type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
return value;
}
// 处理特殊类型标记
if (type === 'object' && value.__type) {
switch (value.__type) {
case 'Date':
return new Date(value.value);
case 'Map':
return new Map(value.value);
case 'Set':
return new Set(value.value);
}
}
// 数组
if (Array.isArray(value)) {
return value.map(item => this.deserializeValue(item));
}
// 普通对象
if (type === 'object') {
const result: Record<string, any> = {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
result[key] = this.deserializeValue(value[key]);
}
}
return result;
}
return value;
}
/**
* 验证序列化数据的版本
*
* @param serializedData 序列化数据
* @param expectedVersion 期望的版本号
* @returns 版本是否匹配
*/
public static validateVersion(
serializedData: SerializedComponent,
expectedVersion: number
): boolean {
return serializedData.version === expectedVersion;
}
/**
* 获取组件的序列化信息
*
* @param component 组件实例或组件类
* @returns 序列化信息对象,包含类型名、版本、可序列化字段列表
*/
public static getSerializationInfo(component: Component | ComponentType): {
type: string;
version: number;
fields: string[];
ignoredFields: string[];
isSerializable: boolean;
} | null {
const metadata = getSerializationMetadata(component);
if (!metadata) {
return {
type: 'unknown',
version: 0,
fields: [],
ignoredFields: [],
isSerializable: false
};
}
const componentType = typeof component === 'function'
? component
: (component.constructor as ComponentType);
return {
type: metadata.options.typeId || getComponentTypeName(componentType),
version: metadata.options.version,
fields: Array.from(metadata.fields.keys()).map(k =>
typeof k === 'symbol' ? k.toString() : k
),
ignoredFields: Array.from(metadata.ignoredFields).map(k =>
typeof k === 'symbol' ? k.toString() : k
),
isSerializable: true
};
}
}

View File

@@ -0,0 +1,194 @@
/**
* 全局组件类型注册表
*
* 用于序列化系统的组件类型查找和管理
*/
import { Component } from '../Component';
import { ComponentType } from '../Core/ComponentStorage';
import { getComponentTypeName } from '../Decorators';
/**
* 全局组件类型注册表
*
* 维护组件类型名称到构造函数的映射,用于序列化/反序列化
*/
export class ComponentTypeRegistry {
/**
* 组件类型映射表
* Map<类型名称, 构造函数>
*/
private static registry = new Map<string, ComponentType>();
/**
* 注册组件类型
*
* @param componentClass 组件构造函数
* @param typeName 组件类型名称(可选,默认使用类名或@ECSComponent装饰器指定的名称
*
* @example
* ```typescript
* @ECSComponent('Player')
* @Serializable({ version: 1 })
* class PlayerComponent extends Component {
* @Serialize() name: string = '';
* }
*
* // 注册组件
* ComponentTypeRegistry.register(PlayerComponent);
* ```
*/
public static register(componentClass: ComponentType, typeName?: string): void {
const name = typeName || getComponentTypeName(componentClass);
if (this.registry.has(name)) {
console.warn(`Component type "${name}" is already registered, overwriting...`);
}
this.registry.set(name, componentClass);
}
/**
* 批量注册组件类型
*
* @param componentClasses 组件构造函数数组
*
* @example
* ```typescript
* ComponentTypeRegistry.registerMany([
* PlayerComponent,
* PositionComponent,
* VelocityComponent
* ]);
* ```
*/
public static registerMany(componentClasses: ComponentType[]): void {
for (const componentClass of componentClasses) {
this.register(componentClass);
}
}
/**
* 获取组件类型
*
* @param typeName 组件类型名称
* @returns 组件构造函数如果未找到则返回undefined
*/
public static get(typeName: string): ComponentType | undefined {
return this.registry.get(typeName);
}
/**
* 检查组件类型是否已注册
*
* @param typeName 组件类型名称
* @returns 如果已注册返回true
*/
public static has(typeName: string): boolean {
return this.registry.has(typeName);
}
/**
* 取消注册组件类型
*
* @param typeName 组件类型名称
* @returns 如果成功取消注册返回true
*/
public static unregister(typeName: string): boolean {
return this.registry.delete(typeName);
}
/**
* 清空注册表
*/
public static clear(): void {
this.registry.clear();
}
/**
* 获取所有已注册的组件类型名称
*
* @returns 组件类型名称数组
*/
public static getAllTypeNames(): string[] {
return Array.from(this.registry.keys());
}
/**
* 获取所有已注册的组件类型
*
* @returns 组件构造函数数组
*/
public static getAllTypes(): ComponentType[] {
return Array.from(this.registry.values());
}
/**
* 获取注册表的Map副本
*
* @returns 组件类型注册表的副本
*/
public static getRegistry(): Map<string, ComponentType> {
return new Map(this.registry);
}
/**
* 获取注册的组件数量
*
* @returns 已注册的组件类型数量
*/
public static get size(): number {
return this.registry.size;
}
/**
* 从组件实例获取类型名称
*
* @param component 组件实例
* @returns 组件类型名称
*/
public static getTypeName(component: Component): string {
return getComponentTypeName(component.constructor as ComponentType);
}
/**
* 根据组件类查找已注册的类型名称
*
* @param componentClass 组件构造函数
* @returns 类型名称如果未注册则返回undefined
*/
public static findTypeName(componentClass: ComponentType): string | undefined {
const typeName = getComponentTypeName(componentClass);
// 检查是否已注册
if (this.registry.get(typeName) === componentClass) {
return typeName;
}
// 遍历查找
for (const [name, cls] of this.registry) {
if (cls === componentClass) {
return name;
}
}
return undefined;
}
/**
* 自动发现并注册所有装饰的组件
*
* 注意:此方法需要组件类已经被加载到内存中
*
* @param components 组件类数组
*/
public static autoRegister(components: ComponentType[]): void {
for (const component of components) {
try {
this.register(component);
} catch (error) {
console.error(`Failed to auto-register component ${component.name}:`, error);
}
}
}
}

View File

@@ -0,0 +1,223 @@
/**
* 实体序列化器
*
* 负责实体的序列化和反序列化操作
*/
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentType } from '../Core/ComponentStorage';
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
/**
* 序列化后的实体数据
*/
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
* @returns 反序列化后的实体
*/
public static deserialize(
serializedEntity: SerializedEntity,
componentRegistry: Map<string, ComponentType>,
idGenerator: () => number,
preserveIds: boolean = false
): Entity {
// 创建实体使用原始ID或新生成的ID
const entityId = preserveIds ? serializedEntity.id : idGenerator();
const entity = new Entity(serializedEntity.name, entityId);
// 恢复实体属性
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
);
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
* @returns 反序列化后的实体数组
*/
public static deserializeEntities(
serializedEntities: SerializedEntity[],
componentRegistry: Map<string, ComponentType>,
idGenerator: () => number,
preserveIds: boolean = false
): Entity[] {
const result: Entity[] = [];
for (const serialized of serializedEntities) {
const entity = this.deserialize(
serialized,
componentRegistry,
idGenerator,
preserveIds
);
result.push(entity);
}
return result;
}
/**
* 创建实体的深拷贝
*
* @param entity 要拷贝的实体
* @param componentRegistry 组件类型注册表
* @param idGenerator ID生成器
* @returns 拷贝后的新实体
*/
public static clone(
entity: Entity,
componentRegistry: Map<string, ComponentType>,
idGenerator: () => number
): Entity {
const serialized = this.serialize(entity, true);
return this.deserialize(serialized, componentRegistry, idGenerator, false);
}
}

View File

@@ -0,0 +1,529 @@
/**
* 场景序列化器
*
* 负责整个场景的序列化和反序列化,包括实体、组件等
*/
import type { IScene } from '../IScene';
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentType } from '../Core/ComponentStorage';
import { EntitySerializer, SerializedEntity } from './EntitySerializer';
import { getComponentTypeName } from '../Decorators';
import { getSerializationMetadata } from './SerializationDecorators';
import { ComponentTypeRegistry } from './ComponentTypeRegistry';
/**
* 场景序列化格式
*/
export type SerializationFormat = 'json' | 'binary';
/**
* 场景序列化策略
*/
export type DeserializationStrategy = 'merge' | 'replace';
/**
* 版本迁移函数
*/
export type MigrationFunction = (
oldVersion: number,
newVersion: number,
data: any
) => any;
/**
* 场景序列化选项
*/
export interface SceneSerializationOptions {
/**
* 要序列化的组件类型列表
* 如果未指定,则序列化所有可序列化的组件
*/
components?: ComponentType[];
/**
* 是否序列化系统状态(当前不支持)
*/
systems?: boolean;
/**
* 序列化格式
*/
format?: SerializationFormat;
/**
* 是否美化JSON输出仅在format='json'时有效)
*/
pretty?: boolean;
/**
* 是否包含元数据(如序列化时间、版本等)
*/
includeMetadata?: boolean;
}
/**
* 场景反序列化选项
*/
export interface SceneDeserializationOptions {
/**
* 反序列化策略
* - 'merge': 合并到现有场景
* - 'replace': 替换现有场景内容
*/
strategy?: DeserializationStrategy;
/**
* 版本迁移函数
*/
migration?: MigrationFunction;
/**
* 是否保持原始实体ID
*/
preserveIds?: boolean;
/**
* 组件类型注册表
* 如果未提供,将尝试从全局注册表获取
*/
componentRegistry?: Map<string, ComponentType>;
}
/**
* 序列化后的场景数据
*/
export interface SerializedScene {
/**
* 场景名称
*/
name: string;
/**
* 序列化版本
*/
version: number;
/**
* 序列化时间戳
*/
timestamp?: number;
/**
* 场景自定义数据
*
* 存储场景级别的配置和状态
*/
sceneData?: Record<string, any>;
/**
* 实体列表
*/
entities: SerializedEntity[];
/**
* 元数据
*/
metadata?: {
entityCount: number;
componentTypeCount: number;
serializationOptions?: SceneSerializationOptions;
};
/**
* 组件类型注册信息
*/
componentTypeRegistry: Array<{
typeName: string;
version: number;
}>;
}
/**
* 场景序列化器类
*/
export class SceneSerializer {
/**
* 当前序列化版本
*/
private static readonly SERIALIZATION_VERSION = 1;
/**
* 序列化场景
*
* @param scene 要序列化的场景
* @param options 序列化选项
* @returns 序列化后的数据JSON字符串或二进制数据
*/
public static serialize(scene: IScene, options?: SceneSerializationOptions): string {
const opts: SceneSerializationOptions = {
systems: false,
format: 'json',
pretty: true,
includeMetadata: true,
...options
};
// 过滤实体和组件
const entities = this.filterEntities(scene, opts);
// 序列化实体
const serializedEntities = EntitySerializer.serializeEntities(entities, true);
// 收集组件类型信息
const componentTypeRegistry = this.buildComponentTypeRegistry(entities);
// 序列化场景自定义数据
const sceneData = this.serializeSceneData(scene.sceneData);
// 构建序列化数据
const serializedScene: SerializedScene = {
name: scene.name,
version: this.SERIALIZATION_VERSION,
entities: serializedEntities,
componentTypeRegistry
};
// 添加场景数据(如果有)
if (sceneData && Object.keys(sceneData).length > 0) {
serializedScene.sceneData = sceneData;
}
// 添加元数据
if (opts.includeMetadata) {
serializedScene.timestamp = Date.now();
serializedScene.metadata = {
entityCount: serializedEntities.length,
componentTypeCount: componentTypeRegistry.length,
serializationOptions: opts
};
}
// 根据格式返回数据
if (opts.format === 'json') {
return opts.pretty
? JSON.stringify(serializedScene, null, 2)
: JSON.stringify(serializedScene);
} else {
// 二进制格式(未来实现)
throw new Error('Binary serialization format is not yet implemented');
}
}
/**
* 反序列化场景
*
* @param scene 目标场景
* @param saveData 序列化的数据
* @param options 反序列化选项
*/
public static deserialize(
scene: IScene,
saveData: string,
options?: SceneDeserializationOptions
): void {
const opts: SceneDeserializationOptions = {
strategy: 'replace',
preserveIds: false,
...options
};
// 解析数据
let serializedScene: SerializedScene;
try {
serializedScene = JSON.parse(saveData);
} catch (error) {
throw new Error(`Failed to parse save data: ${error}`);
}
// 版本迁移
if (opts.migration && serializedScene.version !== this.SERIALIZATION_VERSION) {
serializedScene = opts.migration(
serializedScene.version,
this.SERIALIZATION_VERSION,
serializedScene
);
}
// 构建组件注册表
const componentRegistry = opts.componentRegistry || this.getGlobalComponentRegistry();
// 根据策略处理场景
if (opts.strategy === 'replace') {
// 清空场景
scene.destroyAllEntities();
}
// ID生成器
const idGenerator = () => scene.identifierPool.checkOut();
// 反序列化实体
const entities = EntitySerializer.deserializeEntities(
serializedScene.entities,
componentRegistry,
idGenerator,
opts.preserveIds || false
);
// 将实体添加到场景
for (const entity of entities) {
scene.addEntity(entity);
}
// 反序列化场景自定义数据
if (serializedScene.sceneData) {
this.deserializeSceneData(serializedScene.sceneData, scene.sceneData);
}
}
/**
* 序列化场景自定义数据
*
* 将 Map<string, any> 转换为普通对象
*/
private static serializeSceneData(sceneData: Map<string, any>): Record<string, any> {
const result: Record<string, any> = {};
for (const [key, value] of sceneData) {
result[key] = this.serializeValue(value);
}
return result;
}
/**
* 反序列化场景自定义数据
*
* 将普通对象还原为 Map<string, any>
*/
private static deserializeSceneData(
data: Record<string, any>,
targetMap: Map<string, any>
): void {
targetMap.clear();
for (const [key, value] of Object.entries(data)) {
targetMap.set(key, this.deserializeValue(value));
}
}
/**
* 序列化单个值
*/
private static serializeValue(value: any): any {
if (value === null || value === undefined) {
return value;
}
// 基本类型
const type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
return value;
}
// Date
if (value instanceof Date) {
return { __type: 'Date', value: value.toISOString() };
}
// Map
if (value instanceof Map) {
return { __type: 'Map', value: Array.from(value.entries()) };
}
// Set
if (value instanceof Set) {
return { __type: 'Set', value: Array.from(value) };
}
// 数组
if (Array.isArray(value)) {
return value.map(item => this.serializeValue(item));
}
// 普通对象
if (type === 'object') {
const result: Record<string, any> = {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
result[key] = this.serializeValue(value[key]);
}
}
return result;
}
// 其他类型不序列化
return undefined;
}
/**
* 反序列化单个值
*/
private static deserializeValue(value: any): any {
if (value === null || value === undefined) {
return value;
}
// 基本类型
const type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
return value;
}
// 处理特殊类型标记
if (type === 'object' && value.__type) {
switch (value.__type) {
case 'Date':
return new Date(value.value);
case 'Map':
return new Map(value.value);
case 'Set':
return new Set(value.value);
}
}
// 数组
if (Array.isArray(value)) {
return value.map(item => this.deserializeValue(item));
}
// 普通对象
if (type === 'object') {
const result: Record<string, any> = {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
result[key] = this.deserializeValue(value[key]);
}
}
return result;
}
return value;
}
/**
* 过滤要序列化的实体和组件
*/
private static filterEntities(scene: IScene, options: SceneSerializationOptions): Entity[] {
const entities = Array.from(scene.entities.buffer);
// 如果指定了组件类型过滤
if (options.components && options.components.length > 0) {
const componentTypeSet = new Set(options.components);
// 只返回拥有指定组件的实体
return entities.filter(entity => {
return Array.from(entity.components).some(component =>
componentTypeSet.has(component.constructor as ComponentType)
);
});
}
return entities;
}
/**
* 构建组件类型注册表
*/
private static buildComponentTypeRegistry(
entities: Entity[]
): Array<{ typeName: string; version: number }> {
const registry = new Map<string, number>();
for (const entity of entities) {
for (const component of entity.components) {
const componentType = component.constructor as ComponentType;
const typeName = getComponentTypeName(componentType);
const metadata = getSerializationMetadata(component);
if (metadata && !registry.has(typeName)) {
registry.set(typeName, metadata.options.version);
}
}
}
return Array.from(registry.entries()).map(([typeName, version]) => ({
typeName,
version
}));
}
/**
* 获取全局组件注册表
*
* 从所有已注册的组件类型构建注册表
*/
private static getGlobalComponentRegistry(): Map<string, ComponentType> {
return ComponentTypeRegistry.getRegistry();
}
/**
* 验证保存数据的有效性
*
* @param saveData 序列化的数据
* @returns 验证结果
*/
public static validate(saveData: string): {
valid: boolean;
version?: number;
errors?: string[];
} {
const errors: string[] = [];
try {
const data = JSON.parse(saveData);
if (!data.version) {
errors.push('Missing version field');
}
if (!data.entities || !Array.isArray(data.entities)) {
errors.push('Missing or invalid entities field');
}
if (!data.componentTypeRegistry || !Array.isArray(data.componentTypeRegistry)) {
errors.push('Missing or invalid componentTypeRegistry field');
}
return {
valid: errors.length === 0,
version: data.version,
errors: errors.length > 0 ? errors : undefined
};
} catch (error) {
return {
valid: false,
errors: [`JSON parse error: ${error}`]
};
}
}
/**
* 获取保存数据的信息(不完全反序列化)
*
* @param saveData 序列化的数据
* @returns 保存数据的元信息
*/
public static getInfo(saveData: string): {
name: string;
version: number;
timestamp?: number;
entityCount: number;
componentTypeCount: number;
} | null {
try {
const data: SerializedScene = JSON.parse(saveData);
return {
name: data.name,
version: data.version,
timestamp: data.timestamp,
entityCount: data.metadata?.entityCount || data.entities.length,
componentTypeCount: data.componentTypeRegistry.length
};
} catch (error) {
return null;
}
}
}

View File

@@ -0,0 +1,254 @@
/**
* 序列化装饰器
*
* 提供组件级别的序列化支持,包括字段级装饰器和类级装饰器
*/
import { Component } from '../Component';
/**
* 序列化元数据的Symbol键
*/
export const SERIALIZABLE_METADATA = Symbol('SerializableMetadata');
export const SERIALIZE_FIELD = Symbol('SerializeField');
export const SERIALIZE_OPTIONS = Symbol('SerializeOptions');
/**
* 可序列化配置选项
*/
export interface SerializableOptions {
/**
* 序列化版本号,用于数据迁移
*/
version: number;
/**
* 组件类型标识符(可选,默认使用类名)
*/
typeId?: string;
}
/**
* 字段序列化配置
*/
export interface FieldSerializeOptions {
/**
* 自定义序列化器
*/
serializer?: (value: any) => any;
/**
* 自定义反序列化器
*/
deserializer?: (value: any) => any;
/**
* 字段别名(用于序列化后的键名)
*/
alias?: string;
}
/**
* 序列化元数据
*/
export interface SerializationMetadata {
options: SerializableOptions;
fields: Map<string | symbol, FieldSerializeOptions>;
ignoredFields: Set<string | symbol>;
}
/**
* 组件可序列化装饰器
*
* 标记组件类为可序列化,必须与字段装饰器配合使用
*
* @param options 序列化配置选项
*
* @example
* ```typescript
* @ECSComponent('Player')
* @Serializable({ version: 1 })
* class PlayerComponent extends Component {
* @Serialize() name: string = 'Player';
* @Serialize() level: number = 1;
* }
* ```
*/
export function Serializable(options: SerializableOptions) {
return function <T extends new (...args: any[]) => Component>(target: T): T {
if (!options || typeof options.version !== 'number') {
throw new Error('Serializable装饰器必须提供有效的版本号');
}
// 初始化或获取现有元数据
let metadata: SerializationMetadata = (target as any)[SERIALIZABLE_METADATA];
if (!metadata) {
metadata = {
options,
fields: new Map(),
ignoredFields: new Set()
};
(target as any)[SERIALIZABLE_METADATA] = metadata;
} else {
metadata.options = options;
}
return target;
};
}
/**
* 字段序列化装饰器
*
* 标记字段为可序列化
*
* @param options 字段序列化选项(可选)
*
* @example
* ```typescript
* @Serialize()
* name: string = 'Player';
*
* @Serialize({ alias: 'hp' })
* health: number = 100;
* ```
*/
export function Serialize(options?: FieldSerializeOptions) {
return function (target: any, propertyKey: string | symbol) {
const constructor = target.constructor;
// 获取或创建元数据
let metadata: SerializationMetadata = constructor[SERIALIZABLE_METADATA];
if (!metadata) {
metadata = {
options: { version: 1 }, // 默认版本
fields: new Map(),
ignoredFields: new Set()
};
constructor[SERIALIZABLE_METADATA] = metadata;
}
// 记录字段
metadata.fields.set(propertyKey, options || {});
};
}
/**
* Map序列化装饰器
*
* 专门用于序列化Map类型字段
*
* @example
* ```typescript
* @SerializeAsMap()
* inventory: Map<string, number> = new Map();
* ```
*/
export function SerializeAsMap() {
return function (target: any, propertyKey: string | symbol) {
Serialize({
serializer: (value: Map<any, any>) => {
if (!(value instanceof Map)) {
return null;
}
return Array.from(value.entries());
},
deserializer: (value: any) => {
if (!Array.isArray(value)) {
return new Map();
}
return new Map(value);
}
})(target, propertyKey);
};
}
/**
* Set序列化装饰器
*
* 专门用于序列化Set类型字段
*
* @example
* ```typescript
* @SerializeAsSet()
* tags: Set<string> = new Set();
* ```
*/
export function SerializeAsSet() {
return function (target: any, propertyKey: string | symbol) {
Serialize({
serializer: (value: Set<any>) => {
if (!(value instanceof Set)) {
return null;
}
return Array.from(value);
},
deserializer: (value: any) => {
if (!Array.isArray(value)) {
return new Set();
}
return new Set(value);
}
})(target, propertyKey);
};
}
/**
* 忽略序列化装饰器
*
* 标记字段不参与序列化
*
* @example
* ```typescript
* @IgnoreSerialization()
* tempCache: any = null;
* ```
*/
export function IgnoreSerialization() {
return function (target: any, propertyKey: string | symbol) {
const constructor = target.constructor;
// 获取或创建元数据
let metadata: SerializationMetadata = constructor[SERIALIZABLE_METADATA];
if (!metadata) {
metadata = {
options: { version: 1 },
fields: new Map(),
ignoredFields: new Set()
};
constructor[SERIALIZABLE_METADATA] = metadata;
}
// 记录忽略字段
metadata.ignoredFields.add(propertyKey);
};
}
/**
* 获取组件的序列化元数据
*
* @param componentClass 组件类或组件实例
* @returns 序列化元数据如果组件不可序列化则返回null
*/
export function getSerializationMetadata(componentClass: any): SerializationMetadata | null {
if (!componentClass) {
return null;
}
// 如果是实例,获取其构造函数
const constructor = typeof componentClass === 'function'
? componentClass
: componentClass.constructor;
return constructor[SERIALIZABLE_METADATA] || null;
}
/**
* 检查组件是否可序列化
*
* @param component 组件类或组件实例
* @returns 如果组件可序列化返回true
*/
export function isSerializable(component: any): boolean {
return getSerializationMetadata(component) !== null;
}

View File

@@ -0,0 +1,371 @@
/**
* 版本迁移系统
*
* 提供组件和场景数据的版本迁移支持
*/
import { SerializedComponent } from './ComponentSerializer';
import { SerializedScene } from './SceneSerializer';
/**
* 组件迁移函数
*/
export type ComponentMigrationFunction = (data: any, fromVersion: number, toVersion: number) => any;
/**
* 场景迁移函数
*/
export type SceneMigrationFunction = (
scene: SerializedScene,
fromVersion: number,
toVersion: number
) => SerializedScene;
/**
* 版本迁移管理器
*/
export class VersionMigrationManager {
/**
* 组件迁移函数注册表
* Map<组件类型名, Map<版本号, 迁移函数>>
*/
private static componentMigrations = new Map<string, Map<number, ComponentMigrationFunction>>();
/**
* 场景迁移函数注册表
* Map<版本号, 迁移函数>
*/
private static sceneMigrations = new Map<number, SceneMigrationFunction>();
/**
* 注册组件迁移函数
*
* @param componentType 组件类型名称
* @param fromVersion 源版本号
* @param toVersion 目标版本号
* @param migration 迁移函数
*
* @example
* ```typescript
* // 从版本1迁移到版本2
* VersionMigrationManager.registerComponentMigration(
* 'PlayerComponent',
* 1,
* 2,
* (data) => {
* // 添加新字段
* data.experience = 0;
* return data;
* }
* );
* ```
*/
public static registerComponentMigration(
componentType: string,
fromVersion: number,
toVersion: number,
migration: ComponentMigrationFunction
): void {
if (!this.componentMigrations.has(componentType)) {
this.componentMigrations.set(componentType, new Map());
}
const versionMap = this.componentMigrations.get(componentType)!;
// 使用fromVersion作为key表示"从这个版本迁移"
versionMap.set(fromVersion, migration);
}
/**
* 注册场景迁移函数
*
* @param fromVersion 源版本号
* @param toVersion 目标版本号
* @param migration 迁移函数
*
* @example
* ```typescript
* VersionMigrationManager.registerSceneMigration(
* 1,
* 2,
* (scene) => {
* // 迁移场景结构
* scene.metadata = { ...scene.metadata, migratedFrom: 1 };
* return scene;
* }
* );
* ```
*/
public static registerSceneMigration(
fromVersion: number,
toVersion: number,
migration: SceneMigrationFunction
): void {
this.sceneMigrations.set(fromVersion, migration);
}
/**
* 迁移组件数据
*
* @param component 序列化的组件数据
* @param targetVersion 目标版本号
* @returns 迁移后的组件数据
*/
public static migrateComponent(
component: SerializedComponent,
targetVersion: number
): SerializedComponent {
const currentVersion = component.version;
if (currentVersion === targetVersion) {
return component; // 版本相同,无需迁移
}
const migrations = this.componentMigrations.get(component.type);
if (!migrations) {
console.warn(`No migration path found for component ${component.type}`);
return component;
}
let migratedData = { ...component };
let version = currentVersion;
// 执行迁移链
while (version < targetVersion) {
const migration = migrations.get(version);
if (!migration) {
console.warn(
`Missing migration from version ${version} to ${version + 1} for ${component.type}`
);
break;
}
migratedData.data = migration(migratedData.data, version, version + 1);
version++;
}
migratedData.version = version;
return migratedData;
}
/**
* 迁移场景数据
*
* @param scene 序列化的场景数据
* @param targetVersion 目标版本号
* @returns 迁移后的场景数据
*/
public static migrateScene(scene: SerializedScene, targetVersion: number): SerializedScene {
const currentVersion = scene.version;
if (currentVersion === targetVersion) {
return scene; // 版本相同,无需迁移
}
let migratedScene = { ...scene };
let version = currentVersion;
// 执行场景级迁移
while (version < targetVersion) {
const migration = this.sceneMigrations.get(version);
if (!migration) {
console.warn(`Missing scene migration from version ${version} to ${version + 1}`);
break;
}
migratedScene = migration(migratedScene, version, version + 1);
version++;
}
migratedScene.version = version;
// 迁移所有组件
migratedScene = this.migrateSceneComponents(migratedScene);
return migratedScene;
}
/**
* 迁移场景中所有组件的版本
*/
private static migrateSceneComponents(scene: SerializedScene): SerializedScene {
const migratedScene = { ...scene };
migratedScene.entities = scene.entities.map(entity => ({
...entity,
components: entity.components.map(component => {
// 查找组件的目标版本
const typeInfo = scene.componentTypeRegistry.find(
t => t.typeName === component.type
);
if (typeInfo && typeInfo.version !== component.version) {
return this.migrateComponent(component, typeInfo.version);
}
return component;
}),
children: this.migrateEntitiesComponents(entity.children, scene.componentTypeRegistry)
}));
return migratedScene;
}
/**
* 递归迁移实体的组件
*/
private static migrateEntitiesComponents(
entities: any[],
typeRegistry: Array<{ typeName: string; version: number }>
): any[] {
return entities.map(entity => ({
...entity,
components: entity.components.map((component: SerializedComponent) => {
const typeInfo = typeRegistry.find(t => t.typeName === component.type);
if (typeInfo && typeInfo.version !== component.version) {
return this.migrateComponent(component, typeInfo.version);
}
return component;
}),
children: this.migrateEntitiesComponents(entity.children, typeRegistry)
}));
}
/**
* 清除所有迁移函数
*/
public static clearMigrations(): void {
this.componentMigrations.clear();
this.sceneMigrations.clear();
}
/**
* 获取组件的迁移路径
*
* @param componentType 组件类型名称
* @returns 可用的迁移版本列表
*/
public static getComponentMigrationPath(componentType: string): number[] {
const migrations = this.componentMigrations.get(componentType);
if (!migrations) {
return [];
}
return Array.from(migrations.keys()).sort((a, b) => a - b);
}
/**
* 获取场景的迁移路径
*
* @returns 可用的场景迁移版本列表
*/
public static getSceneMigrationPath(): number[] {
return Array.from(this.sceneMigrations.keys()).sort((a, b) => a - b);
}
/**
* 检查是否可以迁移组件
*
* @param componentType 组件类型名称
* @param fromVersion 源版本
* @param toVersion 目标版本
* @returns 是否存在完整的迁移路径
*/
public static canMigrateComponent(
componentType: string,
fromVersion: number,
toVersion: number
): boolean {
if (fromVersion === toVersion) {
return true;
}
const migrations = this.componentMigrations.get(componentType);
if (!migrations) {
return false;
}
// 检查是否存在完整的迁移路径
for (let v = fromVersion; v < toVersion; v++) {
if (!migrations.has(v)) {
return false;
}
}
return true;
}
/**
* 检查是否可以迁移场景
*
* @param fromVersion 源版本
* @param toVersion 目标版本
* @returns 是否存在完整的迁移路径
*/
public static canMigrateScene(fromVersion: number, toVersion: number): boolean {
if (fromVersion === toVersion) {
return true;
}
// 检查是否存在完整的场景迁移路径
for (let v = fromVersion; v < toVersion; v++) {
if (!this.sceneMigrations.has(v)) {
return false;
}
}
return true;
}
}
/**
* 便捷的迁移构建器
*
* 提供链式API来定义迁移
*/
export class MigrationBuilder {
private componentType?: string;
private fromVersion: number = 1;
private toVersion: number = 2;
/**
* 设置组件类型
*/
public forComponent(componentType: string): this {
this.componentType = componentType;
return this;
}
/**
* 设置版本范围
*/
public fromVersionToVersion(from: number, to: number): this {
this.fromVersion = from;
this.toVersion = to;
return this;
}
/**
* 注册迁移函数
*/
public migrate(migration: ComponentMigrationFunction | SceneMigrationFunction): void {
if (this.componentType) {
VersionMigrationManager.registerComponentMigration(
this.componentType,
this.fromVersion,
this.toVersion,
migration as ComponentMigrationFunction
);
} else {
VersionMigrationManager.registerSceneMigration(
this.fromVersion,
this.toVersion,
migration as SceneMigrationFunction
);
}
}
}

View File

@@ -0,0 +1,54 @@
/**
* ECS序列化系统
*
* 提供完整的场景、实体和组件序列化支持
*/
// 装饰器
export {
Serializable,
Serialize,
SerializeAsMap,
SerializeAsSet,
IgnoreSerialization,
getSerializationMetadata,
isSerializable,
SERIALIZABLE_METADATA,
SERIALIZE_FIELD,
SERIALIZE_OPTIONS
} from './SerializationDecorators';
export type {
SerializableOptions,
FieldSerializeOptions,
SerializationMetadata
} from './SerializationDecorators';
// 组件序列化器
export { ComponentSerializer } from './ComponentSerializer';
export type { SerializedComponent } from './ComponentSerializer';
// 实体序列化器
export { EntitySerializer } from './EntitySerializer';
export type { SerializedEntity } from './EntitySerializer';
// 场景序列化器
export { SceneSerializer } from './SceneSerializer';
export type {
SerializedScene,
SerializationFormat,
DeserializationStrategy,
MigrationFunction,
SceneSerializationOptions,
SceneDeserializationOptions
} from './SceneSerializer';
// 版本迁移
export { VersionMigrationManager, MigrationBuilder } from './VersionMigration';
export type {
ComponentMigrationFunction,
SceneMigrationFunction
} from './VersionMigration';
// 组件类型注册表
export { ComponentTypeRegistry } from './ComponentTypeRegistry';