UNPKG

shoehive

Version:

WebSocket-based multiplayer game framework for real-time, event-driven gameplay

165 lines (164 loc) 5.74 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Player = void 0; const EventTypes_1 = require("../events/EventTypes"); const WebSocket = __importStar(require("ws")); const crypto_1 = __importDefault(require("crypto")); /** * Represents a connected client in the game. * * ✅ Attribute Support * * The Player class handles communication with the client and keeps track * of the player's current table and custom attributes. * */ class Player { constructor(socket, eventBus, id) { this.table = null; this.attributes = new Map(); this.disconnectCallbacks = []; this.id = id || crypto_1.default.randomUUID(); this.socket = socket; this.eventBus = eventBus; this.setupSocketListeners(); } setupSocketListeners() { this.socket.on('close', () => { this.eventBus.emit(EventTypes_1.PLAYER_EVENTS.DISCONNECTED, { player: this }); // Call all disconnect callbacks this.disconnectCallbacks.forEach((callback) => callback()); }); this.socket.on('error', (error) => { console.error(`Socket error for player ${this.id}:`, error); }); } /** * Register a callback to be called when the player disconnects * @param callback The function to call when the player disconnects */ onDisconnect({ callback }) { this.disconnectCallbacks.push(callback); } sendMessage({ message }) { if (this.socket.readyState === WebSocket.WebSocket.OPEN) { this.socket.send(JSON.stringify(message)); } } /** * Updates the socket connection for this player. * Useful for handling reconnections without losing player state. * @param socket The new WebSocket connection */ setSocket({ socket }) { this.socket = socket; this.setupSocketListeners(); } setTable({ table }) { this.table = table; } getTable() { return this.table; } /** * Set a single attribute on the player and emit an event for the change. * * @param key The attribute name * @param value The attribute value * @param notify Whether to emit an event (defaults to true) */ setAttribute({ key, value, notify = true, }) { this.attributes.set(key, value); if (notify) { this.eventBus.emit(EventTypes_1.PLAYER_EVENTS.ATTRIBUTE_CHANGED, { player: this, key, value }); } } /** * Set multiple attributes at once and emit a single event. * This is more efficient than calling setAttribute multiple times. * * @param attributes Object containing attribute key-value pairs */ setAttributes({ attributes }) { const changedKeys = []; // Set all attributes first for (const [key, value] of Object.entries(attributes)) { this.attributes.set(key, value); changedKeys.push(key); } // Then emit a single event for all changes if (changedKeys.length > 0) { this.eventBus.emit(EventTypes_1.PLAYER_EVENTS.ATTRIBUTES_CHANGED, { player: this, changedKeys, attributes, }); // Also emit individual events for backward compatibility for (const key of changedKeys) { this.eventBus.emit(EventTypes_1.PLAYER_EVENTS.ATTRIBUTE_CHANGED, { player: this, key, value: attributes[key], }); } } } /** * Get a single attribute from the player. * @param key - The key of the attribute to get * @returns The value of the attribute, or undefined if it doesn't exist */ getAttribute({ key }) { return this.attributes.get(key); } /** * Get all attributes from the player. * @returns An object containing all player attributes */ getAttributes() { return Object.fromEntries(this.attributes.entries()); } /** * Check if the player has an attribute. * @param key - The key of the attribute to check * @returns True if the attribute exists, false otherwise */ hasAttribute({ key }) { return this.attributes.has(key); } /** * Disconnect the player from the server. */ disconnect() { if (this.socket.readyState === WebSocket.WebSocket.OPEN) { this.socket.close(); } } } exports.Player = Player;