重新整理网络架构,tsrpc/syncvar并行

This commit is contained in:
YHH
2025-08-10 12:35:39 +08:00
parent 6e21ff08d5
commit 2783448de5
80 changed files with 3662 additions and 16000 deletions

View File

@@ -0,0 +1,431 @@
/**
* TSRPC 客户端传输层
*
* 封装TSRPC客户端功能提供服务端连接和消息收发
*/
import { WsClient } from 'tsrpc';
import { createLogger } from '@esengine/ecs-framework';
import { serviceProto, ServiceType } from './protocols/serviceProto';
import { NetworkConfig, NetworkMessage } from '../types/NetworkTypes';
import {
ReqJoinRoom, ResJoinRoom,
ReqServerStatus, ResServerStatus,
ReqPing, ResPing,
MsgNetworkMessage,
MsgSyncVar,
MsgRpcCall,
MsgNetworkObjectSpawn,
MsgNetworkObjectDespawn,
MsgClientDisconnected,
MsgAuthorityChange
} from './protocols/NetworkProtocols';
const logger = createLogger('TsrpcClient');
/**
* 连接状态
*/
type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';
/**
* TSRPC客户端包装器
*/
export class TsrpcClient {
private client: WsClient<ServiceType> | null = null;
private config: NetworkConfig;
private connectionState: ConnectionState = 'disconnected';
private clientId: number = 0;
private roomId: string = '';
private reconnectAttempts: number = 0;
private maxReconnectAttempts: number = 5;
private reconnectInterval: number = 2000;
private heartbeatInterval: NodeJS.Timeout | null = null;
/** 统计信息 */
private stats = {
messagesSent: 0,
messagesReceived: 0,
bytesSent: 0,
bytesReceived: 0,
latency: 0
};
/** 事件处理器 */
public onConnected?: () => void;
public onDisconnected?: (reason?: string) => void;
public onReconnecting?: () => void;
public onMessage?: (message: NetworkMessage) => void;
public onError?: (error: Error) => void;
constructor(config: NetworkConfig) {
this.config = config;
}
/**
* 连接到服务端
*/
public async connect(): Promise<void> {
if (this.connectionState !== 'disconnected') {
throw new Error('客户端已连接或正在连接中');
}
this.connectionState = 'connecting';
try {
// 创建WebSocket客户端
this.client = new WsClient(serviceProto, {
server: `ws://${this.config.host}:${this.config.port}`,
// 自动重连配置
heartbeat: {
interval: 30000,
timeout: 5000
}
});
this.setupEventHandlers();
// 连接到服务端
const connectResult = await this.client.connect();
if (!connectResult.isSucc) {
throw new Error(`连接失败: ${connectResult.errMsg}`);
}
// 加入房间
const joinResult = await this.client.callApi('network/JoinRoom', {
roomId: this.config.roomId,
clientInfo: {
version: '1.0.0',
platform: typeof window !== 'undefined' ? 'browser' : 'node'
}
});
if (!joinResult.isSucc) {
throw new Error(`加入房间失败: ${joinResult.err.message}`);
}
this.clientId = joinResult.res.clientId;
this.roomId = joinResult.res.roomId;
this.connectionState = 'connected';
this.reconnectAttempts = 0;
// 启动心跳
this.startHeartbeat();
logger.info(`连接成功客户端ID: ${this.clientId}, 房间: ${this.roomId}`);
this.onConnected?.();
} catch (error) {
this.connectionState = 'disconnected';
logger.error('连接服务端失败:', error);
this.onError?.(error as Error);
throw error;
}
}
/**
* 断开连接
*/
public async disconnect(): Promise<void> {
if (this.connectionState === 'disconnected') {
return;
}
this.connectionState = 'disconnected';
this.stopHeartbeat();
if (this.client) {
await this.client.disconnect();
this.client = null;
}
logger.info('客户端已断开连接');
this.onDisconnected?.();
}
/**
* 发送消息到服务端
*/
public async sendMessage(message: NetworkMessage): Promise<void> {
if (!this.isConnected()) {
throw new Error('客户端未连接');
}
try {
const tsrpcMessage: MsgNetworkMessage = {
type: message.type as 'syncvar' | 'rpc',
networkId: message.networkId,
data: message.data,
timestamp: message.timestamp
};
await this.client!.sendMsg('network/NetworkMessage', tsrpcMessage);
this.stats.messagesSent++;
logger.debug(`发送消息: ${message.type}, 网络ID: ${message.networkId}`);
} catch (error) {
logger.error('发送消息失败:', error);
throw error;
}
}
/**
* 发送SyncVar同步消息
*/
public async sendSyncVar(
networkId: number,
componentType: string,
propertyName: string,
value: any
): Promise<void> {
if (!this.isConnected()) {
throw new Error('客户端未连接');
}
try {
const message: MsgSyncVar = {
networkId,
componentType,
propertyName,
value,
timestamp: Date.now()
};
await this.client!.sendMsg('network/SyncVar', message);
this.stats.messagesSent++;
logger.debug(`发送SyncVar: ${componentType}.${propertyName} = ${value}`);
} catch (error) {
logger.error('发送SyncVar失败:', error);
throw error;
}
}
/**
* 发送RPC调用消息
*/
public async sendRpcCall(
networkId: number,
componentType: string,
methodName: string,
args: any[],
isClientRpc: boolean
): Promise<void> {
if (!this.isConnected()) {
throw new Error('客户端未连接');
}
try {
const message: MsgRpcCall = {
networkId,
componentType,
methodName,
args,
isClientRpc,
timestamp: Date.now()
};
await this.client!.sendMsg('network/RpcCall', message);
this.stats.messagesSent++;
logger.debug(`发送RPC: ${componentType}.${methodName}(${isClientRpc ? 'ClientRpc' : 'Command'})`);
} catch (error) {
logger.error('发送RPC失败:', error);
throw error;
}
}
/**
* 查询服务端状态
*/
public async getServerStatus(): Promise<ResServerStatus> {
if (!this.isConnected()) {
throw new Error('客户端未连接');
}
const result = await this.client!.callApi('network/ServerStatus', {});
if (!result.isSucc) {
throw new Error(`查询服务端状态失败: ${result.err.message}`);
}
return result.res;
}
/**
* 发送心跳
*/
public async ping(): Promise<number> {
if (!this.isConnected()) {
throw new Error('客户端未连接');
}
const startTime = Date.now();
const result = await this.client!.callApi('network/Ping', {
timestamp: startTime
});
if (!result.isSucc) {
throw new Error(`心跳失败: ${result.err.message}`);
}
const latency = Date.now() - startTime;
this.stats.latency = latency;
return latency;
}
/**
* 获取连接状态
*/
public getConnectionState(): ConnectionState {
return this.connectionState;
}
/**
* 是否已连接
*/
public isConnected(): boolean {
return this.connectionState === 'connected' && (this.client?.isConnected || false);
}
/**
* 获取客户端ID
*/
public getClientId(): number {
return this.clientId;
}
/**
* 获取统计信息
*/
public getStats() {
return { ...this.stats };
}
/**
* 设置事件处理器
*/
private setupEventHandlers(): void {
if (!this.client) return;
// 连接断开处理
this.client.flows.postDisconnectFlow.push((v) => {
if (this.connectionState !== 'disconnected') {
logger.warn('连接意外断开,尝试重连...');
this.connectionState = 'reconnecting';
this.onReconnecting?.();
this.attemptReconnect();
}
return v;
});
// 消息监听
this.client.listenMsg('network/NetworkMessage', msg => {
this.stats.messagesReceived++;
const networkMessage: NetworkMessage = {
type: msg.type,
networkId: msg.networkId,
data: msg.data,
timestamp: msg.timestamp
};
this.onMessage?.(networkMessage);
});
// SyncVar消息监听
this.client.listenMsg('network/SyncVar', msg => {
this.stats.messagesReceived++;
const networkMessage: NetworkMessage = {
type: 'syncvar',
networkId: msg.networkId,
data: {
componentType: msg.componentType,
propertyName: msg.propertyName,
value: msg.value
},
timestamp: msg.timestamp
};
this.onMessage?.(networkMessage);
});
// RPC消息监听
this.client.listenMsg('network/RpcCall', msg => {
this.stats.messagesReceived++;
const networkMessage: NetworkMessage = {
type: 'rpc',
networkId: msg.networkId,
data: {
componentType: msg.componentType,
methodName: msg.methodName,
args: msg.args
},
timestamp: msg.timestamp
};
this.onMessage?.(networkMessage);
});
// 客户端断开通知
this.client.listenMsg('network/ClientDisconnected', msg => {
logger.info(`客户端 ${msg.clientId} 断开连接: ${msg.reason}`);
});
// 权威转移通知
this.client.listenMsg('network/AuthorityChange', msg => {
logger.info(`网络对象 ${msg.networkId} 权威转移给客户端 ${msg.newOwnerId}`);
});
}
/**
* 尝试重连
*/
private async attemptReconnect(): Promise<void> {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
logger.error('重连次数已达上限,停止重连');
this.connectionState = 'disconnected';
this.onDisconnected?.('max_reconnect_attempts_reached');
return;
}
this.reconnectAttempts++;
logger.info(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
try {
await new Promise(resolve => setTimeout(resolve, this.reconnectInterval));
// 重新连接
await this.connect();
} catch (error) {
logger.error(`重连失败:`, error);
// 继续尝试重连
this.attemptReconnect();
}
}
/**
* 启动心跳
*/
private startHeartbeat(): void {
this.heartbeatInterval = setInterval(async () => {
try {
await this.ping();
} catch (error) {
logger.warn('心跳失败:', error);
}
}, 30000); // 30秒心跳
}
/**
* 停止心跳
*/
private stopHeartbeat(): void {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = null;
}
}
}

