重构network库(mvp版本)搭建基础设施和核心接口
定义ITransport/ISerializer/INetworkMessage接口 NetworkIdentity组件 基础事件定义
This commit is contained in:
@@ -1,177 +0,0 @@
|
||||
/**
|
||||
* ClientRpc 装饰器
|
||||
*
|
||||
* 用于标记可以在服务端调用,在客户端执行的方法
|
||||
*/
|
||||
|
||||
import 'reflect-metadata';
|
||||
import { RpcMetadata, DecoratorTarget, Constructor, RpcParameterType, RpcReturnType } from '../types/NetworkTypes';
|
||||
import { getNetworkComponentMetadata } from './NetworkComponent';
|
||||
|
||||
/**
|
||||
* ClientRpc 装饰器选项
|
||||
*/
|
||||
export interface ClientRpcOptions {
|
||||
/** 是否需要权限验证 */
|
||||
requiresAuth?: boolean;
|
||||
/** 是否可靠传输,默认为 true */
|
||||
reliable?: boolean;
|
||||
/** 是否需要响应 */
|
||||
requiresResponse?: boolean;
|
||||
/** 目标客户端筛选器 */
|
||||
targetFilter?: 'all' | 'others' | 'owner' | 'specific';
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储 ClientRpc 元数据的 Symbol
|
||||
*/
|
||||
export const CLIENT_RPC_METADATA_KEY = Symbol('client_rpc_metadata');
|
||||
|
||||
/**
|
||||
* ClientRpc 装饰器
|
||||
*
|
||||
* @param options 装饰器选项
|
||||
* @returns 方法装饰器函数
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @NetworkComponent()
|
||||
* class PlayerController extends Component {
|
||||
* @ClientRpc({ targetFilter: 'all' })
|
||||
* public showDamageEffect(damage: number, position: Vector3): void {
|
||||
* // 在所有客户端显示伤害效果
|
||||
* console.log(`Showing damage: ${damage} at ${position}`);
|
||||
* }
|
||||
*
|
||||
* @ClientRpc({ targetFilter: 'owner', reliable: false })
|
||||
* public updateUI(data: UIData): void {
|
||||
* // 只在拥有者客户端更新UI,使用不可靠传输
|
||||
* }
|
||||
*
|
||||
* @ClientRpc({ requiresResponse: true })
|
||||
* public requestClientData(): ClientData {
|
||||
* // 请求客户端数据并等待响应
|
||||
* return this.getClientData();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function ClientRpc(options: ClientRpcOptions = {}): MethodDecorator {
|
||||
return function (target: unknown, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
|
||||
if (typeof propertyKey !== 'string') {
|
||||
throw new Error('ClientRpc can only be applied to string method names');
|
||||
}
|
||||
|
||||
// 获取或创建元数据数组
|
||||
let metadata: RpcMetadata[] = Reflect.getMetadata(CLIENT_RPC_METADATA_KEY, (target as { constructor: Constructor }).constructor);
|
||||
if (!metadata) {
|
||||
metadata = [];
|
||||
Reflect.defineMetadata(CLIENT_RPC_METADATA_KEY, metadata, (target as { constructor: Constructor }).constructor);
|
||||
}
|
||||
|
||||
// 创建 RPC 元数据
|
||||
const rpcMetadata: RpcMetadata = {
|
||||
methodName: propertyKey,
|
||||
rpcType: 'client-rpc',
|
||||
requiresAuth: options.requiresAuth || false,
|
||||
reliable: options.reliable !== false,
|
||||
requiresResponse: options.requiresResponse || false
|
||||
};
|
||||
|
||||
metadata.push(rpcMetadata);
|
||||
|
||||
// 更新 NetworkComponent 元数据
|
||||
const componentMetadata = getNetworkComponentMetadata((target as { constructor: Constructor }).constructor);
|
||||
if (componentMetadata) {
|
||||
const existingIndex = componentMetadata.rpcs.findIndex(rpc => rpc.methodName === propertyKey);
|
||||
if (existingIndex >= 0) {
|
||||
componentMetadata.rpcs[existingIndex] = rpcMetadata;
|
||||
} else {
|
||||
componentMetadata.rpcs.push(rpcMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存原方法
|
||||
const originalMethod = descriptor.value;
|
||||
if (typeof originalMethod !== 'function') {
|
||||
throw new Error(`ClientRpc can only be applied to methods, got ${typeof originalMethod}`);
|
||||
}
|
||||
|
||||
// 包装方法以添加网络调用逻辑
|
||||
descriptor.value = function (this: Record<string, unknown> & {
|
||||
isServer?: () => boolean;
|
||||
sendClientRpc?: (methodName: string, args: RpcParameterType[], options: ClientRpcOptions, metadata: RpcMetadata) => RpcReturnType;
|
||||
}, ...args: RpcParameterType[]): RpcReturnType {
|
||||
// 如果在服务端调用,发送到客户端
|
||||
const isServer = this.isServer?.() || (typeof window === 'undefined' && typeof process !== 'undefined');
|
||||
if (isServer) {
|
||||
return this.sendClientRpc?.(propertyKey, args, options, rpcMetadata) as RpcReturnType;
|
||||
}
|
||||
|
||||
// 如果在客户端,直接执行本地方法
|
||||
return (originalMethod as (...args: RpcParameterType[]) => RpcReturnType).apply(this, args);
|
||||
};
|
||||
|
||||
// 保存原方法的引用,供直接调用
|
||||
const decoratedFunction = descriptor.value as typeof descriptor.value & {
|
||||
__originalMethod: typeof originalMethod;
|
||||
__rpcMetadata: RpcMetadata;
|
||||
__rpcOptions: ClientRpcOptions;
|
||||
};
|
||||
decoratedFunction.__originalMethod = originalMethod;
|
||||
decoratedFunction.__rpcMetadata = rpcMetadata;
|
||||
decoratedFunction.__rpcOptions = options;
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的 ClientRpc 元数据
|
||||
*/
|
||||
export function getClientRpcMetadata(target: Constructor): RpcMetadata[] {
|
||||
return Reflect.getMetadata(CLIENT_RPC_METADATA_KEY, target) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查方法是否为 ClientRpc
|
||||
*/
|
||||
export function isClientRpc(target: Constructor, methodName: string): boolean {
|
||||
const metadata = getClientRpcMetadata(target);
|
||||
return metadata.some(m => m.methodName === methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特定方法的 ClientRpc 元数据
|
||||
*/
|
||||
export function getClientRpcMethodMetadata(target: Constructor, methodName: string): RpcMetadata | null {
|
||||
const metadata = getClientRpcMetadata(target);
|
||||
return metadata.find(m => m.methodName === methodName) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用原方法(跳过网络逻辑)
|
||||
*/
|
||||
export function invokeClientRpcLocally(instance: Record<string, unknown>, methodName: string, args: RpcParameterType[]): RpcReturnType {
|
||||
const method = instance[methodName] as { __originalMethod?: (...args: RpcParameterType[]) => RpcReturnType } | undefined;
|
||||
if (method && typeof method.__originalMethod === 'function') {
|
||||
return method.__originalMethod.apply(instance, args);
|
||||
}
|
||||
throw new Error(`Method ${methodName} is not a valid ClientRpc or original method not found`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 ClientRpc 是否需要响应
|
||||
*/
|
||||
export function clientRpcRequiresResponse(instance: Record<string, unknown>, methodName: string): boolean {
|
||||
const method = instance[methodName] as { __rpcMetadata?: RpcMetadata } | undefined;
|
||||
return method?.__rpcMetadata?.requiresResponse || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ClientRpc 的选项
|
||||
*/
|
||||
export function getClientRpcOptions(instance: Record<string, unknown>, methodName: string): ClientRpcOptions | null {
|
||||
const method = instance[methodName] as { __rpcOptions?: ClientRpcOptions } | undefined;
|
||||
return method?.__rpcOptions || null;
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/**
|
||||
* NetworkComponent 装饰器
|
||||
*
|
||||
* 用于标记网络组件,自动注册到网络系统
|
||||
*/
|
||||
|
||||
import 'reflect-metadata';
|
||||
import { NetworkComponentMetadata } from '../types/NetworkTypes';
|
||||
|
||||
/**
|
||||
* NetworkComponent 装饰器选项
|
||||
*/
|
||||
export interface NetworkComponentOptions {
|
||||
/** 是否自动生成 protobuf 协议 */
|
||||
autoGenerateProtocol?: boolean;
|
||||
/** 自定义组件类型名 */
|
||||
typeName?: string;
|
||||
/** 是否仅服务端存在 */
|
||||
serverOnly?: boolean;
|
||||
/** 是否仅客户端存在 */
|
||||
clientOnly?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储 NetworkComponent 元数据的 Symbol
|
||||
*/
|
||||
export const NETWORK_COMPONENT_METADATA_KEY = Symbol('network_component_metadata');
|
||||
|
||||
/**
|
||||
* NetworkComponent 装饰器
|
||||
*
|
||||
* @param options 装饰器选项
|
||||
* @returns 类装饰器函数
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @NetworkComponent({ autoGenerateProtocol: true })
|
||||
* class PlayerController extends Component implements INetworkComponent {
|
||||
* networkObject: INetworkObject | null = null;
|
||||
* networkId: number = 0;
|
||||
* hasAuthority: boolean = false;
|
||||
* componentType: string = 'PlayerController';
|
||||
*
|
||||
* @SyncVar()
|
||||
* public health: number = 100;
|
||||
*
|
||||
* @ClientRpc()
|
||||
* public showDamage(damage: number): void {
|
||||
* // 显示伤害效果
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function NetworkComponent(options: NetworkComponentOptions = {}): ClassDecorator {
|
||||
return function <T extends Function>(target: T) {
|
||||
const metadata: NetworkComponentMetadata = {
|
||||
componentType: options.typeName || target.name,
|
||||
syncVars: [],
|
||||
rpcs: [],
|
||||
autoGenerateProtocol: options.autoGenerateProtocol !== false,
|
||||
};
|
||||
|
||||
// 存储元数据
|
||||
Reflect.defineMetadata(NETWORK_COMPONENT_METADATA_KEY, metadata, target);
|
||||
|
||||
// 注册到全局组件注册表
|
||||
NetworkComponentRegistry.register(target as any, metadata);
|
||||
|
||||
return target;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的 NetworkComponent 元数据
|
||||
*/
|
||||
export function getNetworkComponentMetadata(target: any): NetworkComponentMetadata | null {
|
||||
return Reflect.getMetadata(NETWORK_COMPONENT_METADATA_KEY, target) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查类是否为 NetworkComponent
|
||||
*/
|
||||
export function isNetworkComponent(target: any): boolean {
|
||||
return Reflect.hasMetadata(NETWORK_COMPONENT_METADATA_KEY, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* 网络组件注册表
|
||||
*/
|
||||
class NetworkComponentRegistry {
|
||||
private static components = new Map<string, {
|
||||
constructor: any;
|
||||
metadata: NetworkComponentMetadata;
|
||||
}>();
|
||||
|
||||
/**
|
||||
* 注册网络组件
|
||||
*/
|
||||
static register(constructor: any, metadata: NetworkComponentMetadata): void {
|
||||
this.components.set(metadata.componentType, {
|
||||
constructor,
|
||||
metadata
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件信息
|
||||
*/
|
||||
static getComponent(typeName: string) {
|
||||
return this.components.get(typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有组件
|
||||
*/
|
||||
static getAllComponents() {
|
||||
return Array.from(this.components.entries()).map(([typeName, info]) => ({
|
||||
typeName,
|
||||
...info
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查组件是否已注册
|
||||
*/
|
||||
static hasComponent(typeName: string): boolean {
|
||||
return this.components.has(typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空注册表 (主要用于测试)
|
||||
*/
|
||||
static clear(): void {
|
||||
this.components.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export { NetworkComponentRegistry };
|
||||
@@ -1,178 +0,0 @@
|
||||
/**
|
||||
* ServerRpc 装饰器
|
||||
*
|
||||
* 用于标记可以在客户端调用,在服务端执行的方法
|
||||
*/
|
||||
|
||||
import 'reflect-metadata';
|
||||
import { RpcMetadata, DecoratorTarget, Constructor, RpcParameterType, RpcReturnType } from '../types/NetworkTypes';
|
||||
import { getNetworkComponentMetadata } from './NetworkComponent';
|
||||
|
||||
/**
|
||||
* ServerRpc 装饰器选项
|
||||
*/
|
||||
export interface ServerRpcOptions {
|
||||
/** 是否需要权限验证 */
|
||||
requiresAuth?: boolean;
|
||||
/** 是否可靠传输,默认为 true */
|
||||
reliable?: boolean;
|
||||
/** 是否需要响应 */
|
||||
requiresResponse?: boolean;
|
||||
/** 是否需要拥有者权限 */
|
||||
requiresOwnership?: boolean;
|
||||
/** 调用频率限制 (调用/秒) */
|
||||
rateLimit?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储 ServerRpc 元数据的 Symbol
|
||||
*/
|
||||
export const SERVER_RPC_METADATA_KEY = Symbol('server_rpc_metadata');
|
||||
|
||||
/**
|
||||
* ServerRpc 装饰器
|
||||
*
|
||||
* @param options 装饰器选项
|
||||
* @returns 方法装饰器函数
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @NetworkComponent()
|
||||
* class PlayerController extends Component {
|
||||
* @ServerRpc({ requiresOwnership: true, rateLimit: 10 })
|
||||
* public movePlayer(direction: Vector3): void {
|
||||
* // 在服务端处理玩家移动,需要拥有者权限,限制每秒10次调用
|
||||
* this.transform.position.add(direction);
|
||||
* }
|
||||
*
|
||||
* @ServerRpc({ requiresAuth: true })
|
||||
* public purchaseItem(itemId: string): boolean {
|
||||
* // 购买物品,需要认证
|
||||
* return this.inventory.tryPurchase(itemId);
|
||||
* }
|
||||
*
|
||||
* @ServerRpc({ requiresResponse: true })
|
||||
* public getPlayerStats(): PlayerStats {
|
||||
* // 获取玩家统计数据并返回给客户端
|
||||
* return this.stats.toObject();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function ServerRpc(options: ServerRpcOptions = {}): MethodDecorator {
|
||||
return function (target: unknown, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
|
||||
if (typeof propertyKey !== 'string') {
|
||||
throw new Error('ServerRpc can only be applied to string method names');
|
||||
}
|
||||
|
||||
// 获取或创建元数据数组
|
||||
const targetConstructor = (target as { constructor: Constructor }).constructor;
|
||||
let metadata: RpcMetadata[] = Reflect.getMetadata(SERVER_RPC_METADATA_KEY, targetConstructor);
|
||||
if (!metadata) {
|
||||
metadata = [];
|
||||
Reflect.defineMetadata(SERVER_RPC_METADATA_KEY, metadata, targetConstructor);
|
||||
}
|
||||
|
||||
// 创建 RPC 元数据
|
||||
const rpcMetadata: RpcMetadata = {
|
||||
methodName: propertyKey,
|
||||
rpcType: 'server-rpc',
|
||||
requiresAuth: options.requiresAuth || false,
|
||||
reliable: options.reliable !== false,
|
||||
requiresResponse: options.requiresResponse || false
|
||||
};
|
||||
|
||||
metadata.push(rpcMetadata);
|
||||
|
||||
// 更新 NetworkComponent 元数据
|
||||
const componentMetadata = getNetworkComponentMetadata(targetConstructor);
|
||||
if (componentMetadata) {
|
||||
const existingIndex = componentMetadata.rpcs.findIndex(rpc => rpc.methodName === propertyKey);
|
||||
if (existingIndex >= 0) {
|
||||
componentMetadata.rpcs[existingIndex] = rpcMetadata;
|
||||
} else {
|
||||
componentMetadata.rpcs.push(rpcMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存原方法
|
||||
const originalMethod = descriptor.value;
|
||||
if (typeof originalMethod !== 'function') {
|
||||
throw new Error(`ServerRpc can only be applied to methods, got ${typeof originalMethod}`);
|
||||
}
|
||||
|
||||
// 包装方法以添加网络调用逻辑
|
||||
descriptor.value = function (this: any, ...args: any[]) {
|
||||
// 如果在客户端调用,发送到服务端
|
||||
const isClient = this.isClient?.() || (typeof window !== 'undefined');
|
||||
if (isClient) {
|
||||
return this.sendServerRpc?.(propertyKey, args, options, rpcMetadata);
|
||||
}
|
||||
|
||||
// 如果在服务端,直接执行本地方法
|
||||
return originalMethod.apply(this, args);
|
||||
};
|
||||
|
||||
// 保存原方法的引用,供直接调用
|
||||
(descriptor.value as any).__originalMethod = originalMethod;
|
||||
(descriptor.value as any).__rpcMetadata = rpcMetadata;
|
||||
(descriptor.value as any).__rpcOptions = options;
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Command 装饰器 (ServerRpc 的别名,用于兼容性)
|
||||
*/
|
||||
export const Command = ServerRpc;
|
||||
|
||||
/**
|
||||
* 获取类的 ServerRpc 元数据
|
||||
*/
|
||||
export function getServerRpcMetadata(target: Constructor): RpcMetadata[] {
|
||||
return Reflect.getMetadata(SERVER_RPC_METADATA_KEY, target) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查方法是否为 ServerRpc
|
||||
*/
|
||||
export function isServerRpc(target: Constructor, methodName: string): boolean {
|
||||
const metadata = getServerRpcMetadata(target);
|
||||
return metadata.some(m => m.methodName === methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特定方法的 ServerRpc 元数据
|
||||
*/
|
||||
export function getServerRpcMethodMetadata(target: Constructor, methodName: string): RpcMetadata | null {
|
||||
const metadata = getServerRpcMetadata(target);
|
||||
return metadata.find(m => m.methodName === methodName) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用原方法(跳过网络逻辑)
|
||||
*/
|
||||
export function invokeServerRpcLocally(instance: any, methodName: string, args: any[]): any {
|
||||
const method = instance[methodName];
|
||||
if (method && typeof method.__originalMethod === 'function') {
|
||||
return method.__originalMethod.apply(instance, args);
|
||||
}
|
||||
throw new Error(`Method ${methodName} is not a valid ServerRpc or original method not found`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 ServerRpc 是否需要响应
|
||||
*/
|
||||
export function serverRpcRequiresResponse(instance: any, methodName: string): boolean {
|
||||
const method = instance[methodName];
|
||||
return method?.__rpcMetadata?.requiresResponse || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ServerRpc 的选项
|
||||
*/
|
||||
export function getServerRpcOptions(instance: any, methodName: string): ServerRpcOptions | null {
|
||||
const method = instance[methodName];
|
||||
return method?.__rpcOptions || null;
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
/**
|
||||
* SyncVar 装饰器
|
||||
*
|
||||
* 用于标记需要在网络间自动同步的属性
|
||||
*/
|
||||
|
||||
import 'reflect-metadata';
|
||||
import { SyncVarMetadata, NetworkValue, DecoratorTarget, Constructor } from '../types/NetworkTypes';
|
||||
import { getNetworkComponentMetadata } from './NetworkComponent';
|
||||
|
||||
/**
|
||||
* SyncVar 装饰器选项
|
||||
*/
|
||||
export interface SyncVarOptions {
|
||||
/** 是否仅权威端可修改,默认为 true */
|
||||
authorityOnly?: boolean;
|
||||
/** 变化回调函数名 */
|
||||
onChanged?: string;
|
||||
/** 序列化类型提示 */
|
||||
serializeType?: string;
|
||||
/** 是否使用增量同步 */
|
||||
deltaSync?: boolean;
|
||||
/** 同步优先级,数值越大优先级越高 */
|
||||
priority?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储 SyncVar 元数据的 Symbol
|
||||
*/
|
||||
export const SYNCVAR_METADATA_KEY = Symbol('syncvar_metadata');
|
||||
|
||||
/**
|
||||
* SyncVar 装饰器
|
||||
*
|
||||
* @param options 装饰器选项
|
||||
* @returns 属性装饰器函数
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @NetworkComponent()
|
||||
* class PlayerController extends Component {
|
||||
* @SyncVar({ onChanged: 'onHealthChanged', priority: 10 })
|
||||
* public health: number = 100;
|
||||
*
|
||||
* @SyncVar({ authorityOnly: false })
|
||||
* public playerName: string = '';
|
||||
*
|
||||
* @SyncVar({ deltaSync: true })
|
||||
* public inventory: Item[] = [];
|
||||
*
|
||||
* private onHealthChanged(oldValue: number, newValue: number): void {
|
||||
* console.log(`Health changed from ${oldValue} to ${newValue}`);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function SyncVar<T extends NetworkValue = NetworkValue>(options: SyncVarOptions = {}): PropertyDecorator {
|
||||
return function (target: unknown, propertyKey: string | symbol) {
|
||||
if (typeof propertyKey !== 'string') {
|
||||
throw new Error('SyncVar can only be applied to string property keys');
|
||||
}
|
||||
|
||||
// 获取或创建元数据数组
|
||||
const targetConstructor = (target as { constructor: Constructor }).constructor;
|
||||
let metadata: SyncVarMetadata[] = Reflect.getMetadata(SYNCVAR_METADATA_KEY, targetConstructor);
|
||||
if (!metadata) {
|
||||
metadata = [];
|
||||
Reflect.defineMetadata(SYNCVAR_METADATA_KEY, metadata, targetConstructor);
|
||||
}
|
||||
|
||||
// 创建 SyncVar 元数据
|
||||
const syncVarMetadata: SyncVarMetadata = {
|
||||
propertyName: propertyKey,
|
||||
authorityOnly: options.authorityOnly !== false,
|
||||
onChanged: options.onChanged,
|
||||
serializeType: options.serializeType,
|
||||
deltaSync: options.deltaSync || false,
|
||||
priority: options.priority || 0
|
||||
};
|
||||
|
||||
metadata.push(syncVarMetadata);
|
||||
|
||||
// 更新 NetworkComponent 元数据
|
||||
const componentMetadata = getNetworkComponentMetadata(targetConstructor);
|
||||
if (componentMetadata) {
|
||||
const existingIndex = componentMetadata.syncVars.findIndex(sv => sv.propertyName === propertyKey);
|
||||
if (existingIndex >= 0) {
|
||||
componentMetadata.syncVars[existingIndex] = syncVarMetadata;
|
||||
} else {
|
||||
componentMetadata.syncVars.push(syncVarMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建属性的内部存储和变化跟踪
|
||||
const internalKey = `_${propertyKey}`;
|
||||
const dirtyKey = `_${propertyKey}_dirty`;
|
||||
const previousKey = `_${propertyKey}_previous`;
|
||||
|
||||
// 重新定义属性的 getter 和 setter
|
||||
Object.defineProperty(target, propertyKey, {
|
||||
get: function (this: Record<string, unknown>): T {
|
||||
return this[internalKey] as T;
|
||||
},
|
||||
set: function (this: Record<string, unknown>, newValue: T) {
|
||||
const oldValue = this[internalKey] as T;
|
||||
|
||||
// 检查值是否真的发生了变化
|
||||
if (oldValue === newValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 对于复杂对象,进行深度比较
|
||||
if (typeof newValue === 'object' && newValue !== null &&
|
||||
typeof oldValue === 'object' && oldValue !== null) {
|
||||
if (JSON.stringify(oldValue) === JSON.stringify(newValue)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 保存旧值用于回调
|
||||
this[previousKey] = oldValue;
|
||||
this[internalKey] = newValue;
|
||||
this[dirtyKey] = true;
|
||||
|
||||
// 调用变化回调
|
||||
if (options.onChanged && typeof (this[options.onChanged] as unknown) === 'function') {
|
||||
(this[options.onChanged] as (oldValue: T, newValue: T) => void)(oldValue, newValue);
|
||||
}
|
||||
|
||||
// 通知网络同步系统
|
||||
(this as { notifySyncVarChanged?: (key: string, oldValue: T, newValue: T, metadata: SyncVarMetadata) => void }).notifySyncVarChanged?.(propertyKey, oldValue, newValue, syncVarMetadata);
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
// 初始化内部属性
|
||||
const targetRecord = target as Record<string, unknown>;
|
||||
if (targetRecord[internalKey] === undefined) {
|
||||
targetRecord[internalKey] = targetRecord[propertyKey];
|
||||
}
|
||||
targetRecord[dirtyKey] = false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的 SyncVar 元数据
|
||||
*/
|
||||
export function getSyncVarMetadata(target: Constructor): SyncVarMetadata[] {
|
||||
return Reflect.getMetadata(SYNCVAR_METADATA_KEY, target) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查属性是否为 SyncVar
|
||||
*/
|
||||
export function isSyncVar(target: Constructor, propertyName: string): boolean {
|
||||
const metadata = getSyncVarMetadata(target);
|
||||
return metadata.some(m => m.propertyName === propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 SyncVar 的脏标记
|
||||
*/
|
||||
export function isSyncVarDirty(instance: Record<string, unknown>, propertyName: string): boolean {
|
||||
return (instance[`_${propertyName}_dirty`] as boolean) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除 SyncVar 的脏标记
|
||||
*/
|
||||
export function clearSyncVarDirty(instance: Record<string, unknown>, propertyName: string): void {
|
||||
instance[`_${propertyName}_dirty`] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 SyncVar 的前一个值
|
||||
*/
|
||||
export function getSyncVarPreviousValue<T extends NetworkValue = NetworkValue>(instance: Record<string, unknown>, propertyName: string): T | undefined {
|
||||
return instance[`_${propertyName}_previous`] as T | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制设置 SyncVar 值(跳过权限检查和变化检测)
|
||||
*/
|
||||
export function setSyncVarValue<T extends NetworkValue = NetworkValue>(instance: Record<string, unknown>, propertyName: string, value: T, skipCallback = false): void {
|
||||
const internalKey = `_${propertyName}`;
|
||||
const dirtyKey = `_${propertyName}_dirty`;
|
||||
const previousKey = `_${propertyName}_previous`;
|
||||
|
||||
const oldValue = instance[internalKey] as T;
|
||||
instance[previousKey] = oldValue;
|
||||
instance[internalKey] = value;
|
||||
instance[dirtyKey] = false; // 网络接收的值不标记为脏
|
||||
|
||||
// 可选择性调用回调
|
||||
if (!skipCallback) {
|
||||
const metadata = getSyncVarMetadata((instance as { constructor: Constructor }).constructor);
|
||||
const syncVarMeta = metadata.find(m => m.propertyName === propertyName);
|
||||
|
||||
if (syncVarMeta?.onChanged && typeof (instance[syncVarMeta.onChanged] as unknown) === 'function') {
|
||||
(instance[syncVarMeta.onChanged] as (oldValue: T, newValue: T) => void)(oldValue, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取所有脏的 SyncVar
|
||||
*/
|
||||
export function getDirtySyncVars(instance: Record<string, unknown>): Array<{
|
||||
propertyName: string;
|
||||
oldValue: NetworkValue;
|
||||
newValue: NetworkValue;
|
||||
metadata: SyncVarMetadata;
|
||||
}> {
|
||||
const metadata = getSyncVarMetadata((instance as { constructor: Constructor }).constructor);
|
||||
const dirtyVars: Array<{
|
||||
propertyName: string;
|
||||
oldValue: NetworkValue;
|
||||
newValue: NetworkValue;
|
||||
metadata: SyncVarMetadata;
|
||||
}> = [];
|
||||
|
||||
for (const syncVar of metadata) {
|
||||
if (isSyncVarDirty(instance, syncVar.propertyName)) {
|
||||
const oldValue = getSyncVarPreviousValue(instance, syncVar.propertyName);
|
||||
const newValue = instance[`_${syncVar.propertyName}`] as NetworkValue;
|
||||
|
||||
dirtyVars.push({
|
||||
propertyName: syncVar.propertyName,
|
||||
oldValue: oldValue ?? newValue, // 使用空合并运算符处理undefined
|
||||
newValue: newValue,
|
||||
metadata: syncVar
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 按优先级排序,优先级高的先处理
|
||||
return dirtyVars.sort((a, b) => (b.metadata.priority || 0) - (a.metadata.priority || 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量清除所有脏标记
|
||||
*/
|
||||
export function clearAllDirtySyncVars(instance: Record<string, unknown>): void {
|
||||
const metadata = getSyncVarMetadata((instance as { constructor: Constructor }).constructor);
|
||||
for (const syncVar of metadata) {
|
||||
clearSyncVarDirty(instance, syncVar.propertyName);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* 装饰器导出
|
||||
*/
|
||||
|
||||
export * from './NetworkComponent';
|
||||
export * from './SyncVar';
|
||||
export * from './ClientRpc';
|
||||
export * from './ServerRpc';
|
||||
Reference in New Issue
Block a user