新增syncvar高级特性,使用protobuf定义

This commit is contained in:
YHH
2025-08-07 20:23:49 +08:00
parent ea8523be35
commit 2d389308ea
45 changed files with 9656 additions and 454 deletions

View File

@@ -0,0 +1,303 @@
import { NetworkMessage } from './NetworkMessage';
import { NetworkConnection } from '../Core/NetworkConnection';
import { INetworkMessage, MessageData } from '../types/NetworkTypes';
/**
* 消息处理器接口
*/
export interface IMessageHandler<T extends INetworkMessage = INetworkMessage> {
/**
* 处理消息
*
* @param message - 网络消息
* @param connection - 发送消息的连接(服务端有效)
*/
handle(message: T, connection?: NetworkConnection): Promise<void> | void;
}
/**
* 消息处理器注册信息
*/
interface MessageHandlerInfo<T extends MessageData = MessageData> {
handler: IMessageHandler<INetworkMessage<T>>;
messageClass: new (...args: any[]) => INetworkMessage<T>;
priority: number;
}
/**
* 消息处理器管理器
*
* 负责注册、查找和调用消息处理器
* 支持消息优先级和类型匹配
*/
export class MessageHandler {
private static _instance: MessageHandler | null = null;
private _handlers: Map<number, MessageHandlerInfo[]> = new Map();
private _messageClasses: Map<number, new (...args: any[]) => INetworkMessage> = new Map();
/**
* 获取消息处理器单例
*/
public static get Instance(): MessageHandler {
if (!MessageHandler._instance) {
MessageHandler._instance = new MessageHandler();
}
return MessageHandler._instance;
}
private constructor() {}
/**
* 注册消息处理器
*
* @param messageType - 消息类型ID
* @param messageClass - 消息类构造函数
* @param handler - 消息处理器
* @param priority - 处理优先级(数字越小优先级越高)
*/
public registerHandler<TData extends MessageData, T extends INetworkMessage<TData>>(
messageType: number,
messageClass: new (...args: any[]) => T,
handler: IMessageHandler<T>,
priority: number = 0
): void {
// 注册消息类
this._messageClasses.set(messageType, messageClass);
// 获取或创建处理器列表
if (!this._handlers.has(messageType)) {
this._handlers.set(messageType, []);
}
const handlers = this._handlers.get(messageType)!;
// 检查是否已经注册了相同的处理器
const existingIndex = handlers.findIndex(h => h.handler === handler);
if (existingIndex !== -1) {
console.warn(`[MessageHandler] 消息类型 ${messageType} 的处理器已存在,将替换优先级`);
handlers[existingIndex].priority = priority;
} else {
// 添加新处理器
handlers.push({
handler: handler as IMessageHandler<INetworkMessage>,
messageClass: messageClass as new (...args: any[]) => INetworkMessage,
priority
});
}
// 按优先级排序(数字越小优先级越高)
handlers.sort((a, b) => a.priority - b.priority);
console.log(`[MessageHandler] 注册消息处理器: 类型=${messageType}, 优先级=${priority}`);
}
/**
* 注销消息处理器
*
* @param messageType - 消息类型ID
* @param handler - 消息处理器
*/
public unregisterHandler(messageType: number, handler: IMessageHandler): void {
const handlers = this._handlers.get(messageType);
if (!handlers) {
return;
}
const index = handlers.findIndex(h => h.handler === handler);
if (index !== -1) {
handlers.splice(index, 1);
console.log(`[MessageHandler] 注销消息处理器: 类型=${messageType}`);
}
// 如果没有处理器了,清理映射
if (handlers.length === 0) {
this._handlers.delete(messageType);
this._messageClasses.delete(messageType);
}
}
/**
* 处理原始消息数据
*
* @param data - 原始消息数据
* @param connection - 发送消息的连接(服务端有效)
* @returns 是否成功处理
*/
public async handleRawMessage(data: Uint8Array, connection?: NetworkConnection): Promise<boolean> {
if (data.length < 4) {
console.error('[MessageHandler] 消息数据长度不足至少需要4字节消息类型');
return false;
}
// 读取消息类型前4字节
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
const messageType = view.getUint32(0, true);
// 查找消息类
const MessageClass = this._messageClasses.get(messageType);
if (!MessageClass) {
console.warn(`[MessageHandler] 未知的消息类型: ${messageType}`);
return false;
}
// 创建消息实例并反序列化
try {
const message = new MessageClass();
message.deserialize(data);
return await this.handleMessage(message, connection);
} catch (error) {
console.error(`[MessageHandler] 消息反序列化失败 (类型=${messageType}):`, error);
return false;
}
}
/**
* 处理网络消息
*
* @param message - 网络消息
* @param connection - 发送消息的连接(服务端有效)
* @returns 是否成功处理
*/
public async handleMessage(message: INetworkMessage, connection?: NetworkConnection): Promise<boolean> {
const messageType = message.messageType;
const handlers = this._handlers.get(messageType);
if (!handlers || handlers.length === 0) {
console.warn(`[MessageHandler] 没有找到消息类型 ${messageType} 的处理器`);
return false;
}
let handledCount = 0;
// 按优先级顺序执行所有处理器
for (const handlerInfo of handlers) {
try {
const result = handlerInfo.handler.handle(message, connection);
// 支持异步处理器
if (result instanceof Promise) {
await result;
}
handledCount++;
} catch (error) {
console.error(`[MessageHandler] 处理器执行错误 (类型=${messageType}, 优先级=${handlerInfo.priority}):`, error);
// 继续执行其他处理器
}
}
return handledCount > 0;
}
/**
* 获取已注册的消息类型列表
*
* @returns 消息类型数组
*/
public getRegisteredMessageTypes(): number[] {
return Array.from(this._messageClasses.keys());
}
/**
* 检查消息类型是否已注册
*
* @param messageType - 消息类型ID
* @returns 是否已注册
*/
public isMessageTypeRegistered(messageType: number): boolean {
return this._messageClasses.has(messageType);
}
/**
* 获取消息类型的处理器数量
*
* @param messageType - 消息类型ID
* @returns 处理器数量
*/
public getHandlerCount(messageType: number): number {
const handlers = this._handlers.get(messageType);
return handlers ? handlers.length : 0;
}
/**
* 清除所有处理器
*/
public clear(): void {
this._handlers.clear();
this._messageClasses.clear();
console.log('[MessageHandler] 已清除所有消息处理器');
}
/**
* 获取消息处理器统计信息
*
* @returns 统计信息
*/
public getStats(): {
totalMessageTypes: number;
totalHandlers: number;
messageTypes: Array<{
type: number;
handlerCount: number;
className: string;
}>;
} {
let totalHandlers = 0;
const messageTypes: Array<{ type: number; handlerCount: number; className: string }> = [];
for (const [type, handlers] of this._handlers) {
const handlerCount = handlers.length;
totalHandlers += handlerCount;
const MessageClass = this._messageClasses.get(type);
const className = MessageClass ? MessageClass.name : 'Unknown';
messageTypes.push({
type,
handlerCount,
className
});
}
return {
totalMessageTypes: this._messageClasses.size,
totalHandlers,
messageTypes
};
}
}
/**
* 消息处理器装饰器
*
* 用于自动注册消息处理器
*
* @param messageType - 消息类型ID
* @param messageClass - 消息类构造函数
* @param priority - 处理优先级
*/
export function MessageHandlerDecorator<TData extends MessageData, T extends INetworkMessage<TData>>(
messageType: number,
messageClass: new (...args: any[]) => T,
priority: number = 0
) {
return function(target: unknown, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
if (typeof originalMethod !== 'function') {
throw new Error(`[MessageHandlerDecorator] ${propertyKey} is not a function`);
}
// 注册处理器
const handler: IMessageHandler<T> = {
handle: async (message: T, connection?: NetworkConnection) => {
return await originalMethod.call(target, message, connection);
}
};
MessageHandler.Instance.registerHandler(messageType, messageClass, handler, priority);
return descriptor;
};
}

