重构network库(mvp版本)搭建基础设施和核心接口

定义ITransport/ISerializer/INetworkMessage接口
NetworkIdentity组件
基础事件定义
This commit is contained in:
YHH
2025-08-13 13:07:40 +08:00
parent 25136349ff
commit 62f250b43c
97 changed files with 1877 additions and 16607 deletions

View File

@@ -1,637 +0,0 @@
/**
* 房间管理
*
* 类似于 Unity Mirror 的 Scene 概念,管理一组客户端和网络对象
*/
import { EventEmitter } from 'events';
import { Entity, Scene } from '@esengine/ecs-framework';
import { NetworkValue } from '@esengine/ecs-framework-network-shared';
import { ClientConnection } from '../core/ClientConnection';
import { TransportMessage } from '../core/Transport';
/**
* 房间状态
*/
export enum RoomState {
/** 创建中 */
CREATING = 'creating',
/** 活跃状态 */
ACTIVE = 'active',
/** 暂停状态 */
PAUSED = 'paused',
/** 关闭中 */
CLOSING = 'closing',
/** 已关闭 */
CLOSED = 'closed'
}
/**
* 房间配置
*/
export interface RoomConfig {
/** 房间ID */
id: string;
/** 房间名称 */
name: string;
/** 房间描述 */
description?: string;
/** 最大玩家数 */
maxPlayers: number;
/** 是否私有房间 */
isPrivate?: boolean;
/** 房间密码 */
password?: string;
/** 房间元数据 */
metadata?: Record<string, NetworkValue>;
/** 是否持久化 */
persistent?: boolean;
/** 房间过期时间(毫秒) */
expirationTime?: number;
}
/**
* 玩家数据
*/
export interface PlayerData {
/** 客户端连接 */
client: ClientConnection;
/** 加入时间 */
joinedAt: Date;
/** 是否为房主 */
isOwner: boolean;
/** 玩家自定义数据 */
customData: Record<string, NetworkValue>;
}
/**
* 房间统计信息
*/
export interface RoomStats {
/** 当前玩家数 */
currentPlayers: number;
/** 最大玩家数 */
maxPlayers: number;
/** 总加入过的玩家数 */
totalPlayersJoined: number;
/** 消息总数 */
totalMessages: number;
/** 创建时间 */
createdAt: Date;
/** 房间存活时间(毫秒) */
lifetime: number;
}
/**
* 房间事件
*/
export interface RoomEvents {
/** 玩家加入 */
'player-joined': (player: PlayerData) => void;
/** 玩家离开 */
'player-left': (clientId: string, reason?: string) => void;
/** 房主变更 */
'owner-changed': (newOwnerId: string, oldOwnerId?: string) => void;
/** 房间状态变化 */
'state-changed': (oldState: RoomState, newState: RoomState) => void;
/** 收到消息 */
'message': (clientId: string, message: TransportMessage) => void;
/** 房间更新 */
'room-updated': (updatedFields: Partial<RoomConfig>) => void;
/** 房间错误 */
'error': (error: Error, clientId?: string) => void;
/** 房间即将关闭 */
'closing': (reason: string) => void;
/** 房间已关闭 */
'closed': (reason: string) => void;
}
/**
* 房间类
*/
export class Room extends EventEmitter {
private config: RoomConfig;
private state: RoomState = RoomState.CREATING;
private players = new Map<string, PlayerData>();
private ownerId: string | null = null;
private ecsScene: Scene | null = null;
private stats: RoomStats;
private expirationTimer: NodeJS.Timeout | null = null;
constructor(config: RoomConfig) {
super();
this.config = { ...config };
this.stats = {
currentPlayers: 0,
maxPlayers: config.maxPlayers,
totalPlayersJoined: 0,
totalMessages: 0,
createdAt: new Date(),
lifetime: 0
};
this.initialize();
}
/**
* 获取房间ID
*/
get id(): string {
return this.config.id;
}
/**
* 获取房间名称
*/
get name(): string {
return this.config.name;
}
/**
* 获取房间状态
*/
get currentState(): RoomState {
return this.state;
}
/**
* 获取房间配置
*/
getConfig(): Readonly<RoomConfig> {
return this.config;
}
/**
* 获取房间统计信息
*/
getStats(): RoomStats {
this.stats.lifetime = Date.now() - this.stats.createdAt.getTime();
this.stats.currentPlayers = this.players.size;
return { ...this.stats };
}
/**
* 获取所有玩家
*/
getPlayers(): PlayerData[] {
return Array.from(this.players.values());
}
/**
* 获取指定玩家
*/
getPlayer(clientId: string): PlayerData | undefined {
return this.players.get(clientId);
}
/**
* 检查玩家是否在房间中
*/
hasPlayer(clientId: string): boolean {
return this.players.has(clientId);
}
/**
* 获取当前玩家数量
*/
getPlayerCount(): number {
return this.players.size;
}
/**
* 检查房间是否已满
*/
isFull(): boolean {
return this.players.size >= this.config.maxPlayers;
}
/**
* 检查房间是否为空
*/
isEmpty(): boolean {
return this.players.size === 0;
}
/**
* 获取房主
*/
getOwner(): PlayerData | undefined {
return this.ownerId ? this.players.get(this.ownerId) : undefined;
}
/**
* 获取 ECS 场景
*/
getEcsScene(): Scene | null {
return this.ecsScene;
}
/**
* 玩家加入房间
*/
async addPlayer(client: ClientConnection, customData: Record<string, NetworkValue> = {}): Promise<boolean> {
if (this.state !== RoomState.ACTIVE) {
throw new Error(`Cannot join room in state: ${this.state}`);
}
if (this.hasPlayer(client.id)) {
throw new Error(`Player ${client.id} is already in the room`);
}
if (this.isFull()) {
throw new Error('Room is full');
}
// 检查房间密码
if (this.config.isPrivate && this.config.password) {
const providedPassword = customData.password as string;
if (providedPassword !== this.config.password) {
throw new Error('Invalid room password');
}
}
const isFirstPlayer = this.isEmpty();
const playerData: PlayerData = {
client,
joinedAt: new Date(),
isOwner: isFirstPlayer,
customData: { ...customData }
};
this.players.set(client.id, playerData);
client.joinRoom(this.id);
// 设置房主
if (isFirstPlayer) {
this.ownerId = client.id;
}
this.stats.totalPlayersJoined++;
// 通知其他玩家
await this.broadcast({
type: 'system',
data: {
action: 'player-joined',
playerId: client.id,
playerData: {
id: client.id,
joinedAt: playerData.joinedAt.toISOString(),
isOwner: playerData.isOwner,
customData: playerData.customData
}
}
}, client.id);
console.log(`Player ${client.id} joined room ${this.id}`);
this.emit('player-joined', playerData);
return true;
}
/**
* 玩家离开房间
*/
async removePlayer(clientId: string, reason?: string): Promise<boolean> {
const player = this.players.get(clientId);
if (!player) {
return false;
}
this.players.delete(clientId);
player.client.leaveRoom();
// 如果离开的是房主,转移房主权限
if (this.ownerId === clientId) {
await this.transferOwnership();
}
// 通知其他玩家
await this.broadcast({
type: 'system',
data: {
action: 'player-left',
playerId: clientId,
reason: reason || 'unknown'
}
});
console.log(`Player ${clientId} left room ${this.id}, reason: ${reason || 'unknown'}`);
this.emit('player-left', clientId, reason);
// 如果房间为空,考虑关闭
if (this.isEmpty() && !this.config.persistent) {
await this.close('empty-room');
}
return true;
}
/**
* 转移房主权限
*/
async transferOwnership(newOwnerId?: string): Promise<boolean> {
const oldOwnerId = this.ownerId;
if (newOwnerId) {
const newOwner = this.players.get(newOwnerId);
if (!newOwner) {
return false;
}
this.ownerId = newOwnerId;
newOwner.isOwner = true;
} else {
// 自动选择下一个玩家作为房主
const players = Array.from(this.players.values());
if (players.length > 0) {
const newOwner = players[0];
this.ownerId = newOwner.client.id;
newOwner.isOwner = true;
} else {
this.ownerId = null;
}
}
// 更新旧房主状态
if (oldOwnerId) {
const oldOwner = this.players.get(oldOwnerId);
if (oldOwner) {
oldOwner.isOwner = false;
}
}
// 通知所有玩家房主变更
if (this.ownerId) {
await this.broadcast({
type: 'system',
data: {
action: 'owner-changed',
newOwnerId: this.ownerId,
oldOwnerId: oldOwnerId || ''
}
});
console.log(`Room ${this.id} ownership transferred from ${oldOwnerId || 'none'} to ${this.ownerId}`);
this.emit('owner-changed', this.ownerId, oldOwnerId || undefined);
}
return true;
}
/**
* 广播消息给房间内所有玩家
*/
async broadcast(message: TransportMessage, excludeClientId?: string): Promise<number> {
const players = Array.from(this.players.values())
.filter(player => player.client.id !== excludeClientId);
const promises = players.map(player => player.client.sendMessage(message));
const results = await Promise.allSettled(promises);
return results.filter(result => result.status === 'fulfilled' && result.value).length;
}
/**
* 发送消息给指定玩家
*/
async sendToPlayer(clientId: string, message: TransportMessage): Promise<boolean> {
const player = this.players.get(clientId);
if (!player) {
return false;
}
return await player.client.sendMessage(message);
}
/**
* 处理玩家消息
*/
async handleMessage(clientId: string, message: TransportMessage): Promise<void> {
if (!this.hasPlayer(clientId)) {
return;
}
this.stats.totalMessages++;
this.emit('message', clientId, message);
// 根据消息类型进行处理
switch (message.type) {
case 'rpc':
await this.handleRpcMessage(clientId, message);
break;
case 'syncvar':
await this.handleSyncVarMessage(clientId, message);
break;
case 'system':
await this.handleSystemMessage(clientId, message);
break;
default:
// 转发自定义消息
await this.broadcast(message, clientId);
break;
}
}
/**
* 更新房间配置
*/
async updateConfig(updates: Partial<RoomConfig>): Promise<void> {
// 验证更新
if (updates.maxPlayers !== undefined && updates.maxPlayers < this.players.size) {
throw new Error('Cannot reduce maxPlayers below current player count');
}
const oldConfig = { ...this.config };
Object.assign(this.config, updates);
// 通知所有玩家房间更新
await this.broadcast({
type: 'system',
data: {
action: 'room-updated',
updates
}
});
this.emit('room-updated', updates);
}
/**
* 暂停房间
*/
async pause(): Promise<void> {
if (this.state === RoomState.ACTIVE) {
this.setState(RoomState.PAUSED);
await this.broadcast({
type: 'system',
data: {
action: 'room-paused'
}
});
}
}
/**
* 恢复房间
*/
async resume(): Promise<void> {
if (this.state === RoomState.PAUSED) {
this.setState(RoomState.ACTIVE);
await this.broadcast({
type: 'system',
data: {
action: 'room-resumed'
}
});
}
}
/**
* 关闭房间
*/
async close(reason: string = 'server-shutdown'): Promise<void> {
if (this.state === RoomState.CLOSED || this.state === RoomState.CLOSING) {
return;
}
this.setState(RoomState.CLOSING);
this.emit('closing', reason);
// 通知所有玩家房间即将关闭
await this.broadcast({
type: 'system',
data: {
action: 'room-closing',
reason
}
});
// 移除所有玩家
const playerIds = Array.from(this.players.keys());
for (const clientId of playerIds) {
await this.removePlayer(clientId, 'room-closed');
}
this.cleanup();
this.setState(RoomState.CLOSED);
console.log(`Room ${this.id} closed, reason: ${reason}`);
this.emit('closed', reason);
}
/**
* 初始化房间
*/
private initialize(): void {
// 创建 ECS 场景
this.ecsScene = new Scene();
// 设置过期定时器
if (this.config.expirationTime && this.config.expirationTime > 0) {
this.expirationTimer = setTimeout(() => {
this.close('expired');
}, this.config.expirationTime);
}
this.setState(RoomState.ACTIVE);
}
/**
* 处理 RPC 消息
*/
private async handleRpcMessage(clientId: string, message: TransportMessage): Promise<void> {
// RPC 消息处理逻辑
// 这里可以添加权限检查、速率限制等
await this.broadcast(message, clientId);
}
/**
* 处理 SyncVar 消息
*/
private async handleSyncVarMessage(clientId: string, message: TransportMessage): Promise<void> {
// SyncVar 消息处理逻辑
// 这里可以添加权限检查、数据验证等
await this.broadcast(message, clientId);
}
/**
* 处理系统消息
*/
private async handleSystemMessage(clientId: string, message: TransportMessage): Promise<void> {
const data = message.data as any;
switch (data.action) {
case 'request-ownership':
// 处理房主权限转移请求
if (this.ownerId === clientId) {
await this.transferOwnership(data.newOwnerId);
}
break;
// 其他系统消息处理...
}
}
/**
* 设置房间状态
*/
private setState(newState: RoomState): void {
const oldState = this.state;
if (oldState !== newState) {
this.state = newState;
this.emit('state-changed', oldState, newState);
}
}
/**
* 清理资源
*/
private cleanup(): void {
if (this.expirationTimer) {
clearTimeout(this.expirationTimer);
this.expirationTimer = null;
}
this.removeAllListeners();
if (this.ecsScene) {
this.ecsScene = null;
}
}
/**
* 类型安全的事件监听
*/
override on<K extends keyof RoomEvents>(event: K, listener: RoomEvents[K]): this {
return super.on(event, listener);
}
/**
* 类型安全的事件触发
*/
override emit<K extends keyof RoomEvents>(event: K, ...args: Parameters<RoomEvents[K]>): boolean {
return super.emit(event, ...args);
}
/**
* 序列化房间信息
*/
toJSON(): object {
return {
id: this.id,
name: this.name,
state: this.state,
config: this.config,
stats: this.getStats(),
players: this.getPlayers().map(player => ({
id: player.client.id,
joinedAt: player.joinedAt.toISOString(),
isOwner: player.isOwner,
customData: player.customData
})),
ownerId: this.ownerId
};
}
}

View File

@@ -1,499 +0,0 @@
/**
* 房间管理器
*
* 管理所有房间的创建、销毁、查找等操作
*/
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);
}
}

View File

@@ -1,6 +0,0 @@
/**
* 房间系统导出
*/
export * from './Room';
export * from './RoomManager';