Zurück zum Blog

Was passiert, wenn 700.000 Spieler gleichzeitig dein Indie-Multiplayer-Spiel stürmen (und wie du überlebst)

Veröffentlicht am 26. Juli 2026
Was passiert, wenn 700.000 Spieler gleichzeitig dein Indie-Multiplayer-Spiel stürmen (und wie du überlebst) Mit Hilfe von KI generiert

Kurz und knapp

Erfahre, wie dein Multiplayer-Spiel einen viralen Ansturm von 700.000 Spielern übersteht – mit konkreten Architekturmustern für Lobby und Matchmaking.

Jeder Indie-Entwickler träumt vom viralen Hit über Nacht. Dein Spiel explodiert auf Twitch, die Steam-Concurrents steigen von 200 auf 200.000 in einer Woche, und plötzlich bist du in aller Munde. Was dir in diesem Traum niemand sagt, ist, wie dein Backend um 3 Uhr morgens aussieht, wenn dein Matchmaking-Service brennt, deine Lobby-Datenbank Write-Contention-Fehler wirft und dein Discord voller Spieler ist, die sich mit keinem Spiel verbinden können.

Das ist nicht hypothetisch. Als Goose Goose Duck Ende 2022 viral ging, sahen die Gaggle Studios – ein selbsternanntes kleines Team ohne vorherige Mega-Hit-Erfahrung – die Concurrent-Spielerzahl auf über 700.000 ansteigen. Ihr Backend hielt stand. Nicht weil sie unendliche Ressourcen hatten, sondern weil sie früh spezifische Architekturentscheidungen trafen, die ihnen halfen, den Ansturm zu überleben.

Dieser Beitrag zeigt genau, was diese Entscheidungen waren, was zuerst bricht, wenn ein Multiplayer-Spiel viral geht, und welche konkreten Patterns du auf dein eigenes Projekt anwenden kannst, bevor der Traffic eintrifft.

Die Anatomie eines viralen Multiplayer-Ansturms

Was tatsächlich bricht (in dieser Reihenfolge)

Wenn ein Multiplayer-Spiel das 10- bis 100-fache seiner erwarteten Last erreicht, kaskadieren die Ausfälle in einer vorhersagbaren Reihenfolge. Dieses Verständnis ist entscheidend, weil du dein System in der richtigen Reihenfolge härten musst.

1. Authentifizierung und Login (5–15-fache normale Last in den ersten 48 Stunden)

Jeder Spieler, der spielen will, muss sich zuerst authentifizieren. Das Backend von Steam erledigt die schwere Arbeit für Steam-authentifizierte Spiele, aber dein Server muss trotzdem Tickets validieren, Spielerprofile erstellen oder abrufen und Session-Tokens zurückgeben. Wenn jede Auth-Anfrage deine primäre Datenbank berührt, hast du ein Problem. Ein Burst von 50.000 Login-Anfragen pro Minute, die jeweils eine PostgreSQL-Write-Anfrage zur Session-Erstellung auslösen, sättigt deinen Connection Pool in unter 90 Sekunden.

2. Lobby-Suche und Matchmaking (10–50-fache normale Last)

Das ist der erste Dominostein, der tatsächlich das Spielerlebnis zerstört. Wenn 200.000 Spieler gleichzeitig Lobbys durchsuchen, geht dein Lobby-Listen-Abfrage-Muster von „Hunderte Reads pro Sekunde“ zu „Zehntausende Reads pro Sekunde“. Wenn der Lobby-Zustand in deiner primären relationalen Datenbank lebt, kämpfst du jetzt mit Read Replicas, die mit dem Replikations-Lag nicht Schritt halten können und veraltete Lobby-Daten zurückgeben, die Räume als verfügbar anzeigen, obwohl sie bereits voll sind.

3. Lobby-Erstellung und Beitrittsoperationen (Write-lastiger Spike)

Jede neue Spiel-Lobby ist ein Write. Jeder Spieler, der einer Lobby beitritt, ist ein Write (Aktualisierung der Spielerliste). Jeder Spieler, der geht, ist ein Write. Beim Goose Goose Duck-Verkehrsspitze bedeutete das tausende Lobby-Zustands-Mutationen pro Sekunde. Gaggle Studios verwendete ein Peer-to-Peer-Modell für das eigentliche Gameplay, aber die Lobby-Koordination benötigte dennoch Zentralisierung – Spieler müssen einander finden, bevor sie sich direkt verbinden können.

