更新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,499 @@
/**
* 房间管理器
*
* 管理所有房间的创建、销毁、查找等操作
*/
import { EventEmitter } from 'events';
import { Room, RoomConfig, RoomState, PlayerData } from './Room';
import { ClientConnection } from '../core/ClientConnection';
import { NetworkValue } from '@esengine/ecs-framework-network-shared';
/**
* 房间管理器配置
*/
export interface RoomManagerConfig {
/** 最大房间数量 */
maxRooms?: number;
/** 默认房间过期时间(毫秒) */
defaultExpirationTime?: number;
/** 是否启用房间统计 */
enableStats?: boolean;
/** 房间清理间隔(毫秒) */
cleanupInterval?: number;
}
/**
* 房间查询选项
*/
export interface RoomQueryOptions {
/** 房间名称模糊搜索 */
namePattern?: string;
/** 房间状态过滤 */
state?: RoomState;
/** 是否私有房间 */
isPrivate?: boolean;
/** 最小空位数 */
minAvailableSlots?: number;
/** 最大空位数 */
maxAvailableSlots?: number;
/** 元数据过滤 */
metadata?: Record<string, NetworkValue>;
/** 限制结果数量 */
limit?: number;
/** 跳过条数 */
offset?: number;
}
/**
* 房间管理器统计信息
*/
export interface RoomManagerStats {
/** 总房间数 */
totalRooms: number;
/** 活跃房间数 */
activeRooms: number;
/** 总玩家数 */
totalPlayers: number;
/** 私有房间数 */
privateRooms: number;
/** 持久化房间数 */
persistentRooms: number;
/** 创建的房间总数 */
roomsCreated: number;
/** 关闭的房间总数 */
roomsClosed: number;
}
/**
* 房间管理器事件
*/
export interface RoomManagerEvents {
/** 房间创建 */
'room-created': (room: Room) => void;
/** 房间关闭 */
'room-closed': (roomId: string, reason: string) => void;
/** 玩家加入房间 */
'player-joined-room': (roomId: string, player: PlayerData) => void;
/** 玩家离开房间 */
'player-left-room': (roomId: string, clientId: string, reason?: string) => void;
/** 房间管理器错误 */
'error': (error: Error, roomId?: string) => void;
}
/**
* 房间管理器
*/
export class RoomManager extends EventEmitter {
private config: RoomManagerConfig;
private rooms = new Map<string, Room>();
private stats: RoomManagerStats;
private cleanupTimer: NodeJS.Timeout | null = null;
constructor(config: RoomManagerConfig = {}) {
super();
this.config = {
maxRooms: 1000,
defaultExpirationTime: 0, // 0 = 不过期
enableStats: true,
cleanupInterval: 60000, // 1分钟
...config
};
this.stats = {
totalRooms: 0,
activeRooms: 0,
totalPlayers: 0,
privateRooms: 0,
persistentRooms: 0,
roomsCreated: 0,
roomsClosed: 0
};
this.initialize();
}
/**
* 获取房间管理器配置
*/
getConfig(): Readonly<RoomManagerConfig> {
return this.config;
}
/**
* 获取房间管理器统计信息
*/
getStats(): RoomManagerStats {
this.updateStats();
return { ...this.stats };
}
/**
* 创建房间
*/
async createRoom(config: RoomConfig, creatorClient?: ClientConnection): Promise<Room> {
// 检查房间数量限制
if (this.config.maxRooms && this.rooms.size >= this.config.maxRooms) {
throw new Error('Maximum number of rooms reached');
}
// 检查房间ID是否已存在
if (this.rooms.has(config.id)) {
throw new Error(`Room with id "${config.id}" already exists`);
}
// 应用默认过期时间
const roomConfig: RoomConfig = {
expirationTime: this.config.defaultExpirationTime,
...config
};
const room = new Room(roomConfig);
// 设置房间事件监听
this.setupRoomEvents(room);
this.rooms.set(room.id, room);
this.stats.roomsCreated++;
console.log(`Room created: ${room.id} by ${creatorClient?.id || 'system'}`);
this.emit('room-created', room);
// 如果有创建者,自动加入房间
if (creatorClient) {
try {
await room.addPlayer(creatorClient);
} catch (error) {
console.error(`Failed to add creator to room ${room.id}:`, error);
}
}
return room;
}
/**
* 获取房间
*/
getRoom(roomId: string): Room | undefined {
return this.rooms.get(roomId);
}
/**
* 检查房间是否存在
*/
hasRoom(roomId: string): boolean {
return this.rooms.has(roomId);
}
/**
* 获取所有房间
*/
getAllRooms(): Room[] {
return Array.from(this.rooms.values());
}
/**
* 查询房间
*/
findRooms(options: RoomQueryOptions = {}): Room[] {
let rooms = Array.from(this.rooms.values());
// 状态过滤
if (options.state !== undefined) {
rooms = rooms.filter(room => room.currentState === options.state);
}
// 私有房间过滤
if (options.isPrivate !== undefined) {
rooms = rooms.filter(room => room.getConfig().isPrivate === options.isPrivate);
}
// 名称模糊搜索
if (options.namePattern) {
const pattern = options.namePattern.toLowerCase();
rooms = rooms.filter(room =>
room.getConfig().name.toLowerCase().includes(pattern)
);
}
// 空位数过滤
if (options.minAvailableSlots !== undefined) {
rooms = rooms.filter(room => {
const available = room.getConfig().maxPlayers - room.getPlayerCount();
return available >= options.minAvailableSlots!;
});
}
if (options.maxAvailableSlots !== undefined) {
rooms = rooms.filter(room => {
const available = room.getConfig().maxPlayers - room.getPlayerCount();
return available <= options.maxAvailableSlots!;
});
}
// 元数据过滤
if (options.metadata) {
rooms = rooms.filter(room => {
const roomMetadata = room.getConfig().metadata || {};
return Object.entries(options.metadata!).every(([key, value]) =>
roomMetadata[key] === value
);
});
}
// 排序(按创建时间,最新的在前)
rooms.sort((a, b) =>
b.getStats().createdAt.getTime() - a.getStats().createdAt.getTime()
);
// 分页
const offset = options.offset || 0;
const limit = options.limit || rooms.length;
return rooms.slice(offset, offset + limit);
}
/**
* 关闭房间
*/
async closeRoom(roomId: string, reason: string = 'manual'): Promise<boolean> {
const room = this.rooms.get(roomId);
if (!room) {
return false;
}
try {
await room.close(reason);
return true;
} catch (error) {
this.emit('error', error as Error, roomId);
return false;
}
}
/**
* 玩家加入房间
*/
async joinRoom(
roomId: string,
client: ClientConnection,
customData: Record<string, NetworkValue> = {}
): Promise<boolean> {
const room = this.rooms.get(roomId);
if (!room) {
throw new Error(`Room "${roomId}" not found`);
}
try {
return await room.addPlayer(client, customData);
} catch (error) {
this.emit('error', error as Error, roomId);
throw error;
}
}
/**
* 玩家离开房间
*/
async leaveRoom(roomId: string, clientId: string, reason?: string): Promise<boolean> {
const room = this.rooms.get(roomId);
if (!room) {
return false;
}
try {
return await room.removePlayer(clientId, reason);
} catch (error) {
this.emit('error', error as Error, roomId);
return false;
}
}
/**
* 玩家离开所有房间
*/
async leaveAllRooms(clientId: string, reason?: string): Promise<number> {
let leftCount = 0;
for (const room of this.rooms.values()) {
if (room.hasPlayer(clientId)) {
try {
await room.removePlayer(clientId, reason);
leftCount++;
} catch (error) {
console.error(`Error removing player ${clientId} from room ${room.id}:`, error);
}
}
}
return leftCount;
}
/**
* 获取玩家所在的房间
*/
getPlayerRooms(clientId: string): Room[] {
return Array.from(this.rooms.values())
.filter(room => room.hasPlayer(clientId));
}
/**
* 获取房间数量
*/
getRoomCount(): number {
return this.rooms.size;
}
/**
* 获取总玩家数量
*/
getTotalPlayerCount(): number {
return Array.from(this.rooms.values())
.reduce((total, room) => total + room.getPlayerCount(), 0);
}
/**
* 清理空闲房间
*/
async cleanupRooms(): Promise<number> {
let cleanedCount = 0;
const now = Date.now();
for (const room of this.rooms.values()) {
const config = room.getConfig();
const stats = room.getStats();
// 清理条件:
// 1. 非持久化的空房间
// 2. 已过期的房间
// 3. 已关闭的房间
let shouldClean = false;
let reason = '';
if (room.currentState === RoomState.CLOSED) {
shouldClean = true;
reason = 'room-closed';
} else if (!config.persistent && room.isEmpty()) {
shouldClean = true;
reason = 'empty-room';
} else if (config.expirationTime && config.expirationTime > 0) {
const expireTime = stats.createdAt.getTime() + config.expirationTime;
if (now >= expireTime) {
shouldClean = true;
reason = 'expired';
}
}
if (shouldClean) {
try {
if (room.currentState !== RoomState.CLOSED) {
await room.close(reason);
}
this.rooms.delete(room.id);
cleanedCount++;
console.log(`Cleaned up room: ${room.id}, reason: ${reason}`);
} catch (error) {
console.error(`Error cleaning up room ${room.id}:`, error);
}
}
}
return cleanedCount;
}
/**
* 关闭所有房间
*/
async closeAllRooms(reason: string = 'shutdown'): Promise<void> {
const rooms = Array.from(this.rooms.values());
const promises = rooms.map(room => room.close(reason));
await Promise.allSettled(promises);
this.rooms.clear();
console.log(`Closed ${rooms.length} rooms, reason: ${reason}`);
}
/**
* 销毁房间管理器
*/
async destroy(): Promise<void> {
// 停止清理定时器
if (this.cleanupTimer) {
clearInterval(this.cleanupTimer);
this.cleanupTimer = null;
}
// 关闭所有房间
await this.closeAllRooms('manager-destroyed');
// 移除所有事件监听器
this.removeAllListeners();
}
/**
* 初始化房间管理器
*/
private initialize(): void {
// 启动清理定时器
if (this.config.cleanupInterval && this.config.cleanupInterval > 0) {
this.cleanupTimer = setInterval(() => {
this.cleanupRooms().catch(error => {
console.error('Error during room cleanup:', error);
});
}, this.config.cleanupInterval);
}
}
/**
* 设置房间事件监听
*/
private setupRoomEvents(room: Room): void {
room.on('player-joined', (player) => {
this.emit('player-joined-room', room.id, player);
});
room.on('player-left', (clientId, reason) => {
this.emit('player-left-room', room.id, clientId, reason);
});
room.on('closed', (reason) => {
this.rooms.delete(room.id);
this.stats.roomsClosed++;
console.log(`Room ${room.id} removed from manager, reason: ${reason}`);
this.emit('room-closed', room.id, reason);
});
room.on('error', (error) => {
this.emit('error', error, room.id);
});
}
/**
* 更新统计信息
*/
private updateStats(): void {
this.stats.totalRooms = this.rooms.size;
this.stats.activeRooms = Array.from(this.rooms.values())
.filter(room => room.currentState === RoomState.ACTIVE).length;
this.stats.totalPlayers = this.getTotalPlayerCount();
this.stats.privateRooms = Array.from(this.rooms.values())
.filter(room => room.getConfig().isPrivate).length;
this.stats.persistentRooms = Array.from(this.rooms.values())
.filter(room => room.getConfig().persistent).length;
}
/**
* 类型安全的事件监听
*/
override on<K extends keyof RoomManagerEvents>(event: K, listener: RoomManagerEvents[K]): this {
return super.on(event, listener);
}
/**
* 类型安全的事件触发
*/
override emit<K extends keyof RoomManagerEvents>(event: K, ...args: Parameters<RoomManagerEvents[K]>): boolean {
return super.emit(event, ...args);
}
}