新增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,271 @@
import 'reflect-metadata';
/**
* SyncVar配置选项
*/
export interface SyncVarOptions {
/**
* 值变化时的回调函数名
*
* 回调函数签名: (oldValue: T, newValue: T) => void
*/
hook?: string;
/**
* 是否只有拥有权限的客户端才能修改
*
* 默认为false任何客户端都可以修改
*/
authorityOnly?: boolean;
/**
* 自定义序列化函数
*
* 如果不提供,将使用默认的类型序列化
*/
serializer?: (value: any) => Uint8Array;
/**
* 自定义反序列化函数
*/
deserializer?: (data: Uint8Array) => any;
/**
* 同步频率限制(毫秒)
*
* 防止过于频繁的网络同步默认为0不限制
*/
throttleMs?: number;
}
/**
* SyncVar元数据信息
*/
export interface SyncVarMetadata {
/**
* 属性名称
*/
propertyKey: string;
/**
* 字段编号用于protobuf序列化
*/
fieldNumber: number;
/**
* 配置选项
*/
options: SyncVarOptions;
/**
* 属性类型
*/
type: Function;
/**
* 最后同步时间(用于频率限制)
*/
lastSyncTime: number;
}
/**
* SyncVar元数据存储
*/
const SYNCVAR_METADATA_KEY = Symbol('syncvar:metadata');
const SYNCVAR_FIELD_COUNTER = Symbol('syncvar:field_counter');
/**
* 获取类的SyncVar元数据
*
* @param target - 目标类
* @returns SyncVar元数据数组
*/
export function getSyncVarMetadata(target: any): SyncVarMetadata[] {
return Reflect.getMetadata(SYNCVAR_METADATA_KEY, target) || [];
}
/**
* 设置类的SyncVar元数据
*
* @param target - 目标类
* @param metadata - 元数据数组
*/
export function setSyncVarMetadata(target: any, metadata: SyncVarMetadata[]): void {
Reflect.defineMetadata(SYNCVAR_METADATA_KEY, metadata, target);
}
/**
* 获取下一个可用的字段编号
*
* @param target - 目标类
* @returns 字段编号
*/
function getNextFieldNumber(target: any): number {
let counter = Reflect.getMetadata(SYNCVAR_FIELD_COUNTER, target) || 1;
const nextNumber = counter;
Reflect.defineMetadata(SYNCVAR_FIELD_COUNTER, counter + 1, target);
return nextNumber;
}
/**
* 检查属性是否为SyncVar
*
* @param target - 目标对象
* @param propertyKey - 属性名
* @returns 是否为SyncVar
*/
export function isSyncVar(target: any, propertyKey: string): boolean {
const metadata = getSyncVarMetadata(target.constructor);
return metadata.some(m => m.propertyKey === propertyKey);
}
/**
* 获取指定属性的SyncVar元数据
*
* @param target - 目标对象
* @param propertyKey - 属性名
* @returns SyncVar元数据
*/
export function getSyncVarMetadataForProperty(target: any, propertyKey: string): SyncVarMetadata | undefined {
const metadata = getSyncVarMetadata(target.constructor);
return metadata.find(m => m.propertyKey === propertyKey);
}
/**
* SyncVar装饰器
*
* 标记字段为自动同步变量,当值改变时会自动发送给其他客户端
*
* @param options - 配置选项
*
* @example
* ```typescript
* class PlayerComponent extends NetworkComponent {
* @SyncVar()
* public health: number = 100;
*
* @SyncVar({ hook: 'onNameChanged' })
* public playerName: string = 'Player';
*
* @SyncVar({ authorityOnly: true })
* public isReady: boolean = false;
*
* onNameChanged(oldName: string, newName: string) {
* console.log(`Name changed: ${oldName} -> ${newName}`);
* }
* }
* ```
*/
export function SyncVar(options: SyncVarOptions = {}): PropertyDecorator {
return function (target: any, propertyKey: string | symbol) {
if (typeof propertyKey !== 'string') {
throw new Error('SyncVar装饰器只能用于字符串属性名');
}
// 获取属性类型
const type = Reflect.getMetadata('design:type', target, propertyKey);
if (!type) {
console.warn(`[SyncVar] 无法获取属性 ${propertyKey} 的类型信息`);
}
// 获取现有元数据
const existingMetadata = getSyncVarMetadata(target.constructor);
// 检查是否已经存在
const existingIndex = existingMetadata.findIndex(m => m.propertyKey === propertyKey);
if (existingIndex !== -1) {
console.warn(`[SyncVar] 属性 ${propertyKey} 已经被标记为SyncVar将覆盖配置`);
existingMetadata[existingIndex].options = options;
existingMetadata[existingIndex].type = type;
} else {
// 添加新的元数据
const fieldNumber = getNextFieldNumber(target.constructor);
const metadata: SyncVarMetadata = {
propertyKey,
fieldNumber,
options,
type,
lastSyncTime: 0
};
existingMetadata.push(metadata);
}
// 保存元数据
setSyncVarMetadata(target.constructor, existingMetadata);
console.log(`[SyncVar] 注册同步变量: ${target.constructor.name}.${propertyKey}, 字段编号: ${existingMetadata.find(m => m.propertyKey === propertyKey)?.fieldNumber}`);
};
}
/**
* 验证SyncVar配置的有效性
*
* @param target - 目标类实例
* @param metadata - SyncVar元数据
* @returns 验证结果
*/
export function validateSyncVarMetadata(target: any, metadata: SyncVarMetadata): {
isValid: boolean;
errors: string[];
} {
const errors: string[] = [];
// 检查属性是否存在
if (!(metadata.propertyKey in target)) {
errors.push(`属性 ${metadata.propertyKey} 不存在于类 ${target.constructor.name}`);
}
// 检查hook函数是否存在
if (metadata.options.hook) {
if (typeof target[metadata.options.hook] !== 'function') {
errors.push(`Hook函数 ${metadata.options.hook} 不存在或不是函数`);
}
}
// 检查自定义序列化函数
if (metadata.options.serializer && typeof metadata.options.serializer !== 'function') {
errors.push(`自定义序列化函数必须是function类型`);
}
if (metadata.options.deserializer && typeof metadata.options.deserializer !== 'function') {
errors.push(`自定义反序列化函数必须是function类型`);
}
// 检查频率限制
if (metadata.options.throttleMs !== undefined &&
(typeof metadata.options.throttleMs !== 'number' || metadata.options.throttleMs < 0)) {
errors.push(`throttleMs必须是非负数`);
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* 获取类的所有SyncVar统计信息
*
* @param target - 目标类
* @returns 统计信息
*/
export function getSyncVarStats(target: any): {
totalCount: number;
withHooks: number;
authorityOnly: number;
customSerialized: number;
throttled: number;
fieldNumbers: number[];
} {
const metadata = getSyncVarMetadata(target);
return {
totalCount: metadata.length,
withHooks: metadata.filter(m => m.options.hook).length,
authorityOnly: metadata.filter(m => m.options.authorityOnly).length,
customSerialized: metadata.filter(m => m.options.serializer || m.options.deserializer).length,
throttled: metadata.filter(m => m.options.throttleMs !== undefined && m.options.throttleMs > 0).length,
fieldNumbers: metadata.map(m => m.fieldNumber).sort((a, b) => a - b)
};
}

View File

@@ -0,0 +1,81 @@
import { createSyncVarProxy } from './SyncVarProxy';
import { getSyncVarMetadata } from './SyncVarDecorator';
import { INetworkSyncable } from '../types/NetworkTypes';
/**
* SyncVar工厂函数
*
* 为NetworkComponent创建带有SyncVar代理的实例
* 这是必需的因为TypeScript类构造函数不能直接返回代理对象
*/
/**
* 创建带SyncVar支持的NetworkComponent实例
*
* @param ComponentClass - 组件类构造函数
* @param args - 构造函数参数
* @returns 带代理的组件实例
*/
export function createNetworkComponent<T extends INetworkSyncable>(
ComponentClass: new (...args: any[]) => T,
...args: any[]
): T {
// 创建组件实例
const instance = new ComponentClass(...args);
// 检查是否有SyncVar字段
const metadata = getSyncVarMetadata(ComponentClass);
if (metadata.length === 0) {
// 没有SyncVar直接返回原实例
return instance;
}
// 创建代理包装实例
const proxy = createSyncVarProxy(instance, {
debugLog: false // 可以根据需要启用调试
});
console.log(`[SyncVarFactory] 为 ${ComponentClass.name} 创建了SyncVar代理包含 ${metadata.length} 个同步字段`);
return proxy;
}
/**
* SyncVar组件装饰器
*
* 装饰器版本的工厂函数自动为类添加SyncVar支持
* 注意由于TypeScript装饰器的限制这个方法有一些局限性
*
* @param options - 配置选项
*/
export function NetworkComponentWithSyncVar(options: { debugLog?: boolean } = {}) {
return function <T extends new (...args: any[]) => INetworkSyncable>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(...args);
// 检查是否需要创建代理
const metadata = getSyncVarMetadata(constructor);
if (metadata.length > 0) {
// 返回代理实例
return createSyncVarProxy(this as INetworkSyncable, {
debugLog: options.debugLog || false
}) as this;
}
return this;
}
} as T;
};
}
/**
* 便捷方法检查实例是否使用了SyncVar工厂创建
*
* @param instance - 组件实例
* @returns 是否使用了SyncVar工厂
*/
export function isNetworkComponentWithSyncVar(instance: any): boolean {
return instance && (instance._syncVarProxied === true || instance.hasSyncVars?.() === true);
}

