移除json序列化只保留protobuf

This commit is contained in:
YHH
2025-08-06 17:42:12 +08:00
parent f3d2950df3
commit 9a08ae74b6
2 changed files with 173 additions and 287 deletions

View File

@@ -18,12 +18,10 @@ import {
* 序列化数据接口
*/
export interface SerializedData {
/** 序列化类型 */
type: 'protobuf' | 'json';
/** 组件类型名称 */
componentType: string;
/** 序列化后的数据 */
data: Uint8Array | any;
data: Uint8Array;
/** 数据大小(字节) */
size: number;
}
@@ -35,15 +33,36 @@ export class ProtobufSerializer {
private registry: ProtobufRegistry;
private static instance: ProtobufSerializer;
/** protobuf.js实例 */
/** protobuf.js实例 */
private protobuf: any = null;
private root: any = null;
/** MessageType缓存映射表 */
private messageTypeCache: Map<string, any> = new Map();
/** 是否启用数据验证 */
private enableValidation: boolean = process.env.NODE_ENV === 'development';
private constructor() {
this.registry = ProtobufRegistry.getInstance();
this.initializeProtobuf();
}
/**
* 设置性能选项
*/
public setPerformanceOptions(options: {
enableValidation?: boolean;
clearCache?: boolean;
}): void {
if (options.enableValidation !== undefined) {
this.enableValidation = options.enableValidation;
}
if (options.clearCache) {
this.messageTypeCache.clear();
}
}
/**
* 自动初始化protobuf支持
*/
@@ -52,9 +71,9 @@ export class ProtobufSerializer {
// 动态导入protobufjs
this.protobuf = await import('protobufjs');
this.buildProtoDefinitions();
console.log('[ProtobufSerializer] Protobuf支持已自动启用');
console.log('[ProtobufSerializer] Protobuf支持已启用');
} catch (error) {
console.warn('[ProtobufSerializer] 无法加载protobufjs将使用JSON序列化:', error);
throw new Error('[ProtobufSerializer] 无法加载protobufjs: ' + error);
}
}
@@ -66,9 +85,9 @@ export class ProtobufSerializer {
}
/**
* 手动初始化protobuf.js(可选,通常会自动初始化)
* 手动初始化protobuf.js
*
* @param protobufJs - protobuf.js库实例
* @param protobufJs protobuf.js库实例
*/
public initialize(protobufJs: any): void {
this.protobuf = protobufJs;
@@ -79,44 +98,44 @@ export class ProtobufSerializer {
/**
* 序列化组件
*
* @param component - 要序列化的组件
* @param component 要序列化的组件
* @returns 序列化数据
* @throws Error 如果组件不支持protobuf序列化
*/
public serialize(component: Component): SerializedData {
const componentType = component.constructor.name;
// 检查是否支持protobuf序列化
if (!isProtoSerializable(component)) {
return this.fallbackToJSON(component);
throw new Error(`[ProtobufSerializer] 组件 ${componentType} 不支持protobuf序列化请添加@ProtoSerializable装饰器`);
}
const protoName = getProtoName(component);
if (!protoName) {
throw new Error(`[ProtobufSerializer] 组件 ${componentType} 未设置protobuf名称`);
}
const definition = this.registry.getComponentDefinition(protoName);
if (!definition) {
throw new Error(`[ProtobufSerializer] 未找到组件定义: ${protoName}`);
}
// 获取protobuf消息类型
const MessageType = this.getMessageType(protoName);
if (!MessageType) {
throw new Error(`[ProtobufSerializer] 未找到消息类型: ${protoName}`);
}
try {
const protoName = getProtoName(component);
if (!protoName) {
return this.fallbackToJSON(component);
}
const definition = this.registry.getComponentDefinition(protoName);
if (!definition) {
console.warn(`[ProtobufSerializer] 未找到组件定义: ${protoName}`);
return this.fallbackToJSON(component);
}
// 构建protobuf数据对象
const protoData = this.buildProtoData(component, definition);
// 获取protobuf消息类型
const MessageType = this.getMessageType(protoName);
if (!MessageType) {
console.warn(`[ProtobufSerializer] 未找到消息类型: ${protoName}`);
return this.fallbackToJSON(component);
}
// 验证数据
const error = MessageType.verify(protoData);
if (error) {
console.warn(`[ProtobufSerializer] 数据验证失败: ${error}`);
return this.fallbackToJSON(component);
// 数据验证(仅在开发环境)
if (this.enableValidation) {
const error = MessageType.verify(protoData);
if (error) {
throw new Error(`[ProtobufSerializer] 数据验证失败: ${error}`);
}
}
// 创建消息并编码
@@ -124,52 +143,44 @@ export class ProtobufSerializer {
const buffer = MessageType.encode(message).finish();
return {
type: 'protobuf',
componentType: componentType,
data: buffer,
size: buffer.length
};
} catch (error) {
console.warn(`[ProtobufSerializer] 序列化失败回退到JSON: ${componentType}`, error);
return this.fallbackToJSON(component);
throw new Error(`[ProtobufSerializer] 序列化失败: ${componentType} - ${error}`);
}
}
/**
* 反序列化组件
*
* @param component - 目标组件实例
* @param serializedData - 序列化数据
* @param component 目标组件实例
* @param serializedData 序列化数据
* @throws Error 如果反序列化失败
*/
public deserialize(component: Component, serializedData: SerializedData): void {
if (serializedData.type === 'json') {
this.deserializeFromJSON(component, serializedData.data);
return;
const protoName = getProtoName(component);
if (!protoName) {
throw new Error(`[ProtobufSerializer] 组件 ${component.constructor.name} 未设置protobuf名称`);
}
const MessageType = this.getMessageType(protoName);
if (!MessageType) {
throw new Error(`[ProtobufSerializer] 未找到消息类型: ${protoName}`);
}
try {
const protoName = getProtoName(component);
if (!protoName) {
this.deserializeFromJSON(component, serializedData.data);
return;
}
const MessageType = this.getMessageType(protoName);
if (!MessageType) {
console.warn(`[ProtobufSerializer] 反序列化时未找到消息类型: ${protoName}`);
return;
}
// 解码消息
const message = MessageType.decode(serializedData.data as Uint8Array);
const message = MessageType.decode(serializedData.data);
const data = MessageType.toObject(message);
// 应用数据到组件
this.applyDataToComponent(component, data);
} catch (error) {
console.warn(`[ProtobufSerializer] 反序列化失败: ${component.constructor.name}`, error);
throw new Error(`[ProtobufSerializer] 反序列化失败: ${component.constructor.name} - ${error}`);
}
}
@@ -181,16 +192,84 @@ export class ProtobufSerializer {
return isProtoSerializable(component);
}
/**
* 批量序列化组件
*
* @param components 要序列化的组件数组
* @returns 序列化结果数组
*/
public serializeBatch(components: Component[]): SerializedData[] {
const results: SerializedData[] = [];
// 按组件类型分组,减少重复查找
const componentGroups = new Map<string, Component[]>();
for (const component of components) {
if (!isProtoSerializable(component)) {
throw new Error(`[ProtobufSerializer] 组件 ${component.constructor.name} 不支持protobuf序列化`);
}
const protoName = getProtoName(component);
if (!protoName) {
throw new Error(`[ProtobufSerializer] 组件 ${component.constructor.name} 未设置protobuf名称`);
}
if (!componentGroups.has(protoName)) {
componentGroups.set(protoName, []);
}
componentGroups.get(protoName)!.push(component);
}
// 按组分别序列化
for (const [protoName, groupComponents] of componentGroups) {
const definition = this.registry.getComponentDefinition(protoName);
const MessageType = this.getMessageType(protoName);
if (!definition || !MessageType) {
throw new Error(`[ProtobufSerializer] 组件类型 ${protoName} 未正确注册`);
}
for (const component of groupComponents) {
try {
const protoData = this.buildProtoData(component, definition);
// 数据验证(仅在开发环境)
if (this.enableValidation) {
const error = MessageType.verify(protoData);
if (error) {
throw new Error(`[ProtobufSerializer] 数据验证失败: ${error}`);
}
}
const message = MessageType.create(protoData);
const buffer = MessageType.encode(message).finish();
results.push({
componentType: component.constructor.name,
data: buffer,
size: buffer.length
});
} catch (error) {
throw new Error(`[ProtobufSerializer] 批量序列化失败: ${component.constructor.name} - ${error}`);
}
}
}
return results;
}
/**
* 获取序列化统计信息
*/
public getStats(): {
registeredComponents: number;
protobufAvailable: boolean;
cacheSize: number;
} {
return {
registeredComponents: this.registry.getAllComponents().size,
protobufAvailable: !!this.protobuf
protobufAvailable: !!this.protobuf,
cacheSize: this.messageTypeCache.size
};
}
@@ -223,7 +302,7 @@ export class ProtobufSerializer {
}
/**
* 转换单个值
* 转换单个值为protobuf类型
*/
private convertSingleValue(value: any, type: ProtoFieldType): any {
switch (type) {
@@ -232,17 +311,17 @@ export class ProtobufSerializer {
case ProtoFieldType.SINT32:
case ProtoFieldType.FIXED32:
case ProtoFieldType.SFIXED32:
return parseInt(value) || 0;
return typeof value === 'number' ? (value | 0) : (parseInt(value) || 0);
case ProtoFieldType.FLOAT:
case ProtoFieldType.DOUBLE:
return parseFloat(value) || 0;
return typeof value === 'number' ? value : (parseFloat(value) || 0);
case ProtoFieldType.BOOL:
return Boolean(value);
return typeof value === 'boolean' ? value : Boolean(value);
case ProtoFieldType.STRING:
return String(value);
return typeof value === 'string' ? value : String(value);
default:
return value;
@@ -267,80 +346,6 @@ export class ProtobufSerializer {
}
}
/**
* 回退到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;
}
/**
* 构建protobuf定义
*/
@@ -350,21 +355,34 @@ export class ProtobufSerializer {
try {
const protoDefinition = this.registry.generateProtoDefinition();
this.root = this.protobuf.parse(protoDefinition).root;
// 清空缓存schema已更新
this.messageTypeCache.clear();
} catch (error) {
console.error('[ProtobufSerializer] 构建protobuf定义失败:', error);
}
}
/**
* 获取消息类型
* 获取消息类型并缓存结果
*/
private getMessageType(typeName: string): any {
if (!this.root) return null;
// 检查缓存
const fullTypeName = `ecs.${typeName}`;
if (this.messageTypeCache.has(fullTypeName)) {
return this.messageTypeCache.get(fullTypeName);
}
try {
return this.root.lookupType(`ecs.${typeName}`);
const messageType = this.root.lookupType(fullTypeName);
// 缓存结果
this.messageTypeCache.set(fullTypeName, messageType);
return messageType;
} catch (error) {
console.warn(`[ProtobufSerializer] 未找到消息类型: ecs.${typeName}`);
console.warn(`[ProtobufSerializer] 未找到消息类型: ${fullTypeName}`);
// 缓存null结果以避免重复查找
this.messageTypeCache.set(fullTypeName, null);
return null;
}
}

View File

@@ -8,7 +8,7 @@ import { isProtoSerializable } from '../Serialization/ProtobufDecorators';
* 快照管理器
*
* 负责创建和管理ECS系统的快照支持完整快照和增量快照
* 现在支持protobuf和JSON混合序列化
* 使用protobuf序列化
*/
export class SnapshotManager {
/** 默认快照配置 */
@@ -167,15 +167,13 @@ export class SnapshotManager {
component.enabled = componentSnapshot.enabled;
// 恢复组件数据
if (this.hasSerializeMethod(component)) {
try {
(component as any).deserialize(componentSnapshot.data);
} catch (error) {
console.warn(`[SnapshotManager] 组件 ${componentSnapshot.type} 反序列化失败:`, error);
}
} else {
this.defaultDeserializeComponent(component, componentSnapshot.data);
const serializedData = componentSnapshot.data as SerializedData;
if (!isProtoSerializable(component)) {
throw new Error(`[SnapshotManager] 组件 ${component.constructor.name} 不支持protobuf反序列化`);
}
this.protobufSerializer.deserialize(component, serializedData);
} catch (error) {
console.error(`[SnapshotManager] 创建组件失败: ${componentSnapshot.type}`, error);
}
@@ -350,28 +348,19 @@ export class SnapshotManager {
/**
* 创建组件快照
*
* 现在支持protobuf和JSON混合序列化
* 使用protobuf序列化
*/
private createComponentSnapshot(component: Component): ComponentSnapshot | null {
if (!this.isComponentSnapshotable(component)) {
return null;
}
let serializedData: SerializedData;
// 优先尝试protobuf序列化
if (isProtoSerializable(component) && this.protobufSerializer.canSerialize(component)) {
try {
serializedData = this.protobufSerializer.serialize(component);
} catch (error) {
console.warn(`[SnapshotManager] Protobuf序列化失败回退到传统方式: ${component.constructor.name}`, error);
serializedData = this.createLegacySerializedData(component);
}
} else {
// 使用传统序列化方式
serializedData = this.createLegacySerializedData(component);
if (!isProtoSerializable(component)) {
throw new Error(`[SnapshotManager] 组件 ${component.constructor.name} 不支持protobuf序列化请添加@ProtoSerializable装饰器`);
}
const serializedData = this.protobufSerializer.serialize(component);
return {
type: component.constructor.name,
id: component.id,
@@ -380,76 +369,6 @@ export class SnapshotManager {
config: this.getComponentSnapshotConfig(component)
};
}
/**
* 创建传统序列化数据
*/
private createLegacySerializedData(component: Component): SerializedData {
let data: any;
if (this.hasSerializeMethod(component)) {
try {
data = (component as any).serialize();
} catch (error) {
console.warn(`[SnapshotManager] 组件序列化失败: ${component.constructor.name}`, error);
data = this.defaultSerializeComponent(component);
}
} else {
data = this.defaultSerializeComponent(component);
}
const jsonString = JSON.stringify(data);
return {
type: 'json',
componentType: component.constructor.name,
data: data,
size: new Blob([jsonString]).size
};
}
/**
* 默认组件序列化
*/
private defaultSerializeComponent(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;
}
/**
* 检查值是否可序列化
*/
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;
}
/**
* 检查组件是否支持快照
@@ -472,12 +391,6 @@ export class SnapshotManager {
return SnapshotManager.DEFAULT_CONFIG;
}
/**
* 检查组件是否有序列化方法
*/
private hasSerializeMethod(component: Component): boolean {
return typeof (component as any).serialize === 'function';
}
/**
* 恢复完整快照
@@ -540,7 +453,7 @@ export class SnapshotManager {
/**
* 从快照恢复组件
*
* 现在支持protobuf和JSON混合反序列化
* 使用protobuf反序列化
*/
private restoreComponentFromSnapshot(entity: Entity, componentSnapshot: ComponentSnapshot): void {
// 查找现有组件
@@ -558,56 +471,11 @@ export class SnapshotManager {
// 恢复组件数据
const serializedData = componentSnapshot.data as SerializedData;
// 检查数据是否为新的SerializedData格式
if (serializedData && typeof serializedData === 'object' && 'type' in serializedData) {
// 使用新的序列化格式
if (serializedData.type === 'protobuf' && isProtoSerializable(component)) {
try {
this.protobufSerializer.deserialize(component, serializedData);
} catch (error) {
console.warn(`[SnapshotManager] Protobuf反序列化失败: ${componentSnapshot.type}`, error);
}
} else if (serializedData.type === 'json') {
// JSON格式反序列化
this.deserializeLegacyData(component, serializedData.data);
}
} else {
// 兼容旧格式数据
this.deserializeLegacyData(component, componentSnapshot.data);
}
}
/**
* 反序列化传统格式数据
*/
private deserializeLegacyData(component: Component, data: any): void {
if (this.hasSerializeMethod(component)) {
try {
(component as any).deserialize(data);
} catch (error) {
console.warn(`[SnapshotManager] 组件 ${component.constructor.name} 反序列化失败:`, error);
}
} else {
// 使用默认反序列化
this.defaultDeserializeComponent(component, data);
}
}
/**
* 默认组件反序列化
*/
private defaultDeserializeComponent(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];
}
if (!isProtoSerializable(component)) {
throw new Error(`[SnapshotManager] 组件 ${component.constructor.name} 不支持protobuf反序列化`);
}
this.protobufSerializer.deserialize(component, serializedData);
}
/**