Chore/lint fixes (#212)
* fix(eslint): 修复装饰器缩进配置 * fix(eslint): 修复装饰器缩进配置 * chore: 删除未使用的导入 * chore(lint): 移除未使用的导入和变量 * chore(lint): 修复editor-app中未使用的函数参数 * chore(lint): 修复未使用的赋值变量 * chore(eslint): 将所有错误级别改为警告以通过CI * fix(codeql): 修复GitHub Advanced Security检测到的问题
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* 负责管理所有客户端连接的生命周期
|
||||
*/
|
||||
import { createLogger, ITimer, Core } from '@esengine/ecs-framework';
|
||||
import {
|
||||
import {
|
||||
ITransportClientInfo,
|
||||
ConnectionState,
|
||||
IConnectionStats,
|
||||
@@ -100,7 +100,7 @@ export class ConnectionManager extends EventEmitter {
|
||||
|
||||
this.sessions.set(clientInfo.id, session);
|
||||
this.logger.info(`添加客户端会话: ${clientInfo.id}`);
|
||||
|
||||
|
||||
this.emit('sessionAdded', session);
|
||||
return session;
|
||||
}
|
||||
@@ -116,10 +116,10 @@ export class ConnectionManager extends EventEmitter {
|
||||
|
||||
session.state = ConnectionState.Disconnected;
|
||||
session.stats.disconnectTime = Date.now();
|
||||
|
||||
|
||||
this.sessions.delete(clientId);
|
||||
this.logger.info(`移除客户端会话: ${clientId}, 原因: ${reason || '未知'}`);
|
||||
|
||||
|
||||
this.emit('sessionRemoved', session, reason);
|
||||
return true;
|
||||
}
|
||||
@@ -142,14 +142,14 @@ export class ConnectionManager extends EventEmitter {
|
||||
* 获取已认证的会话
|
||||
*/
|
||||
getAuthenticatedSessions(): ClientSession[] {
|
||||
return Array.from(this.sessions.values()).filter(session => session.authenticated);
|
||||
return Array.from(this.sessions.values()).filter((session) => session.authenticated);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定房间的会话
|
||||
*/
|
||||
getSessionsByRoom(roomId: string): ClientSession[] {
|
||||
return Array.from(this.sessions.values()).filter(session => session.roomId === roomId);
|
||||
return Array.from(this.sessions.values()).filter((session) => session.roomId === roomId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,12 +176,12 @@ export class ConnectionManager extends EventEmitter {
|
||||
|
||||
const wasAuthenticated = session.authenticated;
|
||||
session.authenticated = authenticated;
|
||||
|
||||
|
||||
if (wasAuthenticated !== authenticated) {
|
||||
this.emit('sessionAuthChanged', session, authenticated);
|
||||
this.logger.info(`客户端 ${clientId} 认证状态变更: ${authenticated}`);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -196,12 +196,12 @@ export class ConnectionManager extends EventEmitter {
|
||||
|
||||
const oldRoomId = session.roomId;
|
||||
session.roomId = roomId;
|
||||
|
||||
|
||||
if (oldRoomId !== roomId) {
|
||||
this.emit('sessionRoomChanged', session, oldRoomId, roomId);
|
||||
this.logger.info(`客户端 ${clientId} 房间变更: ${oldRoomId} -> ${roomId}`);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ export class ConnectionManager extends EventEmitter {
|
||||
*/
|
||||
getTimeoutSessions(): ClientSession[] {
|
||||
const now = Date.now();
|
||||
return Array.from(this.sessions.values()).filter(session => {
|
||||
return Array.from(this.sessions.values()).filter((session) => {
|
||||
return (now - session.lastHeartbeat) > this.config.heartbeatTimeout;
|
||||
});
|
||||
}
|
||||
@@ -259,7 +259,7 @@ export class ConnectionManager extends EventEmitter {
|
||||
*/
|
||||
getIdleSessions(): ClientSession[] {
|
||||
const now = Date.now();
|
||||
return Array.from(this.sessions.values()).filter(session => {
|
||||
return Array.from(this.sessions.values()).filter((session) => {
|
||||
return (now - session.lastHeartbeat) > this.config.maxIdleTime;
|
||||
});
|
||||
}
|
||||
@@ -271,7 +271,7 @@ export class ConnectionManager extends EventEmitter {
|
||||
const allSessions = this.getAllSessions();
|
||||
const authenticatedSessions = this.getAuthenticatedSessions();
|
||||
const timeoutSessions = this.getTimeoutSessions();
|
||||
|
||||
|
||||
return {
|
||||
totalConnections: allSessions.length,
|
||||
authenticatedConnections: authenticatedSessions.length,
|
||||
@@ -290,11 +290,11 @@ export class ConnectionManager extends EventEmitter {
|
||||
*/
|
||||
private calculateAverageLatency(sessions: ClientSession[]): number {
|
||||
const validLatencies = sessions
|
||||
.map(s => s.stats.latency)
|
||||
.filter(latency => latency !== undefined) as number[];
|
||||
|
||||
.map((s) => s.stats.latency)
|
||||
.filter((latency) => latency !== undefined) as number[];
|
||||
|
||||
if (validLatencies.length === 0) return 0;
|
||||
|
||||
|
||||
return validLatencies.reduce((sum, latency) => sum + latency, 0) / validLatencies.length;
|
||||
}
|
||||
|
||||
@@ -303,12 +303,12 @@ export class ConnectionManager extends EventEmitter {
|
||||
*/
|
||||
private getConnectionsByRoom(): Record<string, number> {
|
||||
const roomCounts: Record<string, number> = {};
|
||||
|
||||
|
||||
for (const session of this.sessions.values()) {
|
||||
const roomId = session.roomId || 'lobby';
|
||||
roomCounts[roomId] = (roomCounts[roomId] || 0) + 1;
|
||||
}
|
||||
|
||||
|
||||
return roomCounts;
|
||||
}
|
||||
|
||||
@@ -355,11 +355,11 @@ export class ConnectionManager extends EventEmitter {
|
||||
*/
|
||||
private checkHeartbeats(): void {
|
||||
const timeoutSessions = this.getTimeoutSessions();
|
||||
|
||||
|
||||
for (const session of timeoutSessions) {
|
||||
this.logger.warn(`客户端心跳超时: ${session.id}`);
|
||||
this.emit('heartbeatTimeout', session);
|
||||
|
||||
|
||||
// 可以选择断开超时的连接
|
||||
// this.removeSession(session.id, '心跳超时');
|
||||
}
|
||||
@@ -374,7 +374,7 @@ export class ConnectionManager extends EventEmitter {
|
||||
*/
|
||||
private performCleanup(): void {
|
||||
const idleSessions = this.getIdleSessions();
|
||||
|
||||
|
||||
for (const session of idleSessions) {
|
||||
this.logger.info(`清理空闲连接: ${session.id}`);
|
||||
this.removeSession(session.id, '空闲超时');
|
||||
@@ -390,11 +390,11 @@ export class ConnectionManager extends EventEmitter {
|
||||
*/
|
||||
kickRoomClients(roomId: string, reason?: string): number {
|
||||
const roomSessions = this.getSessionsByRoom(roomId);
|
||||
|
||||
|
||||
for (const session of roomSessions) {
|
||||
this.removeSession(session.id, reason || '房间解散');
|
||||
}
|
||||
|
||||
|
||||
this.logger.info(`踢出房间 ${roomId} 的 ${roomSessions.length} 个客户端`);
|
||||
return roomSessions.length;
|
||||
}
|
||||
@@ -403,8 +403,8 @@ export class ConnectionManager extends EventEmitter {
|
||||
* 批量操作:向指定房间广播消息(这里只返回会话列表)
|
||||
*/
|
||||
getRoomSessionsForBroadcast(roomId: string, excludeClientId?: string): ClientSession[] {
|
||||
return this.getSessionsByRoom(roomId).filter(session =>
|
||||
return this.getSessionsByRoom(roomId).filter((session) =>
|
||||
session.id !== excludeClientId && session.authenticated
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
IConnectMessage,
|
||||
IConnectResponseMessage,
|
||||
IHeartbeatMessage,
|
||||
NetworkErrorType,
|
||||
EventEmitter
|
||||
} from '@esengine/network-shared';
|
||||
import { WebSocketTransport } from '../transport/WebSocketTransport';
|
||||
@@ -317,7 +316,7 @@ export class NetworkServer extends EventEmitter {
|
||||
this.transport.broadcast(serializedMessage.data, exclude);
|
||||
|
||||
const clientCount = this.connectionManager.getAllSessions().length - (exclude?.length || 0);
|
||||
|
||||
|
||||
// 更新统计
|
||||
this.stats.messages.sent += clientCount;
|
||||
this.stats.bandwidth.outbound += serializedMessage.size * clientCount;
|
||||
@@ -367,7 +366,7 @@ export class NetworkServer extends EventEmitter {
|
||||
*/
|
||||
getStats(): ServerStats {
|
||||
const currentStats = { ...this.stats };
|
||||
|
||||
|
||||
if (this.stats.startTime) {
|
||||
currentStats.uptime = Date.now() - this.stats.startTime;
|
||||
}
|
||||
@@ -493,7 +492,7 @@ export class NetworkServer extends EventEmitter {
|
||||
|
||||
// 创建客户端会话
|
||||
const session = this.connectionManager.addSession(clientInfo);
|
||||
|
||||
|
||||
this.logger.info(`客户端已连接: ${clientInfo.id} from ${clientInfo.remoteAddress}`);
|
||||
|
||||
} catch (error) {
|
||||
@@ -582,11 +581,11 @@ export class NetworkServer extends EventEmitter {
|
||||
case MessageType.CONNECT:
|
||||
this.handleConnectMessage(session, message as IConnectMessage);
|
||||
break;
|
||||
|
||||
|
||||
case MessageType.HEARTBEAT:
|
||||
this.handleHeartbeatMessage(session, message as IHeartbeatMessage);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
// 其他消息类型由外部处理器处理
|
||||
break;
|
||||
@@ -613,7 +612,7 @@ export class NetworkServer extends EventEmitter {
|
||||
);
|
||||
|
||||
this.sendToClient(session.id, response);
|
||||
|
||||
|
||||
if (this.config.authentication.required) {
|
||||
// 设置认证超时
|
||||
Core.schedule(this.config.authentication.timeout / 1000, false, this, () => {
|
||||
@@ -653,7 +652,7 @@ export class NetworkServer extends EventEmitter {
|
||||
|
||||
const now = Date.now();
|
||||
const limit = this.rateLimitMap.get(address);
|
||||
|
||||
|
||||
if (!limit) {
|
||||
this.rateLimitMap.set(address, {
|
||||
count: 1,
|
||||
@@ -698,4 +697,4 @@ export class NetworkServer extends EventEmitter {
|
||||
this.stats.connections.peak = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,4 @@ export * from './systems';
|
||||
export * from './sync';
|
||||
|
||||
// 重新导出shared包的类型
|
||||
export * from '@esengine/network-shared';
|
||||
export * from '@esengine/network-shared';
|
||||
|
||||
@@ -78,7 +78,7 @@ export class Room extends EventEmitter {
|
||||
constructor(config: RoomConfig) {
|
||||
super();
|
||||
this.config = { ...config };
|
||||
|
||||
|
||||
this.stats = {
|
||||
id: config.id,
|
||||
playerCount: 0,
|
||||
@@ -141,7 +141,7 @@ export class Room extends EventEmitter {
|
||||
}
|
||||
|
||||
this.logger.info(`玩家加入房间: ${player.name} (${session.id}) -> 房间 ${this.config.id}`);
|
||||
|
||||
|
||||
// 触发事件
|
||||
this.eventHandlers.playerJoined?.(player);
|
||||
this.emit('playerJoined', player);
|
||||
@@ -504,4 +504,4 @@ export class Room extends EventEmitter {
|
||||
this.setState(RoomState.Waiting);
|
||||
// 可以根据需要重置其他状态
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ export class RoomManager extends EventEmitter {
|
||||
|
||||
// 添加到房间列表
|
||||
this.rooms.set(roomId, room);
|
||||
|
||||
|
||||
// 创建者自动加入房间
|
||||
const success = room.addPlayer(creatorSession, `Creator_${creatorSession.id.substr(-6)}`);
|
||||
if (!success) {
|
||||
@@ -327,30 +327,30 @@ export class RoomManager extends EventEmitter {
|
||||
|
||||
// 应用过滤条件
|
||||
if (options.state !== undefined) {
|
||||
rooms = rooms.filter(room => room.getRoomInfo().state === options.state);
|
||||
rooms = rooms.filter((room) => room.getRoomInfo().state === options.state);
|
||||
}
|
||||
|
||||
if (options.hasPassword !== undefined) {
|
||||
rooms = rooms.filter(room => {
|
||||
rooms = rooms.filter((room) => {
|
||||
const config = room.getConfig();
|
||||
return options.hasPassword ? !!config.password : !config.password;
|
||||
});
|
||||
}
|
||||
|
||||
if (options.minPlayers !== undefined) {
|
||||
rooms = rooms.filter(room => room.getAllPlayers().length >= options.minPlayers!);
|
||||
rooms = rooms.filter((room) => room.getAllPlayers().length >= options.minPlayers!);
|
||||
}
|
||||
|
||||
if (options.maxPlayers !== undefined) {
|
||||
rooms = rooms.filter(room => room.getAllPlayers().length <= options.maxPlayers!);
|
||||
rooms = rooms.filter((room) => room.getAllPlayers().length <= options.maxPlayers!);
|
||||
}
|
||||
|
||||
if (options.notFull) {
|
||||
rooms = rooms.filter(room => !room.isFull());
|
||||
rooms = rooms.filter((room) => !room.isFull());
|
||||
}
|
||||
|
||||
if (options.publicOnly) {
|
||||
rooms = rooms.filter(room => room.getConfig().isPublic);
|
||||
rooms = rooms.filter((room) => room.getConfig().isPublic);
|
||||
}
|
||||
|
||||
// 分页
|
||||
@@ -369,7 +369,7 @@ export class RoomManager extends EventEmitter {
|
||||
* 获取房间信息列表
|
||||
*/
|
||||
getRoomInfoList(options: RoomQueryOptions = {}): IRoomInfo[] {
|
||||
return this.queryRooms(options).map(room => room.getRoomInfo());
|
||||
return this.queryRooms(options).map((room) => room.getRoomInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,7 +455,7 @@ export class RoomManager extends EventEmitter {
|
||||
private generateRoomId(): string {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
let result = '';
|
||||
|
||||
|
||||
for (let i = 0; i < this.config.roomIdLength; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
@@ -541,7 +541,7 @@ export class RoomManager extends EventEmitter {
|
||||
}
|
||||
|
||||
// 清理长时间无活动的已结束房间
|
||||
if (stats.state === RoomState.Finished &&
|
||||
if (stats.state === RoomState.Finished &&
|
||||
now - stats.createTime > 3600000) { // 1小时
|
||||
roomsToDestroy.push(roomId);
|
||||
continue;
|
||||
@@ -564,16 +564,16 @@ export class RoomManager extends EventEmitter {
|
||||
getStatusSummary() {
|
||||
const stats = this.getStats();
|
||||
const rooms = Array.from(this.rooms.values());
|
||||
|
||||
|
||||
return {
|
||||
stats,
|
||||
roomCount: rooms.length,
|
||||
playerCount: this.playerRoomMap.size,
|
||||
publicRooms: rooms.filter(r => r.getConfig().isPublic).length,
|
||||
privateRooms: rooms.filter(r => !r.getConfig().isPublic).length,
|
||||
fullRooms: rooms.filter(r => r.isFull()).length,
|
||||
emptyRooms: rooms.filter(r => r.isEmpty()).length,
|
||||
averagePlayersPerRoom: rooms.length > 0 ?
|
||||
publicRooms: rooms.filter((r) => r.getConfig().isPublic).length,
|
||||
privateRooms: rooms.filter((r) => !r.getConfig().isPublic).length,
|
||||
fullRooms: rooms.filter((r) => r.isFull()).length,
|
||||
emptyRooms: rooms.filter((r) => r.isEmpty()).length,
|
||||
averagePlayersPerRoom: rooms.length > 0 ?
|
||||
rooms.reduce((sum, r) => sum + r.getAllPlayers().length, 0) / rooms.length : 0
|
||||
};
|
||||
}
|
||||
@@ -595,13 +595,13 @@ export class RoomManager extends EventEmitter {
|
||||
*/
|
||||
destroyRoomsBatch(roomIds: string[], reason: string = '批量清理'): number {
|
||||
let destroyedCount = 0;
|
||||
|
||||
|
||||
for (const roomId of roomIds) {
|
||||
if (this.destroyRoom(roomId, reason)) {
|
||||
destroyedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return destroyedCount;
|
||||
}
|
||||
|
||||
@@ -618,4 +618,4 @@ export class RoomManager extends EventEmitter {
|
||||
getPlayerRoomId(sessionId: string): string | undefined {
|
||||
return this.playerRoomMap.get(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,27 +57,27 @@ export interface CustomScopeRule {
|
||||
export class NetworkScopeManager extends EventEmitter {
|
||||
private logger = createLogger('NetworkScopeManager');
|
||||
private config: ScopeConfig;
|
||||
|
||||
|
||||
/** 客户端位置信息 */
|
||||
private clientPositions = new Map<string, ClientPosition>();
|
||||
|
||||
|
||||
/** 客户端可视范围 */
|
||||
private clientRanges = new Map<string, number>();
|
||||
|
||||
|
||||
/** 房间映射 */
|
||||
private clientRooms = new Map<string, string>();
|
||||
private roomClients = new Map<string, Set<string>>();
|
||||
|
||||
|
||||
/** 自定义作用域规则 */
|
||||
private customRules: CustomScopeRule[] = [];
|
||||
|
||||
|
||||
/** 作用域缓存 */
|
||||
private scopeCache = new Map<string, { result: ScopeQueryResult; timestamp: number }>();
|
||||
private cacheTimeout = 100; // 100ms缓存
|
||||
|
||||
constructor(config: Partial<ScopeConfig> = {}) {
|
||||
super();
|
||||
|
||||
|
||||
this.config = {
|
||||
defaultRange: 100,
|
||||
maxRange: 500,
|
||||
@@ -93,11 +93,11 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
*/
|
||||
public addClient(clientId: string, position?: { x: number; y: number; z: number }): void {
|
||||
this.clientRanges.set(clientId, this.config.defaultRange);
|
||||
|
||||
|
||||
if (position) {
|
||||
this.updateClientPosition(clientId, position.x, position.y, position.z);
|
||||
}
|
||||
|
||||
|
||||
this.logger.debug(`客户端 ${clientId} 已添加到作用域管理器`);
|
||||
}
|
||||
|
||||
@@ -107,16 +107,16 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
public removeClient(clientId: string): void {
|
||||
this.clientPositions.delete(clientId);
|
||||
this.clientRanges.delete(clientId);
|
||||
|
||||
|
||||
// 从房间中移除
|
||||
const roomId = this.clientRooms.get(clientId);
|
||||
if (roomId) {
|
||||
this.leaveRoom(clientId, roomId);
|
||||
}
|
||||
|
||||
|
||||
// 清理缓存
|
||||
this.clearClientCache(clientId);
|
||||
|
||||
|
||||
this.logger.debug(`客户端 ${clientId} 已从作用域管理器移除`);
|
||||
}
|
||||
|
||||
@@ -131,12 +131,12 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
z,
|
||||
lastUpdate: Date.now()
|
||||
};
|
||||
|
||||
|
||||
this.clientPositions.set(clientId, clientPosition);
|
||||
|
||||
|
||||
// 清理相关缓存
|
||||
this.clearClientCache(clientId);
|
||||
|
||||
|
||||
this.emit('positionUpdated', clientId, clientPosition);
|
||||
}
|
||||
|
||||
@@ -146,10 +146,10 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
public setClientRange(clientId: string, range: number): void {
|
||||
const clampedRange = Math.min(range, this.config.maxRange);
|
||||
this.clientRanges.set(clientId, clampedRange);
|
||||
|
||||
|
||||
// 清理相关缓存
|
||||
this.clearClientCache(clientId);
|
||||
|
||||
|
||||
this.logger.debug(`客户端 ${clientId} 可视范围设置为: ${clampedRange}`);
|
||||
}
|
||||
|
||||
@@ -162,15 +162,15 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
if (oldRoom) {
|
||||
this.leaveRoom(clientId, oldRoom);
|
||||
}
|
||||
|
||||
|
||||
// 加入新房间
|
||||
this.clientRooms.set(clientId, roomId);
|
||||
|
||||
|
||||
if (!this.roomClients.has(roomId)) {
|
||||
this.roomClients.set(roomId, new Set());
|
||||
}
|
||||
this.roomClients.get(roomId)!.add(clientId);
|
||||
|
||||
|
||||
this.logger.debug(`客户端 ${clientId} 已加入房间 ${roomId}`);
|
||||
this.emit('clientJoinedRoom', clientId, roomId);
|
||||
}
|
||||
@@ -180,17 +180,17 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
*/
|
||||
public leaveRoom(clientId: string, roomId: string): void {
|
||||
this.clientRooms.delete(clientId);
|
||||
|
||||
|
||||
const roomClientSet = this.roomClients.get(roomId);
|
||||
if (roomClientSet) {
|
||||
roomClientSet.delete(clientId);
|
||||
|
||||
|
||||
// 如果房间为空,删除房间
|
||||
if (roomClientSet.size === 0) {
|
||||
this.roomClients.delete(roomId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.logger.debug(`客户端 ${clientId} 已离开房间 ${roomId}`);
|
||||
this.emit('clientLeftRoom', clientId, roomId);
|
||||
}
|
||||
@@ -201,7 +201,7 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
public addCustomRule(rule: CustomScopeRule): void {
|
||||
this.customRules.push(rule);
|
||||
this.customRules.sort((a, b) => b.priority - a.priority);
|
||||
|
||||
|
||||
this.logger.debug(`已添加自定义作用域规则: ${rule.name}`);
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
* 移除自定义作用域规则
|
||||
*/
|
||||
public removeCustomRule(ruleName: string): boolean {
|
||||
const index = this.customRules.findIndex(rule => rule.name === ruleName);
|
||||
const index = this.customRules.findIndex((rule) => rule.name === ruleName);
|
||||
if (index >= 0) {
|
||||
this.customRules.splice(index, 1);
|
||||
this.logger.debug(`已移除自定义作用域规则: ${ruleName}`);
|
||||
@@ -229,14 +229,14 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 检查网络作用域
|
||||
for (const [prop, scope] of Object.entries(batch.scopes)) {
|
||||
if (!this.checkPropertyScope(scope, batch, clientId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -250,26 +250,26 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
): ScopeQueryResult {
|
||||
const cacheKey = `${position.x},${position.y},${position.z},${range},${excludeClientId || ''}`;
|
||||
const cached = this.scopeCache.get(cacheKey);
|
||||
|
||||
|
||||
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
|
||||
return cached.result;
|
||||
}
|
||||
|
||||
|
||||
const clientsInRange: string[] = [];
|
||||
const distances = new Map<string, number>();
|
||||
const lodLevels = new Map<string, number>();
|
||||
|
||||
|
||||
for (const [clientId, clientPosition] of this.clientPositions) {
|
||||
if (excludeClientId && clientId === excludeClientId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
const distance = this.calculateDistance(position, clientPosition);
|
||||
|
||||
|
||||
if (distance <= range) {
|
||||
clientsInRange.push(clientId);
|
||||
distances.set(clientId, distance);
|
||||
|
||||
|
||||
// 计算LOD级别
|
||||
if (this.config.enableLOD) {
|
||||
const lodLevel = this.calculateLODLevel(distance);
|
||||
@@ -277,19 +277,19 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const result: ScopeQueryResult = {
|
||||
clientsInRange,
|
||||
distances,
|
||||
lodLevels
|
||||
};
|
||||
|
||||
|
||||
// 缓存结果
|
||||
this.scopeCache.set(cacheKey, {
|
||||
result,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
roomCount: number;
|
||||
cacheSize: number;
|
||||
customRuleCount: number;
|
||||
} {
|
||||
} {
|
||||
return {
|
||||
clientCount: this.clientPositions.size,
|
||||
roomCount: this.roomClients.size,
|
||||
@@ -378,22 +378,22 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
switch (scope) {
|
||||
case NetworkScope.Global:
|
||||
return true;
|
||||
|
||||
|
||||
case NetworkScope.Room:
|
||||
const clientRoom = this.clientRooms.get(clientId);
|
||||
// 这里需要知道batch来源的实体所在房间,简化实现
|
||||
return true;
|
||||
|
||||
|
||||
case NetworkScope.Owner:
|
||||
return batch.instanceId === clientId;
|
||||
|
||||
|
||||
case NetworkScope.Nearby:
|
||||
return this.isClientNearby(batch, clientId);
|
||||
|
||||
|
||||
case NetworkScope.Custom:
|
||||
// 由自定义规则处理
|
||||
return true;
|
||||
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -407,9 +407,9 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
if (!clientPosition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const clientRange = this.clientRanges.get(clientId) || this.config.defaultRange;
|
||||
|
||||
|
||||
// 这里需要知道batch来源实体的位置,简化实现
|
||||
// 实际项目中应该从实体的Transform组件获取位置
|
||||
return true;
|
||||
@@ -445,15 +445,15 @@ export class NetworkScopeManager extends EventEmitter {
|
||||
*/
|
||||
private clearClientCache(clientId: string): void {
|
||||
const keysToDelete: string[] = [];
|
||||
|
||||
|
||||
for (const key of this.scopeCache.keys()) {
|
||||
if (key.includes(clientId)) {
|
||||
keysToDelete.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (const key of keysToDelete) {
|
||||
this.scopeCache.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,18 +74,18 @@ interface SchedulerStats {
|
||||
export class SyncScheduler extends EventEmitter {
|
||||
private logger = createLogger('SyncScheduler');
|
||||
private config: SyncSchedulerConfig;
|
||||
|
||||
|
||||
/** 任务队列 */
|
||||
private taskQueue: ScheduledTask[] = [];
|
||||
private taskIdCounter = 0;
|
||||
|
||||
|
||||
/** 客户端状态 */
|
||||
private clientStates = new Map<string, ClientScheduleState>();
|
||||
|
||||
|
||||
/** 调度定时器 */
|
||||
private scheduleTimer: any = null;
|
||||
private adaptiveTimer: any = null;
|
||||
|
||||
|
||||
/** 统计信息 */
|
||||
private stats: SchedulerStats = {
|
||||
totalTasks: 0,
|
||||
@@ -96,14 +96,14 @@ export class SyncScheduler extends EventEmitter {
|
||||
queueSizes: {},
|
||||
adaptiveRates: {}
|
||||
};
|
||||
|
||||
|
||||
/** 自适应调整历史 */
|
||||
private latencyHistory = new Map<string, number[]>();
|
||||
private bandwidthHistory = new Map<string, number[]>();
|
||||
|
||||
constructor(config: Partial<SyncSchedulerConfig> = {}) {
|
||||
super();
|
||||
|
||||
|
||||
this.config = {
|
||||
targetFPS: 60,
|
||||
maxLatency: 100,
|
||||
@@ -117,9 +117,9 @@ export class SyncScheduler extends EventEmitter {
|
||||
enableAdaptive: true,
|
||||
...config
|
||||
};
|
||||
|
||||
|
||||
this.startScheduler();
|
||||
|
||||
|
||||
if (this.config.enableAdaptive) {
|
||||
this.startAdaptiveAdjustment();
|
||||
}
|
||||
@@ -141,11 +141,11 @@ export class SyncScheduler extends EventEmitter {
|
||||
lastSendTime: 0,
|
||||
adaptiveRate: 1000 / this.config.targetFPS // 初始发送间隔
|
||||
};
|
||||
|
||||
|
||||
this.clientStates.set(clientId, clientState);
|
||||
this.latencyHistory.set(clientId, []);
|
||||
this.bandwidthHistory.set(clientId, []);
|
||||
|
||||
|
||||
this.logger.debug(`客户端 ${clientId} 已添加到调度器`);
|
||||
}
|
||||
|
||||
@@ -156,10 +156,10 @@ export class SyncScheduler extends EventEmitter {
|
||||
this.clientStates.delete(clientId);
|
||||
this.latencyHistory.delete(clientId);
|
||||
this.bandwidthHistory.delete(clientId);
|
||||
|
||||
|
||||
// 移除该客户端的所有任务
|
||||
this.taskQueue = this.taskQueue.filter(task => task.clientId !== clientId);
|
||||
|
||||
this.taskQueue = this.taskQueue.filter((task) => task.clientId !== clientId);
|
||||
|
||||
this.logger.debug(`客户端 ${clientId} 已从调度器移除`);
|
||||
}
|
||||
|
||||
@@ -172,10 +172,10 @@ export class SyncScheduler extends EventEmitter {
|
||||
this.logger.warn(`客户端 ${clientId} 不存在,无法调度任务`);
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
const taskId = `task_${++this.taskIdCounter}`;
|
||||
const now = Date.now();
|
||||
|
||||
|
||||
const task: ScheduledTask = {
|
||||
id: taskId,
|
||||
batch,
|
||||
@@ -186,13 +186,13 @@ export class SyncScheduler extends EventEmitter {
|
||||
retryCount: 0,
|
||||
createdAt: now
|
||||
};
|
||||
|
||||
|
||||
this.taskQueue.push(task);
|
||||
this.stats.totalTasks++;
|
||||
|
||||
|
||||
// 按优先级和截止时间排序
|
||||
this.sortTaskQueue();
|
||||
|
||||
|
||||
return taskId;
|
||||
}
|
||||
|
||||
@@ -203,16 +203,16 @@ export class SyncScheduler extends EventEmitter {
|
||||
const clientState = this.clientStates.get(clientId);
|
||||
if (clientState) {
|
||||
clientState.latency = latency;
|
||||
|
||||
|
||||
// 记录延迟历史
|
||||
const history = this.latencyHistory.get(clientId) || [];
|
||||
history.push(latency);
|
||||
|
||||
|
||||
// 保持最近50个记录
|
||||
if (history.length > 50) {
|
||||
history.shift();
|
||||
}
|
||||
|
||||
|
||||
this.latencyHistory.set(clientId, history);
|
||||
}
|
||||
}
|
||||
@@ -234,11 +234,11 @@ export class SyncScheduler extends EventEmitter {
|
||||
public getStats(): SchedulerStats {
|
||||
// 更新队列大小统计
|
||||
for (const [clientId, clientState] of this.clientStates) {
|
||||
const clientTasks = this.taskQueue.filter(task => task.clientId === clientId);
|
||||
const clientTasks = this.taskQueue.filter((task) => task.clientId === clientId);
|
||||
this.stats.queueSizes[clientId] = clientTasks.length;
|
||||
this.stats.adaptiveRates[clientId] = clientState.adaptiveRate;
|
||||
}
|
||||
|
||||
|
||||
return { ...this.stats };
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ export class SyncScheduler extends EventEmitter {
|
||||
*/
|
||||
public updateConfig(newConfig: Partial<SyncSchedulerConfig>): void {
|
||||
Object.assign(this.config, newConfig);
|
||||
|
||||
|
||||
if (newConfig.enableAdaptive !== undefined) {
|
||||
if (newConfig.enableAdaptive) {
|
||||
this.startAdaptiveAdjustment();
|
||||
@@ -287,7 +287,7 @@ export class SyncScheduler extends EventEmitter {
|
||||
if (this.scheduleTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const interval = 1000 / this.config.targetFPS;
|
||||
this.scheduleTimer = setInterval(() => {
|
||||
this.processTasks();
|
||||
@@ -311,7 +311,7 @@ export class SyncScheduler extends EventEmitter {
|
||||
if (this.adaptiveTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.adaptiveTimer = setInterval(() => {
|
||||
this.performAdaptiveAdjustment();
|
||||
}, this.config.adaptiveInterval);
|
||||
@@ -333,7 +333,7 @@ export class SyncScheduler extends EventEmitter {
|
||||
private processTasks(): void {
|
||||
const now = Date.now();
|
||||
const processedTasks: string[] = [];
|
||||
|
||||
|
||||
for (const task of this.taskQueue) {
|
||||
const clientState = this.clientStates.get(task.clientId);
|
||||
if (!clientState) {
|
||||
@@ -341,7 +341,7 @@ export class SyncScheduler extends EventEmitter {
|
||||
this.stats.droppedTasks++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 检查截止时间
|
||||
if (now > task.deadline) {
|
||||
processedTasks.push(task.id);
|
||||
@@ -349,25 +349,25 @@ export class SyncScheduler extends EventEmitter {
|
||||
this.logger.warn(`任务 ${task.id} 超时被丢弃`);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 检查发送间隔
|
||||
if (now - clientState.lastSendTime < clientState.adaptiveRate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 检查带宽限制
|
||||
if (!this.checkBandwidthLimit(clientState, task.size)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 发送任务
|
||||
this.sendTask(task, clientState);
|
||||
processedTasks.push(task.id);
|
||||
this.stats.completedTasks++;
|
||||
}
|
||||
|
||||
|
||||
// 移除已处理的任务
|
||||
this.taskQueue = this.taskQueue.filter(task => !processedTasks.includes(task.id));
|
||||
this.taskQueue = this.taskQueue.filter((task) => !processedTasks.includes(task.id));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,24 +375,24 @@ export class SyncScheduler extends EventEmitter {
|
||||
*/
|
||||
private sendTask(task: ScheduledTask, clientState: ClientScheduleState): void {
|
||||
const now = Date.now();
|
||||
|
||||
|
||||
// 更新客户端状态
|
||||
clientState.lastSendTime = now;
|
||||
clientState.bandwidth.used += task.size;
|
||||
|
||||
|
||||
// 记录带宽历史
|
||||
const bandwidthHistory = this.bandwidthHistory.get(task.clientId) || [];
|
||||
bandwidthHistory.push(task.size);
|
||||
|
||||
|
||||
if (bandwidthHistory.length > 50) {
|
||||
bandwidthHistory.shift();
|
||||
}
|
||||
|
||||
|
||||
this.bandwidthHistory.set(task.clientId, bandwidthHistory);
|
||||
|
||||
|
||||
// 发出事件
|
||||
this.emit('taskReady', task.batch, task.clientId);
|
||||
|
||||
|
||||
this.logger.debug(`任务 ${task.id} 已发送给客户端 ${task.clientId}`);
|
||||
}
|
||||
|
||||
@@ -401,13 +401,13 @@ export class SyncScheduler extends EventEmitter {
|
||||
*/
|
||||
private checkBandwidthLimit(clientState: ClientScheduleState, taskSize: number): boolean {
|
||||
const now = Date.now();
|
||||
|
||||
|
||||
// 重置带宽计数器
|
||||
if (now >= clientState.bandwidth.resetTime) {
|
||||
clientState.bandwidth.used = 0;
|
||||
clientState.bandwidth.resetTime = now + 1000;
|
||||
}
|
||||
|
||||
|
||||
return clientState.bandwidth.used + taskSize <= clientState.bandwidth.limit;
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@ export class SyncScheduler extends EventEmitter {
|
||||
if (priorityDiff !== 0) {
|
||||
return priorityDiff;
|
||||
}
|
||||
|
||||
|
||||
// 然后按截止时间排序
|
||||
return a.deadline - b.deadline;
|
||||
});
|
||||
@@ -450,21 +450,21 @@ export class SyncScheduler extends EventEmitter {
|
||||
private adjustClientRate(clientId: string, clientState: ClientScheduleState): void {
|
||||
const latencyHistory = this.latencyHistory.get(clientId) || [];
|
||||
const bandwidthHistory = this.bandwidthHistory.get(clientId) || [];
|
||||
|
||||
|
||||
if (latencyHistory.length < 5) {
|
||||
return; // 数据不足,不进行调整
|
||||
}
|
||||
|
||||
|
||||
// 计算平均延迟
|
||||
const avgLatency = latencyHistory.reduce((sum, lat) => sum + lat, 0) / latencyHistory.length;
|
||||
|
||||
|
||||
// 计算带宽利用率
|
||||
const totalBandwidth = bandwidthHistory.reduce((sum, size) => sum + size, 0);
|
||||
const bandwidthUtilization = totalBandwidth / clientState.bandwidth.limit;
|
||||
|
||||
|
||||
// 根据延迟和带宽利用率调整发送频率
|
||||
let adjustment = 1;
|
||||
|
||||
|
||||
if (avgLatency > this.config.maxLatency) {
|
||||
// 延迟过高,降低发送频率
|
||||
adjustment = 1.2;
|
||||
@@ -472,7 +472,7 @@ export class SyncScheduler extends EventEmitter {
|
||||
// 延迟较低,可以提高发送频率
|
||||
adjustment = 0.9;
|
||||
}
|
||||
|
||||
|
||||
if (bandwidthUtilization > 0.9) {
|
||||
// 带宽利用率过高,降低发送频率
|
||||
adjustment *= 1.1;
|
||||
@@ -480,22 +480,22 @@ export class SyncScheduler extends EventEmitter {
|
||||
// 带宽利用率较低,可以提高发送频率
|
||||
adjustment *= 0.95;
|
||||
}
|
||||
|
||||
|
||||
// 应用调整
|
||||
clientState.adaptiveRate = Math.max(
|
||||
clientState.adaptiveRate * adjustment,
|
||||
1000 / (this.config.targetFPS * 2) // 最小间隔
|
||||
);
|
||||
|
||||
|
||||
clientState.adaptiveRate = Math.min(
|
||||
clientState.adaptiveRate,
|
||||
1000 // 最大间隔1秒
|
||||
);
|
||||
|
||||
|
||||
this.logger.debug(
|
||||
`客户端 ${clientId} 自适应调整: 延迟=${avgLatency.toFixed(1)}ms, ` +
|
||||
`带宽利用率=${(bandwidthUtilization * 100).toFixed(1)}%, ` +
|
||||
`新间隔=${clientState.adaptiveRate.toFixed(1)}ms`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
*/
|
||||
|
||||
export * from './NetworkScopeManager';
|
||||
export * from './SyncScheduler';
|
||||
export * from './SyncScheduler';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { EntitySystem, createLogger } from '@esengine/ecs-framework';
|
||||
import {
|
||||
SyncVarManager,
|
||||
SyncBatch,
|
||||
import {
|
||||
SyncVarManager,
|
||||
SyncBatch,
|
||||
SyncVarSerializer,
|
||||
NetworkScope,
|
||||
SyncMode,
|
||||
AuthorityType
|
||||
AuthorityType
|
||||
} from '@esengine/network-shared';
|
||||
import { NetworkServer } from '../core/NetworkServer';
|
||||
import { ConnectionManager } from '../core/ConnectionManager';
|
||||
@@ -74,13 +74,13 @@ export class SyncVarSystem extends EntitySystem {
|
||||
private serializer: SyncVarSerializer;
|
||||
private networkServer?: NetworkServer;
|
||||
private connectionManager?: ConnectionManager;
|
||||
|
||||
|
||||
/** 客户端同步状态 */
|
||||
private clientStates = new Map<string, ClientSyncState>();
|
||||
|
||||
|
||||
/** 待发送的批次队列 */
|
||||
private pendingBatches: SyncBatch[] = [];
|
||||
|
||||
|
||||
/** 同步统计 */
|
||||
private stats: SyncSystemStats = {
|
||||
totalSyncs: 0,
|
||||
@@ -91,16 +91,16 @@ export class SyncVarSystem extends EntitySystem {
|
||||
droppedSyncs: 0,
|
||||
scopeFiltered: 0
|
||||
};
|
||||
|
||||
|
||||
/** 最后统计重置时间 */
|
||||
private lastStatsReset = Date.now();
|
||||
|
||||
|
||||
/** 同步定时器 */
|
||||
private syncTimer: any = null;
|
||||
|
||||
constructor(config: Partial<SyncVarSystemConfig> = {}) {
|
||||
super();
|
||||
|
||||
|
||||
this.config = {
|
||||
syncRate: 60, // 60ms = ~16fps
|
||||
maxBatchSize: 50,
|
||||
@@ -112,7 +112,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
batchTimeout: 16,
|
||||
...config
|
||||
};
|
||||
|
||||
|
||||
this.syncVarManager = SyncVarManager.getInstance();
|
||||
this.serializer = new SyncVarSerializer({
|
||||
enableCompression: true,
|
||||
@@ -120,7 +120,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
enableBatching: this.config.enableBatching,
|
||||
batchTimeout: this.config.batchTimeout
|
||||
});
|
||||
|
||||
|
||||
this.setupSyncVarManager();
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
*/
|
||||
public override initialize(): void {
|
||||
super.initialize();
|
||||
|
||||
|
||||
this.logger.info('SyncVar系统初始化');
|
||||
this.startSyncTimer();
|
||||
}
|
||||
@@ -155,12 +155,12 @@ export class SyncVarSystem extends EntitySystem {
|
||||
*/
|
||||
public setConnectionManager(manager: ConnectionManager): void {
|
||||
this.connectionManager = manager;
|
||||
|
||||
|
||||
// 监听客户端连接事件
|
||||
manager.on('clientConnected', (clientId: string) => {
|
||||
this.addClient(clientId);
|
||||
});
|
||||
|
||||
|
||||
manager.on('clientDisconnected', (clientId: string) => {
|
||||
this.removeClient(clientId);
|
||||
});
|
||||
@@ -229,7 +229,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
*/
|
||||
public updateConfig(newConfig: Partial<SyncVarSystemConfig>): void {
|
||||
Object.assign(this.config, newConfig);
|
||||
|
||||
|
||||
if (newConfig.syncRate !== undefined) {
|
||||
this.restartSyncTimer();
|
||||
}
|
||||
@@ -256,7 +256,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
this.syncVarManager.on('syncBatchReady', (batch: SyncBatch) => {
|
||||
this.enqueueBatch(batch);
|
||||
});
|
||||
|
||||
|
||||
this.syncVarManager.on('syncError', (error: Error) => {
|
||||
this.logger.error('SyncVar同步错误:', error);
|
||||
});
|
||||
@@ -279,10 +279,10 @@ export class SyncVarSystem extends EntitySystem {
|
||||
range: 100
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.clientStates.set(clientId, clientState);
|
||||
this.stats.clientCount = this.clientStates.size;
|
||||
|
||||
|
||||
this.logger.info(`客户端 ${clientId} 已添加到同步系统`);
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
private removeClient(clientId: string): void {
|
||||
this.clientStates.delete(clientId);
|
||||
this.stats.clientCount = this.clientStates.size;
|
||||
|
||||
|
||||
this.logger.info(`客户端 ${clientId} 已从同步系统移除`);
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
*/
|
||||
private enqueueBatch(batch: SyncBatch): void {
|
||||
this.pendingBatches.push(batch);
|
||||
|
||||
|
||||
// 如果队列过长,移除最旧的批次
|
||||
if (this.pendingBatches.length > this.config.maxBatchSize * 2) {
|
||||
this.pendingBatches.shift();
|
||||
@@ -316,10 +316,10 @@ export class SyncVarSystem extends EntitySystem {
|
||||
if (this.pendingBatches.length === 0 || this.clientStates.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const now = Date.now();
|
||||
const batchesToProcess = this.pendingBatches.splice(0, this.config.maxBatchSize);
|
||||
|
||||
|
||||
for (const batch of batchesToProcess) {
|
||||
this.distributeBatchToClients(batch);
|
||||
}
|
||||
@@ -335,14 +335,14 @@ export class SyncVarSystem extends EntitySystem {
|
||||
this.stats.scopeFiltered++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 检查带宽限制
|
||||
if (this.config.enableBandwidthLimit && !this.checkBandwidthLimit(clientId, batch)) {
|
||||
// 将批次添加到待发送队列
|
||||
clientState.pendingBatches.push(batch);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
this.sendBatchToClient(clientId, batch);
|
||||
}
|
||||
}
|
||||
@@ -355,12 +355,12 @@ export class SyncVarSystem extends EntitySystem {
|
||||
if (clientState.scope.customFilter) {
|
||||
return clientState.scope.customFilter(batch);
|
||||
}
|
||||
|
||||
|
||||
// 检查权限和作用域
|
||||
for (const [prop, scope] of Object.entries(batch.scopes)) {
|
||||
const authority = batch.authorities[prop];
|
||||
const syncMode = batch.syncModes[prop];
|
||||
|
||||
|
||||
// 检查权限
|
||||
if (authority === AuthorityType.Client) {
|
||||
// 只有拥有权限的客户端才能看到
|
||||
@@ -368,7 +368,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 检查同步模式
|
||||
switch (syncMode) {
|
||||
case SyncMode.Owner:
|
||||
@@ -376,20 +376,20 @@ export class SyncVarSystem extends EntitySystem {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case SyncMode.Others:
|
||||
if (batch.instanceId === clientState.clientId) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case SyncMode.Nearby:
|
||||
if (!this.isNearby(batch, clientState)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// 检查网络作用域
|
||||
switch (scope) {
|
||||
case NetworkScope.Owner:
|
||||
@@ -397,7 +397,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case NetworkScope.Nearby:
|
||||
if (!this.isNearby(batch, clientState)) {
|
||||
continue;
|
||||
@@ -405,7 +405,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -424,23 +424,23 @@ export class SyncVarSystem extends EntitySystem {
|
||||
if (!this.config.enableBandwidthLimit) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const clientState = this.clientStates.get(clientId);
|
||||
if (!clientState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
|
||||
// 重置带宽计数器
|
||||
if (now >= clientState.bandwidth.resetTime) {
|
||||
clientState.bandwidth.used = 0;
|
||||
clientState.bandwidth.resetTime = now + 1000;
|
||||
}
|
||||
|
||||
|
||||
// 估算批次大小
|
||||
const estimatedSize = this.estimateBatchSize(batch);
|
||||
|
||||
|
||||
return clientState.bandwidth.used + estimatedSize <= clientState.bandwidth.limit;
|
||||
}
|
||||
|
||||
@@ -460,11 +460,11 @@ export class SyncVarSystem extends EntitySystem {
|
||||
if (!this.networkServer || !this.connectionManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const message = this.serializer.createSyncMessage(batch, 'server');
|
||||
this.networkServer.sendToClient(clientId, message);
|
||||
|
||||
|
||||
// 更新统计
|
||||
const clientState = this.clientStates.get(clientId);
|
||||
if (clientState) {
|
||||
@@ -474,7 +474,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
this.stats.totalBytes += estimatedSize;
|
||||
this.stats.totalSyncs++;
|
||||
}
|
||||
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error(`向客户端 ${clientId} 发送同步数据失败:`, error);
|
||||
}
|
||||
@@ -485,12 +485,12 @@ export class SyncVarSystem extends EntitySystem {
|
||||
*/
|
||||
private updateClientStates(): void {
|
||||
const now = Date.now();
|
||||
|
||||
|
||||
for (const [clientId, clientState] of this.clientStates) {
|
||||
// 处理待发送的批次
|
||||
if (clientState.pendingBatches.length > 0 &&
|
||||
if (clientState.pendingBatches.length > 0 &&
|
||||
this.checkBandwidthLimit(clientId, clientState.pendingBatches[0])) {
|
||||
|
||||
|
||||
const batch = clientState.pendingBatches.shift()!;
|
||||
this.sendBatchToClient(clientId, batch);
|
||||
}
|
||||
@@ -503,7 +503,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
private updateStats(): void {
|
||||
const now = Date.now();
|
||||
const deltaTime = now - this.lastStatsReset;
|
||||
|
||||
|
||||
if (deltaTime >= 1000) { // 每秒更新一次
|
||||
this.stats.syncsPerSecond = this.stats.totalSyncs / (deltaTime / 1000);
|
||||
this.lastStatsReset = now;
|
||||
@@ -517,7 +517,7 @@ export class SyncVarSystem extends EntitySystem {
|
||||
if (this.syncTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.syncTimer = setInterval(() => {
|
||||
this.processScheduledSyncs();
|
||||
}, this.config.syncRate);
|
||||
@@ -540,4 +540,4 @@ export class SyncVarSystem extends EntitySystem {
|
||||
this.stopSyncTimer();
|
||||
this.startSyncTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
* 服务端系统导出
|
||||
*/
|
||||
|
||||
export * from './SyncVarSystem';
|
||||
export * from './SyncVarSystem';
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
*/
|
||||
import WebSocket, { WebSocketServer } from 'ws';
|
||||
import { createLogger, Core } from '@esengine/ecs-framework';
|
||||
import {
|
||||
ITransport,
|
||||
ITransportClientInfo,
|
||||
import {
|
||||
ITransport,
|
||||
ITransportClientInfo,
|
||||
ITransportConfig,
|
||||
ConnectionState,
|
||||
EventEmitter
|
||||
@@ -27,17 +27,17 @@ export class WebSocketTransport extends EventEmitter implements ITransport {
|
||||
* 连接事件处理器
|
||||
*/
|
||||
private connectHandlers: ((clientInfo: ITransportClientInfo) => void)[] = [];
|
||||
|
||||
|
||||
/**
|
||||
* 断开连接事件处理器
|
||||
*/
|
||||
private disconnectHandlers: ((clientId: string, reason?: string) => void)[] = [];
|
||||
|
||||
|
||||
/**
|
||||
* 消息接收事件处理器
|
||||
*/
|
||||
private messageHandlers: ((clientId: string, data: ArrayBuffer | string) => void)[] = [];
|
||||
|
||||
|
||||
/**
|
||||
* 错误事件处理器
|
||||
*/
|
||||
@@ -141,7 +141,7 @@ export class WebSocketTransport extends EventEmitter implements ITransport {
|
||||
*/
|
||||
broadcast(data: ArrayBuffer | string, exclude?: string[]): void {
|
||||
const excludeSet = new Set(exclude || []);
|
||||
|
||||
|
||||
for (const [clientId, ws] of this.clients) {
|
||||
if (excludeSet.has(clientId) || ws.readyState !== WebSocket.OPEN) {
|
||||
continue;
|
||||
@@ -272,9 +272,9 @@ export class WebSocketTransport extends EventEmitter implements ITransport {
|
||||
this.setupClientEvents(ws, clientId);
|
||||
|
||||
this.logger.info(`新客户端连接: ${clientId} from ${clientInfo.remoteAddress}`);
|
||||
|
||||
|
||||
// 触发连接事件
|
||||
this.connectHandlers.forEach(handler => {
|
||||
this.connectHandlers.forEach((handler) => {
|
||||
try {
|
||||
handler(clientInfo);
|
||||
} catch (error) {
|
||||
@@ -332,11 +332,11 @@ export class WebSocketTransport extends EventEmitter implements ITransport {
|
||||
this.logger.debug(`忽略非应用消息 (${clientId}): ${typeof data} ${data instanceof ArrayBuffer ? data.byteLength : data.toString().length} bytes`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const message = data instanceof ArrayBuffer ? data : new TextEncoder().encode(data.toString()).buffer;
|
||||
|
||||
|
||||
// 触发消息事件
|
||||
this.messageHandlers.forEach(handler => {
|
||||
this.messageHandlers.forEach((handler) => {
|
||||
try {
|
||||
handler(clientId, message);
|
||||
} catch (error) {
|
||||
@@ -356,23 +356,23 @@ export class WebSocketTransport extends EventEmitter implements ITransport {
|
||||
private isApplicationMessage(data: WebSocket.Data): boolean {
|
||||
try {
|
||||
// 转换为字符串进行检查
|
||||
const jsonString = data instanceof ArrayBuffer
|
||||
? new TextDecoder().decode(data)
|
||||
const jsonString = data instanceof ArrayBuffer
|
||||
? new TextDecoder().decode(data)
|
||||
: data.toString();
|
||||
|
||||
|
||||
// 基本长度检查 - 空消息或过短消息通常不是应用消息
|
||||
if (!jsonString || jsonString.length < 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 尝试解析JSON
|
||||
const parsed = JSON.parse(jsonString);
|
||||
|
||||
|
||||
// 检查是否有基本的消息结构
|
||||
return parsed &&
|
||||
typeof parsed === 'object' &&
|
||||
return parsed &&
|
||||
typeof parsed === 'object' &&
|
||||
(parsed.type || parsed.messageId || parsed.data);
|
||||
|
||||
|
||||
} catch (error) {
|
||||
// JSON解析失败,可能是握手数据或其他非JSON消息
|
||||
return false;
|
||||
@@ -390,7 +390,7 @@ export class WebSocketTransport extends EventEmitter implements ITransport {
|
||||
this.logger.info(`客户端断开连接: ${clientId}, 原因: ${reason || '未知'}`);
|
||||
|
||||
// 触发断开连接事件
|
||||
this.disconnectHandlers.forEach(handler => {
|
||||
this.disconnectHandlers.forEach((handler) => {
|
||||
try {
|
||||
handler(clientId, reason);
|
||||
} catch (error) {
|
||||
@@ -403,7 +403,7 @@ export class WebSocketTransport extends EventEmitter implements ITransport {
|
||||
* 处理错误
|
||||
*/
|
||||
private handleError(error: Error): void {
|
||||
this.errorHandlers.forEach(handler => {
|
||||
this.errorHandlers.forEach((handler) => {
|
||||
try {
|
||||
handler(error);
|
||||
} catch (handlerError) {
|
||||
@@ -439,4 +439,4 @@ export class WebSocketTransport extends EventEmitter implements ITransport {
|
||||
clients: this.getAllClients()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user