import { readFileSync, existsSync, statSync } from "fs"; export const LOG_FILE = "/home/minecraft/server/logs/latest.log"; export type ChatMessage = { time: string; type: "chat" | "join" | "leave" | "death" | "server"; player: string; message: string; }; export function parseLogLine(line: string): ChatMessage | null { const chatMatch = line.match( /\[(\d{2}:\d{2}:\d{2})\].*\[minecraft\/(?:DedicatedServer|MinecraftServer)\]:\s*<(\w+)>\s*(.*)/ ); if (chatMatch) { return { time: chatMatch[1], type: "chat", player: chatMatch[2], message: chatMatch[3] }; } const joinMatch = line.match( /\[(\d{2}:\d{2}:\d{2})\].*\[minecraft\/(?:PlayerList|ServerPlayer)\]:\s*(\w+)\s+joined the game/ ); if (joinMatch) { return { time: joinMatch[1], type: "join", player: joinMatch[2], message: "joined the game" }; } const leaveMatch = line.match( /\[(\d{2}:\d{2}:\d{2})\].*\[minecraft\/(?:PlayerList|ServerPlayer)\]:\s*(\w+)\s+left the game/ ); if (leaveMatch) { return { time: leaveMatch[1], type: "leave", player: leaveMatch[2], message: "left the game" }; } const deathMatch = line.match( /\[(\d{2}:\d{2}:\d{2})\].*\[minecraft\/(?:DedicatedServer|MinecraftServer)\]:\s*(\w+)\s+(was |died|drowned|burned|fell|starved|suffocated|hit|blew|withered|tried|experienced|went|walked|froze|was prick|was stung|was impaled|was squashed|was skewered|was squished|was pummeled|discovered)(.*)/ ); if (deathMatch) { return { time: deathMatch[1], type: "death", player: deathMatch[2], message: deathMatch[3] + (deathMatch[4] || ""), }; } const sayMatch = line.match( /\[(\d{2}:\d{2}:\d{2})\].*\[minecraft\/(?:DedicatedServer|MinecraftServer)\]:\s*\[Server\]\s*(.*)/ ); if (sayMatch) { return { time: sayMatch[1], type: "server", player: "Server", message: sayMatch[2] }; } return null; } export function readChatMessages(maxLines = 50): ChatMessage[] { if (!existsSync(LOG_FILE)) return []; const content = readFileSync(LOG_FILE, "utf8"); const lines = content.split("\n"); const messages: ChatMessage[] = []; for (let i = lines.length - 1; i >= 0 && messages.length < maxLines; i--) { const msg = parseLogLine(lines[i]); if (msg) messages.unshift(msg); } return messages; } export function logMtime(): number { try { return statSync(LOG_FILE).mtimeMs; } catch { return 0; } }