Add Hytale player detection via log parsing
All checks were successful
Deploy GSM / deploy (push) Successful in 26s

- Add getHytalePlayers function to ssh.js that parses server logs
- Track player joins via [Universe|P] Adding player pattern
- Track disconnects via Removing player pattern
- Integrate with rcon.js getPlayers and getPlayerList functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-15 14:14:38 +01:00
parent 52a06e435f
commit 9a732c819c
2 changed files with 52 additions and 1 deletions

View File

@@ -1,4 +1,5 @@
import { Rcon } from 'rcon-client';
import { getHytalePlayers } from './ssh.js';
const rconConnections = new Map();
const playerCache = new Map();
@@ -109,6 +110,10 @@ export async function getPlayers(server) {
// Use REST API instead of RCON for Palworld
const data = await getPalworldPlayers(server);
result = { online: data.players?.length || 0, max: null };
} else if (server.type === 'hytale') {
// Use log parsing for Hytale (no RCON support)
const data = await getHytalePlayers(server);
result = { online: data.online, max: 32 };
}
playerCache.set(cacheKey, { data: result, time: Date.now() });
@@ -171,6 +176,10 @@ export async function getPlayerList(server) {
// Use REST API instead of RCON for Palworld
const data = await getPalworldPlayers(server);
players = (data.players || []).map(p => p.name);
} else if (server.type === 'hytale') {
// Use log parsing for Hytale (no RCON support)
const data = await getHytalePlayers(server);
players = data.players || [];
}
const result = { players };

View File

@@ -643,8 +643,50 @@ export async function writeOpenTTDConfig(server, content) {
return true;
}
// Hytale Config Management
// ============ HYTALE FUNCTIONS ============
const HYTALE_CONFIG_PATH = "/opt/hytale/Server/config.json";
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);
// 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()) {
return { online: 0, players: [] };
}
const logFile = logFileResult.stdout.trim();
// Parse log for player joins and disconnects
// Join pattern: [Universe|P] Adding player 'PlayerName (UUID)
// Disconnect pattern: Search for connection closed or player removed
const result = await ssh.execCommand(`grep -E "\\[Universe\\|P\\] Adding player|Removing player|Connection.*closed|disconnect" ${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
const joinMatch = line.match(/\[Universe\|P\] Adding player '([^']+) \(([a-f0-9-]+)\)/i);
if (joinMatch) {
const playerName = joinMatch[1];
const uuid = joinMatch[2];
players.set(uuid, playerName);
continue;
}
// Check for player disconnect (various patterns)
const disconnectMatch = line.match(/Removing player.*\(([a-f0-9-]+)\)/i);
if (disconnectMatch) {
players.delete(disconnectMatch[1]);
}
}
const playerList = Array.from(players.values());
return { online: playerList.length, players: playerList };
}
export async function readHytaleConfig(server) {
const ssh = await getConnection(server.host, server.sshUser);