4. NAT-Traversal und P2P-Verbindungsaufbau

Hier stößt die Peer-to-Peer-Architektur an ihre Grenzen. Selbst mit STUN/TURN-Infrastruktur scheitern P2P-Verbindungen. Der Branchendurchschnitt für die P2P-Verbindungserfolgsrate ohne Relay-Fallback liegt bei etwa 75–85 % der Spielerpaare. Die verbleibenden 15–25 % benötigen TURN-Relay-Server. Bei 700.000 gleichzeitigen Spielern, die tausende Verbindungen pro Sekunde versuchen, brauchst du eine Relay-Infrastruktur, die die meisten Indie-Teams noch nie aufgebaut haben.

Warum P2P die richtige Entscheidung war (bis es das nicht mehr war)

Gaggle Studios entschied sich für Peer-to-Peer für das eigentliche Gameplay von Goose Goose Duck, und für ein Social-Deduction-Spiel mit 2–16 Spielern pro Session war das tatsächlich die richtige Wahl. Hier ist der Grund und wo die Trade-offs zuschlagen.

Das P2P-Kostenmodell

Betrachten wir die Mathematik. Eine Dedicated-Server-Architektur für ein 16-Spieler-Match, das 15 Minuten auf einer bescheidenen Cloud-Instanz läuft (~0,04 $/Stunde für eine geteilte vCPU), kostet etwa 0,01 $ pro Match. Multipliziert mit 500.000 gleichzeitigen Matches während der Spitzenzeiten, landest du bei 5.000 $/Stunde allein für Rechenleistung. Das sind 120.000 $ pro Tag.

P2P verlagert diese Rechenkosten auf den Rechner des Host-Spielers. Deine Infrastrukturkosten sinken auf die Koordinationsebene: Matchmaking-Server, Lobby-Zustand, Authentifizierung und STUN/TURN-Relay. Für Goose Goose Duck bedeutete das, dass ihre Infrastrukturrechnung selbst bei explodierenden Spielerzahlen überschaubar blieb.

Die P2P-Zuverlässigkeitsgrenze

Aber P2P bringt Ausfallmodi mit sich, die Dedicated Server nicht haben:

  • Host-Migration: Wenn der Host-Spieler die Verbindung verliert, muss die Session die Autorität an einen anderen Peer übertragen. Für ein Social-Deduction-Spiel bedeutet eine fehlgeschlagene Host-Migration verlorene Abstimmungszustände, desyncete Rollenzuweisungen und ein ruiniertes Match. Eine typische Host-Migration sieht so aus:
// Simplified peer-to-peer host migration logic
// When the current host becomes unreachable

void OnHostUnreachable(float timeoutSeconds = 3.0f) {
    // 1. All peers detect host disconnect via heartbeat timeout
    // 2. Each peer independently evaluates whether it should become the new host
    
    TArray<FPlayerInfo> remainingPeers = GetConnectedPeers();
    FPlayerInfo newHost = SelectNewHost(remainingPeers);  // Lowest latency, highest bandwidth
    
    if (newHost.PlayerId == GetLocalPlayerId()) {
        // This peer becomes the new host
        BecomeHost();
        
        // Reconstruct authoritative game state from local cache
        GameState = ReconstructFromLastKnownState();
        
        // Tell all other peers to connect to the new host
        BroadcastHostMigration(newHost.Address);
        
        // Resume gameplay - votes, timers, and role assignments must survive this transition
        ResumeSessionWithReconciledState();
    } else {
        // Wait for migration signal, then connect to new host
        ConnectToNewHost(newHost.Address, timeoutSeconds);
    }
}

