mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-19 15:18:33 +02:00
update block broadcasting and chat system
This commit is contained in:
+107
-28
@@ -50,14 +50,14 @@ app.get('/', function(req, res) {
|
||||
if (DEBUG_MODE) {
|
||||
console.log("🐛 DEBUG MODE ENABLED - Simulating blocks every 30 seconds");
|
||||
|
||||
// Initial debug block
|
||||
io.emit('blockheight', debugBlockHeight);
|
||||
// Initial debug block broadcast
|
||||
broadcastBlockHeight(debugBlockHeight);
|
||||
|
||||
// Debug block height simulator
|
||||
// Debug block height simulator - advances every 30 seconds
|
||||
setInterval(function() {
|
||||
debugBlockHeight++;
|
||||
console.log(`🐛 DEBUG: New simulated block: ${debugBlockHeight}`);
|
||||
io.emit('blockheight', debugBlockHeight);
|
||||
broadcastBlockHeight(debugBlockHeight);
|
||||
|
||||
// Start games for waiting players
|
||||
startGamesForWaiting(debugBlockHeight);
|
||||
@@ -66,6 +66,13 @@ if (DEBUG_MODE) {
|
||||
checkGamesTimeout(debugBlockHeight);
|
||||
|
||||
}, 30000); // Every 30 seconds
|
||||
|
||||
// Regular status broadcasting - sends current block height every 5 seconds
|
||||
// This ensures all clients stay up-to-date even if they miss a block change
|
||||
setInterval(function() {
|
||||
broadcastBlockHeight(debugBlockHeight);
|
||||
}, 5000); // Every 5 seconds
|
||||
|
||||
} else {
|
||||
// Your original block check code
|
||||
setInterval(function() {
|
||||
@@ -107,7 +114,7 @@ function startGamesForWaiting(blockHeight) {
|
||||
if (currentUser) {
|
||||
// For queue entry, player gets 3 blocks starting from their entry block
|
||||
currentUser.blockRec = blockHeight;
|
||||
console.log(`🕒 QUEUE ENTRY: Player starts on block ${currentUser.blockRec}, will die after block ${currentUser.blockRec + 2}`);
|
||||
console.log(`🕒 QUEUE ENTRY: Player enters on block ${currentUser.blockRec}, will die when block ${currentUser.blockRec + 1} starts`);
|
||||
|
||||
try {
|
||||
const game = currentUser.startGame(80, 40);
|
||||
@@ -138,11 +145,11 @@ function checkGamesTimeout(currentHeight) {
|
||||
activeGames.forEach((game, socketId) => {
|
||||
const user = getUserBySocket(socketId);
|
||||
|
||||
// Player has 3 blocks to complete the dungeon
|
||||
// If they started on block 2, they must escape before block 5 is found
|
||||
// Note: Auto-entry players start timing from next block for consistent behavior
|
||||
if (user && user.blockRec && currentHeight > user.blockRec + 2) {
|
||||
console.log(`💀 GAME TIMEOUT for player ${socketId}: started timing on block ${user.blockRec}, current block ${currentHeight} (died after block ${user.blockRec + 2})`);
|
||||
// Players die the block after they enter
|
||||
// If they entered on block 1, they die when block 2 starts
|
||||
// If they entered on block 2, they die when block 3 starts
|
||||
if (user && user.blockRec && currentHeight > user.blockRec) {
|
||||
console.log(`💀 GAME TIMEOUT for player ${socketId}: entered on block ${user.blockRec}, died on block ${currentHeight}`);
|
||||
|
||||
// Game has timed out - player didn't escape in time
|
||||
game.gameState = 'lost';
|
||||
@@ -157,6 +164,52 @@ function checkGamesTimeout(currentHeight) {
|
||||
});
|
||||
}
|
||||
|
||||
// ====== SOCKET EVENT BROADCASTING HELPERS ======
|
||||
// These functions abstract the broadcasting logic to support future features like spectating
|
||||
|
||||
/**
|
||||
* Send game state update to player and any spectators
|
||||
* @param {string} playerSocketId - The socket ID of the player
|
||||
* @param {object} gameState - The game state to broadcast
|
||||
*/
|
||||
function sendGameUpdate(playerSocketId, gameState) {
|
||||
// Send to the player
|
||||
io.to(playerSocketId).emit('game_update', gameState);
|
||||
|
||||
// TODO: Future spectator support
|
||||
// Get list of spectators for this game and broadcast to them too
|
||||
// const spectators = getSpectatorsForPlayer(playerSocketId);
|
||||
// spectators.forEach(spectatorId => {
|
||||
// io.to(spectatorId).emit('spectator_update', {
|
||||
// playerSocketId: playerSocketId,
|
||||
// gameState: gameState
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast block height to all connected clients
|
||||
* @param {number} blockHeight - Current block height
|
||||
*/
|
||||
function broadcastBlockHeight(blockHeight) {
|
||||
console.log(`📡 Broadcasting block height ${blockHeight} to all clients`);
|
||||
io.emit('blockheight', blockHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send status update to a specific player
|
||||
* @param {string} socketId - The socket ID of the player
|
||||
* @param {string} type - Type of status (info, error, warning, etc.)
|
||||
* @param {string} message - The status message
|
||||
*/
|
||||
function sendStatusUpdate(socketId, type, message) {
|
||||
io.to(socketId).emit('status_update', {
|
||||
type: type,
|
||||
message: message,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
// Socket.io handlers
|
||||
io.on('connection', function(socket) {
|
||||
console.log('A user connected');
|
||||
@@ -175,23 +228,30 @@ io.on('connection', function(socket) {
|
||||
// Insert into visitors DB
|
||||
db.insertVisitor(socket.client.id, socket.handshake.address, 0);
|
||||
|
||||
// Send welcome message
|
||||
// Send welcome message and immediate status
|
||||
io.to(socket.client.id).emit('welcome', socket.client.id);
|
||||
|
||||
// Send current block height immediately to new connections
|
||||
const currentBlock = DEBUG_MODE ? debugBlockHeight : lastBlockHeight;
|
||||
console.log(`📈 Sending current block height ${currentBlock} to new connection ${socket.id}`);
|
||||
io.to(socket.id).emit('blockheight', currentBlock);
|
||||
|
||||
// Send connection status update (player-specific)
|
||||
sendStatusUpdate(socket.id, 'connection', 'Connected to Wowngeon server');
|
||||
|
||||
socket.on('chat message', function(msg) {
|
||||
console.log('Message received:', msg);
|
||||
|
||||
// Handle game commands (player-specific responses)
|
||||
if (msg.toLowerCase() == 'hello') {
|
||||
io.to(`${socket.client.id}`).emit('message',
|
||||
// Send status update to this player only
|
||||
sendStatusUpdate(socket.id, 'help',
|
||||
'Welcome, to enter the dungeon type Enter, and you will be given a Wownero address, ' +
|
||||
'which you must send between 10-100 WOW to enter. The more you send, the more you can win.');
|
||||
return; // Don't broadcast commands as chat
|
||||
}
|
||||
// ====== GAME ENTRY HANDLERS ======
|
||||
// There are two ways to enter a game:
|
||||
// 1. QUEUE ENTRY: Type "enter" and wait for next block (players get 3 blocks from entry block)
|
||||
// 2. AUTO ENTRY: Type "enter" and start immediately in debug mode (players get 3 blocks from next block)
|
||||
|
||||
// Update the 'enter' command handler to start game immediately for testing
|
||||
// Handle game entry commands
|
||||
if (msg.toLowerCase() == 'enter') {
|
||||
console.log(`Player ${socket.id} requested to enter the dungeon - STARTING IMMEDIATELY`);
|
||||
|
||||
@@ -203,11 +263,11 @@ io.on('connection', function(socket) {
|
||||
|
||||
// Start game immediately for faster testing
|
||||
try {
|
||||
// For auto-entry in debug mode, give player 3 blocks starting from NEXT block
|
||||
// This ensures consistent death timing regardless of entry method
|
||||
// For auto-entry in debug mode, player enters on current block
|
||||
// They will die when the next block starts
|
||||
const currentBlock = debugBlockHeight || lastBlockHeight || 1;
|
||||
currentUser.blockRec = currentBlock + 1; // Start timing from NEXT block
|
||||
console.log(`🕒 AUTO-ENTRY: Player starts on block ${currentUser.blockRec}, will die after block ${currentUser.blockRec + 2}`);
|
||||
currentUser.blockRec = currentBlock; // Player enters on current block
|
||||
console.log(`🕒 AUTO-ENTRY: Player enters on block ${currentUser.blockRec}, will die when block ${currentUser.blockRec + 1} starts`);
|
||||
|
||||
const game = currentUser.startGame(80, 40);
|
||||
activeGames.set(socket.id, game);
|
||||
@@ -220,11 +280,12 @@ io.on('connection', function(socket) {
|
||||
console.log(`Game started immediately for player ${socket.id}`);
|
||||
} catch (error) {
|
||||
console.error(`Error creating game:`, error);
|
||||
io.to(socket.id).emit('message', 'Error starting game: ' + error.message);
|
||||
sendStatusUpdate(socket.id, 'error', 'Error starting game: ' + error.message);
|
||||
}
|
||||
} else {
|
||||
io.to(socket.id).emit('message', 'Error: Could not start game. Please try again.');
|
||||
sendStatusUpdate(socket.id, 'error', 'Error: Could not start game. Please try again.');
|
||||
}
|
||||
return; // Don't broadcast commands as chat
|
||||
}
|
||||
// Add a handler for the 'cancel' command
|
||||
else if (msg.toLowerCase() == 'cancel') {
|
||||
@@ -233,16 +294,32 @@ io.on('connection', function(socket) {
|
||||
|
||||
if (index !== -1) {
|
||||
WAITING_PLAYERS.splice(index, 1);
|
||||
io.to(socket.id).emit('message', 'You have left the queue.');
|
||||
sendStatusUpdate(socket.id, 'info', 'You have left the queue.');
|
||||
|
||||
// Reset to welcome screen
|
||||
io.to(socket.id).emit('queue_cancelled');
|
||||
} else {
|
||||
io.to(socket.id).emit('message', 'You were not in the queue.');
|
||||
// Send status update to this player only
|
||||
sendStatusUpdate(socket.id, 'error', 'You were not in the queue.');
|
||||
}
|
||||
return; // Don't broadcast commands as chat
|
||||
}
|
||||
|
||||
// For all other messages (actual chat), broadcast to all clients
|
||||
else {
|
||||
io.emit('message', msg);
|
||||
console.log(`💬 Broadcasting chat message from ${socket.id}: "${msg}"`);
|
||||
|
||||
// Get user info for chat display
|
||||
const currentUser = getUserBySocket(socket.id);
|
||||
const username = currentUser?.username || `User_${socket.id.substr(-4)}`;
|
||||
|
||||
// Broadcast chat message to ALL clients
|
||||
io.emit('chat_broadcast', {
|
||||
username: username,
|
||||
message: msg,
|
||||
timestamp: Date.now(),
|
||||
socketId: socket.id
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -309,12 +386,14 @@ io.on('connection', function(socket) {
|
||||
// Log before sending to client for debugging
|
||||
console.log(`Sending game_update to ${socket.id} after player move. Player:`, updatedGameState.player, "Visible tiles keys:", Object.keys(updatedGameState.visibleTiles || {}));
|
||||
|
||||
io.to(socket.id).emit('game_update', updatedGameState);
|
||||
// Send game update to player (current implementation)
|
||||
// TODO: In future, also broadcast to spectators of this game
|
||||
sendGameUpdate(socket.id, updatedGameState);
|
||||
} else {
|
||||
console.log(`Player move from ${socket.id} was invalid or resulted in no change.`);
|
||||
// Optionally, send an update even for invalid moves if you want to provide feedback
|
||||
// const currentGameState = game.getState();
|
||||
// io.to(socket.id).emit('game_update', currentGameState);
|
||||
// sendGameUpdate(socket.id, currentGameState);
|
||||
}
|
||||
} else {
|
||||
console.error(`Invalid moveData received from ${socket.id}:`, moveData);
|
||||
|
||||
Reference in New Issue
Block a user