View File

@@ -0,0 +1,827 @@
import {
SyncVarMetadata,
getSyncVarMetadata,
validateSyncVarMetadata,
getSyncVarMetadataForProperty
} from './SyncVarDecorator';
import { NetworkEnvironment } from '../Core/NetworkEnvironment';
import { SyncVarUpdateMessage, SyncVarFieldUpdate } from '../Messaging/MessageTypes';
import {
SyncVarValue,
INetworkSyncable,
NetworkComponentType,
TypeGuards
} from '../types/NetworkTypes';
/**
* SyncVar变化记录
*/
export interface SyncVarChange {
/**
* 属性名
*/
propertyKey: string;
/**
* 字段编号
*/
fieldNumber: number;
/**
* 旧值
*/
oldValue: SyncVarValue;
/**
* 新值
*/
newValue: SyncVarValue;
/**
* 变化时间戳
*/
timestamp: number;
/**
* 是否需要网络同步
*/
needsSync: boolean;
}
/**
* SyncVar同步数据
*/
export interface SyncVarSyncData {
/**
* 组件类名
*/
componentType: string;
/**
* 网络对象ID将来实现
*/
networkId?: string;
/**
* 字段更新数据
*/
fieldUpdates: Array<{
fieldNumber: number;
data: Uint8Array;
}>;
/**
* 时间戳
*/
timestamp: number;
}
/**
* SyncVar管理器
*
* 负责管理组件的SyncVar变量检测变化处理序列化和同步
*/
export class SyncVarManager {
private static _instance: SyncVarManager | null = null;
/**
* 组件实例的SyncVar变化监听器
* Key: 组件实例的唯一ID
* Value: 变化记录数组
*/
private _componentChanges: Map<string, SyncVarChange[]> = new Map();
/**
* 组件实例的最后同步时间
*/
private _lastSyncTimes: Map<string, Map<string, number>> = new Map();
/**
* 获取SyncVarManager单例
*/
public static get Instance(): SyncVarManager {
if (!SyncVarManager._instance) {
SyncVarManager._instance = new SyncVarManager();
}
return SyncVarManager._instance;
}
private constructor() {}
/**
* 初始化组件的SyncVar系统
*
* @param component - 网络组件实例
* @returns 是否成功初始化
*/
public initializeComponent(component: INetworkSyncable): boolean {
const componentId = this.getComponentId(component);
const metadata = getSyncVarMetadata(component.constructor as NetworkComponentType);
if (metadata.length === 0) {
// 没有SyncVar无需初始化
return false;
}
// 验证所有SyncVar配置
const validationErrors: string[] = [];
for (const meta of metadata) {
const validation = validateSyncVarMetadata(component, meta);
if (!validation.isValid) {
validationErrors.push(...validation.errors);
}
}
if (validationErrors.length > 0) {
console.error(`[SyncVarManager] 组件 ${component.constructor.name} 的SyncVar配置错误:`, validationErrors);
return false;
}
// 初始化变化记录
this._componentChanges.set(componentId, []);
this._lastSyncTimes.set(componentId, new Map());
console.log(`[SyncVarManager] 初始化组件 ${component.constructor.name} 的SyncVar系统${metadata.length} 个同步变量`);
return true;
}
/**
* 清理组件的SyncVar系统
*
* @param component - 网络组件实例
*/
public cleanupComponent(component: INetworkSyncable): void {
const componentId = this.getComponentId(component);
this._componentChanges.delete(componentId);
this._lastSyncTimes.delete(componentId);
}
/**
* 记录SyncVar字段的变化
*
* @param component - 组件实例
* @param propertyKey - 属性名
* @param oldValue - 旧值
* @param newValue - 新值
*/
public recordChange(
component: INetworkSyncable,
propertyKey: string,
oldValue: SyncVarValue,
newValue: SyncVarValue
): void {
const componentId = this.getComponentId(component);
const metadata = getSyncVarMetadataForProperty(component, propertyKey);
if (!metadata) {
console.warn(`[SyncVarManager] 属性 ${propertyKey} 不是SyncVar`);
return;
}
// 检查值是否真的发生了变化
if (!TypeGuards.isSyncVarValue(oldValue) || !TypeGuards.isSyncVarValue(newValue)) {
console.warn(`[SyncVarManager] 无效的SyncVar值类型: ${typeof oldValue}, ${typeof newValue}`);
return;
}
if (this.isValueEqual(oldValue, newValue)) {
return;
}
// 检查频率限制
const now = Date.now();
const lastSyncTimes = this._lastSyncTimes.get(componentId);
const lastSyncTime = lastSyncTimes?.get(propertyKey) || 0;
if (metadata.options.throttleMs && metadata.options.throttleMs > 0) {
if (now - lastSyncTime < metadata.options.throttleMs) {
console.log(`[SyncVarManager] 属性 ${propertyKey} 变化过于频繁,跳过同步`);
return;
}
}
// 检查权限
if (metadata.options.authorityOnly && !this.hasAuthority(component)) {
console.warn(`[SyncVarManager] 属性 ${propertyKey} 需要权限才能修改,但当前没有权限`);
return;
}
// 记录变化
const change: SyncVarChange = {
propertyKey,
fieldNumber: metadata.fieldNumber,
oldValue,
newValue,
timestamp: now,
needsSync: this.shouldSync(component, metadata)
};
let changes = this._componentChanges.get(componentId);
if (!changes) {
changes = [];
this._componentChanges.set(componentId, changes);
}
changes.push(change);
// 更新最后同步时间
if (lastSyncTimes) {
lastSyncTimes.set(propertyKey, now);
}
console.log(`[SyncVarManager] 记录变化: ${component.constructor.name}.${propertyKey} = ${newValue} (was ${oldValue})`);
// 触发hook回调
this.triggerHook(component, metadata, oldValue, newValue);
}
/**
* 获取组件的待同步变化
*
* @param component - 组件实例
* @returns 待同步的变化数组
*/
public getPendingChanges(component: any): SyncVarChange[] {
const componentId = this.getComponentId(component);
const changes = this._componentChanges.get(componentId) || [];
return changes.filter(change => change.needsSync);
}
/**
* 清除组件的变化记录
*
* @param component - 组件实例
* @param propertyKeys - 要清除的属性名数组,如果不提供则清除所有
*/
public clearChanges(component: any, propertyKeys?: string[]): void {
const componentId = this.getComponentId(component);
const changes = this._componentChanges.get(componentId);
if (!changes) {
return;
}
if (propertyKeys) {
// 清除指定属性的变化
const filteredChanges = changes.filter(change => !propertyKeys.includes(change.propertyKey));
this._componentChanges.set(componentId, filteredChanges);
} else {
// 清除所有变化
this._componentChanges.set(componentId, []);
}
}
/**
* 创建同步数据
*
* @param component - 组件实例
* @returns 同步数据
*/
public createSyncData(component: any): SyncVarSyncData | null {
const pendingChanges = this.getPendingChanges(component);
if (pendingChanges.length === 0) {
return null;
}
const fieldUpdates: Array<{ fieldNumber: number; data: Uint8Array }> = [];
for (const change of pendingChanges) {
try {
const serializedData = this.serializeValue(component, change.propertyKey, change.newValue);
fieldUpdates.push({
fieldNumber: change.fieldNumber,
data: serializedData
});
} catch (error) {
console.error(`[SyncVarManager] 序列化失败 ${change.propertyKey}:`, error);
}
}
if (fieldUpdates.length === 0) {
return null;
}
return {
componentType: component.constructor.name,
fieldUpdates,
timestamp: Date.now()
};
}
/**
* 应用同步数据
*
* @param component - 组件实例
* @param syncData - 同步数据
*/
public applySyncData(component: any, syncData: SyncVarSyncData): void {
const metadata = getSyncVarMetadata(component.constructor);
const metadataMap = new Map(metadata.map(m => [m.fieldNumber, m]));
for (const update of syncData.fieldUpdates) {
const meta = metadataMap.get(update.fieldNumber);
if (!meta) {
console.warn(`[SyncVarManager] 未找到字段编号 ${update.fieldNumber} 的元数据`);
continue;
}
try {
const newValue = this.deserializeValue(component, meta.propertyKey, update.data);
const oldValue = component[meta.propertyKey];
// 直接设置值,不通过代理(避免循环触发)
this.setValueDirectly(component, meta.propertyKey, newValue);
// 触发hook回调
this.triggerHook(component, meta, oldValue, newValue);
console.log(`[SyncVarManager] 应用同步: ${component.constructor.name}.${meta.propertyKey} = ${newValue}`);
} catch (error) {
console.error(`[SyncVarManager] 反序列化失败 ${meta.propertyKey}:`, error);
}
}
}
/**
* 生成组件的唯一ID
*
* @param component - 组件实例
* @returns 唯一ID
*/
private getComponentId(component: any): string {
// 简单实现将来可以集成网络ID系统
if (!component._syncVarId) {
component._syncVarId = `${component.constructor.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
return component._syncVarId;
}
/**
* 检查两个值是否相等
*
* @param a - 值A
* @param b - 值B
* @returns 是否相等
*/
private isValueEqual(a: any, b: any): boolean {
// 基础类型比较
if (typeof a !== typeof b) {
return false;
}
if (a === b) {
return true;
}
// 对象比较(浅比较)
if (typeof a === 'object' && a !== null && b !== null) {
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) {
return false;
}
return keysA.every(key => a[key] === b[key]);
}
return false;
}
/**
* 检查组件是否有修改权限
*
* @param component - 组件实例
* @returns 是否有权限
*/
private hasAuthority(component: any): boolean {
// 简单实现:服务端始终有权限
if (NetworkEnvironment.isServer) {
return true;
}
// 客户端检查组件的权限设置
// 如果组件有hasAuthority方法使用它否则默认客户端没有权限
if (typeof component.hasAuthority === 'function') {
return component.hasAuthority();
}
// 默认情况下,客户端对权威字段没有权限
return false;
}
/**
* 检查是否应该同步
*
* @param component - 组件实例
* @param metadata - SyncVar元数据
* @returns 是否应该同步
*/
private shouldSync(component: any, metadata: SyncVarMetadata): boolean {
// 权限检查:权威字段只有在有权限时才同步
if (metadata.options.authorityOnly && !this.hasAuthority(component)) {
console.log(`[SyncVarManager] 字段 ${metadata.propertyKey} 是权威字段,但当前没有权限,跳过同步`);
return false;
}
// 环境检查:服务端可以同步所有字段
if (NetworkEnvironment.isServer) {
return true;
}
// 客户端:非权威字段可以同步,权威字段需要检查权限
if (metadata.options.authorityOnly) {
return this.hasAuthority(component);
}
// 普通字段客户端也可以同步
return true;
}
/**
* 触发hook回调
*
* @param component - 组件实例
* @param metadata - SyncVar元数据
* @param oldValue - 旧值
* @param newValue - 新值
*/
private triggerHook(component: any, metadata: SyncVarMetadata, oldValue: any, newValue: any): void {
if (!metadata.options.hook) {
return;
}
const hookFunction = component[metadata.options.hook];
if (typeof hookFunction === 'function') {
try {
hookFunction.call(component, oldValue, newValue);
} catch (error) {
console.error(`[SyncVarManager] Hook函数执行失败 ${metadata.options.hook}:`, error);
}
}
}
/**
* 序列化值
*
* @param component - 组件实例
* @param propertyKey - 属性名
* @param value - 值
* @returns 序列化数据
*/
private serializeValue(component: any, propertyKey: string, value: any): Uint8Array {
const metadata = getSyncVarMetadataForProperty(component, propertyKey);
if (metadata?.options.serializer) {
return metadata.options.serializer(value);
}
return this.serializeValueToBinary(value);
}
/**
* 反序列化值
*
* @param component - 组件实例
* @param propertyKey - 属性名
* @param data - 序列化数据
* @returns 反序列化的值
*/
private deserializeValue(component: any, propertyKey: string, data: Uint8Array): any {
const metadata = getSyncVarMetadataForProperty(component, propertyKey);
if (metadata?.options.deserializer) {
return metadata.options.deserializer(data);
}
return this.deserializeValueFromBinary(data);
}
/**
* 将值序列化为二进制数据
*/
private serializeValueToBinary(value: any): Uint8Array {
if (value === null || value === undefined) {
return new Uint8Array([0]);
}
if (typeof value === 'boolean') {
return new Uint8Array([1, value ? 1 : 0]);
}
if (typeof value === 'number') {
const buffer = new ArrayBuffer(9);
const view = new DataView(buffer);
view.setUint8(0, 2);
view.setFloat64(1, value, true);
return new Uint8Array(buffer);
}
if (typeof value === 'string') {
const encoded = new TextEncoder().encode(value);
const buffer = new Uint8Array(5 + encoded.length);
const view = new DataView(buffer.buffer);
view.setUint8(0, 3);
view.setUint32(1, encoded.length, true);
buffer.set(encoded, 5);
return buffer;
}
const jsonString = JSON.stringify(value);
const encoded = new TextEncoder().encode(jsonString);
const buffer = new Uint8Array(5 + encoded.length);
const view = new DataView(buffer.buffer);
view.setUint8(0, 4);
view.setUint32(1, encoded.length, true);
buffer.set(encoded, 5);
return buffer;
}
/**
* 从二进制数据反序列化值
*/
private deserializeValueFromBinary(data: Uint8Array): any {
if (data.length === 0) return null;
const view = new DataView(data.buffer, data.byteOffset);
const type = view.getUint8(0);
switch (type) {
case 0: return null;
case 1: return view.getUint8(1) === 1;
case 2: return view.getFloat64(1, true);
case 3: {
const length = view.getUint32(1, true);
return new TextDecoder().decode(data.subarray(5, 5 + length));
}
case 4: {
const length = view.getUint32(1, true);
const jsonString = new TextDecoder().decode(data.subarray(5, 5 + length));
return JSON.parse(jsonString);
}
default:
throw new Error(`未知的序列化类型: ${type}`);
}
}
/**
* 直接设置值(绕过代理)
*
* @param component - 组件实例
* @param propertyKey - 属性名
* @param value - 值
*/
private setValueDirectly(component: any, propertyKey: string, value: any): void {
// 临时禁用代理监听
const originalValue = component._syncVarDisabled;
component._syncVarDisabled = true;
try {
component[propertyKey] = value;
} finally {
component._syncVarDisabled = originalValue;
}
}
/**
* 创建SyncVar更新消息
*
* @param component - 组件实例
* @param networkId - 网络对象ID
* @param senderId - 发送者ID
* @param syncSequence - 同步序号
* @param isFullSync - 是否是完整同步
* @returns SyncVar更新消息如果没有待同步的变化则返回null
*/
public createSyncVarUpdateMessage(
component: any,
networkId: string = '',
senderId: string = '',
syncSequence: number = 0,
isFullSync: boolean = false
): SyncVarUpdateMessage | null {
const pendingChanges = this.getPendingChanges(component);
if (pendingChanges.length === 0) {
return null;
}
// 转换变化记录为消息格式
const fieldUpdates: SyncVarFieldUpdate[] = [];
for (const change of pendingChanges) {
const metadata = getSyncVarMetadataForProperty(component, change.propertyKey);
if (!metadata) {
continue;
}
const fieldUpdate: SyncVarFieldUpdate = {
fieldNumber: change.fieldNumber,
propertyKey: change.propertyKey,
newValue: change.newValue as any,
oldValue: change.oldValue as any,
timestamp: change.timestamp,
authorityOnly: metadata.options.authorityOnly
};
fieldUpdates.push(fieldUpdate);
}
if (fieldUpdates.length === 0) {
return null;
}
const message = new SyncVarUpdateMessage(
networkId,
component.constructor.name,
fieldUpdates,
isFullSync,
senderId,
syncSequence
);
console.log(`[SyncVarManager] 创建SyncVar更新消息: ${component.constructor.name}, ${fieldUpdates.length} 个字段`);
return message;
}
/**
* 应用SyncVar更新消息
*
* @param component - 组件实例
* @param message - SyncVar更新消息
*/
public applySyncVarUpdateMessage(component: any, message: SyncVarUpdateMessage): void {
if (message.componentType !== component.constructor.name) {
console.warn(`[SyncVarManager] 组件类型不匹配: 期望 ${component.constructor.name}, 收到 ${message.componentType}`);
return;
}
const metadata = getSyncVarMetadata(component.constructor);
const metadataMap = new Map(metadata.map(m => [m.fieldNumber, m]));
for (const fieldUpdate of message.fieldUpdates) {
const meta = metadataMap.get(fieldUpdate.fieldNumber);
if (!meta) {
console.warn(`[SyncVarManager] 未找到字段编号 ${fieldUpdate.fieldNumber} 的元数据`);
continue;
}
// 权限检查:权威字段在客户端通常应该接受来自服务端的更新
// 只有当客户端试图应用自己产生的权威字段更新时才拒绝
if (fieldUpdate.authorityOnly && NetworkEnvironment.isClient && !this.hasAuthority(component)) {
// 如果这是来自服务端的更新,则允许应用
// 这里简单实现:客户端接受所有权威字段的更新
console.log(`[SyncVarManager] 客户端接受权威字段更新: ${fieldUpdate.propertyKey}`);
}
try {
const oldValue = component[meta.propertyKey];
// 直接设置值,不通过代理(避免循环触发)
this.setValueDirectly(component, meta.propertyKey, fieldUpdate.newValue);
// 触发hook回调
this.triggerHook(component, meta, oldValue, fieldUpdate.newValue);
console.log(`[SyncVarManager] 应用SyncVar消息更新: ${component.constructor.name}.${meta.propertyKey} = ${fieldUpdate.newValue}`);
} catch (error) {
console.error(`[SyncVarManager] 应用SyncVar更新失败 ${meta.propertyKey}:`, error);
}
}
// 清除对应的变化记录(已经同步完成)
this.clearChanges(component, message.fieldUpdates.map(u => u.propertyKey));
}
/**
* 批量创建多个组件的SyncVar更新消息
*
* @param components - 组件实例数组
* @param networkIds - 对应的网络对象ID数组
* @param senderId - 发送者ID
* @param syncSequence - 同步序号
* @returns SyncVar更新消息数组
*/
public createBatchSyncVarUpdateMessages(
components: any[],
networkIds: string[] = [],
senderId: string = '',
syncSequence: number = 0
): SyncVarUpdateMessage[] {
const messages: SyncVarUpdateMessage[] = [];
for (let i = 0; i < components.length; i++) {
const component = components[i];
const networkId = networkIds[i] || '';
const message = this.createSyncVarUpdateMessage(
component,
networkId,
senderId,
syncSequence + i
);
if (message) {
messages.push(message);
}
}
return messages;
}
/**
* 过滤需要同步的组件
*
* @param components - 组件数组
* @returns 有待同步变化的组件数组
*/
public filterComponentsWithChanges(components: any[]): any[] {
return components.filter(component => {
const pendingChanges = this.getPendingChanges(component);
return pendingChanges.length > 0;
});
}
/**
* 获取组件的变化统计
*
* @param component - 组件实例
* @returns 变化统计信息
*/
public getComponentChangeStats(component: any): {
totalChanges: number;
pendingChanges: number;
lastChangeTime: number;
fieldChangeCounts: Map<string, number>;
hasAuthorityOnlyChanges: boolean;
} {
const componentId = this.getComponentId(component);
const changes = this._componentChanges.get(componentId) || [];
const pendingChanges = changes.filter(c => c.needsSync);
const fieldChangeCounts = new Map<string, number>();
let lastChangeTime = 0;
let hasAuthorityOnlyChanges = false;
for (const change of changes) {
const count = fieldChangeCounts.get(change.propertyKey) || 0;
fieldChangeCounts.set(change.propertyKey, count + 1);
lastChangeTime = Math.max(lastChangeTime, change.timestamp);
if (!hasAuthorityOnlyChanges) {
const metadata = getSyncVarMetadataForProperty(component, change.propertyKey);
if (metadata?.options.authorityOnly) {
hasAuthorityOnlyChanges = true;
}
}
}
return {
totalChanges: changes.length,
pendingChanges: pendingChanges.length,
lastChangeTime,
fieldChangeCounts,
hasAuthorityOnlyChanges
};
}
/**
* 获取管理器统计信息
*
* @returns 统计信息
*/
public getStats(): {
totalComponents: number;
totalChanges: number;
pendingChanges: number;
components: Array<{
id: string;
changes: number;
pending: number;
}>;
} {
let totalChanges = 0;
let pendingChanges = 0;
const components: Array<{ id: string; changes: number; pending: number }> = [];
for (const [componentId, changes] of this._componentChanges) {
const pendingCount = changes.filter(c => c.needsSync).length;
totalChanges += changes.length;
pendingChanges += pendingCount;
components.push({
id: componentId,
changes: changes.length,
pending: pendingCount
});
}
return {
totalComponents: this._componentChanges.size,
totalChanges,
pendingChanges,
components
};
}
}

View File

@@ -0,0 +1,285 @@
import { IMessageHandler } from '../Messaging/MessageHandler';
import { SyncVarUpdateMessage } from '../Messaging/MessageTypes';
import { NetworkConnection } from '../Core/NetworkConnection';
import { NetworkIdentityRegistry } from '../Core/NetworkIdentity';
import { SyncVarManager } from './SyncVarManager';
import { NetworkEnvironment } from '../Core/NetworkEnvironment';
import { ComponentRegistry } from '@esengine/ecs-framework';
import { NetworkManager } from '../Core/NetworkManager';
/**
* SyncVar更新消息处理器
*
* 处理接收到的SyncVar更新消息自动查找目标网络对象并应用更新
*/
export class SyncVarMessageHandler implements IMessageHandler<SyncVarUpdateMessage> {
private _processedMessages: Set<string> = new Set();
private _maxProcessedCache: number = 1000;
/**
* 处理SyncVar更新消息
*
* @param message - SyncVar更新消息
* @param connection - 发送消息的连接(服务端有效)
*/
public async handle(message: SyncVarUpdateMessage, connection?: NetworkConnection): Promise<void> {
try {
// 生成消息唯一标识符用于去重
const messageKey = this.generateMessageKey(message);
if (this._processedMessages.has(messageKey)) {
console.log(`[SyncVarMessageHandler] 跳过重复消息: ${messageKey}`);
return;
}
// 添加到已处理缓存
this.addToProcessedCache(messageKey);
// 验证消息基本有效性
if (!this.validateMessage(message)) {
console.error('[SyncVarMessageHandler] 消息验证失败');
return;
}
// 查找目标网络对象
const targetIdentity = NetworkIdentityRegistry.Instance.find(message.networkId);
if (!targetIdentity) {
console.warn(`[SyncVarMessageHandler] 未找到网络对象: ${message.networkId}`);
return;
}
// 权限检查
if (!this.checkAuthority(message, connection, targetIdentity)) {
console.warn(`[SyncVarMessageHandler] 权限检查失败: ${message.networkId}`);
return;
}
// 查找目标组件
const targetComponent = this.findTargetComponent(targetIdentity, message.componentType);
if (!targetComponent) {
console.warn(`[SyncVarMessageHandler] 未找到目标组件: ${message.componentType} on ${message.networkId}`);
return;
}
// 应用SyncVar更新
this.applySyncVarUpdates(targetComponent, message);
// 更新网络对象的同步信息
targetIdentity.updateSyncTime();
if (message.syncSequence > targetIdentity.syncSequence) {
targetIdentity.syncSequence = message.syncSequence;
}
// 如果是服务端接收的消息,需要转发给其他客户端
if (NetworkEnvironment.isServer && connection) {
await this.forwardToOtherClients(message, connection);
}
console.log(`[SyncVarMessageHandler] 成功处理SyncVar更新: ${message.networkId}.${message.componentType}, ${message.fieldUpdates.length}个字段`);
} catch (error) {
console.error('[SyncVarMessageHandler] 处理SyncVar更新失败:', error);
}
}
/**
* 生成消息唯一标识符
*/
private generateMessageKey(message: SyncVarUpdateMessage): string {
return `${message.networkId}_${message.componentType}_${message.syncSequence}_${message.timestamp}`;
}
/**
* 添加到已处理消息缓存
*/
private addToProcessedCache(messageKey: string): void {
this._processedMessages.add(messageKey);
// 限制缓存大小
if (this._processedMessages.size > this._maxProcessedCache) {
const toDelete = Array.from(this._processedMessages).slice(0, this._maxProcessedCache / 2);
toDelete.forEach(key => this._processedMessages.delete(key));
}
}
/**
* 验证消息基本有效性
*/
private validateMessage(message: SyncVarUpdateMessage): boolean {
if (!message.networkId || !message.componentType) {
console.error('[SyncVarMessageHandler] 消息缺少必要字段');
return false;
}
if (!message.fieldUpdates || message.fieldUpdates.length === 0) {
console.error('[SyncVarMessageHandler] 消息没有字段更新');
return false;
}
// 检查时间戳合理性(不能是未来的时间,不能太久以前)
const now = Date.now();
const maxAge = 60000; // 1分钟
if (message.timestamp > now + 5000 || message.timestamp < now - maxAge) {
console.warn(`[SyncVarMessageHandler] 消息时间戳异常: ${message.timestamp}, 当前: ${now}`);
return false;
}
return true;
}
/**
* 检查操作权限
*/
private checkAuthority(
message: SyncVarUpdateMessage,
connection: NetworkConnection | undefined,
targetIdentity: any
): boolean {
// 服务端始终有权限处理消息
if (NetworkEnvironment.isServer) {
// 但需要检查客户端发送的消息是否有权限修改对象
if (connection) {
// 检查是否是对象拥有者
if (targetIdentity.ownerId && targetIdentity.ownerId !== connection.connectionId) {
// 非拥有者只能发送非权威字段更新
const hasAuthorityOnlyUpdates = message.fieldUpdates.some(update => update.authorityOnly);
if (hasAuthorityOnlyUpdates) {
console.warn(`[SyncVarMessageHandler] 非拥有者 ${connection.connectionId} 尝试修改权威字段`);
return false;
}
}
}
return true;
}
// 客户端接收到的消息通常来自服务端,应该允许
if (NetworkEnvironment.isClient) {
return true;
}
return false;
}
/**
* 查找目标组件
*/
private findTargetComponent(targetIdentity: any, componentType: string): any {
const entity = targetIdentity.entity;
if (!entity || typeof entity.getComponent !== 'function') {
console.error('[SyncVarMessageHandler] NetworkIdentity缺少有效的Entity引用');
return null;
}
try {
// 获取组件类
const ComponentClass = this.getComponentClassByName(componentType);
if (!ComponentClass) {
return null;
}
// 使用Entity的getComponent方法查找组件
const component = entity.getComponent(ComponentClass);
if (!component) {
console.warn(`[SyncVarMessageHandler] Entity ${entity.id} 上未找到组件: ${componentType}`);
return null;
}
return component;
} catch (error) {
console.error(`[SyncVarMessageHandler] 查找组件失败: ${componentType}`, error);
return null;
}
}
/**
* 根据组件名称获取组件类
*/
private getComponentClassByName(componentType: string): any {
const componentClass = ComponentRegistry.getComponentType(componentType);
if (!componentClass) {
console.warn(`[SyncVarMessageHandler] 未找到组件类型: ${componentType}`);
return null;
}
return componentClass;
}
/**
* 应用SyncVar更新到组件
*/
private applySyncVarUpdates(targetComponent: any, message: SyncVarUpdateMessage): void {
const syncVarManager = SyncVarManager.Instance;
try {
syncVarManager.applySyncVarUpdateMessage(targetComponent, message);
} catch (error) {
console.error('[SyncVarMessageHandler] 应用SyncVar更新失败:', error);
throw error;
}
}
/**
* 转发消息给其他客户端(服务端专用)
*/
private async forwardToOtherClients(
message: SyncVarUpdateMessage,
senderConnection: NetworkConnection
): Promise<void> {
try {
// 获取NetworkServer实例
const server = NetworkManager.GetServer();
if (!server || !server.isRunning) {
console.warn('[SyncVarMessageHandler] NetworkServer未运行无法转发消息');
return;
}
// 使用NetworkServer的broadcastSyncVarMessageExcept方法排除发送者
const successCount = await server.broadcastSyncVarMessageExcept(message, senderConnection.connectionId);
if (successCount > 0) {
console.log(`[SyncVarMessageHandler] 成功转发消息给 ${successCount} 个其他客户端 (发送者: ${senderConnection.connectionId})`);
} else {
console.log(`[SyncVarMessageHandler] 没有其他客户端需要转发消息 (发送者: ${senderConnection.connectionId})`);
}
} catch (error) {
console.error(`[SyncVarMessageHandler] 转发消息失败 (发送者: ${senderConnection.connectionId}):`, error);
}
}
/**
* 获取处理器统计信息
*/
public getStats(): {
processedMessages: number;
cacheSize: number;
maxCacheSize: number;
} {
return {
processedMessages: this._processedMessages.size,
cacheSize: this._processedMessages.size,
maxCacheSize: this._maxProcessedCache
};
}
/**
* 清理已处理消息缓存
*/
public clearProcessedCache(): void {
this._processedMessages.clear();
console.log('[SyncVarMessageHandler] 已清理消息处理缓存');
}
/**
* 设置最大缓存大小
*/
public setMaxCacheSize(maxSize: number): void {
this._maxProcessedCache = Math.max(100, maxSize);
// 如果当前缓存超过新的最大值,进行清理
if (this._processedMessages.size > this._maxProcessedCache) {
const toDelete = Array.from(this._processedMessages).slice(0, this._processedMessages.size - this._maxProcessedCache);
toDelete.forEach(key => this._processedMessages.delete(key));
}
}
}

View File

@@ -0,0 +1,476 @@
import { SyncVarUpdateMessage, SyncVarFieldUpdate } from '../Messaging/MessageTypes';
/**
* SyncVar优化配置
*/
export interface SyncVarOptimizationConfig {
/** 是否启用消息合并 */
enableMessageMerging: boolean;
/** 最大合并时间窗口(毫秒) */
mergeTimeWindow: number;
/** 是否启用Delta压缩 */
enableDeltaCompression: boolean;
/** 是否启用批量发送 */
enableBatchSending: boolean;
/** 批量大小限制 */
batchSizeLimit: number;
/** 是否启用优先级队列 */
enablePriorityQueue: boolean;
/** 是否启用距离剔除 */
enableDistanceCulling: boolean;
/** 距离剔除半径 */
cullingDistance: number;
/** 是否启用频率限制 */
enableRateLimit: boolean;
/** 每秒最大消息数 */
maxMessagesPerSecond: number;
}
/**
* 消息合并器
*/
export class SyncVarMessageMerger {
private _pendingMessages: Map<string, SyncVarUpdateMessage[]> = new Map();
private _mergeTimers: Map<string, NodeJS.Timeout> = new Map();
private _config: SyncVarOptimizationConfig;
constructor(config: SyncVarOptimizationConfig) {
this._config = config;
}
/**
* 添加消息到合并队列
*
* @param message - SyncVar更新消息
* @param onMerged - 合并完成回调
*/
public addMessage(
message: SyncVarUpdateMessage,
onMerged: (mergedMessage: SyncVarUpdateMessage) => void
): void {
if (!this._config.enableMessageMerging) {
onMerged(message);
return;
}
const key = `${message.networkId}_${message.componentType}`;
// 获取或创建消息列表
let messages = this._pendingMessages.get(key);
if (!messages) {
messages = [];
this._pendingMessages.set(key, messages);
}
// 添加消息到列表
messages.push(message);
// 清除现有计时器
const existingTimer = this._mergeTimers.get(key);
if (existingTimer) {
clearTimeout(existingTimer);
}
// 设置新的合并计时器
const timer = setTimeout(() => {
this.mergeAndSend(key, onMerged);
}, this._config.mergeTimeWindow);
this._mergeTimers.set(key, timer);
}
/**
* 合并并发送消息
*/
private mergeAndSend(
key: string,
onMerged: (mergedMessage: SyncVarUpdateMessage) => void
): void {
const messages = this._pendingMessages.get(key);
if (!messages || messages.length === 0) {
return;
}
// 清理
this._pendingMessages.delete(key);
this._mergeTimers.delete(key);
if (messages.length === 1) {
// 只有一个消息,直接发送
onMerged(messages[0]);
return;
}
// 合并多个消息
const mergedMessage = this.mergeMessages(messages);
onMerged(mergedMessage);
}
/**
* 合并多个消息为单个消息
*/
private mergeMessages(messages: SyncVarUpdateMessage[]): SyncVarUpdateMessage {
if (messages.length === 1) {
return messages[0];
}
const firstMessage = messages[0];
const fieldUpdateMap = new Map<number, SyncVarFieldUpdate>();
// 合并字段更新(后面的覆盖前面的)
for (const message of messages) {
for (const fieldUpdate of message.fieldUpdates) {
fieldUpdateMap.set(fieldUpdate.fieldNumber, fieldUpdate);
}
}
// 创建合并后的消息
const mergedFieldUpdates = Array.from(fieldUpdateMap.values());
const lastMessage = messages[messages.length - 1];
return new SyncVarUpdateMessage(
firstMessage.networkId,
firstMessage.componentType,
mergedFieldUpdates,
false, // 合并的消息总是增量同步
firstMessage.senderId,
lastMessage.syncSequence // 使用最新的序列号
);
}
/**
* 强制刷新所有待合并的消息
*/
public flush(onMerged: (mergedMessage: SyncVarUpdateMessage) => void): void {
for (const key of this._pendingMessages.keys()) {
this.mergeAndSend(key, onMerged);
}
}
/**
* 清理所有待合并的消息
*/
public clear(): void {
// 清除所有计时器
for (const timer of this._mergeTimers.values()) {
clearTimeout(timer);
}
this._pendingMessages.clear();
this._mergeTimers.clear();
}
}
/**
* 频率限制器
*/
export class SyncVarRateLimiter {
private _messageCount: Map<string, number> = new Map();
private _resetTimers: Map<string, NodeJS.Timeout> = new Map();
private _config: SyncVarOptimizationConfig;
constructor(config: SyncVarOptimizationConfig) {
this._config = config;
}
/**
* 检查是否允许发送消息
*
* @param networkId - 网络对象ID
* @returns 是否允许发送
*/
public canSend(networkId: string): boolean {
if (!this._config.enableRateLimit) {
return true;
}
const currentCount = this._messageCount.get(networkId) || 0;
if (currentCount >= this._config.maxMessagesPerSecond) {
return false;
}
// 增加计数
this._messageCount.set(networkId, currentCount + 1);
// 如果这是第一个消息,设置重置计时器
if (currentCount === 0) {
const timer = setTimeout(() => {
this._messageCount.delete(networkId);
this._resetTimers.delete(networkId);
}, 1000);
this._resetTimers.set(networkId, timer);
}
return true;
}
/**
* 重置指定对象的频率限制
*/
public reset(networkId: string): void {
this._messageCount.delete(networkId);
const timer = this._resetTimers.get(networkId);
if (timer) {
clearTimeout(timer);
this._resetTimers.delete(networkId);
}
}
/**
* 清理所有频率限制
*/
public clear(): void {
for (const timer of this._resetTimers.values()) {
clearTimeout(timer);
}
this._messageCount.clear();
this._resetTimers.clear();
}
}
/**
* 距离剔除器
*/
export class SyncVarDistanceCuller {
private _config: SyncVarOptimizationConfig;
private _positionCache: Map<string, { x: number; y: number; z?: number }> = new Map();
constructor(config: SyncVarOptimizationConfig) {
this._config = config;
}
/**
* 更新对象位置
*
* @param networkId - 网络对象ID
* @param position - 位置坐标
*/
public updatePosition(networkId: string, position: { x: number; y: number; z?: number }): void {
this._positionCache.set(networkId, { ...position });
}
/**
* 检查是否应该向指定观察者发送消息
*
* @param targetId - 目标对象ID
* @param observerId - 观察者ID
* @returns 是否应该发送
*/
public shouldSendTo(targetId: string, observerId: string): boolean {
if (!this._config.enableDistanceCulling) {
return true;
}
const targetPos = this._positionCache.get(targetId);
const observerPos = this._positionCache.get(observerId);
if (!targetPos || !observerPos) {
// 位置信息不完整,默认发送
return true;
}
const distance = this.calculateDistance(targetPos, observerPos);
return distance <= this._config.cullingDistance;
}
/**
* 获取在指定范围内的观察者列表
*
* @param targetId - 目标对象ID
* @param observerIds - 观察者ID列表
* @returns 在范围内的观察者ID列表
*/
public getObserversInRange(targetId: string, observerIds: string[]): string[] {
if (!this._config.enableDistanceCulling) {
return observerIds;
}
return observerIds.filter(observerId => this.shouldSendTo(targetId, observerId));
}
/**
* 计算两点之间的距离
*/
private calculateDistance(
pos1: { x: number; y: number; z?: number },
pos2: { x: number; y: number; z?: number }
): number {
const dx = pos1.x - pos2.x;
const dy = pos1.y - pos2.y;
const dz = (pos1.z || 0) - (pos2.z || 0);
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
/**
* 清理位置缓存
*/
public clear(): void {
this._positionCache.clear();
}
/**
* 移除指定对象的位置信息
*/
public remove(networkId: string): void {
this._positionCache.delete(networkId);
}
}
/**
* SyncVar性能优化器
*/
export class SyncVarOptimizer {
private _config: SyncVarOptimizationConfig;
private _messageMerger: SyncVarMessageMerger;
private _rateLimiter: SyncVarRateLimiter;
private _distanceCuller: SyncVarDistanceCuller;
// 统计信息
private _stats = {
messagesProcessed: 0,
messagesBlocked: 0,
messagesMerged: 0,
bytesSaved: 0
};
constructor(config?: Partial<SyncVarOptimizationConfig>) {
// 默认配置
this._config = {
enableMessageMerging: true,
mergeTimeWindow: 16, // 1帧时间
enableDeltaCompression: true,
enableBatchSending: true,
batchSizeLimit: 10,
enablePriorityQueue: true,
enableDistanceCulling: false,
cullingDistance: 100,
enableRateLimit: true,
maxMessagesPerSecond: 60,
...config
};
this._messageMerger = new SyncVarMessageMerger(this._config);
this._rateLimiter = new SyncVarRateLimiter(this._config);
this._distanceCuller = new SyncVarDistanceCuller(this._config);
}
/**
* 处理SyncVar消息优化
*
* @param message - 原始消息
* @param targetObservers - 目标观察者列表
* @param onOptimized - 优化完成回调
*/
public optimizeMessage(
message: SyncVarUpdateMessage,
targetObservers: string[] = [],
onOptimized: (optimizedMessages: SyncVarUpdateMessage[], observers: string[]) => void
): void {
this._stats.messagesProcessed++;
// 频率限制检查
if (!this._rateLimiter.canSend(message.networkId)) {
this._stats.messagesBlocked++;
console.log(`[SyncVarOptimizer] 消息被频率限制阻止: ${message.networkId}`);
return;
}
// 距离剔除
const validObservers = this._distanceCuller.getObserversInRange(message.networkId, targetObservers);
if (validObservers.length === 0 && targetObservers.length > 0) {
this._stats.messagesBlocked++;
console.log(`[SyncVarOptimizer] 消息被距离剔除阻止: ${message.networkId}`);
return;
}
// 消息合并
this._messageMerger.addMessage(message, (mergedMessage) => {
if (mergedMessage !== message) {
this._stats.messagesMerged++;
console.log(`[SyncVarOptimizer] 消息已合并: ${message.networkId}`);
}
onOptimized([mergedMessage], validObservers);
});
}
/**
* 更新对象位置(用于距离剔除)
*/
public updateObjectPosition(networkId: string, position: { x: number; y: number; z?: number }): void {
this._distanceCuller.updatePosition(networkId, position);
}
/**
* 配置优化器
*/
public configure(config: Partial<SyncVarOptimizationConfig>): void {
this._config = { ...this._config, ...config };
console.log('[SyncVarOptimizer] 配置已更新:', this._config);
}
/**
* 强制刷新所有待处理的消息
*/
public flush(onOptimized?: (optimizedMessages: SyncVarUpdateMessage[], observers: string[]) => void): void {
this._messageMerger.flush((mergedMessage) => {
if (onOptimized) {
onOptimized([mergedMessage], []);
}
});
}
/**
* 重置指定对象的优化状态
*/
public resetObject(networkId: string): void {
this._rateLimiter.reset(networkId);
this._distanceCuller.remove(networkId);
}
/**
* 获取优化统计信息
*/
public getStats(): typeof SyncVarOptimizer.prototype._stats & {
config: SyncVarOptimizationConfig;
optimizationRatio: number;
} {
const optimizationRatio = this._stats.messagesProcessed > 0
? (this._stats.messagesBlocked + this._stats.messagesMerged) / this._stats.messagesProcessed
: 0;
return {
...this._stats,
config: { ...this._config },
optimizationRatio
};
}
/**
* 重置统计信息
*/
public resetStats(): void {
this._stats = {
messagesProcessed: 0,
messagesBlocked: 0,
messagesMerged: 0,
bytesSaved: 0
};
}
/**
* 清理优化器
*/
public cleanup(): void {
this._messageMerger.clear();
this._rateLimiter.clear();
this._distanceCuller.clear();
this.resetStats();
}
}

View File

@@ -0,0 +1,296 @@
import { getSyncVarMetadata, isSyncVar } from './SyncVarDecorator';
import { SyncVarManager } from './SyncVarManager';
import { INetworkSyncable, SyncVarValue, TypeGuards } from '../types/NetworkTypes';
/**
* SyncVar代理配置
*/
export interface SyncVarProxyOptions {
/**
* 是否启用调试日志
*/
debugLog?: boolean;
/**
* 自定义属性过滤器
*/
propertyFilter?: (propertyKey: string) => boolean;
}
/**
* 创建SyncVar代理
*
* 为组件实例创建Proxy拦截SyncVar字段的读写操作
* 当字段值发生变化时自动触发同步逻辑
*
* @param target - 目标组件实例
* @param options - 代理配置选项
* @returns 代理包装的组件实例
*/
export function createSyncVarProxy<T extends INetworkSyncable>(
target: T,
options: SyncVarProxyOptions = {}
): T {
const { debugLog = false, propertyFilter } = options;
const syncVarManager = SyncVarManager.Instance;
// 检查目标是否有SyncVar
const metadata = getSyncVarMetadata(target.constructor);
if (metadata.length === 0) {
if (debugLog) {
console.log(`[SyncVarProxy] 对象 ${target.constructor.name} 没有SyncVar返回原对象`);
}
return target;
}
// 初始化SyncVar管理器
syncVarManager.initializeComponent(target);
if (debugLog) {
console.log(`[SyncVarProxy] 为 ${target.constructor.name} 创建代理SyncVar字段:`,
metadata.map(m => m.propertyKey));
}
// 存储原始值的副本,用于比较变化
const originalValues = new Map<string, unknown>();
// 初始化原始值
for (const meta of metadata) {
if (meta.propertyKey in target) {
originalValues.set(meta.propertyKey, (target as Record<string, unknown>)[meta.propertyKey]);
}
}
const proxy = new Proxy(target, {
/**
* 拦截属性读取
*/
get(obj: T, prop: string | symbol): unknown {
// 内部属性和方法直接返回
if (typeof prop === 'symbol' || prop.startsWith('_') || prop.startsWith('$')) {
return Reflect.get(obj, prop);
}
const propertyKey = prop as string;
// 如果有自定义过滤器且不通过,直接返回
if (propertyFilter && !propertyFilter(propertyKey)) {
return Reflect.get(obj, prop);
}
const value = Reflect.get(obj, prop);
if (debugLog && isSyncVar(obj, propertyKey)) {
console.log(`[SyncVarProxy] GET ${obj.constructor.name}.${propertyKey} = ${value}`);
}
return value;
},
/**
* 拦截属性设置
*/
set(obj: T, prop: string | symbol, newValue: unknown): boolean {
// 内部属性和方法直接设置
if (typeof prop === 'symbol' || prop.startsWith('_') || prop.startsWith('$')) {
return Reflect.set(obj, prop, newValue);
}
const propertyKey = prop as string;
// 如果有自定义过滤器且不通过,直接设置
if (propertyFilter && !propertyFilter(propertyKey)) {
return Reflect.set(obj, prop, newValue);
}
// 检查是否被临时禁用(用于避免循环)
if ((obj as any)._syncVarDisabled) {
return Reflect.set(obj, prop, newValue);
}
// 检查是否为SyncVar
if (!isSyncVar(obj, propertyKey)) {
return Reflect.set(obj, prop, newValue);
}
// 获取旧值
const oldValue = originalValues.get(propertyKey);
if (debugLog) {
console.log(`[SyncVarProxy] SET ${obj.constructor.name}.${propertyKey} = ${newValue} (was ${oldValue})`);
}
// 设置新值
const result = Reflect.set(obj, prop, newValue);
if (result) {
// 更新原始值记录
originalValues.set(propertyKey, newValue);
// 记录变化到SyncVar管理器
try {
if (TypeGuards.isSyncVarValue(oldValue) && TypeGuards.isSyncVarValue(newValue)) {
syncVarManager.recordChange(obj, propertyKey, oldValue, newValue);
}
} catch (error) {
console.error(`[SyncVarProxy] 记录SyncVar变化失败:`, error);
}
}
return result;
},
/**
* 拦截属性删除
*/
deleteProperty(obj: T, prop: string | symbol): boolean {
const propertyKey = prop as string;
if (typeof prop === 'string' && isSyncVar(obj, propertyKey)) {
console.warn(`[SyncVarProxy] 尝试删除SyncVar属性 ${propertyKey},这可能会导致同步问题`);
}
return Reflect.deleteProperty(obj, prop);
},
/**
* 拦截属性枚举
*/
ownKeys(obj: T): ArrayLike<string | symbol> {
return Reflect.ownKeys(obj);
},
/**
* 拦截属性描述符获取
*/
getOwnPropertyDescriptor(obj: T, prop: string | symbol): PropertyDescriptor | undefined {
return Reflect.getOwnPropertyDescriptor(obj, prop);
},
/**
* 拦截in操作符
*/
has(obj: T, prop: string | symbol): boolean {
return Reflect.has(obj, prop);
}
});
// 标记为已代理
(proxy as T & { _syncVarProxied: boolean; _syncVarOptions: SyncVarProxyOptions })._syncVarProxied = true;
(proxy as T & { _syncVarProxied: boolean; _syncVarOptions: SyncVarProxyOptions })._syncVarOptions = options;
if (debugLog) {
console.log(`[SyncVarProxy] ${target.constructor.name} 代理创建完成`);
}
return proxy;
}
/**
* 检查对象是否已经被SyncVar代理
*
* @param obj - 要检查的对象
* @returns 是否已被代理
*/
export function isSyncVarProxied(obj: unknown): obj is { _syncVarProxied: boolean } {
return typeof obj === 'object' && obj !== null && '_syncVarProxied' in obj && (obj as any)._syncVarProxied === true;
}
/**
* 获取代理对象的原始目标
*
* @param proxy - 代理对象
* @returns 原始目标对象,如果不是代理则返回原对象
*/
export function getSyncVarProxyTarget<T>(proxy: T): T {
// 注意JavaScript的Proxy没有直接方法获取target
// 这里返回proxy本身因为我们的代理是透明的
return proxy;
}
/**
* 销毁SyncVar代理
*
* 清理代理相关的资源但注意JavaScript的Proxy无法真正"销毁"
* 这个函数主要是清理管理器中的相关数据
*
* @param proxy - 代理对象
*/
export function destroySyncVarProxy(proxy: INetworkSyncable & { _syncVarProxied?: boolean; _syncVarDestroyed?: boolean }): void {
if (!isSyncVarProxied(proxy)) {
return;
}
// 清理SyncVar管理器中的数据
const syncVarManager = SyncVarManager.Instance;
syncVarManager.cleanupComponent(proxy);
// 标记为已销毁(虽然代理仍然存在)
proxy._syncVarProxied = false;
proxy._syncVarDestroyed = true;
console.log(`[SyncVarProxy] ${proxy.constructor?.name || 'Unknown'} 代理已销毁`);
}
/**
* 临时禁用SyncVar代理监听
*
* 在回调函数执行期间禁用SyncVar变化监听避免循环触发
*
* @param proxy - 代理对象
* @param callback - 要执行的回调函数
* @returns 回调函数的返回值
*/
export function withSyncVarDisabled<TResult>(proxy: INetworkSyncable & { _syncVarDisabled?: boolean; _syncVarProxied?: boolean }, callback: () => TResult): TResult {
if (!isSyncVarProxied(proxy)) {
return callback();
}
const wasDisabled = proxy._syncVarDisabled;
proxy._syncVarDisabled = true;
try {
return callback();
} finally {
proxy._syncVarDisabled = wasDisabled;
}
}
/**
* 批量更新SyncVar字段
*
* 在批量更新期间暂时禁用同步,最后一次性触发变化检测
*
* @param proxy - 代理对象
* @param updates - 要更新的字段和值的映射
*/
export function batchUpdateSyncVar(proxy: INetworkSyncable & { _syncVarProxied?: boolean; _syncVarDisabled?: boolean }, updates: Record<string, unknown>): void {
if (!isSyncVarProxied(proxy)) {
// 如果不是代理对象,直接批量更新
Object.assign(proxy, updates);
return;
}
withSyncVarDisabled(proxy, () => {
// 记录旧值
const oldValues: Record<string, unknown> = {};
for (const key of Object.keys(updates)) {
if (isSyncVar(proxy, key)) {
oldValues[key] = (proxy as unknown as Record<string, unknown>)[key];
}
}
// 批量更新
Object.assign(proxy, updates);
const syncVarManager = SyncVarManager.Instance;
for (const [key, newValue] of Object.entries(updates)) {
if (isSyncVar(proxy, key)) {
const oldValue = oldValues[key];
if (TypeGuards.isSyncVarValue(oldValue) && TypeGuards.isSyncVarValue(newValue)) {
syncVarManager.recordChange(proxy, key, oldValue, newValue);
}
}
}
});
}

View File

@@ -0,0 +1,477 @@
import { SyncVarManager } from './SyncVarManager';
import { NetworkIdentityRegistry, NetworkIdentity } from '../Core/NetworkIdentity';
import { SyncVarUpdateMessage } from '../Messaging/MessageTypes';
import { NetworkEnvironment } from '../Core/NetworkEnvironment';
import { ComponentRegistry } from '@esengine/ecs-framework';
import { NetworkComponent } from '../NetworkComponent';
/**
* SyncVar同步调度配置
*/
export interface SyncVarSyncConfig {
/** 同步频率(毫秒) */
syncInterval: number;
/** 最大批处理消息数量 */
maxBatchSize: number;
/** 最大每帧处理对象数量 */
maxObjectsPerFrame: number;
/** 是否启用优先级排序 */
enablePrioritySort: boolean;
/** 最小同步间隔(防止过于频繁) */
minSyncInterval: number;
/** 是否启用增量同步 */
enableIncrementalSync: boolean;
}
/**
* 同步优先级计算器
*/
export interface ISyncPriorityCalculator {
/**
* 计算组件的同步优先级
*
* @param component - 网络组件
* @param identity - 网络身份
* @returns 优先级值,数字越大优先级越高
*/
calculatePriority(component: any, identity: NetworkIdentity): number;
}
/**
* 默认优先级计算器
*/
export class DefaultSyncPriorityCalculator implements ISyncPriorityCalculator {
public calculatePriority(component: any, identity: NetworkIdentity): number {
let priority = 0;
// 权威对象优先级更高
if (identity.hasAuthority) {
priority += 10;
}
// 距离上次同步时间越长,优先级越高
const timeSinceLastSync = Date.now() - identity.lastSyncTime;
priority += Math.min(timeSinceLastSync / 1000, 10); // 最多加10分
// 变化数量越多,优先级越高
const syncVarManager = SyncVarManager.Instance;
const changes = syncVarManager.getPendingChanges(component);
priority += changes.length;
return priority;
}
}
/**
* SyncVar同步调度器
*
* 负责定期扫描网络对象的SyncVar变化创建和分发同步消息
* 支持批处理、优先级排序和性能优化
*/
export class SyncVarSyncScheduler {
private static _instance: SyncVarSyncScheduler | null = null;
private _config: SyncVarSyncConfig;
private _priorityCalculator: ISyncPriorityCalculator;
private _isRunning: boolean = false;
private _syncTimer: NodeJS.Timeout | null = null;
private _lastSyncTime: number = 0;
private _syncCounter: number = 0;
// 统计信息
private _stats = {
totalSyncCycles: 0,
totalObjectsScanned: 0,
totalMessagesSent: 0,
totalChangesProcessed: 0,
averageCycleTime: 0,
lastCycleTime: 0,
errors: 0
};
// 消息发送回调
private _messageSendCallback: ((message: SyncVarUpdateMessage) => Promise<void>) | null = null;
/**
* 获取调度器单例
*/
public static get Instance(): SyncVarSyncScheduler {
if (!SyncVarSyncScheduler._instance) {
SyncVarSyncScheduler._instance = new SyncVarSyncScheduler();
}
return SyncVarSyncScheduler._instance;
}
private constructor() {
// 默认配置
this._config = {
syncInterval: 50, // 20fps
maxBatchSize: 10,
maxObjectsPerFrame: 50,
enablePrioritySort: true,
minSyncInterval: 16, // 最小16ms (60fps)
enableIncrementalSync: true
};
this._priorityCalculator = new DefaultSyncPriorityCalculator();
}
/**
* 配置调度器
*
* @param config - 调度器配置
*/
public configure(config: Partial<SyncVarSyncConfig>): void {
this._config = { ...this._config, ...config };
// 如果正在运行,重启以应用新配置
if (this._isRunning) {
this.stop();
this.start();
}
console.log('[SyncVarSyncScheduler] 调度器配置已更新:', this._config);
}
/**
* 设置优先级计算器
*
* @param calculator - 优先级计算器
*/
public setPriorityCalculator(calculator: ISyncPriorityCalculator): void {
this._priorityCalculator = calculator;
console.log('[SyncVarSyncScheduler] 优先级计算器已更新');
}
/**
* 设置消息发送回调
*
* @param callback - 消息发送回调函数
*/
public setMessageSendCallback(callback: (message: SyncVarUpdateMessage) => Promise<void>): void {
this._messageSendCallback = callback;
console.log('[SyncVarSyncScheduler] 消息发送回调已设置');
}
/**
* 启动调度器
*/
public start(): void {
if (this._isRunning) {
console.warn('[SyncVarSyncScheduler] 调度器已经在运行');
return;
}
this._isRunning = true;
this._lastSyncTime = Date.now();
// 设置定时器
this._syncTimer = setInterval(() => {
this.performSyncCycle();
}, this._config.syncInterval);
console.log(`[SyncVarSyncScheduler] 调度器已启动,同步间隔: ${this._config.syncInterval}ms`);
}
/**
* 停止调度器
*/
public stop(): void {
if (!this._isRunning) {
return;
}
this._isRunning = false;
if (this._syncTimer) {
clearInterval(this._syncTimer);
this._syncTimer = null;
}
console.log('[SyncVarSyncScheduler] 调度器已停止');
}
/**
* 执行一次同步周期
*/
public performSyncCycle(): void {
if (!this._isRunning) {
return;
}
const cycleStartTime = Date.now();
try {
// 检查最小同步间隔
if (cycleStartTime - this._lastSyncTime < this._config.minSyncInterval) {
return;
}
this._stats.totalSyncCycles++;
this._lastSyncTime = cycleStartTime;
// 获取所有激活的网络对象
const activeObjects = NetworkIdentityRegistry.Instance.getActiveObjects();
this._stats.totalObjectsScanned += activeObjects.length;
// 收集需要同步的组件
const syncCandidates = this.collectSyncCandidates(activeObjects);
// 优先级排序
if (this._config.enablePrioritySort) {
syncCandidates.sort((a, b) => b.priority - a.priority);
}
// 限制每帧处理的对象数量
const objectsToProcess = syncCandidates.slice(0, this._config.maxObjectsPerFrame);
// 创建和发送同步消息
this.processSyncCandidates(objectsToProcess);
// 更新统计信息
const cycleTime = Date.now() - cycleStartTime;
this._stats.lastCycleTime = cycleTime;
this._stats.averageCycleTime = (this._stats.averageCycleTime * (this._stats.totalSyncCycles - 1) + cycleTime) / this._stats.totalSyncCycles;
} catch (error) {
this._stats.errors++;
console.error('[SyncVarSyncScheduler] 同步周期执行失败:', error);
}
}
/**
* 收集同步候选对象
*/
private collectSyncCandidates(activeObjects: NetworkIdentity[]): Array<{
identity: NetworkIdentity;
component: any;
priority: number;
changeCount: number;
}> {
const candidates: Array<{
identity: NetworkIdentity;
component: any;
priority: number;
changeCount: number;
}> = [];
const syncVarManager = SyncVarManager.Instance;
for (const identity of activeObjects) {
try {
// 获取对象的所有网络组件
const components = this.getNetworkComponents(identity);
for (const component of components) {
// 检查组件是否有SyncVar变化
const pendingChanges = syncVarManager.getPendingChanges(component);
if (pendingChanges.length === 0) {
continue;
}
// 权限检查:只有有权限的对象才能发起同步
if (!this.canComponentSync(component, identity)) {
continue;
}
// 计算优先级
const priority = this._priorityCalculator.calculatePriority(component, identity);
candidates.push({
identity,
component,
priority,
changeCount: pendingChanges.length
});
}
} catch (error) {
console.error(`[SyncVarSyncScheduler] 处理网络对象失败: ${identity.networkId}`, error);
}
}
return candidates;
}
/**
* 获取网络对象的所有网络组件
*/
private getNetworkComponents(identity: NetworkIdentity): NetworkComponent[] {
const entity = identity.entity;
if (!entity) {
console.warn(`[SyncVarSyncScheduler] NetworkIdentity ${identity.networkId} 缺少Entity引用`);
return [];
}
const networkComponents: NetworkComponent[] = [];
try {
// 获取所有已注册的组件类型
const allRegisteredTypes = ComponentRegistry.getAllRegisteredTypes();
for (const [ComponentClass] of allRegisteredTypes) {
// 检查是否为NetworkComponent子类
if (ComponentClass.prototype instanceof NetworkComponent || ComponentClass === NetworkComponent) {
const component = entity.getComponent(ComponentClass as any);
if (component && component instanceof NetworkComponent) {
networkComponents.push(component);
}
}
}
} catch (error) {
console.error(`[SyncVarSyncScheduler] 获取网络组件失败 (${identity.networkId}):`, error);
}
return networkComponents;
}
/**
* 检查组件是否可以进行同步
*/
private canComponentSync(component: any, identity: NetworkIdentity): boolean {
// 服务端对象通常有同步权限
if (NetworkEnvironment.isServer && identity.hasAuthority) {
return true;
}
// 客户端只能同步自己拥有的对象
if (NetworkEnvironment.isClient) {
// 这里需要获取当前客户端ID暂时简化处理
return identity.hasAuthority;
}
return false;
}
/**
* 处理同步候选对象
*/
private processSyncCandidates(candidates: Array<{
identity: NetworkIdentity;
component: any;
priority: number;
changeCount: number;
}>): void {
const syncVarManager = SyncVarManager.Instance;
const messageBatch: SyncVarUpdateMessage[] = [];
for (const candidate of candidates) {
try {
// 创建SyncVar更新消息
const message = syncVarManager.createSyncVarUpdateMessage(
candidate.component,
candidate.identity.networkId,
'', // senderId后续可以从环境获取
candidate.identity.getNextSyncSequence(),
false // isFullSync
);
if (message) {
messageBatch.push(message);
this._stats.totalChangesProcessed += candidate.changeCount;
// 更新对象的同步时间
candidate.identity.updateSyncTime();
// 清除已同步的变化
syncVarManager.clearChanges(candidate.component);
}
// 检查批处理大小限制
if (messageBatch.length >= this._config.maxBatchSize) {
this.sendMessageBatch(messageBatch);
messageBatch.length = 0; // 清空数组
}
} catch (error) {
console.error(`[SyncVarSyncScheduler] 处理同步候选对象失败: ${candidate.identity.networkId}`, error);
}
}
// 发送剩余的消息
if (messageBatch.length > 0) {
this.sendMessageBatch(messageBatch);
}
}
/**
* 发送消息批次
*/
private async sendMessageBatch(messages: SyncVarUpdateMessage[]): Promise<void> {
if (!this._messageSendCallback) {
console.warn('[SyncVarSyncScheduler] 没有设置消息发送回调,消息被丢弃');
return;
}
for (const message of messages) {
try {
await this._messageSendCallback(message);
this._stats.totalMessagesSent++;
} catch (error) {
console.error('[SyncVarSyncScheduler] 发送SyncVar消息失败:', error);
this._stats.errors++;
}
}
}
/**
* 手动触发同步
*
* @param networkId - 指定网络对象ID如果不提供则同步所有对象
*/
public manualSync(networkId?: string): void {
if (networkId) {
const identity = NetworkIdentityRegistry.Instance.find(networkId);
if (identity) {
this.performSyncCycle();
}
} else {
this.performSyncCycle();
}
}
/**
* 获取调度器统计信息
*/
public getStats(): typeof SyncVarSyncScheduler.prototype._stats & {
isRunning: boolean;
config: SyncVarSyncConfig;
uptime: number;
} {
return {
...this._stats,
isRunning: this._isRunning,
config: { ...this._config },
uptime: this._isRunning ? Date.now() - (this._lastSyncTime - this._config.syncInterval) : 0
};
}
/**
* 重置统计信息
*/
public resetStats(): void {
this._stats = {
totalSyncCycles: 0,
totalObjectsScanned: 0,
totalMessagesSent: 0,
totalChangesProcessed: 0,
averageCycleTime: 0,
lastCycleTime: 0,
errors: 0
};
console.log('[SyncVarSyncScheduler] 统计信息已重置');
}
/**
* 获取当前配置
*/
public getConfig(): SyncVarSyncConfig {
return { ...this._config };
}
/**
* 检查调度器是否正在运行
*/
public get isRunning(): boolean {
return this._isRunning;
}
}

View File

@@ -0,0 +1,41 @@
/**
* SyncVar同步变量系统导出
*
* 提供自动变量同步功能,支持网络状态的实时同步
*/
// 装饰器和元数据
export * from './SyncVarDecorator';
// 管理器
export { SyncVarManager } from './SyncVarManager';
// 代理系统
export * from './SyncVarProxy';
// 工厂函数
export * from './SyncVarFactory';
// 消息处理器
export { SyncVarMessageHandler } from './SyncVarMessageHandler';
// 同步调度器
export {
SyncVarSyncScheduler,
DefaultSyncPriorityCalculator
} from './SyncVarSyncScheduler';
export type {
SyncVarSyncConfig,
ISyncPriorityCalculator
} from './SyncVarSyncScheduler';
// 性能优化器
export {
SyncVarOptimizer,
SyncVarMessageMerger,
SyncVarRateLimiter,
SyncVarDistanceCuller
} from './SyncVarOptimizer';
export type {
SyncVarOptimizationConfig
} from './SyncVarOptimizer';