Jeder dieser Schritte ist ein potenzieller Fehlerpunkt. Wenn zwei Peers beide entscheiden, dass sie der Host sein sollten (Split-Brain-Szenario), erhältst du zwei abweichende Spielzustände, die nicht miteinander in Einklang gebracht werden können.

  • NAT-Traversal-Fehler: Spieler hinter symmetrischen NATs oder Carrier-Grade-NATs können keine direkten Verbindungen herstellen. Deine TURN-Relay-Infrastruktur muss diese Spieler aufnehmen. Im großen Maßstab sind 15 % von 700.000 gleichzeitigen Spielern 105.000 Spieler, die Relay-Traffic benötigen – und Relay-Bandbreite ist teuer, typischerweise 0,05–0,10 $ pro GB.

  • Cheat-Verwundbarkeit: Der Rechner des Host-Spielers ist autoritativ. Jegliche Client-seitigen Daten können manipuliert werden. Für ein lockeres Party-Spiel ist das weniger katastrophal als für einen kompetitiven Shooter, aber es beeinträchtigt trotzdem das Erlebnis. Server-autoritative Designs (wie die in Fortnites Serveroptimierungsvorschlägen verwendeten) eliminieren ganze Kategorien von Exploits, erfordern aber dedizierte Rechenleistung.

Die Matchmaking-Ebene: Bau für das 10-fache deiner erwarteten Spitze

Das ist der Abschnitt, den die meisten Indie-Entwickler brauchen, aber überspringen, bis es zu spät ist. Dein Matchmaking-System ist die Eingangstür zu deinem Spiel. Wenn es langsam ist, gehen Spieler. Wenn es kaputt ist, können Spieler nicht spielen.

Lobby-Zustandsverwaltungs-Architektur

Das Lobby-System von Goose Goose Duck musste diese Operationen in großem Maßstab bewältigen:

  • Lobbys durchsuchen (read-lastig): Spieler filtern und listen verfügbare Lobbys auf
  • Lobby erstellen (write): Ein neuer Lobby-Eintrag mit Spieleinstellungen, Region und Kapazität
  • Lobby beitreten (conditional write): Atomare Operation – Kapazität prüfen, Spieler hinzufügen, oder fehlschlagen
  • Lobby verlassen (write + mögliches Löschen): Spieler entfernen, Lobby löschen wenn leer
  • Lobby-Einstellungen aktualisieren (write): Host ändert Spielparameter

Hier ist ein vereinfachter Lobby-Manager, der die atomare Beitrittsoperation behandelt, die unter Last am fehleranfälligsten ist:

import asyncio
from dataclasses import dataclass, field
from typing import Optional
import uuid

@dataclass
class Lobby:
    lobby_id: str
    host_id: str
    max_players: int
    players: list = field(default_factory=list)
    region: str = "us-east"
    game_settings: dict = field(default_factory=dict)
    created_at: float = 0.0

class LobbyManager:
    def __init__(self, cache_client, db_client):
        self.cache = cache_client    # Redis or similar
        self.db = db_client           # PostgreSQL or similar
        self.MAX_LOBBIES_PER_REGION = 10000
        self.LOBBY_TTL_SECONDS = 3600  # Auto-cleanup stale lobbies

    async def join_lobby(self, lobby_id: str, player_id: str) -> dict:
        """
        Atomic join operation using Redis optimistic locking.
        Prevents the race condition where two players simultaneously
        join a lobby that has one slot remaining.
        """
        cache_key = f"lobby:{lobby_id}"
        
        # Use a Lua script for atomic check-and-modify in Redis
        # This is the critical path—under viral load, this single 
        # operation runs thousands of times per second
        lua_script = """
        local key = KEYS[1]
        local player_id = ARGV[1]
        local max_players = tonumber(ARGV[2])
        
        local lobby_data = redis.call('HGETALL', key)
        if #lobby_data == 0 then
            return {-1, "lobby_not_found"}
        end
        
        -- Parse the player count from the hash
        local current_players = tonumber(redis.call('HGET', key, 'player_count'))
        if current_players == nil then
            return {-1, "corrupted_state"}
        end
        
        if current_players >= max_players then
            return {0, "lobby_full"}
        end
        
        -- Atomic increment and add player
        redis.call('HINCRBY', key, 'player_count', 1)
        redis.call('SADD', key .. ':players', player_id)
        redis.call('EXPIRE', key, 3600)
        
        return {1, "joined"}
        """
        
        result = await self.cache.eval(
            lua_script,
            keys=[cache_key],
            args=[player_id, str(self.MAX_PLAYERS)]
        )
        
        status_code, message = result
        
        if status_code == -1:
            raise LobbyNotFoundException(message)
        elif status_code == 0:
            raise LobbyFullException(message)
        
        # Async write to persistent DB (non-blocking, eventual consistency is fine here)
        asyncio.create_task(self._persist_join(lobby_id, player_id))
        
        return {"status": "joined", "lobby_id": lobby_id}

    async def _persist_join(self, lobby_id: str, player_id: str):
        """Background persistence—lobby state in Redis is the source of truth for joins.
           DB only lags by milliseconds but is not on the critical path."""
        await self.db.execute(
            "UPDATE lobbies SET player_count = player_count + 1, "
            "updated_at = NOW() WHERE lobby_id = $1",
            lobby_id
        )
        await self.db.execute(
            "INSERT INTO lobby_players (lobby_id, player_id, joined_at) "
            "VALUES ($1, $2, NOW()) ON CONFLICT DO NOTHING",
            lobby_id, player_id
        )

