From e87ee438221e5ccf50c15ef1a5a90e075b7bd25a Mon Sep 17 00:00:00 2001 From: MayaTheShy Date: Mon, 16 Feb 2026 02:31:05 -0500 Subject: [PATCH] feat: Enhance turtle management by broadcasting removal notifications and cleaning up stale turtles --- client/src/store/turtleStore.js | 14 ++++++++-- server/server.js | 47 ++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/client/src/store/turtleStore.js b/client/src/store/turtleStore.js index 88b6fc4..a107ace 100644 --- a/client/src/store/turtleStore.js +++ b/client/src/store/turtleStore.js @@ -49,11 +49,21 @@ export const useTurtleStore = create((set, get) => ({ if (data.turtle.surroundings && data.turtle.position && data.turtle.facing !== undefined) { get().updateBlocksFromSurroundings(data.turtle); } - } else if (data.type === 'turtle_disconnected') { + } else if (data.type === 'turtle_removed' || data.type === 'turtle_disconnected') { + console.log(`๐Ÿ”Œ Turtle ${data.turtleID} removed`); set(state => { const newTurtles = { ...state.turtles }; delete newTurtles[data.turtleID]; - return { turtles: newTurtles }; + + // If the removed turtle was selected, deselect it + const newSelectedId = state.selectedTurtleId === data.turtleID + ? null + : state.selectedTurtleId; + + return { + turtles: newTurtles, + selectedTurtleId: newSelectedId + }; }); } } catch (error) { diff --git a/server/server.js b/server/server.js index d6ea768..bf4bc13 100644 --- a/server/server.js +++ b/server/server.js @@ -15,6 +15,43 @@ const webClients = new Set(); const turtleData = new Map(); // turtleID -> turtle state const worldBlocks = new Map(); // "x,y,z" -> {name, metadata, discoveredBy, timestamp} +// Timeout for considering turtles offline (30 seconds) +const TURTLE_TIMEOUT = 30000; + +// Broadcast to all web clients +function broadcastToClients(data) { + const message = JSON.stringify(data); + webClients.forEach((client) => { + if (client.readyState === 1) { // OPEN + client.send(message); + } + }); +} + +// Cleanup stale turtles periodically +setInterval(() => { + const now = Date.now(); + let removedCount = 0; + + for (const [turtleID, turtle] of turtleData.entries()) { + if (now - turtle.lastUpdate > TURTLE_TIMEOUT) { + console.log(`๐Ÿ”Œ Turtle ${turtleID} timed out (last seen ${Math.floor((now - turtle.lastUpdate) / 1000)}s ago)`); + turtleData.delete(turtleID); + removedCount++; + + // Notify web clients + broadcastToClients({ + type: 'turtle_removed', + turtleID: turtleID + }); + } + } + + if (removedCount > 0) { + console.log(`๐Ÿงน Cleaned up ${removedCount} offline turtle(s)`); + } +}, 10000); // Check every 10 seconds + // Helper to store discovered blocks function storeBlock(x, y, z, blockData, turtleID) { const key = `${x},${y},${z}`; @@ -113,16 +150,6 @@ wss.on('connection', (ws) => { }); }); -// Broadcast to all web clients -function broadcastToClients(data) { - const message = JSON.stringify(data); - webClients.forEach((client) => { - if (client.readyState === 1) { // OPEN - client.send(message); - } - }); -} - // REST API endpoint for turtles to update their status app.post('/api/turtle/update', (req, res) => { try {