shoehive
Version:
WebSocket-based multiplayer game framework for real-time, event-driven gameplay
263 lines (262 loc) • 9.85 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageRouter = void 0;
const index_1 = require("../core/commands/index");
class MessageRouter {
constructor(eventBus) {
this.eventBus = eventBus;
this.commandHandlers = new Map();
// Register built-in command handlers
this.registerStateCommandHandlers();
this.registerLobbyCommandHandlers();
this.registerTableCommandHandlers();
}
/**
* Register a command handler for a specific action. For example, if you
* want a user to be able to make a choice, you could register `game:choice:make`
* and then handle it in your game logic.
* @param action - The action to register the handler for
* @param handler - The handler function to be called when the action is received
*/
registerCommandHandler({ action, handler, }) {
this.commandHandlers.set(action, handler);
}
/**
* Register handlers for state request commands
*/
registerStateCommandHandlers() {
// Player state
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.PLAYER.GET_STATE,
handler: (player, data) => {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.PLAYER.STATE,
data: {
id: player.id,
attributes: player.getAttributes(),
},
},
});
},
});
// Table state
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.TABLE.GET_STATE,
handler: (player, data) => {
const table = player.getTable();
if (table) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.TABLE.STATE,
data: table.getTableState({}),
},
});
}
else {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'You are not at a table',
},
});
}
},
});
// Lobby state
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.LOBBY.GET_STATE,
handler: (player, data) => {
this.eventBus.emit('request:lobby:state', { player });
},
});
}
/**
* Register handlers for lobby commands
*/
registerLobbyCommandHandlers() {
// Join table
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.LOBBY.JOIN_TABLE,
handler: (player, data) => {
if (!data.tableId) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'Missing tableId parameter',
},
});
return;
}
this.eventBus.emit('request:table:join', { player, tableId: data.tableId });
},
});
// Create table
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.LOBBY.CREATE_TABLE,
handler: (player, data) => {
if (!data.gameId) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'Missing gameId parameter',
},
});
return;
}
this.eventBus.emit('request:table:create', {
player,
gameId: data.gameId,
options: data.options,
});
},
});
}
/**
* Register handlers for table commands
*/
registerTableCommandHandlers() {
// Join table
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.TABLE.JOIN,
handler: (player, data) => {
if (!data.tableId) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'Missing tableId parameter',
},
});
return;
}
this.eventBus.emit('request:table:join', { player, tableId: data.tableId });
},
});
// Leave table
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.TABLE.LEAVE,
handler: (player, data) => {
const table = player.getTable();
if (!table) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'You are not at a table',
},
});
return;
}
this.eventBus.emit('request:table:leave', { player, tableId: table.id });
},
});
// Create table
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.TABLE.CREATE,
handler: (player, data) => {
if (!data.gameId) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'Missing gameId parameter',
},
});
return;
}
this.eventBus.emit('request:table:create', {
player,
gameId: data.gameId,
options: data.options,
});
},
});
// Sit at seat
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.TABLE.SEAT_SIT,
handler: (player, data) => {
const table = player.getTable();
if (!table) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'You are not at a table',
},
});
return;
}
if (data.seatIndex === undefined || data.seatIndex === null) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'Missing seatIndex parameter',
},
});
return;
}
this.eventBus.emit('request:table:seat:sit', {
player,
tableId: table.id,
seatIndex: data.seatIndex,
});
},
});
// Stand from seat
this.registerCommandHandler({
action: index_1.CLIENT_COMMAND_TYPES.TABLE.SEAT_STAND,
handler: (player, data) => {
const table = player.getTable();
if (!table) {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'You are not at a table',
},
});
return;
}
this.eventBus.emit('request:table:seat:stand', { player, tableId: table.id });
},
});
}
/**
* Process a message from the client.
* @param player - The player object
* @param messageStr - The message string to process
*/
processMessage({ player, messageStr }) {
try {
const message = JSON.parse(messageStr);
// Validate message format
if (!message.action || typeof message.action !== 'string') {
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'Invalid message format: missing or invalid action',
},
});
return;
}
// First check if we have a registered command handler for this action
const handler = this.commandHandlers.get(message.action);
if (handler) {
handler(player, message);
return;
}
// Otherwise, treat it as an event from the client
// We prefix with 'client:' to prevent spoofing of internal server events
const clientAction = message.action.startsWith('client:')
? message.action
: `client:${message.action}`;
this.eventBus.emit(clientAction, { player, message });
}
catch (error) {
console.error('Error processing message:', error);
player.sendMessage({
message: {
type: index_1.CLIENT_MESSAGE_TYPES.ERROR,
message: 'Failed to process message',
},
});
}
}
}
exports.MessageRouter = MessageRouter;