更新network库及core库优化

This commit is contained in:
YHH
2025-08-12 09:39:07 +08:00
parent c178e2fbcc
commit 9f76d37a82
117 changed files with 17988 additions and 4099 deletions

View File

@@ -0,0 +1,177 @@
/**
* 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;
}

View File

@@ -0,0 +1,138 @@
/**
* 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 };

View File

@@ -0,0 +1,178 @@
/**
* 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;
}

View File

@@ -0,0 +1,249 @@
/**
* 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);
}
}

View File

@@ -0,0 +1,8 @@
/**
* 装饰器导出
*/
export * from './NetworkComponent';
export * from './SyncVar';
export * from './ClientRpc';
export * from './ServerRpc';