View File

@@ -0,0 +1,364 @@
/**
* TSRPC 服务端传输层
*
* 封装TSRPC服务端功能提供网络消息处理和客户端管理
*/
import { WsServer } from 'tsrpc';
import { createLogger } from '@esengine/ecs-framework';
import { serviceProto, ServiceType } from './protocols/serviceProto';
import { NetworkConfig, NetworkMessage } from '../types/NetworkTypes';
import {
ReqJoinRoom, ResJoinRoom,
ReqServerStatus, ResServerStatus,
ReqPing, ResPing,
MsgNetworkMessage,
MsgSyncVar,
MsgRpcCall,
MsgNetworkObjectSpawn,
MsgNetworkObjectDespawn,
MsgClientDisconnected,
MsgAuthorityChange
} from './protocols/NetworkProtocols';
const logger = createLogger('TsrpcServer');
/**
* 客户端连接信息
*/
interface ClientConnection {
/** 客户端ID */
id: number;
/** 连接对象 */
connection: any;
/** 连接时间 */
connectTime: number;
/** 最后活跃时间 */
lastActivity: number;
/** 客户端信息 */
clientInfo?: {
version: string;
platform: string;
};
}
/**
* TSRPC服务端包装器
*/
export class TsrpcServer {
private server: WsServer<ServiceType> | null = null;
private clients: Map<number, ClientConnection> = new Map();
private nextClientId: number = 1;
private config: NetworkConfig;
private startTime: number = 0;
/** 统计信息 */
private stats = {
messagesSent: 0,
messagesReceived: 0,
bytesSent: 0,
bytesReceived: 0
};
/** 事件处理器 */
public onClientConnected?: (clientId: number) => void;
public onClientDisconnected?: (clientId: number, reason?: string) => void;
public onMessage?: (message: NetworkMessage, fromClientId: number) => void;
constructor(config: NetworkConfig) {
this.config = config;
}
/**
* 启动服务端
*/
public async start(): Promise<void> {
if (this.server) {
throw new Error('服务端已经在运行中');
}
// 创建TSRPC WebSocket服务端
this.server = new WsServer(serviceProto, {
port: this.config.port || 7777
});
this.startTime = Date.now();
this.setupApiHandlers();
this.setupMessageHandlers();
this.setupConnectionHandlers();
// 启动服务端
await this.server.start();
logger.info(`TSRPC服务端已启动端口: ${this.config.port}`);
}
/**
* 停止服务端
*/
public async stop(): Promise<void> {
if (this.server) {
await this.server.stop();
this.server = null;
this.clients.clear();
logger.info('TSRPC服务端已停止');
}
}
/**
* 向指定客户端发送消息
*/
public sendToClient(clientId: number, message: any): void {
const client = this.clients.get(clientId);
if (!client) {
logger.warn(`客户端不存在: ${clientId}`);
return;
}
try {
// 发送消息给指定连接
this.server?.broadcastMsg(message.type, message.data || message, [client.connection]);
this.stats.messagesSent++;
logger.debug(`向客户端 ${clientId} 发送消息: ${message.type || 'unknown'}`);
} catch (error) {
logger.error(`向客户端 ${clientId} 发送消息失败:`, error);
}
}
/**
* 向所有客户端广播消息
*/
public broadcast(message: any, excludeClientId?: number): void {
if (!this.server) {
logger.warn('服务端未启动,无法广播消息');
return;
}
try {
if (excludeClientId) {
// 排除指定客户端
const targetConnections = Array.from(this.clients.entries())
.filter(([clientId, client]) => clientId !== excludeClientId)
.map(([clientId, client]) => client.connection);
this.server.broadcastMsg(message.type, message.data || message, targetConnections);
this.stats.messagesSent += targetConnections.length;
} else {
// 广播给所有客户端
this.server.broadcastMsg(message.type, message.data || message);
this.stats.messagesSent += this.clients.size;
}
} catch (error) {
logger.error('广播消息失败:', error);
}
logger.debug(`广播消息给 ${this.clients.size} 个客户端: ${message.type || 'unknown'}`);
}
/**
* 获取连接的客户端列表
*/
public getConnectedClients(): number[] {
return Array.from(this.clients.keys());
}
/**
* 获取客户端数量
*/
public getClientCount(): number {
return this.clients.size;
}
/**
* 获取服务端统计信息
*/
public getStats() {
return {
...this.stats,
clientCount: this.clients.size,
uptime: Date.now() - this.startTime
};
}
/**
* 设置API处理器
*/
private setupApiHandlers(): void {
if (!this.server) return;
// 客户端加入房间
this.server.implementApi('network/JoinRoom', call => {
const clientId = this.nextClientId++;
const client: ClientConnection = {
id: clientId,
connection: call.conn,
connectTime: Date.now(),
lastActivity: Date.now(),
clientInfo: call.req.clientInfo
};
this.clients.set(clientId, client);
logger.info(`客户端 ${clientId} 连接成功`);
// 通知上层
this.onClientConnected?.(clientId);
// 返回响应
call.succ({
clientId,
roomId: call.req.roomId || 'default',
serverInfo: {
version: '1.0.0',
syncRate: this.config.syncRate || 20
}
});
});
// 服务端状态查询
this.server.implementApi('network/ServerStatus', call => {
const stats = this.getStats();
call.succ({
clientCount: stats.clientCount,
networkObjectCount: 0, // 这里需要从NetworkRegistry获取
uptime: stats.uptime,
networkStats: {
messagesSent: stats.messagesSent,
messagesReceived: stats.messagesReceived,
bytesSent: stats.bytesSent,
bytesReceived: stats.bytesReceived
}
});
});
// 心跳检测
this.server.implementApi('network/Ping', call => {
call.succ({
serverTimestamp: Date.now(),
clientTimestamp: call.req.timestamp
});
});
}
/**
* 设置消息处理器
*/
private setupMessageHandlers(): void {
if (!this.server) return;
// 网络消息处理
this.server.listenMsg('network/NetworkMessage', msg => {
const clientId = this.getClientIdByConnection(msg.conn);
if (clientId) {
this.stats.messagesReceived++;
this.updateClientActivity(clientId);
// 转换为内部消息格式
const networkMessage: NetworkMessage = {
type: msg.msg.type,
networkId: msg.msg.networkId,
data: msg.msg.data,
timestamp: msg.msg.timestamp
};
this.onMessage?.(networkMessage, clientId);
}
});
// SyncVar消息处理
this.server.listenMsg('network/SyncVar', msg => {
const clientId = this.getClientIdByConnection(msg.conn);
if (clientId) {
this.stats.messagesReceived++;
this.updateClientActivity(clientId);
// 转换并广播给其他客户端
const syncVarMessage: MsgSyncVar = msg.msg;
this.broadcast({
type: 'network/SyncVar',
data: syncVarMessage
}, clientId);
}
});
// RPC调用消息处理
this.server.listenMsg('network/RpcCall', msg => {
const clientId = this.getClientIdByConnection(msg.conn);
if (clientId) {
this.stats.messagesReceived++;
this.updateClientActivity(clientId);
const rpcMessage: MsgRpcCall = msg.msg;
if (rpcMessage.isClientRpc) {
// 服务端到客户端的RPC广播给所有客户端
this.broadcast({
type: 'network/RpcCall',
data: rpcMessage
});
} else {
// 客户端到服务端的Command只在服务端处理
const networkMessage: NetworkMessage = {
type: 'rpc',
networkId: rpcMessage.networkId,
data: {
componentType: rpcMessage.componentType,
methodName: rpcMessage.methodName,
args: rpcMessage.args
},
timestamp: rpcMessage.timestamp
};
this.onMessage?.(networkMessage, clientId);
}
}
});
}
/**
* 设置连接处理器
*/
private setupConnectionHandlers(): void {
if (!this.server) return;
// 连接断开处理
this.server.flows.postDisconnectFlow.push(conn => {
const clientId = this.getClientIdByConnection(conn);
if (clientId) {
this.clients.delete(clientId);
logger.info(`客户端 ${clientId} 断开连接`);
// 通知其他客户端
this.broadcast({
type: 'network/ClientDisconnected',
data: { clientId, reason: 'disconnected' }
});
// 通知上层
this.onClientDisconnected?.(clientId, 'disconnected');
}
return conn;
});
}
/**
* 根据连接对象获取客户端ID
*/
private getClientIdByConnection(conn: any): number | null {
for (const [clientId, client] of this.clients) {
if (client.connection === conn) {
return clientId;
}
}
return null;
}
/**
* 更新客户端活跃时间
*/
private updateClientActivity(clientId: number): void {
const client = this.clients.get(clientId);
if (client) {
client.lastActivity = Date.now();
}
}
}