View File

@@ -0,0 +1,511 @@
import { NetworkMessage, JsonMessage } from './NetworkMessage';
/**
* 内置消息类型枚举
*/
export enum MessageType {
// 基础消息类型 (0-99)
RAW = 0,
JSON = 1,
PROTOBUF = 2,
// 连接管理消息 (100-199)
CONNECT_REQUEST = 100,
CONNECT_RESPONSE = 101,
DISCONNECT = 102,
PING = 103,
PONG = 104,
// 身份验证消息 (200-299)
AUTH_REQUEST = 200,
AUTH_RESPONSE = 201,
// 网络对象管理 (300-399)
SPAWN_OBJECT = 300,
DESTROY_OBJECT = 301,
TRANSFER_AUTHORITY = 302,
// 组件同步消息 (400-499)
SYNC_VAR_UPDATE = 400,
COMPONENT_STATE = 401,
BATCH_UPDATE = 402,
// RPC调用消息 (500-599)
CLIENT_RPC = 500,
SERVER_RPC = 501,
RPC_RESPONSE = 502,
// 场景管理消息 (600-699)
SCENE_LOAD = 600,
SCENE_LOADED = 601,
SCENE_UNLOAD = 602,
// 自定义消息 (1000+)
CUSTOM = 1000
}
/**
* 连接请求消息
*/
export class ConnectRequestMessage extends JsonMessage<{
clientVersion: string;
protocolVersion: number;
clientId?: string;
}> {
public override readonly messageType: number = MessageType.CONNECT_REQUEST;
constructor(clientVersion: string = '1.0.0', protocolVersion: number = 1, clientId?: string) {
super({
clientVersion,
protocolVersion,
clientId
});
}
}
/**
* 连接响应消息
*/
export class ConnectResponseMessage extends JsonMessage<{
success: boolean;
clientId: string;
serverVersion: string;
protocolVersion: number;
errorMessage?: string;
}> {
public override readonly messageType: number = MessageType.CONNECT_RESPONSE;
constructor(
success: boolean,
clientId: string,
serverVersion: string = '1.0.0',
protocolVersion: number = 1,
errorMessage?: string
) {
super({
success,
clientId,
serverVersion,
protocolVersion,
errorMessage
});
}
}
/**
* 断开连接消息
*/
export class DisconnectMessage extends JsonMessage<{
reason: string;
code?: number;
}> {
public override readonly messageType: number = MessageType.DISCONNECT;
constructor(reason: string, code?: number) {
super({
reason,
code
});
}
}
/**
* 心跳消息
*/
export class PingMessage extends NetworkMessage<{ pingId: number }> {
public readonly messageType: number = MessageType.PING;
private _data: { pingId: number };
public get data(): { pingId: number } {
return this._data;
}
public get pingId(): number {
return this._data.pingId;
}
public set pingId(value: number) {
this._data.pingId = value;
}
constructor(pingId: number = Date.now()) {
super();
this._data = { pingId };
}
public serialize(): Uint8Array {
const buffer = new ArrayBuffer(12); // 4字节时间戳 + 4字节pingId + 4字节消息类型
const view = new DataView(buffer);
view.setUint32(0, this.messageType, true);
view.setUint32(4, this.timestamp, true);
view.setUint32(8, this._data.pingId, true);
return new Uint8Array(buffer);
}
public deserialize(data: Uint8Array): void {
if (data.length < 12) {
throw new Error('Ping消息数据长度不足');
}
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
// messageType在第0-3字节已经被外部处理
this.timestamp = view.getUint32(4, true);
this._data.pingId = view.getUint32(8, true);
}
}
/**
* 心跳响应消息
*/
export class PongMessage extends NetworkMessage<{ pingId: number; serverTime: number }> {
public readonly messageType: number = MessageType.PONG;
private _data: { pingId: number; serverTime: number };
public get data(): { pingId: number; serverTime: number } {
return this._data;
}
public get pingId(): number {
return this._data.pingId;
}
public set pingId(value: number) {
this._data.pingId = value;
}
public get serverTime(): number {
return this._data.serverTime;
}
public set serverTime(value: number) {
this._data.serverTime = value;
}
constructor(pingId: number = 0, serverTime: number = Date.now()) {
super();
this._data = { pingId, serverTime };
}
public serialize(): Uint8Array {
const buffer = new ArrayBuffer(16); // 4字节消息类型 + 4字节时间戳 + 4字节pingId + 4字节服务器时间
const view = new DataView(buffer);
view.setUint32(0, this.messageType, true);
view.setUint32(4, this.timestamp, true);
view.setUint32(8, this._data.pingId, true);
view.setUint32(12, this._data.serverTime, true);
return new Uint8Array(buffer);
}
public deserialize(data: Uint8Array): void {
if (data.length < 16) {
throw new Error('Pong消息数据长度不足');
}
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
// messageType在第0-3字节已经被外部处理
this.timestamp = view.getUint32(4, true);
this._data.pingId = view.getUint32(8, true);
this._data.serverTime = view.getUint32(12, true);
}
}
/**
* 网络对象生成消息
*/
export class SpawnObjectMessage extends JsonMessage<{
networkId: string;
prefabName: string;
position: { x: number; y: number; z?: number };
rotation?: { x: number; y: number; z: number; w: number };
ownerId: string;
hasAuthority: boolean;
components?: Array<{
type: string;
data: string; // base64编码的protobuf数据
}>;
}> {
public override readonly messageType: number = MessageType.SPAWN_OBJECT;
constructor(
networkId: string,
prefabName: string,
position: { x: number; y: number; z?: number },
ownerId: string,
hasAuthority: boolean = false,
rotation?: { x: number; y: number; z: number; w: number },
components?: Array<{ type: string; data: string }>
) {
super({
networkId,
prefabName,
position,
rotation,
ownerId,
hasAuthority,
components
});
}
}
/**
* 网络对象销毁消息
*/
export class DestroyObjectMessage extends JsonMessage<{
networkId: string;
reason?: string;
}> {
public override readonly messageType: number = MessageType.DESTROY_OBJECT;
constructor(networkId: string, reason?: string) {
super({
networkId,
reason
});
}
}
/**
* 权限转移消息
*/
export class TransferAuthorityMessage extends JsonMessage<{
networkId: string;
newOwnerId: string;
previousOwnerId: string;
}> {
public override readonly messageType: number = MessageType.TRANSFER_AUTHORITY;
constructor(networkId: string, newOwnerId: string, previousOwnerId: string) {
super({
networkId,
newOwnerId,
previousOwnerId
});
}
}
/**
* SyncVar字段更新数据
*/
export interface SyncVarFieldUpdate {
/** 字段编号 */
fieldNumber: number;
/** 字段名称(用于调试) */
propertyKey: string;
/** 序列化后的新值 */
newValue: string | number | boolean | null | undefined | Date | Uint8Array | Record<string, unknown> | unknown[];
/** 序列化后的旧值(用于回滚或调试) */
oldValue?: string | number | boolean | null | undefined | Date | Uint8Array | Record<string, unknown> | unknown[];
/** 字段变化时间戳 */
timestamp: number;
/** 是否是权威字段(只有权威端可以修改) */
authorityOnly?: boolean;
}
/**
* SyncVar更新消息数据结构
*/
export interface SyncVarUpdateData extends Record<string, unknown> {
/** 网络对象ID */
networkId: string;
/** 组件类型名称 */
componentType: string;
/** 字段更新列表 */
fieldUpdates: SyncVarFieldUpdate[];
/** 是否是完整状态同步(而非增量更新) */
isFullSync: boolean;
/** 发送者ID */
senderId: string;
/** 同步序号(用于确保顺序) */
syncSequence: number;
}
/**
* SyncVar更新消息
*
* 支持增量同步和批处理
*/
export class SyncVarUpdateMessage extends JsonMessage<SyncVarUpdateData> {
public override readonly messageType: number = MessageType.SYNC_VAR_UPDATE;
/** 网络对象ID */
public get networkId(): string {
return this.payload.networkId;
}
public set networkId(value: string) {
this.payload.networkId = value;
}
/** 组件类型名称 */
public get componentType(): string {
return this.payload.componentType;
}
public set componentType(value: string) {
this.payload.componentType = value;
}
/** 字段更新列表 */
public get fieldUpdates(): SyncVarFieldUpdate[] {
return this.payload.fieldUpdates;
}
public set fieldUpdates(value: SyncVarFieldUpdate[]) {
this.payload.fieldUpdates = value;
}
/** 是否是完整状态同步(而非增量更新) */
public get isFullSync(): boolean {
return this.payload.isFullSync;
}
public set isFullSync(value: boolean) {
this.payload.isFullSync = value;
}
/** 同步序号(用于确保顺序) */
public get syncSequence(): number {
return this.payload.syncSequence;
}
public set syncSequence(value: number) {
this.payload.syncSequence = value;
}
constructor(
networkId: string = '',
componentType: string = '',
fieldUpdates: SyncVarFieldUpdate[] = [],
isFullSync: boolean = false,
senderId: string = '',
syncSequence: number = 0
) {
const data: SyncVarUpdateData = {
networkId,
componentType,
fieldUpdates,
isFullSync,
senderId,
syncSequence
};
super(data, senderId, syncSequence);
}
/**
* 添加字段更新
*/
public addFieldUpdate(update: SyncVarFieldUpdate): void {
this.payload.fieldUpdates.push(update);
}
/**
* 获取指定字段的更新
*/
public getFieldUpdate(fieldNumber: number): SyncVarFieldUpdate | undefined {
return this.payload.fieldUpdates.find(update => update.fieldNumber === fieldNumber);
}
/**
* 移除指定字段的更新
*/
public removeFieldUpdate(fieldNumber: number): boolean {
const index = this.payload.fieldUpdates.findIndex(update => update.fieldNumber === fieldNumber);
if (index !== -1) {
this.payload.fieldUpdates.splice(index, 1);
return true;
}
return false;
}
/**
* 清空所有字段更新
*/
public clearFieldUpdates(): void {
this.payload.fieldUpdates = [];
}
/**
* 获取更新的字段数量
*/
public getUpdateCount(): number {
return this.payload.fieldUpdates.length;
}
/**
* 检查是否有字段更新
*/
public hasUpdates(): boolean {
return this.payload.fieldUpdates.length > 0;
}
/**
* 创建消息副本
*/
public override clone(): SyncVarUpdateMessage {
return new SyncVarUpdateMessage(
this.payload.networkId,
this.payload.componentType,
[...this.payload.fieldUpdates], // 深拷贝字段更新数组
this.payload.isFullSync,
this.payload.senderId,
this.payload.syncSequence
);
}
/**
* 获取消息统计信息
*/
public getStats(): {
updateCount: number;
estimatedSize: number;
hasAuthorityOnlyFields: boolean;
oldestUpdateTime: number;
newestUpdateTime: number;
} {
if (this.payload.fieldUpdates.length === 0) {
return {
updateCount: 0,
estimatedSize: this.getSize(),
hasAuthorityOnlyFields: false,
oldestUpdateTime: 0,
newestUpdateTime: 0
};
}
const timestamps = this.payload.fieldUpdates.map(u => u.timestamp);
const hasAuthorityOnlyFields = this.payload.fieldUpdates.some(u => u.authorityOnly);
return {
updateCount: this.payload.fieldUpdates.length,
estimatedSize: this.getSize(),
hasAuthorityOnlyFields,
oldestUpdateTime: Math.min(...timestamps),
newestUpdateTime: Math.max(...timestamps)
};
}
}
/**
* 批量更新消息
*
* 用于一次性发送多个对象的状态更新
*/
export class BatchUpdateMessage extends JsonMessage<{
updates: Array<{
networkId: string;
componentType: string;
data: string; // base64编码的完整组件状态
}>;
}> {
public override readonly messageType: number = MessageType.BATCH_UPDATE;
constructor(updates: Array<{ networkId: string; componentType: string; data: string }>) {
super({ updates });
}
}

