mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-18 06:41:27 +02:00
update block broadcasting and chat system
This commit is contained in:
+35
-23
@@ -98,29 +98,41 @@
|
||||
console.log("UI available:", typeof UI !== 'undefined');
|
||||
console.log("InputHandler available:", typeof InputHandler !== 'undefined');
|
||||
|
||||
// Initialize Game
|
||||
if (typeof Game !== 'undefined') {
|
||||
console.log("Initializing Game...");
|
||||
Game.init();
|
||||
} else {
|
||||
console.error("Game object not found!");
|
||||
}
|
||||
|
||||
// Initialize SocketHandlers (CRITICAL for receiving game_start events!)
|
||||
if (typeof SocketHandlers !== 'undefined') {
|
||||
console.log("Initializing SocketHandlers...");
|
||||
SocketHandlers.init();
|
||||
} else {
|
||||
console.error("SocketHandlers object not found!");
|
||||
}
|
||||
|
||||
// Initialize InputHandler
|
||||
if (typeof InputHandler !== 'undefined') {
|
||||
console.log("Initializing InputHandler...");
|
||||
InputHandler.init();
|
||||
} else {
|
||||
console.error("InputHandler object not found!");
|
||||
}
|
||||
// Small delay to ensure all modules are fully loaded
|
||||
setTimeout(function() {
|
||||
// Initialize Game first
|
||||
if (typeof Game !== 'undefined') {
|
||||
console.log("Initializing Game...");
|
||||
const gameInitResult = Game.init();
|
||||
console.log("Game initialization result:", gameInitResult);
|
||||
|
||||
// Ensure welcome screen is shown after a brief delay
|
||||
setTimeout(function() {
|
||||
if (gameInitResult && typeof ScreenManager !== 'undefined' && ScreenManager.drawWelcomeScreen) {
|
||||
console.log("Ensuring welcome screen is drawn...");
|
||||
ScreenManager.drawWelcomeScreen();
|
||||
}
|
||||
}, 50);
|
||||
} else {
|
||||
console.error("Game object not found!");
|
||||
}
|
||||
|
||||
// Initialize SocketHandlers (CRITICAL for receiving game_start events!)
|
||||
if (typeof SocketHandlers !== 'undefined') {
|
||||
console.log("Initializing SocketHandlers...");
|
||||
SocketHandlers.init();
|
||||
} else {
|
||||
console.error("SocketHandlers object not found!");
|
||||
}
|
||||
|
||||
// Initialize InputHandler
|
||||
if (typeof InputHandler !== 'undefined') {
|
||||
console.log("Initializing InputHandler...");
|
||||
InputHandler.init();
|
||||
} else {
|
||||
console.error("InputHandler object not found!");
|
||||
}
|
||||
}, 100); // 100ms delay to ensure everything is loaded
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -25,6 +25,8 @@ const SocketHandlers = {
|
||||
socket.on('connect', this.onConnect);
|
||||
socket.on('welcome', this.onWelcome);
|
||||
socket.on('message', this.onMessage);
|
||||
socket.on('status_update', this.onStatusUpdate);
|
||||
socket.on('chat_broadcast', this.onChatBroadcast);
|
||||
|
||||
// Game state handlers
|
||||
socket.on('waiting_status', this.onWaitingStatus);
|
||||
@@ -33,7 +35,7 @@ const SocketHandlers = {
|
||||
socket.on('game_over', this.onGameOver);
|
||||
socket.on('queue_cancelled', this.onQueueCancelled);
|
||||
|
||||
// Block height handler
|
||||
// Block height handler (broadcast to all clients)
|
||||
socket.on('blockheight', this.onBlockHeight);
|
||||
},
|
||||
|
||||
@@ -59,6 +61,27 @@ const SocketHandlers = {
|
||||
UI.scrollChat();
|
||||
},
|
||||
|
||||
onStatusUpdate: function(data) {
|
||||
// Handle player-specific status updates
|
||||
console.log("📨 STATUS UPDATE received:", data);
|
||||
|
||||
// Display status message with appropriate styling
|
||||
const statusClass = data.type === 'error' ? 'error' : 'status';
|
||||
$('#messages').append($(`<li class="${statusClass}">`).text(data.message));
|
||||
UI.scrollChat();
|
||||
},
|
||||
|
||||
onChatBroadcast: function(data) {
|
||||
// Handle chat messages broadcast to all players
|
||||
console.log("💬 CHAT BROADCAST received:", data);
|
||||
|
||||
const timestamp = new Date(data.timestamp || Date.now()).toLocaleTimeString();
|
||||
const chatMsg = `[${timestamp}] ${data.username || 'Anonymous'}: ${data.message}`;
|
||||
|
||||
$('#messages').append($('<li class="chat">').text(chatMsg));
|
||||
UI.scrollChat();
|
||||
},
|
||||
|
||||
onWaitingStatus: function(data) {
|
||||
console.log("🕒 WAITING STATUS received:", data);
|
||||
|
||||
@@ -181,6 +204,28 @@ const SocketHandlers = {
|
||||
if (Game) {
|
||||
Game._gameActive = false;
|
||||
}
|
||||
|
||||
// Auto-return to title screen after 30 seconds
|
||||
console.log("⏰ Setting 30-second timer to return to title screen...");
|
||||
setTimeout(() => {
|
||||
console.log("⏰ 30 seconds elapsed - returning to title screen");
|
||||
$('#messages').append($('<li style="color:#888;">').text("Returning to title screen..."));
|
||||
UI.scrollChat();
|
||||
|
||||
// Return to welcome screen
|
||||
if (Game && Game._drawWelcomeScreen) {
|
||||
Game._drawWelcomeScreen();
|
||||
}
|
||||
|
||||
// Reset game state
|
||||
if (typeof GameState !== 'undefined') {
|
||||
GameState.reset();
|
||||
}
|
||||
|
||||
// Focus chat for new commands
|
||||
$('#chatInput').focus();
|
||||
UI.updateFocusIndicator();
|
||||
}, 30000); // 30 seconds
|
||||
}
|
||||
|
||||
UI.scrollChat();
|
||||
|
||||
+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