View File

@@ -0,0 +1,338 @@
/**
* TSRPC 传输管理器
*
* 统一管理TSRPC服务端和客户端提供通用的传输接口
*/
import { createLogger } from '@esengine/ecs-framework';
import { TsrpcServer } from './TsrpcServer';
import { TsrpcClient } from './TsrpcClient';
import { NetworkConfig, NetworkMessage, NetworkSide } from '../types/NetworkTypes';
const logger = createLogger('TsrpcTransport');
/**
* 传输事件处理器
*/
export interface TransportEventHandlers {
/** 连接建立 */
onConnected?: () => void;
/** 连接断开 */
onDisconnected?: (reason?: string) => void;
/** 客户端连接(仅服务端) */
onClientConnected?: (clientId: number) => void;
/** 客户端断开(仅服务端) */
onClientDisconnected?: (clientId: number, reason?: string) => void;
/** 收到消息 */
onMessage?: (message: NetworkMessage, fromClientId?: number) => void;
/** 发生错误 */
onError?: (error: Error) => void;
}
/**
* TSRPC传输层管理器
*/
export class TsrpcTransport {
private server: TsrpcServer | null = null;
private client: TsrpcClient | null = null;
private networkSide: NetworkSide = 'client';
private config: NetworkConfig;
private eventHandlers: TransportEventHandlers = {};
constructor(config: NetworkConfig) {
this.config = config;
}
/**
* 启动服务端
*/
public async startServer(): Promise<void> {
if (this.server) {
throw new Error('服务端已经在运行中');
}
this.networkSide = 'server';
this.server = new TsrpcServer(this.config);
// 设置服务端事件处理器
this.server.onClientConnected = (clientId) => {
logger.info(`客户端 ${clientId} 已连接`);
this.eventHandlers.onClientConnected?.(clientId);
};
this.server.onClientDisconnected = (clientId, reason) => {
logger.info(`客户端 ${clientId} 已断开: ${reason}`);
this.eventHandlers.onClientDisconnected?.(clientId, reason);
};
this.server.onMessage = (message, fromClientId) => {
this.eventHandlers.onMessage?.(message, fromClientId);
};
await this.server.start();
logger.info('TSRPC服务端已启动');
this.eventHandlers.onConnected?.();
}
/**
* 连接到服务端
*/
public async connectToServer(): Promise<void> {
if (this.client) {
throw new Error('客户端已经连接或正在连接中');
}
this.networkSide = 'client';
this.client = new TsrpcClient(this.config);
// 设置客户端事件处理器
this.client.onConnected = () => {
logger.info('已连接到服务端');
this.eventHandlers.onConnected?.();
};
this.client.onDisconnected = (reason) => {
logger.info(`已断开连接: ${reason}`);
this.eventHandlers.onDisconnected?.(reason);
};
this.client.onMessage = (message) => {
this.eventHandlers.onMessage?.(message);
};
this.client.onError = (error) => {
logger.error('客户端错误:', error);
this.eventHandlers.onError?.(error);
};
await this.client.connect();
}
/**
* 断开连接/停止服务端
*/
public async disconnect(): Promise<void> {
if (this.server) {
await this.server.stop();
this.server = null;
logger.info('TSRPC服务端已停止');
}
if (this.client) {
await this.client.disconnect();
this.client = null;
logger.info('TSRPC客户端已断开');
}
this.eventHandlers.onDisconnected?.();
}
/**
* 发送消息
*/
public async sendMessage(message: NetworkMessage, targetClientId?: number): Promise<void> {
if (this.networkSide === 'server' && this.server) {
// 服务端模式:发送给指定客户端或广播
if (targetClientId) {
this.server.sendToClient(targetClientId, {
type: 'network/NetworkMessage',
data: message
});
} else {
this.server.broadcast({
type: 'network/NetworkMessage',
data: message
});
}
} else if (this.networkSide === 'client' && this.client) {
// 客户端模式:发送给服务端
await this.client.sendMessage(message);
} else {
throw new Error('传输层未初始化或状态错误');
}
}
/**
* 发送SyncVar消息
*/
public async sendSyncVar(
networkId: number,
componentType: string,
propertyName: string,
value: any,
targetClientId?: number
): Promise<void> {
if (this.networkSide === 'server' && this.server) {
const message = {
type: 'network/SyncVar',
data: {
networkId,
componentType,
propertyName,
value,
timestamp: Date.now()
}
};
if (targetClientId) {
this.server.sendToClient(targetClientId, message);
} else {
this.server.broadcast(message);
}
} else if (this.networkSide === 'client' && this.client) {
await this.client.sendSyncVar(networkId, componentType, propertyName, value);
} else {
throw new Error('传输层未初始化或状态错误');
}
}
/**
* 发送RPC消息
*/
public async sendRpcCall(
networkId: number,
componentType: string,
methodName: string,
args: any[],
isClientRpc: boolean,
targetClientId?: number
): Promise<void> {
if (this.networkSide === 'server' && this.server) {
const message = {
type: 'network/RpcCall',
data: {
networkId,
componentType,
methodName,
args,
isClientRpc,
timestamp: Date.now()
}
};
if (targetClientId) {
this.server.sendToClient(targetClientId, message);
} else {
this.server.broadcast(message);
}
} else if (this.networkSide === 'client' && this.client) {
await this.client.sendRpcCall(networkId, componentType, methodName, args, isClientRpc);
} else {
throw new Error('传输层未初始化或状态错误');
}
}
/**
* 获取连接状态
*/
public isConnected(): boolean {
if (this.networkSide === 'server' && this.server) {
return true; // 服务端启动即为连接状态
} else if (this.networkSide === 'client' && this.client) {
return this.client.isConnected();
}
return false;
}
/**
* 获取网络端类型
*/
public getNetworkSide(): NetworkSide {
return this.networkSide;
}
/**
* 获取客户端ID仅客户端模式
*/
public getClientId(): number {
if (this.networkSide === 'client' && this.client) {
return this.client.getClientId();
}
return 0;
}
/**
* 获取连接的客户端列表(仅服务端模式)
*/
public getConnectedClients(): number[] {
if (this.networkSide === 'server' && this.server) {
return this.server.getConnectedClients();
}
return [];
}
/**
* 获取客户端数量(仅服务端模式)
*/
public getClientCount(): number {
if (this.networkSide === 'server' && this.server) {
return this.server.getClientCount();
}
return 0;
}
/**
* 获取统计信息
*/
public getStats() {
if (this.networkSide === 'server' && this.server) {
return this.server.getStats();
} else if (this.networkSide === 'client' && this.client) {
const clientStats = this.client.getStats();
return {
messagesSent: clientStats.messagesSent,
messagesReceived: clientStats.messagesReceived,
bytesSent: clientStats.bytesSent,
bytesReceived: clientStats.bytesReceived,
clientCount: 0,
uptime: 0
};
}
return {
messagesSent: 0,
messagesReceived: 0,
bytesSent: 0,
bytesReceived: 0,
clientCount: 0,
uptime: 0
};
}
/**
* 查询服务端状态(仅客户端模式)
*/
public async getServerStatus() {
if (this.networkSide === 'client' && this.client) {
return await this.client.getServerStatus();
}
throw new Error('只能在客户端模式下查询服务端状态');
}
/**
* 发送心跳(仅客户端模式)
*/
public async ping(): Promise<number> {
if (this.networkSide === 'client' && this.client) {
return await this.client.ping();
}
throw new Error('只能在客户端模式下发送心跳');
}
/**
* 设置事件处理器
*/
public setEventHandlers(handlers: TransportEventHandlers): void {
this.eventHandlers = { ...this.eventHandlers, ...handlers };
}
/**
* 设置单个事件处理器
*/
public on<K extends keyof TransportEventHandlers>(
event: K,
handler: TransportEventHandlers[K]
): void {
this.eventHandlers[event] = handler;
}
}

