Fix Space Engineers player log parsing
All checks were successful
Deploy GSM / deploy (push) Successful in 42s

Use real SE dedicated log patterns:
- Join:  'OnConnectedClient <Name> attempt'
- Leave: 'User left <Name>' (successful) / 'User left [<steamid>]' (failed attempt)

Unresolved leaves pop the oldest pending entry so failed connection attempts
don't stick in the player list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-19 21:29:01 +02:00
parent 8cc7397f44
commit a0a608766a

View File

@@ -701,14 +701,13 @@ export async function getSpaceEngineersPlayers(server) {
try {
const ssh = await getConnection(server.host, server.sshUser);
// SE logs connect/disconnect lines through the wine-wrapped dedicated server.
// Typical patterns emitted by SpaceEngineersDedicated:
// "User <name> joined" / "User <name> connected"
// "User <name> left" / "User <name> disconnected"
// "Player '<name>' connected" / "Player '<name>' disconnected"
// SE (via SpaceEngineersDedicated.exe under wine) emits:
// Join: "OnConnectedClient <Name> attempt"
// Leave (resolved): "User left <Name>"
// Leave (unresolved): "User left [<steamid-prefix>...]" (failed/kicked attempt)
const result = await ssh.execCommand(
`docker logs --tail 2000 ${server.containerName} 2>&1 | ` +
`grep -iE "user .* (joined|connected|left|disconnected)|player '.*' (connected|disconnected)" | tail -200`
`docker logs --tail 3000 ${server.containerName} 2>&1 | ` +
`grep -E "OnConnectedClient .* attempt|User left " | tail -300`
);
const players = new Map();
@@ -716,10 +715,20 @@ export async function getSpaceEngineersPlayers(server) {
for (const line of lines) {
let m;
if ((m = line.match(/Player '([^']+)' connected/i))) { players.set(m[1], true); continue; }
if ((m = line.match(/Player '([^']+)' disconnected/i))) { players.delete(m[1]); continue; }
if ((m = line.match(/User\s+(.+?)\s+(?:joined|connected)/i))) { players.set(m[1].trim(), true); continue; }
if ((m = line.match(/User\s+(.+?)\s+(?:left|disconnected)/i))) { players.delete(m[1].trim()); continue; }
if ((m = line.match(/OnConnectedClient\s+(\S+)\s+attempt/))) {
players.set(m[1], true);
continue;
}
if ((m = line.match(/User left\s+(.+?)\s*$/))) {
const token = m[1].trim();
if (token.startsWith('[')) {
// unresolved leave (failed connection) — drop oldest pending entry
const firstKey = players.keys().next().value;
if (firstKey !== undefined) players.delete(firstKey);
} else {
players.delete(token);
}
}
}
const playerList = Array.from(players.keys());