From a518bb2b7f28a9f3740d80c5b3728e9b47a6b03b Mon Sep 17 00:00:00 2001 From: Alexander Zielonka Date: Thu, 15 Jan 2026 14:22:29 +0100 Subject: [PATCH] Add debug logging to Hytale player detection --- gsm-backend/services/ssh.js | 77 ++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/gsm-backend/services/ssh.js b/gsm-backend/services/ssh.js index d90e18c..5b1c2ec 100644 --- a/gsm-backend/services/ssh.js +++ b/gsm-backend/services/ssh.js @@ -649,44 +649,51 @@ const HYTALE_LOGS_PATH = "/opt/hytale/Server/logs"; // Get Hytale players by parsing server logs export async function getHytalePlayers(server) { - const ssh = await getConnection(server.host, server.sshUser); + try { + const ssh = await getConnection(server.host, server.sshUser); - // Find the most recent log file - const logFileResult = await ssh.execCommand(`ls -t ${HYTALE_LOGS_PATH}/*.log 2>/dev/null | head -1`); - if (!logFileResult.stdout.trim()) { + // Find the most recent log file + const logFileResult = await ssh.execCommand(`ls -t ${HYTALE_LOGS_PATH}/*.log 2>/dev/null | head -1`); + if (!logFileResult.stdout.trim()) { + console.log('[Hytale] No log file found'); + return { online: 0, players: [] }; + } + + const logFile = logFileResult.stdout.trim(); + + // Parse log for player joins and disconnects + // Join: [World|default] Player 'Alex47' joined world 'default' at location ... (UUID) + // Leave: [PlayerSystems] Removing player 'Alex47 (Alex47)' from world 'default' (UUID) + const result = await ssh.execCommand(`grep -E "\\[World\\|.*\\] Player .* joined world|\\[PlayerSystems\\] Removing player" ${logFile} 2>/dev/null | tail -200`); + + const players = new Map(); // UUID -> PlayerName + + const lines = result.stdout.split('\n').filter(l => l.trim()); + for (const line of lines) { + // Check for player join: [World|default] Player 'Name' joined world ... (uuid) + const joinMatch = line.match(/\[World\|[^\]]+\] Player '([^']+)' joined world .* \(([a-f0-9-]+)\)/i); + if (joinMatch) { + const playerName = joinMatch[1]; + const uuid = joinMatch[2]; + players.set(uuid, playerName); + continue; + } + + // Check for player leave: [PlayerSystems] Removing player 'Name (Name)' from world ... (uuid) + const leaveMatch = line.match(/\[PlayerSystems\] Removing player '([^']+) \([^)]+\)' from world .* \(([a-f0-9-]+)\)/i); + if (leaveMatch) { + const uuid = leaveMatch[2]; + players.delete(uuid); + } + } + + const playerList = Array.from(players.values()); + console.log(`[Hytale] Found ${playerList.length} players: ${playerList.join(', ') || 'none'}`); + return { online: playerList.length, players: playerList }; + } catch (err) { + console.error(`[Hytale] Error getting players:`, err.message); return { online: 0, players: [] }; } - - const logFile = logFileResult.stdout.trim(); - - // Parse log for player joins and disconnects - // Join: [World|default] Player 'Alex47' joined world 'default' at location ... (UUID) - // Leave: [PlayerSystems] Removing player 'Alex47 (Alex47)' from world 'default' (UUID) - const result = await ssh.execCommand(`grep -E "\\[World\\|.*\\] Player .* joined world|\\[PlayerSystems\\] Removing player" ${logFile} 2>/dev/null | tail -200`); - - const players = new Map(); // UUID -> PlayerName - - const lines = result.stdout.split('\n'); - for (const line of lines) { - // Check for player join: [World|default] Player 'Name' joined world ... (uuid) - const joinMatch = line.match(/\[World\|[^\]]+\] Player '([^']+)' joined world .* \(([a-f0-9-]+)\)/i); - if (joinMatch) { - const playerName = joinMatch[1]; - const uuid = joinMatch[2]; - players.set(uuid, playerName); - continue; - } - - // Check for player leave: [PlayerSystems] Removing player 'Name (Name)' from world ... (uuid) - const leaveMatch = line.match(/\[PlayerSystems\] Removing player '([^']+) \([^)]+\)' from world .* \(([a-f0-9-]+)\)/i); - if (leaveMatch) { - const uuid = leaveMatch[2]; - players.delete(uuid); - } - } - - const playerList = Array.from(players.values()); - return { online: playerList.length, players: playerList }; } export async function readHytaleConfig(server) {