Files
esengine/packages/core/src/ECS/Serialization/SceneSerializer.ts

537 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 场景序列化器
*
* 负责整个场景的序列化和反序列化,包括实体、组件等
*/
import type { IScene } from '../IScene';
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
import { EntitySerializer, SerializedEntity } from './EntitySerializer';
import { getComponentTypeName } from '../Decorators';
import { getSerializationMetadata } from './SerializationDecorators';
import * as msgpack from 'msgpack-lite';
/**
* 场景序列化格式
*/
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字符串或二进制Buffer
*/
public static serialize(scene: IScene, options?: SceneSerializationOptions): string | Buffer {
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 {
// 二进制格式(使用 MessagePack
return msgpack.encode(serializedScene);
}
}
/**
* 反序列化场景
*
* @param scene 目标场景
* @param saveData 序列化的数据JSON字符串或二进制Buffer
* @param options 反序列化选项
*/
public static deserialize(
scene: IScene,
saveData: string | Buffer,
options?: SceneDeserializationOptions
): void {
const opts: SceneDeserializationOptions = {
strategy: 'replace',
preserveIds: false,
...options
};
// 解析数据
let serializedScene: SerializedScene;
try {
if (typeof saveData === 'string') {
// JSON格式
serializedScene = JSON.parse(saveData);
} else {
// 二进制格式MessagePack
serializedScene = msgpack.decode(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,
scene
);
// 将实体添加到场景
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 ComponentRegistry.getAllComponentNames() as Map<string, ComponentType>;
}
/**
* 验证保存数据的有效性
*
* @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;
}
}
}