Das entscheidende Detail hier ist das Lua-Skript in Redis. Eine naive Implementierung, die einen GET ausführt, die Kapazität im Anwendungscode prüft und dann einen POST ausführt, erzeugt ein Race-Window, in dem 15 Spieler gleichzeitig einer 16-Spieler-Lobby beitreten können, was zu 17 Spielern und kaputter Spiellogik führt. Das Lua-Skript wird atomar innerhalb von Redis ausgeführt – keine Race-Condition, keine verlorenen Beitritte, selbst bei tausenden Operationen pro Sekunde.

Verbindungsübergabe: Lobby zu Gameplay

Sobald eine Lobby voll ist, muss das Spiel von der zentralisierten Lobby-Koordination zum Peer-to-Peer-Gameplay übergehen. Diese Übergabe ist der Punkt, an dem die meisten Indie-Multiplayer-Spiele Latenzspitzen oder komplette Ausfälle verursachen.

Das funktionierende Pattern:

  1. Host-Spieler öffnet einen WebSocket- oder UDP-Listening-Socket
  2. Server (Lobby-System) verteilt die IP und den Port des Hosts an alle Peers
  3. Peers versuchen direkte P2P-Verbindung über STUN
  4. Wenn STUN innerhalb von N Sekunden fehlschlägt, Fallback auf TURN-Relay
  5. Sobald alle Peers „verbunden“ melden, signalisiert der Host den Spielstart

Für die Echtzeitkommunikation während dieser Übergabe sind WebSocket-Verbindungen weitaus zuverlässiger als HTTP-Polling, besonders wenn du Verbindungsstatus-Updates gleichzeitig an 8–16 Clients pushen musst.

Traffic-Shaping während eines viralen Spikes

Eine der klügsten Entscheidungen des Goose Goose Duck-Teams war das Management der Erwartungen während des Spitzenverkehrs. Wenn dein Backend an der Kapazitätsgrenze ist, hast du zwei Optionen: alles unvorhersehbar degradieren lassen (zufällige Trennungen, korrupte Lobby-Zustände, Timeout-Fehler) oder eine Graceful Degradation implementieren.

Graceful-Degradation-Patterns

Connection Queuing: Anstatt Spieler abzuweisen, wenn die Lobby-Server an der Kapazitätsgrenze sind, setze sie in eine virtuelle Warteschlange mit einem Echtzeit-Positionszähler. Spieler warten 2 Minuten. Sie tolerieren keine kryptische „Serverfehler“-Meldung.

// C# connection queue with position feedback
public class ConnectionQueue
{
    private readonly ConcurrentQueue<string> _queue = new();
    private readonly SemaphoreSlim _admissionGate;
    private readonly int _maxConcurrentSessions;
    
    public ConnectionQueue(int maxConcurrentSessions)
    {
        _maxConcurrentSessions = maxConcurrentSessions;
        _admissionGate = new SemaphoreSlim(maxConcurrentSessions, maxConcurrentSessions);
    }
    
    public async Task<QueueResult> TryEnterQueue(string playerId)
    {
        int position = _queue.Count + 1;
        _queue.Enqueue(playerId);
        
        // Estimate wait time: assume ~30 second average session search time
        // at current throughput
        int estimatedWaitSeconds = (position / _maxConcurrentSessions) * 30;
        
        if (_admissionGate.CurrentCount > 0)
        {
            await _admissionGate.WaitAsync();
            _queue.TryDequeue(out _);
            return new QueueResult { Admitted = true, Position = 0 };
        }
        
        return new QueueResult 
        { 
            Admitted = false, 
            Position = position, 
            EstimatedWaitSeconds = estimatedWaitSeconds 
        };
    }
}

