shoehive
Version:
WebSocket-based multiplayer game framework for real-time, event-driven gameplay
166 lines (165 loc) • 6.35 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Lobby = void 0;
const EventTypes_1 = require("../events/EventTypes");
/**
* ✅ Attribute Support
*
* The Lobby class manages the lobby state and broadcasts updates to connected players.
* It is responsible for tracking available games and tables, and notifying players
* when these change.
*/
class Lobby {
constructor(eventBus, gameManager, tableFactory) {
this.eventBus = eventBus;
this.gameManager = gameManager;
this.tableFactory = tableFactory;
this.setupEventListeners();
this.attributes = new Map();
}
/**
* Sets up event listeners for lobby-related events.
* This listens for table creation, table emptying, and player attribute changes
* that would affect lobby display.
*/
setupEventListeners() {
this.eventBus.on(EventTypes_1.TABLE_EVENTS.CREATED, () => {
this.broadcastLobbyUpdate();
});
this.eventBus.on(EventTypes_1.TABLE_EVENTS.EMPTY, () => {
this.broadcastLobbyUpdate();
});
// Listen for player attribute changes that might affect lobby data
this.eventBus.on(EventTypes_1.PLAYER_EVENTS.ATTRIBUTE_CHANGED, (player, key, value) => {
// If the player is at a table and the attribute might affect lobby display
const table = player.getTable();
if (!table)
return;
// Get the game ID for this table
const gameId = table.getAttribute("gameId");
if (!gameId)
return;
// Get the game definition
const gameDefinition = this.gameManager.getGameDefinition(gameId);
if (!gameDefinition)
return;
// Use the game-specific lobby relevant attributes, or fall back to defaults
const lobbyRelevantAttributes = gameDefinition.lobbyRelevantPlayerAttributes ||
["name", "avatar", "isReady", "status"];
// Only update the lobby if the attribute is relevant to lobby display
if (lobbyRelevantAttributes.includes(key)) {
this.broadcastLobbyUpdate();
}
});
// Listen for table attribute changes that might affect lobby display
this.eventBus.on(EventTypes_1.TABLE_EVENTS.ATTRIBUTE_CHANGED, () => {
this.broadcastLobbyUpdate();
});
}
/**
* Creates a new table for a game.
*
* @param gameId The ID of the game.
* @param options Optional options for the table.
* @returns The newly created table, or null if the game definition is not found.
*/
createTable(gameId, options) {
const gameDefinition = this.gameManager.getGameDefinition(gameId);
if (!gameDefinition)
return null;
const table = this.tableFactory.createTable(gameDefinition.defaultSeats, gameDefinition.maxSeatsPerPlayer);
table.setAttribute("gameId", gameId);
table.setAttribute("gameName", gameDefinition.name);
if (options) {
table.setAttribute("options", options);
}
// Call the setupTable function if provided in game definition options
if (gameDefinition.options?.setupTable && typeof gameDefinition.options.setupTable === 'function') {
gameDefinition.options.setupTable(table);
}
return table;
}
/**
* Broadcasts a lobby update to all players.
*/
broadcastLobbyUpdate() {
const lobbyState = {
games: this.gameManager.getAvailableGames(),
tables: this.gameManager.getAllTables().map(table => table.getTableMetadata())
};
this.eventBus.emit(EventTypes_1.LOBBY_EVENTS.UPDATED, lobbyState);
}
/**
* Broadcasts a lobby update to all players.
* This method can be called externally to force a lobby update.
*/
updateLobbyState() {
this.broadcastLobbyUpdate();
}
/**
* Set a single attribute on the lobby 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.LOBBY_EVENTS.ATTRIBUTE_CHANGED, 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.LOBBY_EVENTS.ATTRIBUTES_CHANGED, this, changedKeys, attributes);
// Also emit individual events for backward compatibility
for (const key of changedKeys) {
this.eventBus.emit(EventTypes_1.LOBBY_EVENTS.ATTRIBUTE_CHANGED, this, key, attributes[key]);
}
}
}
/**
* Get a single attribute from the lobby.
* @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 lobby.
* @returns An object containing all lobby attributes
*/
getAttributes() {
return Object.fromEntries(this.attributes.entries());
}
/**
* Check if the lobby 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);
}
/**
* Get the number of tables in the lobby.
* @returns The number of tables in the lobby
*/
getTableCount() {
return this.gameManager.getAllTables().length;
}
}
exports.Lobby = Lobby;