View File

@@ -0,0 +1,9 @@
/**
* 传输层模块导出
*/
export { TsrpcTransport } from './TsrpcTransport';
export { TsrpcServer } from './TsrpcServer';
export { TsrpcClient } from './TsrpcClient';
export * from './protocols/NetworkProtocols';
export { serviceProto, ServiceType } from './protocols/serviceProto';

View File

@@ -0,0 +1,184 @@
/**
* 网络库 TSRPC 协议定义
* 定义所有网络消息的类型和结构
*/
/**
* 客户端连接请求
*/
export interface ReqJoinRoom {
/** 房间ID可选 */
roomId?: string;
/** 客户端信息 */
clientInfo?: {
/** 客户端版本 */
version: string;
/** 客户端平台 */
platform: string;
};
}
/**
* 客户端连接响应
*/
export interface ResJoinRoom {
/** 分配的客户端ID */
clientId: number;
/** 房间ID */
roomId: string;
/** 服务端信息 */
serverInfo: {
/** 服务端版本 */
version: string;
/** 同步频率 */
syncRate: number;
};
}
/**
* 网络消息广播
*/
export interface MsgNetworkMessage {
/** 消息类型 */
type: 'syncvar' | 'rpc';
/** 网络对象ID */
networkId: number;
/** 消息数据 */
data: any;
/** 时间戳 */
timestamp: number;
/** 发送者客户端ID */
senderId?: number;
}
/**
* SyncVar 同步消息
*/
export interface MsgSyncVar {
/** 网络对象ID */
networkId: number;
/** 组件类型名 */
componentType: string;
/** 属性名 */
propertyName: string;
/** 新的属性值 */
value: any;
/** 时间戳 */
timestamp: number;
}
/**
* RPC 调用消息
*/
export interface MsgRpcCall {
/** 网络对象ID */
networkId: number;
/** 组件类型名 */
componentType: string;
/** 方法名 */
methodName: string;
/** 参数 */
args: any[];
/** 是否为客户端RPC */
isClientRpc: boolean;
/** 时间戳 */
timestamp: number;
}
/**
* 网络对象生成通知
*/
export interface MsgNetworkObjectSpawn {
/** 网络对象ID */
networkId: number;
/** 实体名称 */
entityName: string;
/** 所有者客户端ID */
ownerId: number;
/** 是否拥有权威 */
hasAuthority: boolean;
/** 初始组件数据 */
components: Array<{
/** 组件类型 */
type: string;
/** 组件数据 */
data: any;
}>;
}
/**
* 网络对象销毁通知
*/
export interface MsgNetworkObjectDespawn {
/** 网络对象ID */
networkId: number;
}
/**
* 客户端断开连接通知
*/
export interface MsgClientDisconnected {
/** 断开连接的客户端ID */
clientId: number;
/** 断开原因 */
reason?: string;
}
/**
* 权威转移通知
*/
export interface MsgAuthorityChange {
/** 网络对象ID */
networkId: number;
/** 新的权威所有者ID */
newOwnerId: number;
/** 是否拥有权威 */
hasAuthority: boolean;
}
/**
* 服务端状态查询请求
*/
export interface ReqServerStatus {}
/**
* 服务端状态响应
*/
export interface ResServerStatus {
/** 连接的客户端数量 */
clientCount: number;
/** 网络对象数量 */
networkObjectCount: number;
/** 服务器运行时间(毫秒) */
uptime: number;
/** 网络统计 */
networkStats: {
/** 发送的消息数 */
messagesSent: number;
/** 接收的消息数 */
messagesReceived: number;
/** 发送的字节数 */
bytesSent: number;
/** 接收的字节数 */
bytesReceived: number;
};
}
/**
* 心跳请求
*/
export interface ReqPing {
/** 客户端时间戳 */
timestamp: number;
}
/**
* 心跳响应
*/
export interface ResPing {
/** 服务端时间戳 */
serverTimestamp: number;
/** 客户端时间戳(回传) */
clientTimestamp: number;
}