Regionales Load Shedding: Wenn US-East überlastet ist, aber EU-West Kapazität hat, leite neue US-Spieler mit einer Latenz-Warnung nach EU um, anstatt die Verbindung komplett zu verweigern. Ein Ping von 120 ms ist in einem Social-Deduction-Spiel praktisch nicht wahrnehmbar – das sind keine Frame-perfect-Kampfspiele.

Lobby-Erstellungs-Rate-Limiting: Während der Spitzenlast begrenze die Lobby-Erstellung auf eine Lobby pro Spieler alle 30 Sekunden. Das verhindert Bot-gesteuertes Lobby-Spamming (ein echtes Problem für Goose Goose Duck) und reduziert den Write-Druck auf die Lobby-Datenbank.

Kostenaufschlüsselung: Was viraler Maßstab tatsächlich kostet

Setzen wir reale Zahlen darauf. Hier ist ein grobes Kostenmodell für ein Goose Goose Duck-großes virales Event mit verschiedenen Backend-Architekturen:

P2P mit zentralisierter Lobby-Koordination (was Goose Goose Duck gemacht hat):

Komponente Monatliche Kosten (bei 700K Peak CCU)
Lobby-/Matchmaking-Server (12 c5.2xlarge-Instanzen, automatisch skaliert) 3.500–5.000 $
Redis-Cluster für Lobby-Zustand (3 Knoten, r6g.xlarge) 1.800 $
TURN-Relay-Server (für 15 % des Traffics, ~100K Spieler) 8.000–15.000 $
PostgreSQL für persistenten Zustand (RDS Multi-AZ) 600 $
Bandbreite (Lobby-Koordination, ~2 TB/Tag) 1.200 $
Gesamt 15.100–23.600 $/Monat

Komplett Dedicated Server (jedes Match auf einer Cloud-VM):

Komponente Monatliche Kosten (bei 700K Peak CCU)
Game-Server (~50.000 gleichzeitige Matches × 0,04 $/Std.) 1.440.000 $/Monat
Matchmaking und Lobby 5.000 $
Datenbank-Infrastruktur 2.000 $
Gesamt ~1.447.000 $/Monat

Der Kostenunterschied beträgt zwei Größenordnungen. Für ein Free-to-Play-Spiel, das Geld durch Cosmetics verdient, ist das Dedicated-Server-Modell ein direkter Weg in die Insolvenz, es sei denn, die Monetarisierung ist von Tag eins an aggressiv. P2P ist keine faule Architektur – es ist eine bewusste finanzielle Entscheidung.

Allerdings kommen die Einsparungen mit Trade-offs. Die Schwere von Cheats nimmt zu. Die Verbindungsqualität variiert je nach Host. Und deine Koordinationsinfrastruktur muss absolut zuverlässig sein, denn sie ist der Single Point of Failure für jedes Match in deinem Spiel.

Wenn du diese Trade-offs für dein eigenes Projekt abwägst, horizOn übernimmt die Koordinationsebene – Lobby-Management, Matchmaking, Spielerauthentifizierung und Session-Zustand – damit du dich auf das Gameplay konzentrieren kannst, anstatt auf Infrastruktur. Die Plattform wurde speziell für diesen Anwendungsfall entwickelt: Indie-Teams, die skalieren müssen, ohne Monate in Backend-Engineering zu investieren.

5 Backend-Architektur-Patterns zum Überleben viralen Wachstums

Hier sind die konkreten Patterns, die du bevor du sie brauchst implementieren solltest, denn das Nachrüsten während eines Traffic-Spikes verwandelt Backend-Brände in Backend-Beerdigungen:

1. Trenne Lobby-Zustand von Spiel-Zustand

Dein Lobby-Koordinationssystem und dein eigentliches Gameplay-Netzwerk sind unterschiedliche Systeme mit unterschiedlichen Skalierungsprofilen. Lobby-Zustand ist high-read, moderate-write und profitiert von Caching (Redis). Spiel-Zustand ist hochfrequent, niedrige Latenz und gehört auf den Host-Rechner oder einen Dedicated Server. Beide in einer Datenbank zu mischen ist eine Skalierungsfalle.

2. Verwende atomare Operationen für kapazitätssensitive Writes

