/** * 静态Protobuf序列化器 * * 使用预生成的protobuf静态模块进行序列化 */ import { Component } from '../../ECS/Component'; import { ProtobufRegistry, ProtoComponentDefinition, isProtoSerializable, getProtoName } from './ProtobufDecorators'; /** * 序列化数据接口 */ export interface SerializedData { /** 序列化类型 */ type: 'protobuf' | 'json'; /** 组件类型名称 */ componentType: string; /** 序列化后的数据 */ data: Uint8Array | any; /** 数据大小(字节) */ size: number; } /** * 静态Protobuf序列化器 * * 使用CLI预生成的protobuf静态模块 */ export class StaticProtobufSerializer { private registry: ProtobufRegistry; private static instance: StaticProtobufSerializer; /** 预生成的protobuf根对象 */ private protobufRoot: any = null; private isInitialized: boolean = false; private constructor() { this.registry = ProtobufRegistry.getInstance(); this.initializeStaticProtobuf(); } public static getInstance(): StaticProtobufSerializer { if (!StaticProtobufSerializer.instance) { StaticProtobufSerializer.instance = new StaticProtobufSerializer(); } return StaticProtobufSerializer.instance; } /** * 初始化静态protobuf模块 */ private async initializeStaticProtobuf(): Promise { try { // 尝试加载预生成的protobuf模块 const ecsProto = await this.loadGeneratedProtobuf(); if (ecsProto && ecsProto.ecs) { this.protobufRoot = ecsProto.ecs; this.isInitialized = true; console.log('[StaticProtobufSerializer] 预生成的Protobuf模块已加载'); } else { console.warn('[StaticProtobufSerializer] 未找到预生成的protobuf模块,将使用JSON序列化'); console.log('💡 请运行: npm run proto:build'); } } catch (error) { console.warn('[StaticProtobufSerializer] 初始化失败,将使用JSON序列化:', error.message); } } /** * 加载预生成的protobuf模块 */ private async loadGeneratedProtobuf(): Promise { const possiblePaths = [ // 项目中的生成路径 './generated/ecs-components', '../generated/ecs-components', '../../generated/ecs-components', // 相对于当前文件的路径 '../../../generated/ecs-components' ]; for (const path of possiblePaths) { try { const module = await import(path); return module; } catch (error) { // 继续尝试下一个路径 continue; } } // 如果所有路径都失败,尝试require方式 for (const path of possiblePaths) { try { const module = require(path); return module; } catch (error) { continue; } } return null; } /** * 序列化组件 */ public serialize(component: Component): SerializedData { const componentType = component.constructor.name; // 检查是否支持protobuf序列化 if (!isProtoSerializable(component) || !this.isInitialized) { return this.fallbackToJSON(component); } try { const protoName = getProtoName(component); if (!protoName) { return this.fallbackToJSON(component); } const definition = this.registry.getComponentDefinition(protoName); if (!definition) { console.warn(`[StaticProtobufSerializer] 未找到组件定义: ${protoName}`); return this.fallbackToJSON(component); } // 获取对应的protobuf消息类型 const MessageType = this.protobufRoot[protoName]; if (!MessageType) { console.warn(`[StaticProtobufSerializer] 未找到protobuf消息类型: ${protoName}`); return this.fallbackToJSON(component); } // 构建protobuf数据对象 const protoData = this.buildProtoData(component, definition); // 验证数据 const error = MessageType.verify(protoData); if (error) { console.warn(`[StaticProtobufSerializer] 数据验证失败: ${error}`); return this.fallbackToJSON(component); } // 创建消息并编码 const message = MessageType.create(protoData); const buffer = MessageType.encode(message).finish(); return { type: 'protobuf', componentType: componentType, data: buffer, size: buffer.length }; } catch (error) { console.warn(`[StaticProtobufSerializer] 序列化失败,回退到JSON: ${componentType}`, error); return this.fallbackToJSON(component); } } /** * 反序列化组件 */ public deserialize(component: Component, serializedData: SerializedData): void { if (serializedData.type === 'json') { this.deserializeFromJSON(component, serializedData.data); return; } if (!this.isInitialized) { console.warn('[StaticProtobufSerializer] Protobuf未初始化,无法反序列化'); return; } try { const protoName = getProtoName(component); if (!protoName) { this.deserializeFromJSON(component, serializedData.data); return; } const MessageType = this.protobufRoot[protoName]; if (!MessageType) { console.warn(`[StaticProtobufSerializer] 反序列化时未找到消息类型: ${protoName}`); return; } // 解码消息 const message = MessageType.decode(serializedData.data as Uint8Array); const data = MessageType.toObject(message); // 应用数据到组件 this.applyDataToComponent(component, data); } catch (error) { console.warn(`[StaticProtobufSerializer] 反序列化失败: ${component.constructor.name}`, error); } } /** * 检查组件是否支持protobuf序列化 */ public canSerialize(component: Component): boolean { return this.isInitialized && isProtoSerializable(component); } /** * 获取序列化统计信息 */ public getStats(): { registeredComponents: number; protobufAvailable: boolean; initialized: boolean; } { return { registeredComponents: this.registry.getAllComponents().size, protobufAvailable: !!this.protobufRoot, initialized: this.isInitialized }; } /** * 手动设置protobuf根对象(用于测试) */ public setProtobufRoot(root: any): void { this.protobufRoot = root; this.isInitialized = !!root; } /** * 构建protobuf数据对象 */ private buildProtoData(component: Component, definition: ProtoComponentDefinition): any { const data: any = {}; for (const [propertyName, fieldDef] of definition.fields) { const value = (component as any)[propertyName]; if (value !== undefined && value !== null) { data[fieldDef.name] = this.convertValueToProtoType(value, fieldDef.type); } } return data; } /** * 转换值到protobuf类型 */ private convertValueToProtoType(value: any, type: string): any { switch (type) { case 'int32': case 'uint32': case 'sint32': case 'fixed32': case 'sfixed32': return parseInt(value) || 0; case 'float': case 'double': return parseFloat(value) || 0; case 'bool': return Boolean(value); case 'string': return String(value); default: return value; } } /** * 应用数据到组件 */ private applyDataToComponent(component: Component, data: any): void { const protoName = getProtoName(component); if (!protoName) return; const definition = this.registry.getComponentDefinition(protoName); if (!definition) return; for (const [propertyName, fieldDef] of definition.fields) { const value = data[fieldDef.name]; if (value !== undefined) { (component as any)[propertyName] = value; } } } /** * 回退到JSON序列化 */ private fallbackToJSON(component: Component): SerializedData { const data = this.defaultJSONSerialize(component); const jsonString = JSON.stringify(data); return { type: 'json', componentType: component.constructor.name, data: data, size: new Blob([jsonString]).size }; } /** * 默认JSON序列化 */ private defaultJSONSerialize(component: Component): any { const data: any = {}; for (const key in component) { if (component.hasOwnProperty(key) && typeof (component as any)[key] !== 'function' && key !== 'id' && key !== 'entity' && key !== '_enabled' && key !== '_updateOrder') { const value = (component as any)[key]; if (this.isSerializableValue(value)) { data[key] = value; } } } return data; } /** * JSON反序列化 */ private deserializeFromJSON(component: Component, data: any): void { for (const key in data) { if (component.hasOwnProperty(key) && typeof (component as any)[key] !== 'function' && key !== 'id' && key !== 'entity' && key !== '_enabled' && key !== '_updateOrder') { (component as any)[key] = data[key]; } } } /** * 检查值是否可序列化 */ private isSerializableValue(value: any): boolean { if (value === null || value === undefined) return true; if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return true; if (Array.isArray(value)) return value.every(v => this.isSerializableValue(v)); if (typeof value === 'object') { try { JSON.stringify(value); return true; } catch { return false; } } return false; } }