View File

@@ -0,0 +1,108 @@
/**
* TSRPC 服务协议定义
* 定义API调用和消息类型
*/
import { ServiceProto } from 'tsrpc';
import {
ReqJoinRoom, ResJoinRoom,
ReqServerStatus, ResServerStatus,
ReqPing, ResPing,
MsgNetworkMessage,
MsgSyncVar,
MsgRpcCall,
MsgNetworkObjectSpawn,
MsgNetworkObjectDespawn,
MsgClientDisconnected,
MsgAuthorityChange
} from './NetworkProtocols';
/**
* 网络服务协议
* 定义所有可用的API和消息类型
*/
export const serviceProto: ServiceProto<ServiceType> = {
"services": [
{
"id": 0,
"name": "network/JoinRoom",
"type": "api"
},
{
"id": 1,
"name": "network/ServerStatus",
"type": "api"
},
{
"id": 2,
"name": "network/Ping",
"type": "api"
},
{
"id": 3,
"name": "network/NetworkMessage",
"type": "msg"
},
{
"id": 4,
"name": "network/SyncVar",
"type": "msg"
},
{
"id": 5,
"name": "network/RpcCall",
"type": "msg"
},
{
"id": 6,
"name": "network/NetworkObjectSpawn",
"type": "msg"
},
{
"id": 7,
"name": "network/NetworkObjectDespawn",
"type": "msg"
},
{
"id": 8,
"name": "network/ClientDisconnected",
"type": "msg"
},
{
"id": 9,
"name": "network/AuthorityChange",
"type": "msg"
}
],
"types": {}
};
/**
* 服务类型定义
* 用于类型安全的API调用和消息发送
*/
export interface ServiceType {
api: {
"network/JoinRoom": {
req: ReqJoinRoom;
res: ResJoinRoom;
};
"network/ServerStatus": {
req: ReqServerStatus;
res: ResServerStatus;
};
"network/Ping": {
req: ReqPing;
res: ResPing;
};
};
msg: {
"network/NetworkMessage": MsgNetworkMessage;
"network/SyncVar": MsgSyncVar;
"network/RpcCall": MsgRpcCall;
"network/NetworkObjectSpawn": MsgNetworkObjectSpawn;
"network/NetworkObjectDespawn": MsgNetworkObjectDespawn;
"network/ClientDisconnected": MsgClientDisconnected;
"network/AuthorityChange": MsgAuthorityChange;
};
}