Die Join-Lobby-Operation, die ich oben gezeigt habe, ist atomar über Redis Lua. Verlasse dich nicht auf Anwendungsebene-Locking für irgendetwas, das bestimmt, ob ein Spielraum überläuft. Bei 2.000 Beitritten pro Sekunde bedeuten selbst 10 ms Race-Window 20 überbuchte Lobbys.

3. Implementiere Connection Queuing, bevor du es brauchst

Eine Warteschlange mit einer geschätzten Wartezeit von 60 Sekunden behält 70–80 % der Spieler. Eine generische „Verbindung fehlgeschlagen“-Fehlermeldung behält ungefähr null Spieler. Baue das Queue-System in deine ursprüngliche Architektur ein. Du kannst es bei geringem Traffic deaktivieren, aber du kannst es nicht schnell genug bauen, wenn der Traffic ansteigt.

4. Überwache Lobby-zu-Spiel-Übergänge separat

Die meisten Überwachungssysteme verfolgen „Spieler online gesamt“ und „Fehlerrate“. Du brauchst spezifische Metriken für den Übergangspunkt: Wie viel Prozent der vollen Lobbys wechseln erfolgreich zum Gameplay? Wenn diese Zahl unter 95 % fällt, versagt deine STUN/TURN-Infrastruktur oder deine P2P-Hole-Punching-Logik. Das ist die Metrik, die Spielerabwanderung genauer vorhersagt als jede andere.

5. Baue eine Graceful-Degradation-Leiter

Definiere deine Degradationsbedingungen im Voraus:

  • Grün (unter 80 % Kapazität): Volle Funktionalität, keine Einschränkungen
  • Gelb (80–95 % Kapazität): Aktiviere Lobby-Erstellungs-Rate-Limits, bevorzuge Spieler, die bestehenden Lobbys beitreten
  • Orange (95–100 % Kapazität): Aktiviere Connection Queuing, deaktiviere Matchmaking-Filter, akzeptiere Cross-Region-Matches
  • Rot (über Kapazität): Volles Queuing, statische Fallback-Seite für neue Verbindungen, priorisiere bestehende Sessions

Schreibe diese Schwellenwerte in deine Infrastruktur-Konfiguration. Richte Alarme an jeder Grenze ein. Der Unterschied zwischen einem „viralen Moment“ und einer „viralen Katastrophe“ ist, ob du Orange erreichst, bevor du Rot erreichst.

Die größere Lektion

Die Goose Goose Duck-Geschichte zeigt etwas Grundlegendes über Multiplayer-Spiel-Architektur: Die Entscheidung zwischen P2P und Dedicated Servern ist keine Qualitätsentscheidung – sie ist eine wirtschaftliche und architektonische Entscheidung mit weitreichenden Konsequenzen. P2P hat Gaggle Studios potenziell Millionen an Serverkosten gespart, erforderte aber eine robuste Koordinationsebene, sorgfältiges Lobby-Management und die Bereitschaft, bestimmte Qualitätseinbußen in Kauf zu nehmen.

Für Indie-Entwickler, die ihre Multiplayer-Architektur planen, ist die Botschaft klar: Entwirf für deine Spitze, nicht für deinen Durchschnitt. Dein Backend wird am Tag deines viralen Hits das 50- bis 100-fache seiner normalen Last erleben. Wenn du nicht in diesem Maßstab getestet hast, bist du nicht bereit.

Beginne mit der Lobby- und Matchmaking-Ebene. Bekomme atomare Lobby-Operationen richtig hin. Baue Connection Queuing. Implementiere regionales Failover. Das sind die Komponenten, die bestimmen, ob dein viraler Moment eine Erfolgsgeschichte oder ein Postmortem ist.

Wenn du Monate Backend-Engineering überspringen und mit einer Koordinationsebene ausliefern möchtest, die bereits in großem Maßstab kampferprobt ist, bietet horizOn Lobby-Management, Matchmaking und Session-Zustand out of the box – damit du dich darauf konzentrieren kannst, dein Spiel spaßig zu machen, anstatt darüber nachzudenken, ob deine Server halten. Schau dir die API-Dokumentation an, um zu sehen, wie es in deine Architektur passt.


Quelle: Lean bleiben: Wie wir das weltweit größte Social-Deduction-Spiel gebaut haben