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 { Rcon } from 'rcon-client';
|
||||||
|
import { getHytalePlayers } from './ssh.js';
|
||||||
|
|
||||||
const rconConnections = new Map();
|
const rconConnections = new Map();
|
||||||
const playerCache = new Map();
|
const playerCache = new Map();
|
||||||
@@ -109,6 +110,10 @@ export async function getPlayers(server) {
|
|||||||
// Use REST API instead of RCON for Palworld
|
// Use REST API instead of RCON for Palworld
|
||||||
const data = await getPalworldPlayers(server);
|
const data = await getPalworldPlayers(server);
|
||||||
result = { online: data.players?.length || 0, max: null };
|
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() });
|
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
|
// Use REST API instead of RCON for Palworld
|
||||||
const data = await getPalworldPlayers(server);
|
const data = await getPalworldPlayers(server);
|
||||||
players = (data.players || []).map(p => p.name);
|
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 };
|
const result = { players };
|
||||||
|
|||||||
@@ -643,8 +643,50 @@ export async function writeOpenTTDConfig(server, content) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hytale Config Management
|
// ============ HYTALE FUNCTIONS ============
|
||||||
const HYTALE_CONFIG_PATH = "/opt/hytale/Server/config.json";
|
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) {
|
export async function readHytaleConfig(server) {
|
||||||
const ssh = await getConnection(server.host, server.sshUser);
|
const ssh = await getConnection(server.host, server.sshUser);
|
||||||
|
|||||||
Reference in New Issue
Block a user