@gamerstake/game-core 0.1.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/.eslintrc.json +22 -0
- package/.testing-guide-summary.md +261 -0
- package/DEVELOPER_GUIDE.md +996 -0
- package/MANUAL_TESTING.md +369 -0
- package/QUICK_START.md +368 -0
- package/README.md +379 -0
- package/TESTING_OVERVIEW.md +378 -0
- package/dist/index.d.ts +1266 -0
- package/dist/index.js +1632 -0
- package/dist/index.js.map +1 -0
- package/examples/simple-game/README.md +176 -0
- package/examples/simple-game/client.ts +201 -0
- package/examples/simple-game/package.json +14 -0
- package/examples/simple-game/server.ts +233 -0
- package/jest.config.ts +39 -0
- package/package.json +54 -0
- package/src/core/GameLoop.ts +214 -0
- package/src/core/GameRules.ts +103 -0
- package/src/core/GameServer.ts +200 -0
- package/src/core/Room.ts +368 -0
- package/src/entities/Entity.ts +118 -0
- package/src/entities/Registry.ts +161 -0
- package/src/index.ts +51 -0
- package/src/input/Command.ts +41 -0
- package/src/input/InputQueue.ts +130 -0
- package/src/network/Network.ts +112 -0
- package/src/network/Snapshot.ts +59 -0
- package/src/physics/AABB.ts +104 -0
- package/src/physics/Movement.ts +124 -0
- package/src/spatial/Grid.ts +202 -0
- package/src/types/index.ts +117 -0
- package/src/types/protocol.ts +161 -0
- package/src/utils/Logger.ts +112 -0
- package/src/utils/RingBuffer.ts +116 -0
- package/tests/AABB.test.ts +38 -0
- package/tests/Entity.test.ts +35 -0
- package/tests/GameLoop.test.ts +58 -0
- package/tests/GameServer.test.ts +64 -0
- package/tests/Grid.test.ts +28 -0
- package/tests/InputQueue.test.ts +42 -0
- package/tests/Movement.test.ts +37 -0
- package/tests/Network.test.ts +39 -0
- package/tests/Registry.test.ts +36 -0
- package/tests/RingBuffer.test.ts +38 -0
- package/tests/Room.test.ts +80 -0
- package/tests/Snapshot.test.ts +19 -0
- package/tsconfig.json +28 -0
- package/tsup.config.ts +14 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/Logger.ts","../src/core/GameLoop.ts","../src/entities/Registry.ts","../src/spatial/Grid.ts","../src/utils/RingBuffer.ts","../src/input/InputQueue.ts","../src/network/Network.ts","../src/network/Snapshot.ts","../src/core/Room.ts","../src/core/GameServer.ts","../src/entities/Entity.ts","../src/physics/AABB.ts","../src/physics/Movement.ts","../src/types/protocol.ts"],"names":["defaultLogger","pino","level","process","env","LOG_LEVEL","transport","NODE_ENV","target","options","colorize","translateTime","ignore","undefined","base","package","logger","setLogger","customLogger","createChildLogger","bindings","child","Logger","constructor","debug","objOrMsg","msg","info","warn","error","childLogger","GameLoop","tickRate","tickMs","tickNumber","lastTickTime","running","timeout","handlers","tickTimes","metricsWindowSize","addHandler","handler","push","removeHandler","index","indexOf","splice","start","performance","now","scheduleNextTick","stop","clearTimeout","totalTicks","isRunning","getCurrentTick","getTickRate","getTickMs","getMetrics","length","avgTickTime","maxTickTime","minTickTime","ticksPerSecond","sum","reduce","a","b","avg","Math","max","min","elapsed","drift","nextDelay","setTimeout","tick","tickStart","deltaMs","onTick","tickDuration","recordTickTime","duration","budget","shift","Registry","entities","Map","dirtyEntities","Set","dirtyBuffer","allBuffer","add","entity","has","id","entityId","set","remove","get","delete","markDirty","getDirtyEntities","markClean","clear","getAll","values","size","dirtyCount","forEach","callback","filter","predicate","result","Grid","cellSize","cells","entityCells","getCellKey","worldX","worldY","cellX","floor","cellY","getCell","key","cell","x","y","addEntity","removeEntity","cellKey","moveEntity","oldX","oldY","newX","newY","oldKey","newKey","oldCell","newCell","getNearbyEntities","range","centerCellX","centerCellY","dx","dy","getEntitiesInCell","Array","from","getEntityCell","getCellCount","getEntityCount","RingBuffer","buffer","head","tail","count","capacity","item","pushOverwrite","dropped","peek","isEmpty","isFull","getCapacity","InputQueue","queues","maxQueueSize","getQueue","playerId","queue","input","pop","drain","inputs","clearAll","getTotalSize","total","Network","io","sockets","setServer","registerSocket","socket","unregisterSocket","getSocket","broadcast","event","emit","op","opcode","broadcastToRoom","roomId","to","sendTo","sendToMany","playerIds","getPlayerCount","Snapshot","create","timestamp","Date","map","e","entityToSnapshot","vx","vy","createDelta","Room","rules","registry","grid","loop","inputQueue","network","players","tickCount","startTime","config","maxInputQueueSize","maxEntities","visibilityRange","onRoomCreated","addPlayer","player","onPlayerJoin","removePlayer","onPlayerLeave","spawnEntity","destroyEntity","queueInput","command","getSnapshot","getDeltaSnapshot","onCommand","type","delta","shouldEndRoom","getPlayers","getRegistry","getGrid","getNetwork","getInputQueue","getTickCount","getUptime","getConfig","loopMetrics","uptime","playerCount","entityCount","cellCount","queuedInputs","GameServer","rooms","room","createRoom","Error","destroyRoom","getRoom","getRoomAs","hasRoom","getRooms","getRoomCount","getTotalPlayerCount","roomCount","totalPlayers","stopAll","destroyAll","Entity","dirty","lastUpdate","updatePosition","deltaSec","setVelocity","setPosition","toJSON","AABBCollision","overlaps","aHalfW","width","aHalfH","height","bHalfW","bHalfH","abs","containsPoint","aabb","halfW","halfH","fromEntity","distance","combinedHalfW","combinedHalfH","gapX","gapY","sqrt","overlap","overlapX","overlapY","sign","Movement","integrate","applyVelocity","constrainToBoundary","boundary","clamped","minX","maxX","minY","maxY","normalize","velocityFromDirection","dirX","dirY","speed","normalized","ClientOpcode","ServerOpcode"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Logger utility\n *\n * Wrapper around pino for structured logging.\n * Consumers can override this with their own logger.\n */\n\nimport pino from 'pino';\n\n/**\n * Default logger configuration.\n */\nconst defaultLogger = pino({\n level: process.env.LOG_LEVEL || 'info',\n transport:\n process.env.NODE_ENV === 'development'\n ? {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'HH:MM:ss',\n ignore: 'pid,hostname',\n },\n }\n : undefined,\n base: {\n package: '@gamerstake/game-core',\n },\n});\n\n/**\n * Logger instance.\n * Can be replaced by consumers.\n */\nexport let logger = defaultLogger;\n\n/**\n * Set a custom logger instance.\n *\n * @param customLogger - Custom pino logger\n */\nexport function setLogger(customLogger: pino.Logger): void {\n logger = customLogger;\n}\n\n/**\n * Create a child logger with additional context.\n *\n * @param bindings - Additional context fields\n */\nexport function createChildLogger(\n bindings: Record<string, unknown>,\n): pino.Logger {\n return logger.child(bindings);\n}\n\n/**\n * Logger class for dependency injection.\n */\nexport class Logger {\n private logger: pino.Logger;\n\n constructor(bindings?: Record<string, unknown>) {\n this.logger = bindings ? logger.child(bindings) : logger;\n }\n\n debug(obj: object, msg?: string): void;\n debug(msg: string): void;\n debug(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.debug(objOrMsg);\n } else {\n this.logger.debug(objOrMsg, msg);\n }\n }\n\n info(obj: object, msg?: string): void;\n info(msg: string): void;\n info(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.info(objOrMsg);\n } else {\n this.logger.info(objOrMsg, msg);\n }\n }\n\n warn(obj: object, msg?: string): void;\n warn(msg: string): void;\n warn(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.warn(objOrMsg);\n } else {\n this.logger.warn(objOrMsg, msg);\n }\n }\n\n error(obj: object, msg?: string): void;\n error(msg: string): void;\n error(objOrMsg: object | string, msg?: string): void {\n if (typeof objOrMsg === 'string') {\n this.logger.error(objOrMsg);\n } else {\n this.logger.error(objOrMsg, msg);\n }\n }\n\n child(bindings: Record<string, unknown>): Logger {\n const childLogger = new Logger();\n childLogger.logger = this.logger.child(bindings);\n return childLogger;\n }\n}\n","/**\n * Game Loop\n *\n * Fixed tick rate server loop with drift compensation.\n * Processes inputs, updates state, broadcasts changes.\n */\n\nimport { logger } from '../utils/Logger.js';\nimport type { LoopMetrics } from '../types/index.js';\n\n/**\n * Tick handler interface.\n * Implement this to receive tick callbacks.\n */\nexport interface TickHandler {\n onTick(tickNumber: number, deltaMs: number): void;\n}\n\n/**\n * High-precision game loop using setTimeout with drift compensation.\n */\nexport class GameLoop {\n private readonly tickRate: number;\n private readonly tickMs: number;\n private tickNumber = 0;\n private lastTickTime = 0;\n private running = false;\n private timeout: NodeJS.Timeout | null = null;\n private readonly handlers: TickHandler[] = [];\n\n // Performance metrics\n private tickTimes: number[] = [];\n private readonly metricsWindowSize = 100;\n\n /**\n * Create a new game loop.\n *\n * @param tickRate - Ticks per second (default: 20)\n */\n constructor(tickRate = 20) {\n this.tickRate = tickRate;\n this.tickMs = 1000 / tickRate;\n }\n\n /**\n * Register a tick handler.\n */\n addHandler(handler: TickHandler): void {\n this.handlers.push(handler);\n }\n\n /**\n * Remove a tick handler.\n */\n removeHandler(handler: TickHandler): void {\n const index = this.handlers.indexOf(handler);\n if (index !== -1) {\n this.handlers.splice(index, 1);\n }\n }\n\n /**\n * Start the game loop.\n */\n start(): void {\n if (this.running) {\n logger.warn('Game loop already running');\n return;\n }\n\n this.running = true;\n this.lastTickTime = performance.now();\n this.tickNumber = 0;\n\n logger.info(\n { tickRate: this.tickRate, tickMs: this.tickMs },\n 'Game loop started',\n );\n\n this.scheduleNextTick();\n }\n\n /**\n * Stop the game loop.\n */\n stop(): void {\n this.running = false;\n\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n\n logger.info({ totalTicks: this.tickNumber }, 'Game loop stopped');\n }\n\n /**\n * Check if loop is running.\n */\n isRunning(): boolean {\n return this.running;\n }\n\n /**\n * Get current tick number.\n */\n getCurrentTick(): number {\n return this.tickNumber;\n }\n\n /**\n * Get tick rate (TPS).\n */\n getTickRate(): number {\n return this.tickRate;\n }\n\n /**\n * Get tick duration (ms).\n */\n getTickMs(): number {\n return this.tickMs;\n }\n\n /**\n * Get performance metrics.\n */\n getMetrics(): LoopMetrics {\n if (this.tickTimes.length === 0) {\n return {\n avgTickTime: 0,\n maxTickTime: 0,\n minTickTime: 0,\n ticksPerSecond: 0,\n };\n }\n\n const sum = this.tickTimes.reduce((a, b) => a + b, 0);\n const avg = sum / this.tickTimes.length;\n\n return {\n avgTickTime: avg,\n maxTickTime: Math.max(...this.tickTimes),\n minTickTime: Math.min(...this.tickTimes),\n ticksPerSecond: 1000 / avg,\n };\n }\n\n /**\n * Schedule the next tick with drift compensation.\n */\n private scheduleNextTick(): void {\n if (!this.running) return;\n\n const now = performance.now();\n const elapsed = now - this.lastTickTime;\n const drift = elapsed - this.tickMs;\n\n // Compensate for drift (but never go negative)\n const nextDelay = Math.max(0, this.tickMs - drift);\n\n this.timeout = setTimeout(() => this.tick(), nextDelay);\n }\n\n /**\n * Execute one tick.\n */\n private tick(): void {\n const tickStart = performance.now();\n const deltaMs = tickStart - this.lastTickTime;\n this.lastTickTime = tickStart;\n this.tickNumber++;\n\n try {\n // Call all handlers\n for (const handler of this.handlers) {\n handler.onTick(this.tickNumber, deltaMs);\n }\n } catch (error) {\n logger.error({ error, tick: this.tickNumber }, 'Error in tick handler');\n }\n\n // Record tick processing time\n const tickDuration = performance.now() - tickStart;\n this.recordTickTime(tickDuration);\n\n // Warn if tick took too long (>80% of budget)\n if (tickDuration > this.tickMs * 0.8) {\n logger.warn(\n {\n tickNumber: this.tickNumber,\n duration: tickDuration,\n budget: this.tickMs,\n },\n 'Tick took too long',\n );\n }\n\n // Schedule next tick\n this.scheduleNextTick();\n }\n\n /**\n * Record tick time for metrics.\n */\n private recordTickTime(duration: number): void {\n this.tickTimes.push(duration);\n\n // Keep only last N samples\n if (this.tickTimes.length > this.metricsWindowSize) {\n this.tickTimes.shift();\n }\n }\n}\n","/**\n * Entity Registry\n *\n * Manages entity lifecycle and provides efficient queries.\n */\n\nimport { Entity } from './Entity.js';\nimport { logger } from '../utils/Logger.js';\n\n/**\n * Entity registry with lifecycle management.\n *\n * Provides zero-allocation queries using pre-allocated buffers\n * to minimize GC pressure in hot paths.\n */\nexport class Registry<TEntity extends Entity = Entity> {\n private readonly entities = new Map<string, TEntity>();\n private readonly dirtyEntities = new Set<string>();\n\n // Pre-allocated buffers to avoid allocations in hot paths\n private readonly dirtyBuffer: TEntity[] = [];\n private readonly allBuffer: TEntity[] = [];\n\n /**\n * Add an entity to the registry.\n */\n add(entity: TEntity): void {\n if (this.entities.has(entity.id)) {\n logger.warn({ entityId: entity.id }, 'Entity already exists in registry');\n return;\n }\n\n this.entities.set(entity.id, entity);\n this.dirtyEntities.add(entity.id);\n\n logger.debug({ entityId: entity.id }, 'Entity added to registry');\n }\n\n /**\n * Remove an entity from the registry.\n */\n remove(entityId: string): boolean {\n const entity = this.entities.get(entityId);\n if (!entity) return false;\n\n this.entities.delete(entityId);\n this.dirtyEntities.delete(entityId);\n\n logger.debug({ entityId }, 'Entity removed from registry');\n\n return true;\n }\n\n /**\n * Get an entity by ID.\n */\n get(entityId: string): TEntity | undefined {\n return this.entities.get(entityId);\n }\n\n /**\n * Check if entity exists.\n */\n has(entityId: string): boolean {\n return this.entities.has(entityId);\n }\n\n /**\n * Mark an entity as dirty (needs broadcast).\n */\n markDirty(entityId: string): void {\n if (this.entities.has(entityId)) {\n this.dirtyEntities.add(entityId);\n }\n }\n\n /**\n * Get all dirty entities and clear dirty flags.\n * OPTIMIZED: Reuses buffer array to avoid allocations.\n *\n * @returns Array of dirty entities (reused buffer - don't store reference!)\n */\n getDirtyEntities(): TEntity[] {\n // Reset buffer without reallocation\n this.dirtyBuffer.length = 0;\n\n for (const entityId of this.dirtyEntities) {\n const entity = this.entities.get(entityId);\n if (entity) {\n this.dirtyBuffer.push(entity);\n entity.markClean();\n }\n }\n\n this.dirtyEntities.clear();\n\n return this.dirtyBuffer;\n }\n\n /**\n * Get all entities.\n * OPTIMIZED: Reuses buffer array to avoid allocations.\n *\n * @returns Array of all entities (reused buffer - don't store reference!)\n */\n getAll(): TEntity[] {\n this.allBuffer.length = 0;\n for (const entity of this.entities.values()) {\n this.allBuffer.push(entity);\n }\n return this.allBuffer;\n }\n\n /**\n * Get entity count.\n */\n size(): number {\n return this.entities.size;\n }\n\n /**\n * Get dirty entity count.\n */\n dirtyCount(): number {\n return this.dirtyEntities.size;\n }\n\n /**\n * Clear all entities.\n */\n clear(): void {\n this.entities.clear();\n this.dirtyEntities.clear();\n logger.debug('Registry cleared');\n }\n\n /**\n * Execute callback for each entity.\n */\n forEach(callback: (entity: TEntity) => void): void {\n for (const entity of this.entities.values()) {\n callback(entity);\n }\n }\n\n /**\n * Filter entities by predicate.\n *\n * @param predicate - Filter function\n * @returns New array of matching entities\n */\n filter(predicate: (entity: TEntity) => boolean): TEntity[] {\n const result: TEntity[] = [];\n for (const entity of this.entities.values()) {\n if (predicate(entity)) {\n result.push(entity);\n }\n }\n return result;\n }\n}\n","/**\n * Grid System\n *\n * Spatial partitioning using a fixed-size grid.\n * Enables O(1) lookup for nearby entities.\n */\n\nimport { logger } from '../utils/Logger.js';\n\n/**\n * A single cell in the grid.\n */\ninterface GridCell {\n readonly x: number;\n readonly y: number;\n readonly entities: Set<string>;\n}\n\n/**\n * Grid-based spatial partitioning system.\n *\n * Uses a hash map of cells for O(1) entity tracking.\n * Automatically cleans up empty cells to prevent memory leaks.\n */\nexport class Grid {\n private readonly cellSize: number;\n private readonly cells = new Map<string, GridCell>();\n private readonly entityCells = new Map<string, string>(); // entityId -> cellKey\n\n /**\n * Create a new spatial grid.\n *\n * @param cellSize - Size of each cell in world units (default: 512)\n */\n constructor(cellSize = 512) {\n this.cellSize = cellSize;\n }\n\n /**\n * Convert world coordinates to cell key.\n */\n getCellKey(worldX: number, worldY: number): string {\n const cellX = Math.floor(worldX / this.cellSize);\n const cellY = Math.floor(worldY / this.cellSize);\n return `${cellX},${cellY}`;\n }\n\n /**\n * Get or create a cell at world coordinates.\n */\n private getCell(worldX: number, worldY: number): GridCell {\n const key = this.getCellKey(worldX, worldY);\n let cell = this.cells.get(key);\n\n if (!cell) {\n const cellX = Math.floor(worldX / this.cellSize);\n const cellY = Math.floor(worldY / this.cellSize);\n cell = { x: cellX, y: cellY, entities: new Set() };\n this.cells.set(key, cell);\n }\n\n return cell;\n }\n\n /**\n * Add an entity to the grid.\n */\n addEntity(entityId: string, x: number, y: number): void {\n const cell = this.getCell(x, y);\n cell.entities.add(entityId);\n this.entityCells.set(entityId, this.getCellKey(x, y));\n\n logger.debug(\n { entityId, cellX: cell.x, cellY: cell.y },\n 'Entity added to grid',\n );\n }\n\n /**\n * Remove an entity from the grid.\n */\n removeEntity(entityId: string): void {\n const cellKey = this.entityCells.get(entityId);\n if (!cellKey) return;\n\n const cell = this.cells.get(cellKey);\n if (cell) {\n cell.entities.delete(entityId);\n\n // Clean up empty cells\n if (cell.entities.size === 0) {\n this.cells.delete(cellKey);\n }\n }\n\n this.entityCells.delete(entityId);\n\n logger.debug({ entityId }, 'Entity removed from grid');\n }\n\n /**\n * Move an entity to a new position.\n * Returns true if the entity changed cells.\n */\n moveEntity(\n entityId: string,\n oldX: number,\n oldY: number,\n newX: number,\n newY: number,\n ): boolean {\n const oldKey = this.getCellKey(oldX, oldY);\n const newKey = this.getCellKey(newX, newY);\n\n // Same cell, no update needed\n if (oldKey === newKey) {\n return false;\n }\n\n // Remove from old cell\n const oldCell = this.cells.get(oldKey);\n if (oldCell) {\n oldCell.entities.delete(entityId);\n if (oldCell.entities.size === 0) {\n this.cells.delete(oldKey);\n }\n }\n\n // Add to new cell\n const newCell = this.getCell(newX, newY);\n newCell.entities.add(entityId);\n this.entityCells.set(entityId, newKey);\n\n logger.debug({ entityId, oldKey, newKey }, 'Entity moved to new cell');\n\n return true;\n }\n\n /**\n * Get all entities in nearby cells.\n *\n * @param worldX - World X coordinate\n * @param worldY - World Y coordinate\n * @param range - Range in grid cells (default: 1 = 3x3 area)\n */\n getNearbyEntities(worldX: number, worldY: number, range = 1): string[] {\n const centerCellX = Math.floor(worldX / this.cellSize);\n const centerCellY = Math.floor(worldY / this.cellSize);\n\n const entities: string[] = [];\n\n for (let dx = -range; dx <= range; dx++) {\n for (let dy = -range; dy <= range; dy++) {\n const key = `${centerCellX + dx},${centerCellY + dy}`;\n const cell = this.cells.get(key);\n if (cell) {\n entities.push(...cell.entities);\n }\n }\n }\n\n return entities;\n }\n\n /**\n * Get entities in a specific cell.\n */\n getEntitiesInCell(worldX: number, worldY: number): string[] {\n const cell = this.cells.get(this.getCellKey(worldX, worldY));\n return cell ? Array.from(cell.entities) : [];\n }\n\n /**\n * Get the cell an entity is in.\n */\n getEntityCell(entityId: string): string | undefined {\n return this.entityCells.get(entityId);\n }\n\n /**\n * Get total number of active cells.\n */\n getCellCount(): number {\n return this.cells.size;\n }\n\n /**\n * Get total entities in grid.\n */\n getEntityCount(): number {\n return this.entityCells.size;\n }\n\n /**\n * Clear all cells and entities.\n */\n clear(): void {\n this.cells.clear();\n this.entityCells.clear();\n logger.debug('Grid cleared');\n }\n}\n","/**\n * Ring Buffer\n *\n * O(1) insert and remove, fixed capacity, no allocations in hot path.\n * Used for input queues, position history, etc.\n */\n\nexport class RingBuffer<T> {\n private readonly buffer: (T | undefined)[];\n private head = 0; // Next write position\n private tail = 0; // Next read position\n private count = 0;\n\n constructor(private readonly capacity: number) {\n this.buffer = new Array(capacity);\n }\n\n /**\n * Add item to buffer. O(1)\n * Returns false if buffer is full.\n */\n push(item: T): boolean {\n if (this.count >= this.capacity) {\n return false; // Full\n }\n\n this.buffer[this.head] = item;\n this.head = (this.head + 1) % this.capacity;\n this.count++;\n return true;\n }\n\n /**\n * Add item, overwriting oldest if full. O(1)\n */\n pushOverwrite(item: T): T | undefined {\n let dropped: T | undefined;\n\n if (this.count >= this.capacity) {\n // Drop oldest\n dropped = this.buffer[this.tail];\n this.tail = (this.tail + 1) % this.capacity;\n this.count--;\n }\n\n this.buffer[this.head] = item;\n this.head = (this.head + 1) % this.capacity;\n this.count++;\n\n return dropped;\n }\n\n /**\n * Remove and return oldest item. O(1)\n */\n shift(): T | undefined {\n if (this.count === 0) {\n return undefined;\n }\n\n const item = this.buffer[this.tail];\n this.buffer[this.tail] = undefined; // Help GC\n this.tail = (this.tail + 1) % this.capacity;\n this.count--;\n\n return item;\n }\n\n /**\n * Peek at oldest item without removing. O(1)\n */\n peek(): T | undefined {\n if (this.count === 0) {\n return undefined;\n }\n return this.buffer[this.tail];\n }\n\n /**\n * Get current size.\n */\n size(): number {\n return this.count;\n }\n\n /**\n * Check if empty.\n */\n isEmpty(): boolean {\n return this.count === 0;\n }\n\n /**\n * Check if full.\n */\n isFull(): boolean {\n return this.count >= this.capacity;\n }\n\n /**\n * Clear all items. O(1)\n */\n clear(): void {\n // Don't need to clear array, just reset pointers\n this.head = 0;\n this.tail = 0;\n this.count = 0;\n }\n\n /**\n * Get capacity.\n */\n getCapacity(): number {\n return this.capacity;\n }\n}\n","/**\n * Input Queue\n *\n * Buffers player inputs for processing in the game loop.\n * Uses RingBuffer for O(1) push/pop operations.\n */\n\nimport { logger } from '../utils/Logger.js';\nimport { RingBuffer } from '../utils/RingBuffer.js';\nimport type { Command } from './Command.js';\n\n/**\n * Input queue manager using RingBuffer for O(1) operations.\n *\n * Manages input queues for multiple players, with automatic\n * overflow handling (drops oldest inputs when full).\n */\nexport class InputQueue {\n private readonly queues = new Map<string, RingBuffer<Command>>();\n private readonly maxQueueSize: number;\n\n /**\n * Create a new input queue manager.\n *\n * @param maxQueueSize - Maximum inputs per player (default: 100)\n */\n constructor(maxQueueSize = 100) {\n this.maxQueueSize = maxQueueSize;\n }\n\n /**\n * Get or create a player's queue.\n */\n private getQueue(playerId: string): RingBuffer<Command> {\n let queue = this.queues.get(playerId);\n if (!queue) {\n queue = new RingBuffer<Command>(this.maxQueueSize);\n this.queues.set(playerId, queue);\n }\n return queue;\n }\n\n /**\n * Add an input to a player's queue. O(1)\n */\n push(playerId: string, input: Command): void {\n const queue = this.getQueue(playerId);\n\n // Push with overwrite (drops oldest if full)\n const dropped = queue.pushOverwrite(input);\n if (dropped) {\n logger.debug({ playerId }, 'Input queue overflow, dropped oldest');\n }\n }\n\n /**\n * Get and remove the next input for a player. O(1)\n */\n pop(playerId: string): Command | undefined {\n const queue = this.queues.get(playerId);\n if (!queue) return undefined;\n return queue.shift();\n }\n\n /**\n * Peek at the next input without removing. O(1)\n */\n peek(playerId: string): Command | undefined {\n const queue = this.queues.get(playerId);\n return queue?.peek();\n }\n\n /**\n * Get all inputs for a player and clear.\n */\n drain(playerId: string): Command[] {\n const queue = this.queues.get(playerId);\n if (!queue) return [];\n\n const inputs: Command[] = [];\n while (!queue.isEmpty()) {\n const input = queue.shift();\n if (input) inputs.push(input);\n }\n return inputs;\n }\n\n /**\n * Get queue size for a player.\n */\n size(playerId: string): number {\n return this.queues.get(playerId)?.size() ?? 0;\n }\n\n /**\n * Clear a player's queue.\n */\n clear(playerId: string): void {\n const queue = this.queues.get(playerId);\n if (queue) {\n queue.clear();\n }\n // Don't delete the queue itself - reuse it\n }\n\n /**\n * Remove a player's queue entirely.\n */\n remove(playerId: string): void {\n this.queues.delete(playerId);\n }\n\n /**\n * Clear all queues.\n */\n clearAll(): void {\n this.queues.clear();\n }\n\n /**\n * Get total queued inputs across all players.\n */\n getTotalSize(): number {\n let total = 0;\n for (const queue of this.queues.values()) {\n total += queue.size();\n }\n return total;\n }\n}\n","/**\n * Network Layer\n *\n * Broadcast and send utilities for game events.\n */\n\nimport type { Server, Socket } from 'socket.io';\nimport { logger } from '../utils/Logger.js';\nimport type { NetworkEvent } from '../types/index.js';\n\n/**\n * Network layer for broadcasting game events.\n *\n * Wraps Socket.io with game-specific utilities.\n */\nexport class Network {\n private io: Server | null = null;\n private readonly sockets = new Map<string, Socket>();\n\n /**\n * Set the Socket.io server instance.\n */\n setServer(io: Server): void {\n this.io = io;\n }\n\n /**\n * Register a socket connection.\n */\n registerSocket(playerId: string, socket: Socket): void {\n this.sockets.set(playerId, socket);\n logger.debug({ playerId }, 'Socket registered');\n }\n\n /**\n * Unregister a socket connection.\n */\n unregisterSocket(playerId: string): void {\n this.sockets.delete(playerId);\n logger.debug({ playerId }, 'Socket unregistered');\n }\n\n /**\n * Get a socket by player ID.\n */\n getSocket(playerId: string): Socket | undefined {\n return this.sockets.get(playerId);\n }\n\n /**\n * Broadcast event to all connected players.\n */\n broadcast(event: NetworkEvent): void {\n if (!this.io) {\n logger.warn('Cannot broadcast - no Socket.io server set');\n return;\n }\n\n this.io.emit(event.op, event);\n logger.debug({ opcode: event.op }, 'Broadcast event');\n }\n\n /**\n * Broadcast event to all players in a room.\n */\n broadcastToRoom(roomId: string, event: NetworkEvent): void {\n if (!this.io) {\n logger.warn('Cannot broadcast - no Socket.io server set');\n return;\n }\n\n this.io.to(roomId).emit(event.op, event);\n logger.debug({ roomId, opcode: event.op }, 'Broadcast to room');\n }\n\n /**\n * Send event to a specific player.\n */\n sendTo(playerId: string, event: NetworkEvent): void {\n const socket = this.sockets.get(playerId);\n if (!socket) {\n logger.warn({ playerId }, 'Cannot send - socket not found');\n return;\n }\n\n socket.emit(event.op, event);\n logger.debug({ playerId, opcode: event.op }, 'Sent to player');\n }\n\n /**\n * Send event to multiple players.\n */\n sendToMany(playerIds: string[], event: NetworkEvent): void {\n for (const playerId of playerIds) {\n this.sendTo(playerId, event);\n }\n }\n\n /**\n * Get connected player count.\n */\n getPlayerCount(): number {\n return this.sockets.size;\n }\n\n /**\n * Clear all sockets.\n */\n clear(): void {\n this.sockets.clear();\n }\n}\n","/**\n * Snapshot System\n *\n * Full state snapshots for network synchronization.\n */\n\nimport type { Entity } from '../entities/Entity.js';\nimport type { StateSnapshot, EntitySnapshot } from '../types/index.js';\n\n/**\n * Snapshot generator.\n *\n * Creates full state snapshots for sending to clients.\n * Used for initial sync and periodic full updates.\n */\nexport class Snapshot {\n /**\n * Create a full state snapshot from entities.\n *\n * @param tick - Current tick number\n * @param entities - Array of entities to snapshot\n * @returns Full state snapshot\n */\n static create(tick: number, entities: Entity[]): StateSnapshot {\n return {\n tick,\n timestamp: Date.now(),\n entities: entities.map((e) => this.entityToSnapshot(e)),\n };\n }\n\n /**\n * Convert an entity to a snapshot.\n */\n static entityToSnapshot(entity: Entity): EntitySnapshot {\n return {\n id: entity.id,\n x: entity.x,\n y: entity.y,\n vx: entity.vx,\n vy: entity.vy,\n };\n }\n\n /**\n * Create a delta snapshot (only dirty entities).\n *\n * @param tick - Current tick number\n * @param dirtyEntities - Array of dirty entities\n * @returns Delta snapshot\n */\n static createDelta(tick: number, dirtyEntities: Entity[]): StateSnapshot {\n return {\n tick,\n timestamp: Date.now(),\n entities: dirtyEntities.map((e) => this.entityToSnapshot(e)),\n };\n }\n}\n","/**\n * Room\n *\n * A single game room/match instance.\n * Manages entities, tick loop, and networking.\n */\n\nimport { GameLoop, type TickHandler } from './GameLoop.js';\nimport type { GameRules } from './GameRules.js';\nimport { Entity } from '../entities/Entity.js';\nimport { Registry } from '../entities/Registry.js';\nimport { Grid } from '../spatial/Grid.js';\nimport { InputQueue } from '../input/InputQueue.js';\nimport { Network } from '../network/Network.js';\nimport { Snapshot } from '../network/Snapshot.js';\nimport { logger } from '../utils/Logger.js';\nimport type {\n RoomConfig,\n NetworkEvent,\n StateSnapshot,\n} from '../types/index.js';\nimport type { Command } from '../input/Command.js';\n\n/**\n * A single game room/match.\n *\n * Orchestrates all game systems: tick loop, entities, spatial partitioning,\n * input processing, and network synchronization.\n *\n * @example\n * ```typescript\n * const room = new Room('room-1', new MyGameRules(), {\n * tickRate: 20,\n * cellSize: 512,\n * });\n *\n * room.start();\n *\n * // Add players\n * const player = new Entity('player-1', 100, 100);\n * room.addPlayer(player);\n * ```\n */\nexport class Room<TEntity extends Entity = Entity> implements TickHandler {\n /** Room identifier */\n readonly id: string;\n\n /** Game-specific logic */\n readonly rules: GameRules<TEntity>;\n\n // Core systems\n private readonly registry: Registry<TEntity>;\n private readonly grid: Grid;\n private readonly loop: GameLoop;\n private readonly inputQueue: InputQueue;\n private readonly network: Network;\n\n // State\n private readonly players = new Map<string, TEntity>();\n private tickCount = 0;\n private startTime = 0;\n private readonly config: Required<RoomConfig>;\n\n /**\n * Create a new room.\n *\n * @param id - Unique room identifier\n * @param rules - Game-specific logic\n * @param config - Room configuration\n */\n constructor(id: string, rules: GameRules<TEntity>, config?: RoomConfig) {\n this.id = id;\n this.rules = rules;\n\n // Apply defaults\n this.config = {\n tickRate: config?.tickRate ?? 20,\n cellSize: config?.cellSize ?? 512,\n maxInputQueueSize: config?.maxInputQueueSize ?? 100,\n maxEntities: config?.maxEntities ?? 1000,\n visibilityRange: config?.visibilityRange ?? 1,\n };\n\n // Initialize systems\n this.registry = new Registry<TEntity>();\n this.grid = new Grid(this.config.cellSize);\n this.loop = new GameLoop(this.config.tickRate);\n this.inputQueue = new InputQueue(this.config.maxInputQueueSize);\n this.network = new Network();\n\n // Register tick handler\n this.loop.addHandler(this);\n\n logger.info({ roomId: id, config: this.config }, 'Room created');\n }\n\n /**\n * Start the room (begins tick loop).\n */\n start(): void {\n this.startTime = Date.now();\n\n try {\n this.rules.onRoomCreated(this);\n } catch (error) {\n logger.error({ error, roomId: this.id }, 'Error in onRoomCreated');\n }\n\n this.loop.start();\n logger.info({ roomId: this.id }, 'Room started');\n }\n\n /**\n * Stop the room (ends tick loop).\n */\n stop(): void {\n this.loop.stop();\n logger.info(\n { roomId: this.id, totalTicks: this.tickCount },\n 'Room stopped',\n );\n }\n\n /**\n * Add a player to the room.\n */\n addPlayer(player: TEntity): void {\n if (this.players.has(player.id)) {\n logger.warn({ playerId: player.id }, 'Player already in room');\n return;\n }\n\n this.players.set(player.id, player);\n this.registry.add(player);\n this.grid.addEntity(player.id, player.x, player.y);\n\n try {\n this.rules.onPlayerJoin(this, player);\n } catch (error) {\n logger.error({ error, playerId: player.id }, 'Error in onPlayerJoin');\n }\n\n logger.info({ roomId: this.id, playerId: player.id }, 'Player joined');\n }\n\n /**\n * Remove a player from the room.\n */\n removePlayer(playerId: string): void {\n const player = this.players.get(playerId);\n if (!player) return;\n\n this.players.delete(playerId);\n this.registry.remove(playerId);\n this.grid.removeEntity(playerId);\n this.inputQueue.remove(playerId);\n\n try {\n this.rules.onPlayerLeave(this, playerId);\n } catch (error) {\n logger.error({ error, playerId }, 'Error in onPlayerLeave');\n }\n\n logger.info({ roomId: this.id, playerId }, 'Player left');\n }\n\n /**\n * Spawn a non-player entity.\n */\n spawnEntity(entity: TEntity): void {\n if (this.registry.size() >= this.config.maxEntities) {\n logger.warn({ roomId: this.id }, 'Max entities reached, cannot spawn');\n return;\n }\n\n this.registry.add(entity);\n this.grid.addEntity(entity.id, entity.x, entity.y);\n\n logger.debug({ entityId: entity.id }, 'Entity spawned');\n }\n\n /**\n * Destroy an entity.\n */\n destroyEntity(entityId: string): void {\n const entity = this.registry.get(entityId);\n if (!entity) return;\n\n this.registry.remove(entityId);\n this.grid.removeEntity(entityId);\n\n logger.debug({ entityId }, 'Entity destroyed');\n }\n\n /**\n * Queue a player input.\n */\n queueInput(playerId: string, command: Command): void {\n if (!this.players.has(playerId)) {\n logger.warn({ playerId }, 'Input from non-player');\n return;\n }\n\n this.inputQueue.push(playerId, command);\n }\n\n /**\n * Broadcast event to all players.\n */\n broadcast(event: NetworkEvent): void {\n this.network.broadcastToRoom(this.id, event);\n }\n\n /**\n * Send event to specific player.\n */\n sendTo(playerId: string, event: NetworkEvent): void {\n this.network.sendTo(playerId, event);\n }\n\n /**\n * Get full state snapshot.\n */\n getSnapshot(): StateSnapshot {\n return Snapshot.create(this.tickCount, this.registry.getAll());\n }\n\n /**\n * Get delta snapshot (only dirty entities).\n */\n getDeltaSnapshot(): StateSnapshot {\n return Snapshot.createDelta(\n this.tickCount,\n this.registry.getDirtyEntities(),\n );\n }\n\n /**\n * Main tick function (called by GameLoop).\n */\n onTick(tickNumber: number, deltaMs: number): void {\n this.tickCount = tickNumber;\n\n // Process all queued inputs\n for (const [playerId] of this.players) {\n const inputs = this.inputQueue.drain(playerId);\n for (const input of inputs) {\n try {\n this.rules.onCommand(this, playerId, input);\n } catch (error) {\n logger.error(\n { error, playerId, command: input.type },\n 'Error in onCommand',\n );\n }\n }\n }\n\n // Run game logic\n try {\n this.rules.onTick(this, deltaMs);\n } catch (error) {\n logger.error({ error, tick: tickNumber }, 'Error in onTick');\n }\n\n // Broadcast dirty entities\n const dirtyEntities = this.registry.getDirtyEntities();\n if (dirtyEntities.length > 0) {\n const delta = Snapshot.createDelta(this.tickCount, dirtyEntities);\n this.broadcast({\n op: 'S_UPDATE',\n ...delta,\n });\n }\n\n // Check if room should end\n try {\n if (this.rules.shouldEndRoom(this)) {\n logger.info({ roomId: this.id }, 'Room ending per game rules');\n this.stop();\n }\n } catch (error) {\n logger.error({ error }, 'Error in shouldEndRoom');\n }\n }\n\n // Getters\n\n /**\n * Get all players.\n */\n getPlayers(): Map<string, TEntity> {\n return this.players;\n }\n\n /**\n * Get entity registry.\n */\n getRegistry(): Registry<TEntity> {\n return this.registry;\n }\n\n /**\n * Get spatial grid.\n */\n getGrid(): Grid {\n return this.grid;\n }\n\n /**\n * Get network layer.\n */\n getNetwork(): Network {\n return this.network;\n }\n\n /**\n * Get input queue.\n */\n getInputQueue(): InputQueue {\n return this.inputQueue;\n }\n\n /**\n * Get current tick number.\n */\n getTickCount(): number {\n return this.tickCount;\n }\n\n /**\n * Get uptime in milliseconds.\n */\n getUptime(): number {\n return Date.now() - this.startTime;\n }\n\n /**\n * Check if room is running.\n */\n isRunning(): boolean {\n return this.loop.isRunning();\n }\n\n /**\n * Get room configuration.\n */\n getConfig(): Required<RoomConfig> {\n return { ...this.config };\n }\n\n /**\n * Get room metrics.\n */\n getMetrics() {\n const loopMetrics = this.loop.getMetrics();\n return {\n roomId: this.id,\n tickCount: this.tickCount,\n uptime: this.getUptime(),\n playerCount: this.players.size,\n entityCount: this.registry.size(),\n cellCount: this.grid.getCellCount(),\n queuedInputs: this.inputQueue.getTotalSize(),\n ...loopMetrics,\n };\n }\n}\n","/**\n * Game Server\n *\n * Multi-room game server.\n * Manages room lifecycle and routing.\n */\n\nimport type { Server } from 'socket.io';\nimport { Room } from './Room.js';\nimport type { GameRules } from './GameRules.js';\nimport type { Entity } from '../entities/Entity.js';\nimport { logger } from '../utils/Logger.js';\nimport type { RoomConfig, ServerMetrics } from '../types/index.js';\n\n/**\n * Multi-room game server.\n *\n * Orchestrates multiple game rooms and provides routing\n * for Socket.io connections.\n *\n * @example\n * ```typescript\n * const server = new GameServer();\n * server.setServer(io);\n *\n * const room = server.createRoom('room-1', new MyGameRules());\n *\n * // Later...\n * server.destroyRoom('room-1');\n * ```\n */\nexport class GameServer {\n private readonly rooms = new Map<string, Room>();\n private io: Server | null = null;\n\n /**\n * Set the Socket.io server instance.\n *\n * This should be called before creating rooms to enable\n * network functionality.\n */\n setServer(io: Server): void {\n this.io = io;\n\n // Set server on all existing rooms\n for (const room of this.rooms.values()) {\n room.getNetwork().setServer(io);\n }\n\n logger.info('Socket.io server set');\n }\n\n /**\n * Create a new room.\n *\n * @param id - Unique room identifier\n * @param rules - Game-specific logic\n * @param config - Room configuration\n * @returns The created room\n * @throws If room with same ID already exists\n */\n createRoom<TEntity extends Entity = Entity>(\n id: string,\n rules: GameRules<TEntity>,\n config?: RoomConfig,\n ): Room<TEntity> {\n if (this.rooms.has(id)) {\n throw new Error(`Room ${id} already exists`);\n }\n\n const room = new Room(id, rules, config);\n\n // Set network server if available\n if (this.io) {\n room.getNetwork().setServer(this.io);\n }\n\n this.rooms.set(id, room as Room);\n room.start();\n\n logger.info({ roomId: id }, 'Room created and started');\n\n return room;\n }\n\n /**\n * Destroy a room.\n *\n * Stops the room's tick loop and removes it from the server.\n *\n * @param id - Room identifier\n * @returns True if room was destroyed, false if not found\n */\n destroyRoom(id: string): boolean {\n const room = this.rooms.get(id);\n if (!room) {\n logger.warn({ roomId: id }, 'Cannot destroy - room not found');\n return false;\n }\n\n room.stop();\n this.rooms.delete(id);\n\n logger.info({ roomId: id }, 'Room destroyed');\n\n return true;\n }\n\n /**\n * Get a room by ID.\n */\n getRoom(id: string): Room | undefined {\n return this.rooms.get(id);\n }\n\n /**\n * Get a room with specific entity type.\n *\n * @param id - Room identifier\n * @returns Room cast to specific entity type, or undefined\n */\n getRoomAs<TEntity extends Entity>(id: string): Room<TEntity> | undefined {\n return this.rooms.get(id) as Room<TEntity> | undefined;\n }\n\n /**\n * Check if room exists.\n */\n hasRoom(id: string): boolean {\n return this.rooms.has(id);\n }\n\n /**\n * Get all rooms.\n */\n getRooms(): Map<string, Room> {\n return this.rooms;\n }\n\n /**\n * Get room count.\n */\n getRoomCount(): number {\n return this.rooms.size;\n }\n\n /**\n * Get total player count across all rooms.\n */\n getTotalPlayerCount(): number {\n let total = 0;\n for (const room of this.rooms.values()) {\n total += room.getPlayers().size;\n }\n return total;\n }\n\n /**\n * Get server health metrics.\n */\n getMetrics(): ServerMetrics {\n return {\n roomCount: this.rooms.size,\n totalPlayers: this.getTotalPlayerCount(),\n rooms: Array.from(this.rooms.values()).map((room) => ({\n id: room.id,\n playerCount: room.getPlayers().size,\n entityCount: room.getRegistry().size(),\n tickCount: room.getTickCount(),\n isRunning: room.isRunning(),\n avgTickTime: room.getMetrics().avgTickTime,\n ticksPerSecond: room.getMetrics().ticksPerSecond,\n })),\n };\n }\n\n /**\n * Stop all rooms.\n */\n stopAll(): void {\n logger.info({ roomCount: this.rooms.size }, 'Stopping all rooms');\n\n for (const room of this.rooms.values()) {\n room.stop();\n }\n }\n\n /**\n * Destroy all rooms.\n */\n destroyAll(): void {\n logger.info({ roomCount: this.rooms.size }, 'Destroying all rooms');\n\n for (const room of this.rooms.values()) {\n room.stop();\n }\n\n this.rooms.clear();\n }\n}\n","/**\n * Entity System\n *\n * Base entity class for all game objects.\n */\n\n/**\n * Base entity class.\n * All game objects (players, NPCs, items) extend this.\n *\n * Includes position, velocity, and dirty flag for\n * efficient network synchronization.\n */\nexport class Entity {\n /** Unique entity identifier */\n readonly id: string;\n\n /** World X position */\n x: number;\n\n /** World Y position */\n y: number;\n\n /** Velocity X (units/second) */\n vx: number;\n\n /** Velocity Y (units/second) */\n vy: number;\n\n /** Dirty flag - entity needs to be broadcast */\n dirty: boolean;\n\n /** Last update timestamp */\n lastUpdate: number;\n\n /**\n * Create a new entity.\n *\n * @param id - Unique identifier\n * @param x - Initial X position\n * @param y - Initial Y position\n */\n constructor(id: string, x: number, y: number) {\n this.id = id;\n this.x = x;\n this.y = y;\n this.vx = 0;\n this.vy = 0;\n this.dirty = true; // New entities need to be broadcast\n this.lastUpdate = Date.now();\n }\n\n /**\n * Update position based on velocity and delta time.\n *\n * @param deltaMs - Time since last update (milliseconds)\n */\n updatePosition(deltaMs: number): void {\n if (this.vx !== 0 || this.vy !== 0) {\n const deltaSec = deltaMs / 1000;\n this.x += this.vx * deltaSec;\n this.y += this.vy * deltaSec;\n this.dirty = true;\n this.lastUpdate = Date.now();\n }\n }\n\n /**\n * Set velocity.\n */\n setVelocity(vx: number, vy: number): void {\n if (this.vx !== vx || this.vy !== vy) {\n this.vx = vx;\n this.vy = vy;\n this.dirty = true;\n this.lastUpdate = Date.now();\n }\n }\n\n /**\n * Teleport to position (no velocity integration).\n */\n setPosition(x: number, y: number): void {\n if (this.x !== x || this.y !== y) {\n this.x = x;\n this.y = y;\n this.dirty = true;\n this.lastUpdate = Date.now();\n }\n }\n\n /**\n * Mark entity as clean (after broadcast).\n */\n markClean(): void {\n this.dirty = false;\n }\n\n /**\n * Mark entity as dirty (needs broadcast).\n */\n markDirty(): void {\n this.dirty = true;\n }\n\n /**\n * Get entity as plain object for serialization.\n */\n toJSON(): Record<string, unknown> {\n return {\n id: this.id,\n x: this.x,\n y: this.y,\n vx: this.vx,\n vy: this.vy,\n };\n }\n}\n","/**\n * AABB Collision Detection\n *\n * Axis-Aligned Bounding Box collision detection.\n */\n\nimport type { Entity } from '../entities/Entity.js';\n\n/**\n * Axis-Aligned Bounding Box.\n */\nexport interface AABB {\n x: number; // Center X\n y: number; // Center Y\n width: number; // Total width\n height: number; // Total height\n}\n\n/**\n * AABB collision detection utilities.\n */\nexport class AABBCollision {\n /**\n * Check if two AABBs overlap.\n */\n static overlaps(a: AABB, b: AABB): boolean {\n const aHalfW = a.width / 2;\n const aHalfH = a.height / 2;\n const bHalfW = b.width / 2;\n const bHalfH = b.height / 2;\n\n return (\n Math.abs(a.x - b.x) < aHalfW + bHalfW &&\n Math.abs(a.y - b.y) < aHalfH + bHalfH\n );\n }\n\n /**\n * Check if a point is inside an AABB.\n */\n static containsPoint(aabb: AABB, x: number, y: number): boolean {\n const halfW = aabb.width / 2;\n const halfH = aabb.height / 2;\n\n return (\n x >= aabb.x - halfW &&\n x <= aabb.x + halfW &&\n y >= aabb.y - halfH &&\n y <= aabb.y + halfH\n );\n }\n\n /**\n * Create AABB from entity.\n */\n static fromEntity(entity: Entity, width: number, height: number): AABB {\n return {\n x: entity.x,\n y: entity.y,\n width,\n height,\n };\n }\n\n /**\n * Get the distance between two AABBs.\n * Returns 0 if overlapping.\n */\n static distance(a: AABB, b: AABB): number {\n const dx = Math.abs(a.x - b.x);\n const dy = Math.abs(a.y - b.y);\n const combinedHalfW = (a.width + b.width) / 2;\n const combinedHalfH = (a.height + b.height) / 2;\n\n const gapX = Math.max(0, dx - combinedHalfW);\n const gapY = Math.max(0, dy - combinedHalfH);\n\n return Math.sqrt(gapX * gapX + gapY * gapY);\n }\n\n /**\n * Compute the overlap amount between two AABBs.\n * Returns { x: 0, y: 0 } if not overlapping.\n */\n static overlap(a: AABB, b: AABB): { x: number; y: number } {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n\n const combinedHalfW = (a.width + b.width) / 2;\n const combinedHalfH = (a.height + b.height) / 2;\n\n const overlapX = combinedHalfW - Math.abs(dx);\n const overlapY = combinedHalfH - Math.abs(dy);\n\n if (overlapX > 0 && overlapY > 0) {\n return {\n x: overlapX * Math.sign(dx),\n y: overlapY * Math.sign(dy),\n };\n }\n\n return { x: 0, y: 0 };\n }\n}\n","/**\n * Movement Physics\n *\n * Velocity integration and boundary constraints.\n */\n\nimport type { Entity } from '../entities/Entity.js';\n\n/**\n * Boundary constraints for movement.\n */\nexport interface Boundary {\n minX: number;\n maxX: number;\n minY: number;\n maxY: number;\n}\n\n/**\n * Movement physics utilities.\n */\nexport class Movement {\n /**\n * Update entity position based on velocity.\n *\n * @param entity - Entity to update\n * @param deltaMs - Time delta in milliseconds\n */\n static integrate(entity: Entity, deltaMs: number): void {\n if (entity.vx === 0 && entity.vy === 0) return;\n\n const deltaSec = deltaMs / 1000;\n entity.x += entity.vx * deltaSec;\n entity.y += entity.vy * deltaSec;\n entity.markDirty();\n }\n\n /**\n * Apply velocity to entity.\n */\n static applyVelocity(entity: Entity, vx: number, vy: number): void {\n entity.setVelocity(vx, vy);\n }\n\n /**\n * Stop entity movement.\n */\n static stop(entity: Entity): void {\n entity.setVelocity(0, 0);\n }\n\n /**\n * Constrain entity to boundary.\n *\n * @param entity - Entity to constrain\n * @param boundary - Boundary constraints\n * @returns True if entity was clamped\n */\n static constrainToBoundary(entity: Entity, boundary: Boundary): boolean {\n let clamped = false;\n\n if (entity.x < boundary.minX) {\n entity.x = boundary.minX;\n entity.vx = 0;\n clamped = true;\n } else if (entity.x > boundary.maxX) {\n entity.x = boundary.maxX;\n entity.vx = 0;\n clamped = true;\n }\n\n if (entity.y < boundary.minY) {\n entity.y = boundary.minY;\n entity.vy = 0;\n clamped = true;\n } else if (entity.y > boundary.maxY) {\n entity.y = boundary.maxY;\n entity.vy = 0;\n clamped = true;\n }\n\n if (clamped) {\n entity.markDirty();\n }\n\n return clamped;\n }\n\n /**\n * Calculate distance between two entities.\n */\n static distance(a: Entity, b: Entity): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Normalize a direction vector.\n */\n static normalize(x: number, y: number): { x: number; y: number } {\n const length = Math.sqrt(x * x + y * y);\n if (length === 0) return { x: 0, y: 0 };\n return {\n x: x / length,\n y: y / length,\n };\n }\n\n /**\n * Calculate velocity from direction and speed.\n */\n static velocityFromDirection(\n dirX: number,\n dirY: number,\n speed: number,\n ): { vx: number; vy: number } {\n const normalized = this.normalize(dirX, dirY);\n return {\n vx: normalized.x * speed,\n vy: normalized.y * speed,\n };\n }\n}\n","/**\n * Network protocol definitions.\n *\n * Opcodes and message formats for client-server communication.\n */\n\n/**\n * Client → Server opcodes.\n */\nexport enum ClientOpcode {\n /** Player movement input */\n C_MOVE = 'C_MOVE',\n\n /** Player stop input */\n C_STOP = 'C_STOP',\n\n /** Generic action */\n C_ACTION = 'C_ACTION',\n}\n\n/**\n * Server → Client opcodes.\n */\nexport enum ServerOpcode {\n /** Initial state on join */\n S_INIT = 'S_INIT',\n\n /** Delta state update */\n S_UPDATE = 'S_UPDATE',\n\n /** Entity spawned */\n S_SPAWN = 'S_SPAWN',\n\n /** Entity destroyed */\n S_DESPAWN = 'S_DESPAWN',\n\n /** Custom game event */\n S_EVENT = 'S_EVENT',\n\n /** Error message */\n S_ERROR = 'S_ERROR',\n}\n\n/**\n * Client movement input.\n */\nexport interface C_Move {\n op: ClientOpcode.C_MOVE;\n seq: number;\n dir: { x: number; y: number };\n timestamp: number;\n}\n\n/**\n * Client stop input.\n */\nexport interface C_Stop {\n op: ClientOpcode.C_STOP;\n seq: number;\n timestamp: number;\n}\n\n/**\n * Client action input.\n */\nexport interface C_Action {\n op: ClientOpcode.C_ACTION;\n seq: number;\n action: string;\n data?: Record<string, unknown>;\n timestamp: number;\n}\n\n/**\n * Server initial state.\n */\nexport interface S_Init {\n op: ServerOpcode.S_INIT;\n playerId: string;\n tick: number;\n entities: Array<{\n id: string;\n x: number;\n y: number;\n vx: number;\n vy: number;\n }>;\n}\n\n/**\n * Server delta update.\n */\nexport interface S_Update {\n op: ServerOpcode.S_UPDATE;\n tick: number;\n entities: Array<{\n id: string;\n x: number;\n y: number;\n vx: number;\n vy: number;\n seq?: number; // Echo client seq for reconciliation\n }>;\n}\n\n/**\n * Server entity spawn.\n */\nexport interface S_Spawn {\n op: ServerOpcode.S_SPAWN;\n entity: {\n id: string;\n x: number;\n y: number;\n vx: number;\n vy: number;\n };\n}\n\n/**\n * Server entity despawn.\n */\nexport interface S_Despawn {\n op: ServerOpcode.S_DESPAWN;\n entityId: string;\n reason?: string;\n}\n\n/**\n * Server custom event.\n */\nexport interface S_Event {\n op: ServerOpcode.S_EVENT;\n event: string;\n data?: Record<string, unknown>;\n}\n\n/**\n * Server error message.\n */\nexport interface S_Error {\n op: ServerOpcode.S_ERROR;\n code: string;\n message: string;\n}\n\n/**\n * Union of all client messages.\n */\nexport type ClientMessage = C_Move | C_Stop | C_Action;\n\n/**\n * Union of all server messages.\n */\nexport type ServerMessage =\n | S_Init\n | S_Update\n | S_Spawn\n | S_Despawn\n | S_Event\n | S_Error;\n"]}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Simple Game - Manual Testing Example
|
|
2
|
+
|
|
3
|
+
This is a minimal multiplayer game for **manually testing** the `@gamerstake/game-core` package.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
- Creates a persistent game world (1000x1000 units)
|
|
8
|
+
- Allows multiple players to connect
|
|
9
|
+
- Players can move around with velocity-based movement
|
|
10
|
+
- Spawns static obstacle entities
|
|
11
|
+
- Broadcasts game state updates at 20 TPS
|
|
12
|
+
- Logs metrics and player activity
|
|
13
|
+
|
|
14
|
+
## Running the Test
|
|
15
|
+
|
|
16
|
+
### 1. Build the package first
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cd /Users/nbjekovic/GAMESTAKES/gamerstake/packages/game-core
|
|
20
|
+
pnpm build
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 2. Start the server
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
node examples/simple-game/server.js
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
You should see:
|
|
30
|
+
```
|
|
31
|
+
Game server started on port 3000
|
|
32
|
+
Room: test-room
|
|
33
|
+
Tick rate: 20 TPS
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 3. In another terminal, start a client
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node examples/simple-game/client.js
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The client will:
|
|
43
|
+
- Connect to the server
|
|
44
|
+
- Receive initial game state
|
|
45
|
+
- Automatically move around in different patterns
|
|
46
|
+
- Log position updates
|
|
47
|
+
|
|
48
|
+
### 4. (Optional) Start more clients
|
|
49
|
+
|
|
50
|
+
Open additional terminals and run more clients:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
node examples/simple-game/client.js
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Each client is a separate player. You'll see them join in the server logs!
|
|
57
|
+
|
|
58
|
+
## What to Watch For
|
|
59
|
+
|
|
60
|
+
### On the Server
|
|
61
|
+
|
|
62
|
+
- Players connecting/disconnecting
|
|
63
|
+
- Movement commands being processed
|
|
64
|
+
- Game state updates being broadcast
|
|
65
|
+
- Tick performance metrics (should be <40ms)
|
|
66
|
+
|
|
67
|
+
### On the Client
|
|
68
|
+
|
|
69
|
+
- Initial state received
|
|
70
|
+
- Position updates as player moves
|
|
71
|
+
- Other players joining/leaving
|
|
72
|
+
|
|
73
|
+
## Testing Different Scenarios
|
|
74
|
+
|
|
75
|
+
### Test 1: Movement
|
|
76
|
+
|
|
77
|
+
The client automatically cycles through movement patterns:
|
|
78
|
+
- Right, Down, Left, Up
|
|
79
|
+
- Diagonal movement
|
|
80
|
+
- Stop command
|
|
81
|
+
- Custom actions
|
|
82
|
+
|
|
83
|
+
### Test 2: Multiple Players
|
|
84
|
+
|
|
85
|
+
Run 3-5 clients simultaneously to test:
|
|
86
|
+
- Multiple players in the same room
|
|
87
|
+
- State synchronization
|
|
88
|
+
- Network broadcasting
|
|
89
|
+
- Server performance
|
|
90
|
+
|
|
91
|
+
### Test 3: Performance
|
|
92
|
+
|
|
93
|
+
Monitor the server metrics logs:
|
|
94
|
+
```
|
|
95
|
+
Room: X players, Y entities, Avg tick: Zms
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Tick time should stay well below 50ms (the tick budget for 20 TPS).
|
|
99
|
+
|
|
100
|
+
### Test 4: Connection Stability
|
|
101
|
+
|
|
102
|
+
Try:
|
|
103
|
+
- Stopping clients (Ctrl+C) and reconnecting
|
|
104
|
+
- Stopping the server and restarting
|
|
105
|
+
- Network interruptions
|
|
106
|
+
|
|
107
|
+
## Customizing the Test
|
|
108
|
+
|
|
109
|
+
### Change Server Port
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
PORT=4000 node examples/simple-game/server.js
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
SERVER_URL=http://localhost:4000 node examples/simple-game/client.js
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Modify Game Rules
|
|
120
|
+
|
|
121
|
+
Edit `server.ts` and change the `SimpleGameRules` class:
|
|
122
|
+
- Spawn different entities
|
|
123
|
+
- Change movement speed
|
|
124
|
+
- Add collision detection
|
|
125
|
+
- Implement game logic
|
|
126
|
+
|
|
127
|
+
### Add More Commands
|
|
128
|
+
|
|
129
|
+
In `server.ts`, add new socket event handlers:
|
|
130
|
+
```typescript
|
|
131
|
+
socket.on('C_CUSTOM', (data) => {
|
|
132
|
+
room.queueInput(playerId, {
|
|
133
|
+
seq: data.seq,
|
|
134
|
+
type: 'custom',
|
|
135
|
+
// ...custom data
|
|
136
|
+
timestamp: Date.now(),
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Then handle it in `onCommand()`.
|
|
142
|
+
|
|
143
|
+
## Troubleshooting
|
|
144
|
+
|
|
145
|
+
### "Cannot find module './dist/index.js'"
|
|
146
|
+
|
|
147
|
+
You need to build the package first:
|
|
148
|
+
```bash
|
|
149
|
+
pnpm build
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### "Port 3000 already in use"
|
|
153
|
+
|
|
154
|
+
Change the port:
|
|
155
|
+
```bash
|
|
156
|
+
PORT=4000 node examples/simple-game/server.js
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Client can't connect
|
|
160
|
+
|
|
161
|
+
Make sure:
|
|
162
|
+
1. Server is running
|
|
163
|
+
2. Port matches (default 3000)
|
|
164
|
+
3. No firewall blocking
|
|
165
|
+
|
|
166
|
+
## Next Steps
|
|
167
|
+
|
|
168
|
+
After manual testing works, you can:
|
|
169
|
+
|
|
170
|
+
1. **Build a real game** - Use this as a template
|
|
171
|
+
2. **Add collision detection** - Use `AABBCollision` from game-core
|
|
172
|
+
3. **Implement game mechanics** - Shooting, collecting, scoring, etc.
|
|
173
|
+
4. **Build a client UI** - Web-based game client with Phaser/Three.js
|
|
174
|
+
5. **Deploy** - Add Docker, environment configs, monitoring
|
|
175
|
+
|
|
176
|
+
See the **Developer Guide** for more advanced usage!
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual Testing Client
|
|
3
|
+
*
|
|
4
|
+
* A simple client for testing the game server.
|
|
5
|
+
* Connects to the server and simulates player movement.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { io, Socket } from 'socket.io-client';
|
|
9
|
+
|
|
10
|
+
const SERVER_URL = process.env.SERVER_URL || 'http://localhost:3000';
|
|
11
|
+
|
|
12
|
+
let socket: Socket;
|
|
13
|
+
let seq = 0;
|
|
14
|
+
let playerId: string | null = null;
|
|
15
|
+
let entities: Map<string, any> = new Map();
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Connection
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
console.log('Connecting to server:', SERVER_URL);
|
|
22
|
+
|
|
23
|
+
socket = io(SERVER_URL, {
|
|
24
|
+
transports: ['websocket'],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
socket.on('connect', () => {
|
|
28
|
+
console.log('Connected! Socket ID:', socket.id);
|
|
29
|
+
console.log('');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
socket.on('disconnect', () => {
|
|
33
|
+
console.log('Disconnected from server');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
socket.on('connect_error', (error) => {
|
|
37
|
+
console.error('Connection error:', error.message);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Server Events
|
|
43
|
+
// ============================================================================
|
|
44
|
+
|
|
45
|
+
socket.on('S_INIT', (data) => {
|
|
46
|
+
playerId = data.playerId;
|
|
47
|
+
console.log('Initialized! Player ID:', playerId);
|
|
48
|
+
console.log('Initial entities:', data.entities.length);
|
|
49
|
+
|
|
50
|
+
// Store initial entities
|
|
51
|
+
data.entities.forEach((entity: any) => {
|
|
52
|
+
entities.set(entity.id, entity);
|
|
53
|
+
if (entity.id === playerId) {
|
|
54
|
+
console.log(` You are at (${entity.x.toFixed(0)}, ${entity.y.toFixed(0)})`);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
console.log('');
|
|
59
|
+
console.log('Starting movement test...');
|
|
60
|
+
console.log('');
|
|
61
|
+
|
|
62
|
+
// Start automated movement test
|
|
63
|
+
setTimeout(() => startMovementTest(), 1000);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
socket.on('S_UPDATE', (data) => {
|
|
67
|
+
// Update entities
|
|
68
|
+
data.entities?.forEach((entity: any) => {
|
|
69
|
+
entities.set(entity.id, entity);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Remove deleted entities
|
|
73
|
+
data.deleted?.forEach((id: string) => {
|
|
74
|
+
entities.delete(id);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Log player position every few updates
|
|
78
|
+
if (seq % 20 === 0 && playerId) {
|
|
79
|
+
const player = entities.get(playerId);
|
|
80
|
+
if (player) {
|
|
81
|
+
console.log(`Position: (${player.x.toFixed(0)}, ${player.y.toFixed(0)}) | ` +
|
|
82
|
+
`Velocity: (${player.vx.toFixed(0)}, ${player.vy.toFixed(0)}) | ` +
|
|
83
|
+
`Total entities: ${entities.size}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
socket.on('PLAYER_JOINED', (data) => {
|
|
89
|
+
console.log(`Player ${data.playerId} joined at (${data.x.toFixed(0)}, ${data.y.toFixed(0)})`);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
socket.on('PLAYER_LEFT', (data) => {
|
|
93
|
+
console.log(`Player ${data.playerId} left`);
|
|
94
|
+
entities.delete(data.playerId);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
socket.on('PLAYER_ACTION', (data) => {
|
|
98
|
+
console.log(`Player ${data.playerId} performed action: ${data.action}`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// Input Commands
|
|
103
|
+
// ============================================================================
|
|
104
|
+
|
|
105
|
+
function move(dirX: number, dirY: number) {
|
|
106
|
+
socket.emit('C_MOVE', {
|
|
107
|
+
seq: ++seq,
|
|
108
|
+
dir: { x: dirX, y: dirY },
|
|
109
|
+
timestamp: Date.now(),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function stop() {
|
|
114
|
+
socket.emit('C_STOP', {
|
|
115
|
+
seq: ++seq,
|
|
116
|
+
timestamp: Date.now(),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function action(actionName: string, data?: any) {
|
|
121
|
+
socket.emit('C_ACTION', {
|
|
122
|
+
seq: ++seq,
|
|
123
|
+
action: actionName,
|
|
124
|
+
data,
|
|
125
|
+
timestamp: Date.now(),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ============================================================================
|
|
130
|
+
// Automated Movement Test
|
|
131
|
+
// ============================================================================
|
|
132
|
+
|
|
133
|
+
let testPhase = 0;
|
|
134
|
+
|
|
135
|
+
function startMovementTest() {
|
|
136
|
+
setInterval(() => {
|
|
137
|
+
testPhase++;
|
|
138
|
+
|
|
139
|
+
switch (testPhase % 8) {
|
|
140
|
+
case 0:
|
|
141
|
+
console.log('Moving right');
|
|
142
|
+
move(1, 0);
|
|
143
|
+
break;
|
|
144
|
+
case 1:
|
|
145
|
+
console.log('Moving down');
|
|
146
|
+
move(0, 1);
|
|
147
|
+
break;
|
|
148
|
+
case 2:
|
|
149
|
+
console.log('Moving left');
|
|
150
|
+
move(-1, 0);
|
|
151
|
+
break;
|
|
152
|
+
case 3:
|
|
153
|
+
console.log('Moving up');
|
|
154
|
+
move(0, -1);
|
|
155
|
+
break;
|
|
156
|
+
case 4:
|
|
157
|
+
console.log('Moving diagonal');
|
|
158
|
+
move(1, -1);
|
|
159
|
+
break;
|
|
160
|
+
case 5:
|
|
161
|
+
console.log('Stopping');
|
|
162
|
+
stop();
|
|
163
|
+
break;
|
|
164
|
+
case 6:
|
|
165
|
+
console.log('Performing action');
|
|
166
|
+
action('jump', { height: 100 });
|
|
167
|
+
break;
|
|
168
|
+
case 7:
|
|
169
|
+
console.log('Circling...');
|
|
170
|
+
move(0.707, 0.707);
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}, 3000); // Change direction every 3 seconds
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ============================================================================
|
|
177
|
+
// CLI Info
|
|
178
|
+
// ============================================================================
|
|
179
|
+
|
|
180
|
+
console.log('');
|
|
181
|
+
console.log('═══════════════════════════════════════════════════════════');
|
|
182
|
+
console.log(' Game Core - Manual Test Client');
|
|
183
|
+
console.log('═══════════════════════════════════════════════════════════');
|
|
184
|
+
console.log('');
|
|
185
|
+
console.log(' This client will:');
|
|
186
|
+
console.log(' 1. Connect to the game server');
|
|
187
|
+
console.log(' 2. Receive initial game state');
|
|
188
|
+
console.log(' 3. Automatically move around to test the engine');
|
|
189
|
+
console.log('');
|
|
190
|
+
console.log(' Watch the server logs to see the tick processing!');
|
|
191
|
+
console.log('');
|
|
192
|
+
console.log('═══════════════════════════════════════════════════════════');
|
|
193
|
+
console.log('');
|
|
194
|
+
|
|
195
|
+
// Graceful shutdown
|
|
196
|
+
process.on('SIGINT', () => {
|
|
197
|
+
console.log('');
|
|
198
|
+
console.log('Disconnecting...');
|
|
199
|
+
socket.disconnect();
|
|
200
|
+
process.exit(0);
|
|
201
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "game-core-manual-test",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Manual testing example for @gamerstake/game-core",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"server": "node server.js",
|
|
9
|
+
"client": "node client.js",
|
|
10
|
+
"test": "npm run server & sleep 2 && npm run client"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["game-core", "testing", "example"],
|
|
13
|
+
"author": "GamerStake"
|
|
14
|
+
}
|