场景自定义序列化支持

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,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;
}
}
}