Treffer-Toleranz, 2 Ranglisten, Anti-Cheat, CLI-Modi & Icons
- Treffer-Toleranz: Ziel wird geometrisch + bevorzugt getroffen, auch wenn verdeckt - Zwei Ranglisten: Hall of Fame (Allzeit-Top-5) + Heute (Top-10) - Anti-Cheat: server-autoritative Sessions (start/hit), Score = Server-Zahl, Mindestabstand gegen Auto-Klicker, Deckelung nach Spielzeit; Score ohne Session -> 400 - CLI (server/admin.js): list / delete <name> / clear-today / clear-all - Zwei Betriebsmodi per CLI (live, ohne Neustart): public (/ = Spiel) und private (/ gesperrt, Spiel unter geheimem /pfad) + "not allowed to play"-Seite - Board-Icons von Emojis auf echte SVG-Icons, Board heisst "Hall of Fame" Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
43
server/modeStore.js
Normal file
43
server/modeStore.js
Normal file
@@ -0,0 +1,43 @@
|
||||
// Betriebsmodus des Spiels, per CLI umschaltbar, persistent in data/mode.json.
|
||||
// public -> "/" ist das Spiel (Default)
|
||||
// private -> "/" zeigt "nicht erlaubt", Spiel nur unter "/<path>" erreichbar (zum Testen)
|
||||
// Wird pro Request frisch gelesen -> CLI-Umschaltung wirkt SOFORT, ohne Serverneustart.
|
||||
|
||||
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const DATA_DIR = join(__dirname, '..', 'data');
|
||||
const MODE_FILE = join(DATA_DIR, 'mode.json');
|
||||
|
||||
const DEFAULT = { mode: 'public', path: 'play' };
|
||||
|
||||
function sanitizeSlug(slug) {
|
||||
const s = String(slug || '').trim().replace(/^\/+/, '').replace(/[^a-zA-Z0-9_-]/g, '');
|
||||
return s || 'play';
|
||||
}
|
||||
|
||||
export function getMode() {
|
||||
try {
|
||||
if (!existsSync(MODE_FILE)) return { ...DEFAULT };
|
||||
const data = JSON.parse(readFileSync(MODE_FILE, 'utf8'));
|
||||
return {
|
||||
mode: data.mode === 'private' ? 'private' : 'public',
|
||||
path: sanitizeSlug(data.path),
|
||||
};
|
||||
} catch {
|
||||
return { ...DEFAULT };
|
||||
}
|
||||
}
|
||||
|
||||
export function setMode(mode, path) {
|
||||
if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
|
||||
const current = getMode();
|
||||
const next = {
|
||||
mode: mode === 'private' ? 'private' : 'public',
|
||||
path: sanitizeSlug(path || current.path),
|
||||
};
|
||||
writeFileSync(MODE_FILE, JSON.stringify(next, null, 2));
|
||||
return next;
|
||||
}
|
||||
Reference in New Issue
Block a user