@esengine/server 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/router/loader.ts","../src/room/Player.ts","../src/room/Room.ts","../src/room/RoomManager.ts","../src/room/decorators.ts","../src/core/server.ts","../src/helpers/define.ts"],"names":["fileNameToHandlerName","fileName","baseName","replace","split","map","part","charAt","toUpperCase","slice","join","scanDirectory","dir","existsSync","files","entries","readdirSync","withFileTypes","entry","isFile","test","name","startsWith","push","loadApiHandlers","apiDir","handlers","filePath","fileUrl","pathToFileURL","href","module","definition","default","handler","basename","path","err","console","warn","loadMsgHandlers","msgDir","Player","options","id","roomId","data","_conn","_sendFn","_leaveFn","conn","sendFn","leaveFn","initialData","connection","send","type","leave","reason","MESSAGE_HANDLERS","Room","maxPlayers","tickRate","autoDispose","state","_id","_players","Map","_locked","_disposed","_tickInterval","_lastTickTime","_broadcastFn","_disposeFn","players","Array","from","values","playerCount","size","isFull","isLocked","isDisposed","onCreate","onJoin","player","onLeave","onTick","dt","onDispose","broadcast","broadcastExcept","except","getPlayer","get","kick","lock","unlock","dispose","_stopTick","clear","_init","broadcastFn","disposeFn","_create","_startTick","_addPlayer","p","_removePlayer","set","delete","_handleMessage","playerId","method","call","performance","now","setInterval","clearInterval","registerMessageHandler","target","RoomManager","_definitions","_rooms","_playerToRoom","_nextRoomId","define","roomClass","create","def","_generateRoomId","room","log","joinOrCreate","_findAvailableRoom","joinById","handleMessage","getRoom","getPlayerRoom","undefined","getRooms","getRoomsByType","filter","onMessage","propertyKey","_descriptor","DEFAULT_CONFIG","port","createServer","config","opts","cwd","process","apiHandlers","resolve","msgHandlers","length","apiDefs","JoinRoom","rpc","api","LeaveRoom","msgDefs","RoomMessage","msg","protocol","currentTick","tickInterval","rpcServer","roomManager","apiMap","msgMap","gameServer","connections","tick","rooms","start","apiHandlersObj","input","roomType","result","Error","_input","success","Object","ctx","server","msgHandlersObj","payload","serve","createConnData","onStart","onConnect","onDisconnect","stop","defineApi","defineMsg"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @zh 文件路由加载器\n * @en File-based router loader\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport type { ApiDefinition, MsgDefinition, LoadedApiHandler, LoadedMsgHandler } from '../types/index.js'\n\n/**\n * @zh 将文件名转换为 API/消息名称\n * @en Convert filename to API/message name\n *\n * @example\n * 'join.ts' -> 'Join'\n * 'spawn-agent.ts' -> 'SpawnAgent'\n * 'save_blueprint.ts' -> 'SaveBlueprint'\n */\nfunction fileNameToHandlerName(fileName: string): string {\n const baseName = fileName.replace(/\\.(ts|js|mts|mjs)$/, '')\n\n return baseName\n .split(/[-_]/)\n .map(part => part.charAt(0).toUpperCase() + part.slice(1))\n .join('')\n}\n\n/**\n * @zh 扫描目录获取所有处理器文件\n * @en Scan directory for all handler files\n */\nfunction scanDirectory(dir: string): string[] {\n if (!fs.existsSync(dir)) {\n return []\n }\n\n const files: string[] = []\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n if (entry.isFile() && /\\.(ts|js|mts|mjs)$/.test(entry.name)) {\n // 跳过 index 和下划线开头的文件\n if (entry.name.startsWith('_') || entry.name.startsWith('index.')) {\n continue\n }\n files.push(path.join(dir, entry.name))\n }\n }\n\n return files\n}\n\n/**\n * @zh 加载 API 处理器\n * @en Load API handlers\n */\nexport async function loadApiHandlers(apiDir: string): Promise<LoadedApiHandler[]> {\n const files = scanDirectory(apiDir)\n const handlers: LoadedApiHandler[] = []\n\n for (const filePath of files) {\n try {\n const fileUrl = pathToFileURL(filePath).href\n const module = await import(fileUrl)\n const definition = module.default as ApiDefinition<unknown, unknown, unknown>\n\n if (definition && typeof definition.handler === 'function') {\n const name = fileNameToHandlerName(path.basename(filePath))\n handlers.push({\n name,\n path: filePath,\n definition,\n })\n }\n } catch (err) {\n console.warn(`[Server] Failed to load API handler: ${filePath}`, err)\n }\n }\n\n return handlers\n}\n\n/**\n * @zh 加载消息处理器\n * @en Load message handlers\n */\nexport async function loadMsgHandlers(msgDir: string): Promise<LoadedMsgHandler[]> {\n const files = scanDirectory(msgDir)\n const handlers: LoadedMsgHandler[] = []\n\n for (const filePath of files) {\n try {\n const fileUrl = pathToFileURL(filePath).href\n const module = await import(fileUrl)\n const definition = module.default as MsgDefinition<unknown, unknown>\n\n if (definition && typeof definition.handler === 'function') {\n const name = fileNameToHandlerName(path.basename(filePath))\n handlers.push({\n name,\n path: filePath,\n definition,\n })\n }\n } catch (err) {\n console.warn(`[Server] Failed to load msg handler: ${filePath}`, err)\n }\n }\n\n return handlers\n}\n","/**\n * @zh 玩家类\n * @en Player class\n */\n\nimport type { Connection } from '@esengine/rpc'\n\n/**\n * @zh 玩家接口\n * @en Player interface\n */\nexport interface IPlayer<TData = Record<string, unknown>> {\n readonly id: string\n readonly roomId: string\n data: TData\n send<T>(type: string, data: T): void\n leave(reason?: string): void\n}\n\n/**\n * @zh 玩家实现\n * @en Player implementation\n */\nexport class Player<TData = Record<string, unknown>> implements IPlayer<TData> {\n readonly id: string\n readonly roomId: string\n data: TData\n\n private _conn: Connection<any>\n private _sendFn: (conn: Connection<any>, type: string, data: unknown) => void\n private _leaveFn: (player: Player<TData>, reason?: string) => void\n\n constructor(options: {\n id: string\n roomId: string\n conn: Connection<any>\n sendFn: (conn: Connection<any>, type: string, data: unknown) => void\n leaveFn: (player: Player<TData>, reason?: string) => void\n initialData?: TData\n }) {\n this.id = options.id\n this.roomId = options.roomId\n this._conn = options.conn\n this._sendFn = options.sendFn\n this._leaveFn = options.leaveFn\n this.data = options.initialData ?? ({} as TData)\n }\n\n /**\n * @zh 获取底层连接\n * @en Get underlying connection\n */\n get connection(): Connection<any> {\n return this._conn\n }\n\n /**\n * @zh 发送消息给玩家\n * @en Send message to player\n */\n send<T>(type: string, data: T): void {\n this._sendFn(this._conn, type, data)\n }\n\n /**\n * @zh 让玩家离开房间\n * @en Make player leave the room\n */\n leave(reason?: string): void {\n this._leaveFn(this, reason)\n }\n}\n","/**\n * @zh 房间基类\n * @en Room base class\n */\n\nimport { Player } from './Player.js'\n\n/**\n * @zh 房间配置\n * @en Room options\n */\nexport interface RoomOptions {\n [key: string]: unknown\n}\n\n/**\n * @zh 消息处理器元数据\n * @en Message handler metadata\n */\ninterface MessageHandlerMeta {\n type: string\n method: string\n}\n\n/**\n * @zh 消息处理器存储 key\n * @en Message handler storage key\n */\nconst MESSAGE_HANDLERS = Symbol('messageHandlers')\n\n/**\n * @zh 房间基类\n * @en Room base class\n *\n * @example\n * ```typescript\n * class GameRoom extends Room {\n * maxPlayers = 4\n * tickRate = 20\n *\n * onJoin(player: Player) {\n * this.broadcast('Joined', { id: player.id })\n * }\n *\n * @onMessage('Move')\n * handleMove(data: { x: number, y: number }, player: Player) {\n * // handle move\n * }\n * }\n * ```\n */\nexport abstract class Room<TState = any, TPlayerData = Record<string, unknown>> {\n // ========================================================================\n // 配置 | Configuration\n // ========================================================================\n\n /**\n * @zh 最大玩家数\n * @en Maximum players\n */\n maxPlayers = 16\n\n /**\n * @zh Tick 速率(每秒),0 = 不自动 tick\n * @en Tick rate (per second), 0 = no auto tick\n */\n tickRate = 0\n\n /**\n * @zh 空房间自动销毁\n * @en Auto dispose when empty\n */\n autoDispose = true\n\n // ========================================================================\n // 状态 | State\n // ========================================================================\n\n /**\n * @zh 房间状态\n * @en Room state\n */\n state: TState = {} as TState\n\n // ========================================================================\n // 内部属性 | Internal properties\n // ========================================================================\n\n private _id: string = ''\n private _players: Map<string, Player<TPlayerData>> = new Map()\n private _locked = false\n private _disposed = false\n private _tickInterval: ReturnType<typeof setInterval> | null = null\n private _lastTickTime = 0\n private _broadcastFn: ((type: string, data: unknown) => void) | null = null\n private _sendFn: ((conn: any, type: string, data: unknown) => void) | null = null\n private _disposeFn: (() => void) | null = null\n\n // ========================================================================\n // 只读属性 | Readonly properties\n // ========================================================================\n\n /**\n * @zh 房间 ID\n * @en Room ID\n */\n get id(): string {\n return this._id\n }\n\n /**\n * @zh 所有玩家\n * @en All players\n */\n get players(): ReadonlyArray<Player<TPlayerData>> {\n return Array.from(this._players.values())\n }\n\n /**\n * @zh 玩家数量\n * @en Player count\n */\n get playerCount(): number {\n return this._players.size\n }\n\n /**\n * @zh 是否已满\n * @en Is full\n */\n get isFull(): boolean {\n return this._players.size >= this.maxPlayers\n }\n\n /**\n * @zh 是否已锁定\n * @en Is locked\n */\n get isLocked(): boolean {\n return this._locked\n }\n\n /**\n * @zh 是否已销毁\n * @en Is disposed\n */\n get isDisposed(): boolean {\n return this._disposed\n }\n\n // ========================================================================\n // 生命周期 | Lifecycle\n // ========================================================================\n\n /**\n * @zh 房间创建时调用\n * @en Called when room is created\n */\n onCreate(options?: RoomOptions): void | Promise<void> {}\n\n /**\n * @zh 玩家加入时调用\n * @en Called when player joins\n */\n onJoin(player: Player<TPlayerData>): void | Promise<void> {}\n\n /**\n * @zh 玩家离开时调用\n * @en Called when player leaves\n */\n onLeave(player: Player<TPlayerData>, reason?: string): void | Promise<void> {}\n\n /**\n * @zh 游戏循环\n * @en Game tick\n */\n onTick(dt: number): void {}\n\n /**\n * @zh 房间销毁时调用\n * @en Called when room is disposed\n */\n onDispose(): void | Promise<void> {}\n\n // ========================================================================\n // 公共方法 | Public methods\n // ========================================================================\n\n /**\n * @zh 广播消息给所有玩家\n * @en Broadcast message to all players\n */\n broadcast<T>(type: string, data: T): void {\n for (const player of this._players.values()) {\n player.send(type, data)\n }\n }\n\n /**\n * @zh 广播消息给除指定玩家外的所有玩家\n * @en Broadcast message to all players except one\n */\n broadcastExcept<T>(except: Player<TPlayerData>, type: string, data: T): void {\n for (const player of this._players.values()) {\n if (player.id !== except.id) {\n player.send(type, data)\n }\n }\n }\n\n /**\n * @zh 获取玩家\n * @en Get player by id\n */\n getPlayer(id: string): Player<TPlayerData> | undefined {\n return this._players.get(id)\n }\n\n /**\n * @zh 踢出玩家\n * @en Kick player\n */\n kick(player: Player<TPlayerData>, reason?: string): void {\n player.leave(reason ?? 'kicked')\n }\n\n /**\n * @zh 锁定房间\n * @en Lock room\n */\n lock(): void {\n this._locked = true\n }\n\n /**\n * @zh 解锁房间\n * @en Unlock room\n */\n unlock(): void {\n this._locked = false\n }\n\n /**\n * @zh 手动销毁房间\n * @en Manually dispose room\n */\n dispose(): void {\n if (this._disposed) return\n this._disposed = true\n\n this._stopTick()\n\n for (const player of this._players.values()) {\n player.leave('room_disposed')\n }\n this._players.clear()\n\n this.onDispose()\n this._disposeFn?.()\n }\n\n // ========================================================================\n // 内部方法 | Internal methods\n // ========================================================================\n\n /**\n * @internal\n */\n _init(options: {\n id: string\n sendFn: (conn: any, type: string, data: unknown) => void\n broadcastFn: (type: string, data: unknown) => void\n disposeFn: () => void\n }): void {\n this._id = options.id\n this._sendFn = options.sendFn\n this._broadcastFn = options.broadcastFn\n this._disposeFn = options.disposeFn\n }\n\n /**\n * @internal\n */\n async _create(options?: RoomOptions): Promise<void> {\n await this.onCreate(options)\n this._startTick()\n }\n\n /**\n * @internal\n */\n async _addPlayer(id: string, conn: any): Promise<Player<TPlayerData> | null> {\n if (this._locked || this.isFull || this._disposed) {\n return null\n }\n\n const player = new Player<TPlayerData>({\n id,\n roomId: this._id,\n conn,\n sendFn: this._sendFn!,\n leaveFn: (p, reason) => this._removePlayer(p.id, reason),\n })\n\n this._players.set(id, player)\n await this.onJoin(player)\n\n return player\n }\n\n /**\n * @internal\n */\n async _removePlayer(id: string, reason?: string): Promise<void> {\n const player = this._players.get(id)\n if (!player) return\n\n this._players.delete(id)\n await this.onLeave(player, reason)\n\n if (this.autoDispose && this._players.size === 0) {\n this.dispose()\n }\n }\n\n /**\n * @internal\n */\n _handleMessage(type: string, data: unknown, playerId: string): void {\n const player = this._players.get(playerId)\n if (!player) return\n\n const handlers = (this.constructor as any)[MESSAGE_HANDLERS] as MessageHandlerMeta[] | undefined\n if (handlers) {\n for (const handler of handlers) {\n if (handler.type === type) {\n const method = (this as any)[handler.method]\n if (typeof method === 'function') {\n method.call(this, data, player)\n }\n }\n }\n }\n }\n\n private _startTick(): void {\n if (this.tickRate <= 0) return\n\n this._lastTickTime = performance.now()\n this._tickInterval = setInterval(() => {\n const now = performance.now()\n const dt = (now - this._lastTickTime) / 1000\n this._lastTickTime = now\n this.onTick(dt)\n }, 1000 / this.tickRate)\n }\n\n private _stopTick(): void {\n if (this._tickInterval) {\n clearInterval(this._tickInterval)\n this._tickInterval = null\n }\n }\n}\n\n/**\n * @zh 获取消息处理器元数据\n * @en Get message handler metadata\n */\nexport function getMessageHandlers(target: any): MessageHandlerMeta[] {\n return target[MESSAGE_HANDLERS] || []\n}\n\n/**\n * @zh 注册消息处理器元数据\n * @en Register message handler metadata\n */\nexport function registerMessageHandler(target: any, type: string, method: string): void {\n if (!target[MESSAGE_HANDLERS]) {\n target[MESSAGE_HANDLERS] = []\n }\n target[MESSAGE_HANDLERS].push({ type, method })\n}\n","/**\n * @zh 房间管理器\n * @en Room manager\n */\n\nimport { Room, type RoomOptions } from './Room.js'\nimport type { Player } from './Player.js'\n\n/**\n * @zh 房间类型\n * @en Room class type\n */\nexport type RoomClass<T extends Room = Room> = new () => T\n\n/**\n * @zh 房间定义\n * @en Room definition\n */\ninterface RoomDefinition {\n roomClass: RoomClass\n}\n\n/**\n * @zh 房间管理器\n * @en Room manager\n */\nexport class RoomManager {\n private _definitions: Map<string, RoomDefinition> = new Map()\n private _rooms: Map<string, Room> = new Map()\n private _playerToRoom: Map<string, string> = new Map()\n private _nextRoomId = 1\n\n private _sendFn: (conn: any, type: string, data: unknown) => void\n\n constructor(sendFn: (conn: any, type: string, data: unknown) => void) {\n this._sendFn = sendFn\n }\n\n /**\n * @zh 注册房间类型\n * @en Define room type\n */\n define<T extends Room>(name: string, roomClass: RoomClass<T>): void {\n this._definitions.set(name, { roomClass })\n }\n\n /**\n * @zh 创建房间\n * @en Create room\n */\n async create(name: string, options?: RoomOptions): Promise<Room | null> {\n const def = this._definitions.get(name)\n if (!def) {\n console.warn(`[RoomManager] Room type not found: ${name}`)\n return null\n }\n\n const roomId = this._generateRoomId()\n const room = new def.roomClass()\n\n room._init({\n id: roomId,\n sendFn: this._sendFn,\n broadcastFn: (type, data) => {\n for (const player of room.players) {\n player.send(type, data)\n }\n },\n disposeFn: () => {\n this._rooms.delete(roomId)\n },\n })\n\n this._rooms.set(roomId, room)\n await room._create(options)\n\n console.log(`[Room] Created: ${name} (${roomId})`)\n return room\n }\n\n /**\n * @zh 加入或创建房间\n * @en Join or create room\n */\n async joinOrCreate(\n name: string,\n playerId: string,\n conn: any,\n options?: RoomOptions\n ): Promise<{ room: Room; player: Player } | null> {\n // 查找可加入的房间\n let room = this._findAvailableRoom(name)\n\n // 没有则创建\n if (!room) {\n room = await this.create(name, options)\n if (!room) return null\n }\n\n // 加入房间\n const player = await room._addPlayer(playerId, conn)\n if (!player) return null\n\n this._playerToRoom.set(playerId, room.id)\n\n console.log(`[Room] Player ${playerId} joined ${room.id}`)\n return { room, player }\n }\n\n /**\n * @zh 加入指定房间\n * @en Join specific room\n */\n async joinById(\n roomId: string,\n playerId: string,\n conn: any\n ): Promise<{ room: Room; player: Player } | null> {\n const room = this._rooms.get(roomId)\n if (!room) return null\n\n const player = await room._addPlayer(playerId, conn)\n if (!player) return null\n\n this._playerToRoom.set(playerId, room.id)\n\n console.log(`[Room] Player ${playerId} joined ${room.id}`)\n return { room, player }\n }\n\n /**\n * @zh 玩家离开\n * @en Player leave\n */\n async leave(playerId: string, reason?: string): Promise<void> {\n const roomId = this._playerToRoom.get(playerId)\n if (!roomId) return\n\n const room = this._rooms.get(roomId)\n if (room) {\n await room._removePlayer(playerId, reason)\n }\n\n this._playerToRoom.delete(playerId)\n console.log(`[Room] Player ${playerId} left ${roomId}`)\n }\n\n /**\n * @zh 处理消息\n * @en Handle message\n */\n handleMessage(playerId: string, type: string, data: unknown): void {\n const roomId = this._playerToRoom.get(playerId)\n if (!roomId) return\n\n const room = this._rooms.get(roomId)\n if (room) {\n room._handleMessage(type, data, playerId)\n }\n }\n\n /**\n * @zh 获取房间\n * @en Get room\n */\n getRoom(roomId: string): Room | undefined {\n return this._rooms.get(roomId)\n }\n\n /**\n * @zh 获取玩家所在房间\n * @en Get player's room\n */\n getPlayerRoom(playerId: string): Room | undefined {\n const roomId = this._playerToRoom.get(playerId)\n return roomId ? this._rooms.get(roomId) : undefined\n }\n\n /**\n * @zh 获取所有房间\n * @en Get all rooms\n */\n getRooms(): ReadonlyArray<Room> {\n return Array.from(this._rooms.values())\n }\n\n /**\n * @zh 获取指定类型的所有房间\n * @en Get all rooms of a type\n */\n getRoomsByType(name: string): Room[] {\n const def = this._definitions.get(name)\n if (!def) return []\n\n return Array.from(this._rooms.values()).filter(\n room => room instanceof def.roomClass\n )\n }\n\n private _findAvailableRoom(name: string): Room | undefined {\n const def = this._definitions.get(name)\n if (!def) return undefined\n\n for (const room of this._rooms.values()) {\n if (\n room instanceof def.roomClass &&\n !room.isFull &&\n !room.isLocked &&\n !room.isDisposed\n ) {\n return room\n }\n }\n\n return undefined\n }\n\n private _generateRoomId(): string {\n return `room_${this._nextRoomId++}`\n }\n}\n","/**\n * @zh 房间装饰器\n * @en Room decorators\n */\n\nimport { registerMessageHandler } from './Room.js'\n\n/**\n * @zh 消息处理器装饰器\n * @en Message handler decorator\n *\n * @example\n * ```typescript\n * class GameRoom extends Room {\n * @onMessage('Move')\n * handleMove(data: { x: number, y: number }, player: Player) {\n * // handle move\n * }\n *\n * @onMessage('Chat')\n * handleChat(data: { text: string }, player: Player) {\n * this.broadcast('Chat', { from: player.id, text: data.text })\n * }\n * }\n * ```\n */\nexport function onMessage(type: string): MethodDecorator {\n return function (\n target: any,\n propertyKey: string | symbol,\n _descriptor: PropertyDescriptor\n ) {\n registerMessageHandler(target.constructor, type, propertyKey as string)\n }\n}\n","/**\n * @zh 游戏服务器核心\n * @en Game server core\n */\n\nimport * as path from 'node:path'\nimport { serve, type RpcServer } from '@esengine/rpc/server'\nimport { rpc } from '@esengine/rpc'\nimport type {\n ServerConfig,\n ServerConnection,\n GameServer,\n ApiContext,\n MsgContext,\n LoadedApiHandler,\n LoadedMsgHandler,\n} from '../types/index.js'\nimport { loadApiHandlers, loadMsgHandlers } from '../router/loader.js'\nimport { RoomManager, type RoomClass, type Room } from '../room/index.js'\n\n/**\n * @zh 默认配置\n * @en Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<ServerConfig, 'onStart' | 'onConnect' | 'onDisconnect'>> = {\n port: 3000,\n apiDir: 'src/api',\n msgDir: 'src/msg',\n tickRate: 20,\n}\n\n/**\n * @zh 创建游戏服务器\n * @en Create game server\n *\n * @example\n * ```typescript\n * import { createServer, Room, onMessage } from '@esengine/server'\n *\n * class GameRoom extends Room {\n * onJoin(player) {\n * this.broadcast('Joined', { id: player.id })\n * }\n * }\n *\n * const server = await createServer({ port: 3000 })\n * server.define('game', GameRoom)\n * await server.start()\n * ```\n */\nexport async function createServer(config: ServerConfig = {}): Promise<GameServer> {\n const opts = { ...DEFAULT_CONFIG, ...config }\n const cwd = process.cwd()\n\n // 加载文件路由处理器\n const apiHandlers = await loadApiHandlers(path.resolve(cwd, opts.apiDir))\n const msgHandlers = await loadMsgHandlers(path.resolve(cwd, opts.msgDir))\n\n if (apiHandlers.length > 0) {\n console.log(`[Server] Loaded ${apiHandlers.length} API handlers`)\n }\n if (msgHandlers.length > 0) {\n console.log(`[Server] Loaded ${msgHandlers.length} message handlers`)\n }\n\n // 动态构建协议\n const apiDefs: Record<string, ReturnType<typeof rpc.api>> = {\n // 内置 API\n JoinRoom: rpc.api(),\n LeaveRoom: rpc.api(),\n }\n const msgDefs: Record<string, ReturnType<typeof rpc.msg>> = {\n // 内置消息(房间消息透传)\n RoomMessage: rpc.msg(),\n }\n\n for (const handler of apiHandlers) {\n apiDefs[handler.name] = rpc.api()\n }\n for (const handler of msgHandlers) {\n msgDefs[handler.name] = rpc.msg()\n }\n\n const protocol = rpc.define({\n api: apiDefs,\n msg: msgDefs,\n })\n\n // 服务器状态\n let currentTick = 0\n let tickInterval: ReturnType<typeof setInterval> | null = null\n let rpcServer: RpcServer<typeof protocol, Record<string, unknown>> | null = null\n\n // 房间管理器(立即初始化,以便 define() 可在 start() 前调用)\n const roomManager = new RoomManager((conn, type, data) => {\n rpcServer?.send(conn, 'RoomMessage' as any, { type, data } as any)\n })\n\n // 构建 API 处理器映射\n const apiMap: Record<string, LoadedApiHandler> = {}\n for (const handler of apiHandlers) {\n apiMap[handler.name] = handler\n }\n\n // 构建消息处理器映射\n const msgMap: Record<string, LoadedMsgHandler> = {}\n for (const handler of msgHandlers) {\n msgMap[handler.name] = handler\n }\n\n // 游戏服务器实例\n const gameServer: GameServer & {\n rooms: RoomManager\n } = {\n get connections() {\n return (rpcServer?.connections ?? []) as ReadonlyArray<ServerConnection>\n },\n\n get tick() {\n return currentTick\n },\n\n get rooms() {\n return roomManager\n },\n\n /**\n * @zh 注册房间类型\n * @en Define room type\n */\n define(name: string, roomClass: new () => unknown): void {\n roomManager.define(name, roomClass as RoomClass)\n },\n\n async start() {\n // 构建 API handlers\n const apiHandlersObj: Record<string, (input: unknown, conn: any) => Promise<unknown>> = {}\n\n // 内置 JoinRoom API\n apiHandlersObj['JoinRoom'] = async (input: any, conn) => {\n const { roomType, roomId, options } = input as {\n roomType?: string\n roomId?: string\n options?: Record<string, unknown>\n }\n\n if (roomId) {\n const result = await roomManager.joinById(roomId, conn.id, conn)\n if (!result) {\n throw new Error('Failed to join room')\n }\n return { roomId: result.room.id, playerId: result.player.id }\n }\n\n if (roomType) {\n const result = await roomManager.joinOrCreate(roomType, conn.id, conn, options)\n if (!result) {\n throw new Error('Failed to join or create room')\n }\n return { roomId: result.room.id, playerId: result.player.id }\n }\n\n throw new Error('roomType or roomId required')\n }\n\n // 内置 LeaveRoom API\n apiHandlersObj['LeaveRoom'] = async (_input, conn) => {\n await roomManager.leave(conn.id)\n return { success: true }\n }\n\n // 文件路由 API\n for (const [name, handler] of Object.entries(apiMap)) {\n apiHandlersObj[name] = async (input, conn) => {\n const ctx: ApiContext = {\n conn: conn as ServerConnection,\n server: gameServer,\n }\n return handler.definition.handler(input, ctx)\n }\n }\n\n // 构建消息 handlers\n const msgHandlersObj: Record<string, (data: unknown, conn: any) => void | Promise<void>> = {}\n\n // 内置 RoomMessage 处理\n msgHandlersObj['RoomMessage'] = async (data: any, conn) => {\n const { type, payload } = data as { type: string; payload: unknown }\n roomManager.handleMessage(conn.id, type, payload)\n }\n\n // 文件路由消息\n for (const [name, handler] of Object.entries(msgMap)) {\n msgHandlersObj[name] = async (data, conn) => {\n const ctx: MsgContext = {\n conn: conn as ServerConnection,\n server: gameServer,\n }\n await handler.definition.handler(data, ctx)\n }\n }\n\n rpcServer = serve(protocol, {\n port: opts.port,\n createConnData: () => ({}),\n onStart: (p) => {\n console.log(`[Server] Started on ws://localhost:${p}`)\n opts.onStart?.(p)\n },\n onConnect: async (conn) => {\n await config.onConnect?.(conn as ServerConnection)\n },\n onDisconnect: async (conn) => {\n // 玩家断线时自动离开房间\n await roomManager?.leave(conn.id, 'disconnected')\n await config.onDisconnect?.(conn as ServerConnection)\n },\n api: apiHandlersObj as any,\n msg: msgHandlersObj as any,\n })\n\n await rpcServer.start()\n\n // 启动 tick 循环\n if (opts.tickRate > 0) {\n tickInterval = setInterval(() => {\n currentTick++\n }, 1000 / opts.tickRate)\n }\n },\n\n async stop() {\n if (tickInterval) {\n clearInterval(tickInterval)\n tickInterval = null\n }\n if (rpcServer) {\n await rpcServer.stop()\n rpcServer = null\n }\n },\n\n broadcast(name, data) {\n rpcServer?.broadcast(name as any, data as any)\n },\n\n send(conn, name, data) {\n rpcServer?.send(conn as any, name as any, data as any)\n },\n }\n\n return gameServer as GameServer\n}\n","/**\n * @zh API 和消息定义助手\n * @en API and message definition helpers\n */\n\nimport type { ApiDefinition, MsgDefinition } from '../types/index.js'\n\n/**\n * @zh 定义 API 处理器\n * @en Define API handler\n *\n * @example\n * ```typescript\n * // src/api/join.ts\n * import { defineApi } from '@esengine/server'\n *\n * export default defineApi<ReqJoin, ResJoin>({\n * handler(req, ctx) {\n * ctx.conn.data.playerId = generateId()\n * return { playerId: ctx.conn.data.playerId }\n * }\n * })\n * ```\n */\nexport function defineApi<TReq, TRes, TData = Record<string, unknown>>(\n definition: ApiDefinition<TReq, TRes, TData>\n): ApiDefinition<TReq, TRes, TData> {\n return definition\n}\n\n/**\n * @zh 定义消息处理器\n * @en Define message handler\n *\n * @example\n * ```typescript\n * // src/msg/input.ts\n * import { defineMsg } from '@esengine/server'\n *\n * export default defineMsg<MsgInput>({\n * handler(msg, ctx) {\n * console.log('Input from', ctx.conn.id, msg)\n * }\n * })\n * ```\n */\nexport function defineMsg<TMsg, TData = Record<string, unknown>>(\n definition: MsgDefinition<TMsg, TData>\n): MsgDefinition<TMsg, TData> {\n return definition\n}\n"]}
1
+ {"version":3,"sources":["../src/helpers/define.ts"],"names":["defineApi","definition","defineMsg"],"mappings":";;;;;AAwBO,SAASA,UACZC,UAAAA,EAA4C;AAE5C,EAAA,OAAOA,UAAAA;AACX;AAJgBD,MAAAA,CAAAA,SAAAA,EAAAA,WAAAA,CAAAA;AAsBT,SAASE,UACZD,UAAAA,EAAsC;AAEtC,EAAA,OAAOA,UAAAA;AACX;AAJgBC,MAAAA,CAAAA,SAAAA,EAAAA,WAAAA,CAAAA","file":"index.js","sourcesContent":["/**\n * @zh API 和消息定义助手\n * @en API and message definition helpers\n */\n\nimport type { ApiDefinition, MsgDefinition } from '../types/index.js'\n\n/**\n * @zh 定义 API 处理器\n * @en Define API handler\n *\n * @example\n * ```typescript\n * // src/api/join.ts\n * import { defineApi } from '@esengine/server'\n *\n * export default defineApi<ReqJoin, ResJoin>({\n * handler(req, ctx) {\n * ctx.conn.data.playerId = generateId()\n * return { playerId: ctx.conn.data.playerId }\n * }\n * })\n * ```\n */\nexport function defineApi<TReq, TRes, TData = Record<string, unknown>>(\n definition: ApiDefinition<TReq, TRes, TData>\n): ApiDefinition<TReq, TRes, TData> {\n return definition\n}\n\n/**\n * @zh 定义消息处理器\n * @en Define message handler\n *\n * @example\n * ```typescript\n * // src/msg/input.ts\n * import { defineMsg } from '@esengine/server'\n *\n * export default defineMsg<MsgInput>({\n * handler(msg, ctx) {\n * console.log('Input from', ctx.conn.id, msg)\n * }\n * })\n * ```\n */\nexport function defineMsg<TMsg, TData = Record<string, unknown>>(\n definition: MsgDefinition<TMsg, TData>\n): MsgDefinition<TMsg, TData> {\n return definition\n}\n"]}
@@ -0,0 +1,386 @@
1
+ import { Codec } from '@esengine/rpc/codec';
2
+ import { G as GameServer } from '../index-DgaJIm6-.js';
3
+ import { R as Room, P as Player } from '../Room-BnKpl5Sj.js';
4
+ import '@esengine/rpc';
5
+
6
+ /**
7
+ * @zh 测试客户端
8
+ * @en Test client for server testing
9
+ */
10
+
11
+ /**
12
+ * @zh 测试客户端配置
13
+ * @en Test client options
14
+ */
15
+ interface TestClientOptions {
16
+ /**
17
+ * @zh 编解码器
18
+ * @en Codec
19
+ * @defaultValue json()
20
+ */
21
+ codec?: Codec;
22
+ /**
23
+ * @zh API 调用超时(毫秒)
24
+ * @en API call timeout in milliseconds
25
+ * @defaultValue 5000
26
+ */
27
+ timeout?: number;
28
+ /**
29
+ * @zh 连接超时(毫秒)
30
+ * @en Connection timeout in milliseconds
31
+ * @defaultValue 5000
32
+ */
33
+ connectTimeout?: number;
34
+ }
35
+ /**
36
+ * @zh 房间加入结果
37
+ * @en Room join result
38
+ */
39
+ interface JoinRoomResult {
40
+ roomId: string;
41
+ playerId: string;
42
+ }
43
+ /**
44
+ * @zh 收到的消息记录
45
+ * @en Received message record
46
+ */
47
+ interface ReceivedMessage {
48
+ type: string;
49
+ data: unknown;
50
+ timestamp: number;
51
+ }
52
+ /**
53
+ * @zh 测试客户端
54
+ * @en Test client for server integration testing
55
+ *
56
+ * @zh 专为测试设计的客户端,提供便捷的断言方法和消息记录功能
57
+ * @en Client designed for testing, with convenient assertion methods and message recording
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const client = new TestClient(3000)
62
+ * await client.connect()
63
+ *
64
+ * // 加入房间
65
+ * const { roomId } = await client.joinRoom('game')
66
+ *
67
+ * // 发送消息
68
+ * client.sendToRoom('Move', { x: 10, y: 20 })
69
+ *
70
+ * // 等待收到特定消息
71
+ * const msg = await client.waitForMessage('PlayerMoved')
72
+ *
73
+ * // 断言收到消息
74
+ * expect(client.hasReceivedMessage('PlayerMoved')).toBe(true)
75
+ *
76
+ * await client.disconnect()
77
+ * ```
78
+ */
79
+ declare class TestClient {
80
+ private readonly _port;
81
+ private readonly _codec;
82
+ private readonly _timeout;
83
+ private readonly _connectTimeout;
84
+ private _ws;
85
+ private _callIdCounter;
86
+ private _connected;
87
+ private _currentRoomId;
88
+ private _currentPlayerId;
89
+ private readonly _pendingCalls;
90
+ private readonly _msgHandlers;
91
+ private readonly _receivedMessages;
92
+ constructor(port: number, options?: TestClientOptions);
93
+ /**
94
+ * @zh 是否已连接
95
+ * @en Whether connected
96
+ */
97
+ get isConnected(): boolean;
98
+ /**
99
+ * @zh 当前房间 ID
100
+ * @en Current room ID
101
+ */
102
+ get roomId(): string | null;
103
+ /**
104
+ * @zh 当前玩家 ID
105
+ * @en Current player ID
106
+ */
107
+ get playerId(): string | null;
108
+ /**
109
+ * @zh 收到的所有消息
110
+ * @en All received messages
111
+ */
112
+ get receivedMessages(): ReadonlyArray<ReceivedMessage>;
113
+ /**
114
+ * @zh 连接到服务器
115
+ * @en Connect to server
116
+ */
117
+ connect(): Promise<this>;
118
+ /**
119
+ * @zh 断开连接
120
+ * @en Disconnect from server
121
+ */
122
+ disconnect(): Promise<void>;
123
+ /**
124
+ * @zh 加入房间
125
+ * @en Join a room
126
+ */
127
+ joinRoom(roomType: string, options?: Record<string, unknown>): Promise<JoinRoomResult>;
128
+ /**
129
+ * @zh 通过 ID 加入房间
130
+ * @en Join a room by ID
131
+ */
132
+ joinRoomById(roomId: string): Promise<JoinRoomResult>;
133
+ /**
134
+ * @zh 离开房间
135
+ * @en Leave room
136
+ */
137
+ leaveRoom(): Promise<void>;
138
+ /**
139
+ * @zh 发送消息到房间
140
+ * @en Send message to room
141
+ */
142
+ sendToRoom(type: string, data: unknown): void;
143
+ /**
144
+ * @zh 调用 API
145
+ * @en Call API
146
+ */
147
+ call<T = unknown>(name: string, input: unknown): Promise<T>;
148
+ /**
149
+ * @zh 发送消息
150
+ * @en Send message
151
+ */
152
+ send(name: string, data: unknown): void;
153
+ /**
154
+ * @zh 监听消息
155
+ * @en Listen for message
156
+ */
157
+ on(name: string, handler: (data: unknown) => void): this;
158
+ /**
159
+ * @zh 取消监听消息
160
+ * @en Remove message listener
161
+ */
162
+ off(name: string, handler?: (data: unknown) => void): this;
163
+ /**
164
+ * @zh 等待收到指定消息
165
+ * @en Wait for a specific message
166
+ */
167
+ waitForMessage<T = unknown>(type: string, timeout?: number): Promise<T>;
168
+ /**
169
+ * @zh 等待收到指定房间消息
170
+ * @en Wait for a specific room message
171
+ */
172
+ waitForRoomMessage<T = unknown>(type: string, timeout?: number): Promise<T>;
173
+ /**
174
+ * @zh 是否收到过指定消息
175
+ * @en Whether received a specific message
176
+ */
177
+ hasReceivedMessage(type: string): boolean;
178
+ /**
179
+ * @zh 获取指定类型的所有消息
180
+ * @en Get all messages of a specific type
181
+ */
182
+ getMessagesOfType<T = unknown>(type: string): T[];
183
+ /**
184
+ * @zh 获取最后收到的指定类型消息
185
+ * @en Get the last received message of a specific type
186
+ */
187
+ getLastMessage<T = unknown>(type: string): T | undefined;
188
+ /**
189
+ * @zh 清空消息记录
190
+ * @en Clear message records
191
+ */
192
+ clearMessages(): void;
193
+ /**
194
+ * @zh 获取收到的消息数量
195
+ * @en Get received message count
196
+ */
197
+ getMessageCount(type?: string): number;
198
+ private _handleMessage;
199
+ private _handleApiResponse;
200
+ private _handleApiError;
201
+ private _handleMsg;
202
+ private _rejectAllPending;
203
+ }
204
+
205
+ /**
206
+ * @zh 测试服务器工具
207
+ * @en Test server utilities
208
+ */
209
+
210
+ /**
211
+ * @zh 测试服务器配置
212
+ * @en Test server options
213
+ */
214
+ interface TestServerOptions {
215
+ /**
216
+ * @zh 端口号,0 表示随机端口
217
+ * @en Port number, 0 for random port
218
+ * @defaultValue 0
219
+ */
220
+ port?: number;
221
+ /**
222
+ * @zh Tick 速率
223
+ * @en Tick rate
224
+ * @defaultValue 0
225
+ */
226
+ tickRate?: number;
227
+ /**
228
+ * @zh 是否禁用控制台日志
229
+ * @en Whether to suppress console logs
230
+ * @defaultValue true
231
+ */
232
+ silent?: boolean;
233
+ }
234
+ /**
235
+ * @zh 测试环境
236
+ * @en Test environment
237
+ */
238
+ interface TestEnvironment {
239
+ /**
240
+ * @zh 服务器实例
241
+ * @en Server instance
242
+ */
243
+ server: GameServer;
244
+ /**
245
+ * @zh 服务器端口
246
+ * @en Server port
247
+ */
248
+ port: number;
249
+ /**
250
+ * @zh 创建测试客户端
251
+ * @en Create test client
252
+ */
253
+ createClient(options?: TestClientOptions): Promise<TestClient>;
254
+ /**
255
+ * @zh 创建多个测试客户端
256
+ * @en Create multiple test clients
257
+ */
258
+ createClients(count: number, options?: TestClientOptions): Promise<TestClient[]>;
259
+ /**
260
+ * @zh 清理测试环境
261
+ * @en Cleanup test environment
262
+ */
263
+ cleanup(): Promise<void>;
264
+ /**
265
+ * @zh 所有已创建的客户端
266
+ * @en All created clients
267
+ */
268
+ readonly clients: ReadonlyArray<TestClient>;
269
+ }
270
+ /**
271
+ * @zh 创建测试服务器
272
+ * @en Create test server
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * const { server, port, cleanup } = await createTestServer()
277
+ * server.define('game', GameRoom)
278
+ *
279
+ * const client = new TestClient(port)
280
+ * await client.connect()
281
+ *
282
+ * // ... run tests ...
283
+ *
284
+ * await cleanup()
285
+ * ```
286
+ */
287
+ declare function createTestServer(options?: TestServerOptions): Promise<{
288
+ server: GameServer;
289
+ port: number;
290
+ cleanup: () => Promise<void>;
291
+ }>;
292
+ /**
293
+ * @zh 创建完整测试环境
294
+ * @en Create complete test environment
295
+ *
296
+ * @zh 包含服务器、客户端创建和清理功能的完整测试环境
297
+ * @en Complete test environment with server, client creation and cleanup
298
+ *
299
+ * @example
300
+ * ```typescript
301
+ * describe('GameRoom', () => {
302
+ * let env: TestEnvironment
303
+ *
304
+ * beforeEach(async () => {
305
+ * env = await createTestEnv()
306
+ * env.server.define('game', GameRoom)
307
+ * })
308
+ *
309
+ * afterEach(async () => {
310
+ * await env.cleanup()
311
+ * })
312
+ *
313
+ * it('should handle player join', async () => {
314
+ * const client = await env.createClient()
315
+ * const result = await client.joinRoom('game')
316
+ * expect(result.roomId).toBeDefined()
317
+ * })
318
+ *
319
+ * it('should broadcast to all players', async () => {
320
+ * const [client1, client2] = await env.createClients(2)
321
+ *
322
+ * await client1.joinRoom('game')
323
+ * const joinPromise = client1.waitForRoomMessage('PlayerJoined')
324
+ *
325
+ * await client2.joinRoom('game')
326
+ * const msg = await joinPromise
327
+ *
328
+ * expect(msg).toBeDefined()
329
+ * })
330
+ * })
331
+ * ```
332
+ */
333
+ declare function createTestEnv(options?: TestServerOptions): Promise<TestEnvironment>;
334
+
335
+ /**
336
+ * @zh 模拟房间
337
+ * @en Mock room for testing
338
+ */
339
+
340
+ /**
341
+ * @zh 模拟房间状态
342
+ * @en Mock room state
343
+ */
344
+ interface MockRoomState {
345
+ messages: Array<{
346
+ type: string;
347
+ data: unknown;
348
+ playerId: string;
349
+ }>;
350
+ joinCount: number;
351
+ leaveCount: number;
352
+ }
353
+ /**
354
+ * @zh 模拟房间
355
+ * @en Mock room for testing
356
+ *
357
+ * @zh 记录所有事件和消息,用于测试断言
358
+ * @en Records all events and messages for test assertions
359
+ *
360
+ * @example
361
+ * ```typescript
362
+ * const env = await createTestEnv()
363
+ * env.server.define('mock', MockRoom)
364
+ *
365
+ * const client = await env.createClient()
366
+ * await client.joinRoom('mock')
367
+ *
368
+ * client.sendToRoom('Test', { value: 123 })
369
+ * await wait(50)
370
+ *
371
+ * // MockRoom 会广播收到的消息
372
+ * const msg = client.getLastMessage('RoomMessage')
373
+ * ```
374
+ */
375
+ declare class MockRoom extends Room<MockRoomState> {
376
+ state: MockRoomState;
377
+ onCreate(): void;
378
+ onJoin(player: Player): void;
379
+ onLeave(player: Player): void;
380
+ handleAnyMessage(data: unknown, player: Player, type: string): void;
381
+ handleEcho(data: unknown, player: Player): void;
382
+ handleBroadcast(data: unknown, _player: Player): void;
383
+ handlePing(_data: unknown, player: Player): void;
384
+ }
385
+
386
+ export { MockRoom, TestClient, type TestClientOptions, type TestEnvironment, type TestServerOptions, createTestEnv, createTestServer };