View File

@@ -0,0 +1,316 @@
import { INetworkMessage, MessageData } from '../types/NetworkTypes';
/**
* 网络消息基类
*
* 所有网络消息都应该继承此类
* 提供消息的序列化和反序列化功能
*/
export abstract class NetworkMessage<TData extends MessageData = MessageData> implements INetworkMessage<TData> {
/**
* 消息类型ID
* 每个消息类型都应该有唯一的ID
*/
public abstract readonly messageType: number;
/**
* 消息数据
*/
public abstract readonly data: TData;
/**
* 消息时间戳
*/
public timestamp: number = Date.now();
/**
* 发送者ID
*/
public senderId?: string;
/**
* 消息序列号
*/
public sequence?: number;
/**
* 序列化消息为二进制数据
*
* @returns 序列化后的数据
*/
public abstract serialize(): Uint8Array;
/**
* 从二进制数据反序列化消息
*
* @param data - 二进制数据
*/
public abstract deserialize(data: Uint8Array): void;
/**
* 创建消息实例
*/
protected constructor(
senderId?: string,
sequence?: number
) {
this.senderId = senderId;
this.sequence = sequence;
}
/**
* 获取消息大小(字节)
*
* @returns 消息大小
*/
public getSize(): number {
return this.serialize().length;
}
/**
* 创建消息副本
*
* @returns 消息副本
*/
public clone(): NetworkMessage<TData> {
const Constructor = this.constructor as new (senderId?: string, sequence?: number) => NetworkMessage<TData>;
const cloned = new Constructor(this.senderId, this.sequence);
const data = this.serialize();
cloned.deserialize(data);
return cloned;
}
}
/**
* 原始二进制消息
*
* 用于传输原始二进制数据,不进行额外的序列化处理
*/
export class RawMessage extends NetworkMessage<Uint8Array> {
public readonly messageType: number = 0;
private _data: Uint8Array;
public get data(): Uint8Array {
return this._data;
}
constructor(
data: Uint8Array = new Uint8Array(0),
senderId?: string,
sequence?: number
) {
super(senderId, sequence);
this._data = data;
}
public serialize(): Uint8Array {
// 创建包含消息类型的完整消息格式:[4字节消息类型][原始数据]
const buffer = new ArrayBuffer(4 + this._data.length);
const view = new DataView(buffer);
const uint8Array = new Uint8Array(buffer);
// 写入消息类型
view.setUint32(0, this.messageType, true);
// 写入原始数据
uint8Array.set(this._data, 4);
return uint8Array;
}
public deserialize(data: Uint8Array): void {
// 原始数据从第4字节开始前4字节是消息类型
this._data = data.subarray(4);
}
}
/**
* JSON消息
*
* 用于传输JSON数据自动进行JSON序列化和反序列化
*/
export class JsonMessage<T = Record<string, unknown>> extends NetworkMessage<Record<string, unknown>> {
public readonly messageType: number = 1;
private _data: Record<string, unknown>;
public get data(): Record<string, unknown> {
return this._data;
}
constructor(
payload: T = {} as T,
senderId?: string,
sequence?: number
) {
super(senderId, sequence);
this._data = { payload };
}
public get payload(): T {
return this._data.payload as T;
}
public serialize(): Uint8Array {
const payloadBytes = this.serializePayload(this._data.payload);
const senderIdBytes = new TextEncoder().encode(this.senderId || '');
const buffer = new ArrayBuffer(
4 + // messageType
8 + // timestamp
4 + // sequence
4 + // senderId length
senderIdBytes.length + // senderId
payloadBytes.length
);
const view = new DataView(buffer);
const uint8Array = new Uint8Array(buffer);
let offset = 0;
view.setUint32(offset, this.messageType, true);
offset += 4;
view.setBigUint64(offset, BigInt(this.timestamp), true);
offset += 8;
view.setUint32(offset, this.sequence || 0, true);
offset += 4;
view.setUint32(offset, senderIdBytes.length, true);
offset += 4;
uint8Array.set(senderIdBytes, offset);
offset += senderIdBytes.length;
uint8Array.set(payloadBytes, offset);
return uint8Array;
}
public deserialize(data: Uint8Array): void {
const view = new DataView(data.buffer, data.byteOffset);
let offset = 4; // 跳过messageType
this.timestamp = Number(view.getBigUint64(offset, true));
offset += 8;
this.sequence = view.getUint32(offset, true);
offset += 4;
const senderIdLength = view.getUint32(offset, true);
offset += 4;
this.senderId = new TextDecoder().decode(data.subarray(offset, offset + senderIdLength));
offset += senderIdLength;
const payloadBytes = data.subarray(offset);
this._data = { payload: this.deserializePayload(payloadBytes) };
}
/**
* 序列化payload子类可以重写以使用不同的序列化策略
*/
protected serializePayload(payload: unknown): Uint8Array {
const jsonString = JSON.stringify(payload);
return new TextEncoder().encode(jsonString);
}
/**
* 反序列化payload子类可以重写以使用不同的反序列化策略
*/
protected deserializePayload(data: Uint8Array): unknown {
const jsonString = new TextDecoder().decode(data);
return JSON.parse(jsonString);
}
}
/**
* Protobuf消息包装器
*
* 用于包装已经序列化的Protobuf数据
*/
export class ProtobufMessage extends NetworkMessage<Uint8Array> {
public readonly messageType: number = 2;
private _componentType: string;
private _data: Uint8Array;
public get componentType(): string {
return this._componentType;
}
public get data(): Uint8Array {
return this._data;
}
constructor(
componentType: string = '',
data: Uint8Array = new Uint8Array(0),
senderId?: string,
sequence?: number
) {
super(senderId, sequence);
this._componentType = componentType;
this._data = data;
}
public serialize(): Uint8Array {
// 创建包含头部信息的消息格式:
// [4字节消息类型][4字节时间戳][1字节组件类型长度][组件类型字符串][protobuf数据]
const typeBytes = new TextEncoder().encode(this._componentType);
const buffer = new ArrayBuffer(4 + 4 + 1 + typeBytes.length + this._data.length);
const view = new DataView(buffer);
const uint8Array = new Uint8Array(buffer);
let offset = 0;
// 写入消息类型4字节
view.setUint32(offset, this.messageType, true);
offset += 4;
// 写入时间戳4字节
view.setUint32(offset, this.timestamp, true);
offset += 4;
// 写入组件类型长度1字节
view.setUint8(offset, typeBytes.length);
offset += 1;
// 写入组件类型字符串
uint8Array.set(typeBytes, offset);
offset += typeBytes.length;
// 写入protobuf数据
uint8Array.set(this._data, offset);
return uint8Array;
}
public deserialize(data: Uint8Array): void {
if (data.length < 9) { // 4+4+1 = 9字节最小长度
throw new Error('Protobuf消息数据长度不足');
}
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
let offset = 4; // 跳过前4字节消息类型
// 读取时间戳4字节
this.timestamp = view.getUint32(offset, true);
offset += 4;
// 读取组件类型长度1字节
const typeLength = view.getUint8(offset);
offset += 1;
if (data.length < offset + typeLength) {
throw new Error('Protobuf消息组件类型数据不足');
}
// 读取组件类型字符串
const typeBytes = data.subarray(offset, offset + typeLength);
this._componentType = new TextDecoder().decode(typeBytes);
offset += typeLength;
// 读取protobuf数据
this._data = data.subarray(offset);
}
}

View File

@@ -0,0 +1,13 @@
/**
* 消息系统导出
*
* 提供网络消息的定义、处理和管理功能
*/
// 消息基类和类型
export * from './NetworkMessage';
export * from './MessageTypes';
export * from './MessageHandler';
// 导出SyncVar相关的接口和类型
export type { SyncVarFieldUpdate } from './MessageTypes';