Add Hytale player detection via log parsing
All checks were successful
Deploy GSM / deploy (push) Successful in 26s
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:
@@ -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 };
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user