场景自定义序列化支持
This commit is contained in:
371
packages/core/src/ECS/Serialization/VersionMigration.ts
Normal file
371
packages/core/src/ECS/Serialization/VersionMigration.ts
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user