2025-05-28 05:51:38 +02:00
|
|
|
const express = require('express');
|
|
|
|
|
const http = require('http');
|
|
|
|
|
const ws = require('ws');
|
|
|
|
|
const path = require('path');
|
|
|
|
|
const fs = require('fs');
|
|
|
|
|
|
|
|
|
|
// --- Server Setup ---
|
2025-05-28 17:23:52 +02:00
|
|
|
const PORT = process.env.PORT || 3000;
|
|
|
|
|
const HOST = '0.0.0.0';
|
|
|
|
|
|
2025-05-28 05:51:38 +02:00
|
|
|
const app = express();
|
|
|
|
|
const server = http.createServer(app);
|
|
|
|
|
const wss = new ws.Server({ server });
|
|
|
|
|
|
2025-05-28 06:26:56 +02:00
|
|
|
let spiritPos = 0;
|
2025-05-28 07:13:04 +02:00
|
|
|
const SPIRIT_INTERVAL_MS = 18000; // 20 Sekunden
|
2025-05-28 06:26:56 +02:00
|
|
|
let lastSpiritSpawn = Date.now();
|
2025-05-28 06:27:06 +02:00
|
|
|
let spiritTimer = null;
|
2025-05-28 06:26:56 +02:00
|
|
|
|
2025-05-28 05:51:38 +02:00
|
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
|
|
|
|
|
2025-05-28 06:07:24 +02:00
|
|
|
const SPIRITS_PATH = path.join(__dirname, '.', 'spirits', 'spirit_list.json');
|
|
|
|
|
let spirits = [];
|
2025-05-28 05:59:19 +02:00
|
|
|
function shuffleArray(arr) {
|
|
|
|
|
for (let i = arr.length - 1; i > 0; i--) {
|
|
|
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
|
|
|
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-28 05:50:27 +02:00
|
|
|
try {
|
|
|
|
|
spirits = JSON.parse(fs.readFileSync(SPIRITS_PATH, 'utf8'));
|
|
|
|
|
if (!Array.isArray(spirits) || spirits.length === 0) throw 'Spirit-Liste leer oder ungültig!';
|
2025-05-28 05:59:19 +02:00
|
|
|
shuffleArray(spirits);
|
2025-05-28 05:50:27 +02:00
|
|
|
} catch (e) {
|
|
|
|
|
console.error('Fehler beim Laden der Spirits:', e);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-28 06:25:25 +02:00
|
|
|
// --- Helper ---
|
2025-05-28 05:59:19 +02:00
|
|
|
function nextSpirit() {
|
|
|
|
|
spiritPos++;
|
|
|
|
|
if (spiritPos >= spirits.length) {
|
|
|
|
|
shuffleArray(spirits);
|
|
|
|
|
spiritPos = 0;
|
|
|
|
|
}
|
2025-05-28 06:07:24 +02:00
|
|
|
lastSpiritSpawn = Date.now();
|
2025-05-28 05:59:19 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-28 06:25:25 +02:00
|
|
|
// --- WebSocket Logik ---
|
2025-05-28 02:29:36 +02:00
|
|
|
function pushSpiritToAllClients() {
|
2025-05-28 05:59:19 +02:00
|
|
|
const spirit = spirits[spiritPos];
|
2025-05-28 06:17:07 +02:00
|
|
|
lastSpiritSpawn = Date.now();
|
|
|
|
|
const payload = JSON.stringify({
|
|
|
|
|
type: 'spirit',
|
2025-05-28 06:25:25 +02:00
|
|
|
data: spirit,
|
|
|
|
|
timeSinceSpawnMs: 0,
|
|
|
|
|
spiritIntervalMs: SPIRIT_INTERVAL_MS
|
2025-05-28 06:17:07 +02:00
|
|
|
});
|
2025-05-28 02:29:36 +02:00
|
|
|
wss.clients.forEach(client => {
|
|
|
|
|
if (client.readyState === ws.OPEN) {
|
|
|
|
|
client.send(payload);
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-05-28 07:18:27 +02:00
|
|
|
//console.log(`[Server] Spirit "${spirit.Name}" gesendet (${spiritPos + 1}/${spirits.length})`);
|
2025-05-28 02:29:36 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-28 06:25:25 +02:00
|
|
|
// --- Timer ---
|
2025-05-28 05:48:44 +02:00
|
|
|
function startSpiritTimer() {
|
|
|
|
|
if (!spiritTimer) {
|
|
|
|
|
spiritTimer = setInterval(() => {
|
2025-05-28 06:25:25 +02:00
|
|
|
// Vorher weiterzählen, DANN pushen!
|
2025-05-28 06:22:08 +02:00
|
|
|
nextSpirit();
|
2025-05-28 06:25:25 +02:00
|
|
|
pushSpiritToAllClients();
|
2025-05-28 06:07:24 +02:00
|
|
|
}, SPIRIT_INTERVAL_MS);
|
2025-05-28 07:18:27 +02:00
|
|
|
//console.log('[Server] Spirit-Timer gestartet');
|
2025-05-28 05:48:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Timer stoppen
|
|
|
|
|
function stopSpiritTimer() {
|
|
|
|
|
if (spiritTimer) {
|
|
|
|
|
clearInterval(spiritTimer);
|
|
|
|
|
spiritTimer = null;
|
2025-05-28 07:18:27 +02:00
|
|
|
//console.log('[Server] Spirit-Timer gestoppt');
|
2025-05-28 06:17:07 +02:00
|
|
|
nextSpirit(); // Rotiert für Singleuser wie gewünscht
|
2025-05-28 05:48:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Helper: Gibt es noch offene Clients?
|
|
|
|
|
function hasOpenClients() {
|
|
|
|
|
let found = false;
|
|
|
|
|
wss.clients.forEach(client => {
|
|
|
|
|
if (client.readyState === ws.OPEN) found = true;
|
|
|
|
|
});
|
|
|
|
|
return found;
|
|
|
|
|
}
|
2025-05-28 02:29:36 +02:00
|
|
|
|
2025-05-28 05:48:44 +02:00
|
|
|
// --- WebSocket Logik ---
|
|
|
|
|
wss.on('connection', (socket) => {
|
2025-05-28 07:18:27 +02:00
|
|
|
//console.log('[Server] Neuer Client verbunden');
|
2025-05-28 05:59:19 +02:00
|
|
|
|
2025-05-28 06:26:00 +02:00
|
|
|
// Zeit seit letztem Spirit-Spawn:
|
2025-05-28 06:07:24 +02:00
|
|
|
const now = Date.now();
|
|
|
|
|
const timeSinceSpawnMs = now - lastSpiritSpawn;
|
|
|
|
|
const spirit = spirits[spiritPos];
|
|
|
|
|
|
2025-05-28 06:26:00 +02:00
|
|
|
// Sende Spirit, Zeitdifferenz und Intervall an neuen Client
|
2025-05-28 06:07:24 +02:00
|
|
|
socket.send(JSON.stringify({
|
|
|
|
|
type: 'spirit',
|
|
|
|
|
data: spirit,
|
|
|
|
|
timeSinceSpawnMs,
|
|
|
|
|
spiritIntervalMs: SPIRIT_INTERVAL_MS
|
|
|
|
|
}));
|
|
|
|
|
|
2025-05-28 05:48:44 +02:00
|
|
|
|
2025-05-28 06:26:00 +02:00
|
|
|
// Timer starten, falls es der erste Client ist:
|
2025-05-28 05:48:44 +02:00
|
|
|
if (wss.clients.size === 1) {
|
2025-05-28 06:26:00 +02:00
|
|
|
// NICHT doppelt senden!
|
|
|
|
|
// NUR starten, nicht noch mal pushen!
|
2025-05-28 05:54:53 +02:00
|
|
|
startSpiritTimer();
|
2025-05-28 05:48:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verbindung verloren: Timer ggf. stoppen
|
|
|
|
|
socket.on('close', () => {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
if (!hasOpenClients()) {
|
|
|
|
|
stopSpiritTimer();
|
|
|
|
|
}
|
2025-05-28 06:12:05 +02:00
|
|
|
}, 100);
|
2025-05-28 05:48:44 +02:00
|
|
|
});
|
|
|
|
|
});
|
2025-05-28 02:29:36 +02:00
|
|
|
|
2025-05-28 06:26:00 +02:00
|
|
|
// --- Server Start, initialen Spirit pushen (optional, für "Demo" ohne Client)
|
|
|
|
|
pushSpiritToAllClients();
|
|
|
|
|
|
2025-05-28 02:29:36 +02:00
|
|
|
// --- Server Start ---
|
2025-05-28 17:23:52 +02:00
|
|
|
server.listen(PORT, HOST, () => {
|
|
|
|
|
console.log(`[Server] Läuft auf http://${HOST}:${PORT}`);
|
2025-05-28 02:02:42 +02:00
|
|
|
});
|