Organisator kann im selben Browser selbst mitspielen

Ein Aufrufer darf Organisator- und Spieler-Zugang kombinieren
(Authorization + X-Player-Token). Berechtigungen prüfen jetzt einzelne
Merkmale statt einer Rangstufe. In der Lobby gibt es „Selbst mitspielen?“,
Teamlinks funktionieren auch im Organisator-Browser. Online-Status wird
direkt nach dem Beitritt aktualisiert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SPP UserandClaude Opus 5.5 committed 2026-10-25 17:53:39 +01:00
1 parent 470b12f232
commit 4152f9c0a6
15 files changed
+248 -59

No files matched your search

+12 -6
View File
@@ -17,12 +17,17 @@ export function attachRealtime(httpServer, { service, config }) {
service.presence = (matchId) => new Set((presence.get(matchId) ?? new Map()).values());
const sendState = (socket) => {
const { matchId, token } = socket.data;
const { matchId, token, playerToken } = socket.data;
try {
const viewer = service.resolveViewer(matchId, token);
const viewer = service.resolveViewer(matchId, [token, playerToken]);
// Rolle kann sich geändert haben (z. B. beigetreten, entfernt) – Anwesenheit vor dem Snapshot nachziehen
// und die anderen informieren, damit der Online-Status sofort stimmt.
const map = presence.get(matchId);
const key = viewer.playerId ?? `socket:${socket.id}`;
const changed = map && map.get(socket.id) !== key;
map?.set(socket.id, key);
socket.emit('match:state', service.snapshot(matchId, viewer));
// Rolle kann sich geändert haben (z. B. Spieler entfernt, neuer Captain) – Anwesenheit nachziehen.
presence.get(matchId)?.set(socket.id, viewer.playerId ?? `socket:${socket.id}`);
if (changed) broadcastMatch(matchId);
} catch (err) {
socket.emit('match:error', { error: err.message, code: err.code ?? 'error' });
}
@@ -56,10 +61,11 @@ export function attachRealtime(httpServer, { service, config }) {
socket.emit('overview', { matches: service.listMatches() });
});
socket.on('match:subscribe', ({ matchId, token } = {}) => {
socket.on('match:subscribe', ({ matchId, token, playerToken } = {}) => {
if (typeof matchId !== 'string') return;
for (const room of socket.rooms) if (room.startsWith('match:')) leave(room.slice(6));
socket.data = { matchId, token: typeof token === 'string' ? token : null };
const str = (v) => (typeof v === 'string' ? v : null);
socket.data = { matchId, token: str(token), playerToken: str(playerToken) };
try {
service.getMatch(matchId);
} catch (err) {