From atum-gamedev
Multiplayer game networking pattern library — choice between client-server (server-authoritative, anti-cheat friendly, server costs) vs peer-to-peer (cheap, NAT punch-through, dedicated host elected) vs deterministic lockstep (RTS / fighting games, perfect sync but rollback complex), Unity Netcode for GameObjects (NGO replacing UNet/Mirror, Unity Transport, RPCs, NetworkVariables, ownership), Mirror Networking (open source, mature, KCP/Telepathy/Steamworks transports), Photon (PUN2 legacy, Fusion modern with prediction + rollback, Quantum deterministic), Godot 4 high-level multiplayer API (MultiplayerSpawner + MultiplayerSynchronizer + RPC, ENet/WebSocket/WebRTC backends), Unreal Replication system (Replicated UPROPERTY, RepNotify, Net Roles, RPC types Server/Client/NetMulticast), netcode patterns (client-side prediction, server reconciliation, lag compensation, interpolation, extrapolation, snapshot interpolation, delta compression), matchmaking (Steam Lobby, EOS, Unity Lobby + Relay, PlayFab, GameLift), dedicated server hosting (GameLift, PlayFab Multiplayer Servers, Hathora, Edgegap), VOIP (Vivox, Photon Voice, Wwise), and anti-cheat (EAC Easy Anti-Cheat, BattlEye, Wellbia XIGNCODE3). Use when implementing multiplayer in any game (co-op, competitive, MMO, real-time, turn-based), choosing between architectural models, or hardening an existing netcode against cheaters and lag. Differentiates from generic backend WebSocket patterns by game-specific concerns (tick rate, prediction, rollback, anti-cheat, deterministic simulation).
npx claudepluginhub arnwaldn/atum-plugins-collection --plugin atum-gamedevThis skill uses the workspace's default tool permissions.
Le multiplayer est **le domaine le plus complexe du game dev**. Ce skill couvre les choix architecturaux et les patterns implémentation par moteur.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides agent creation for Claude Code plugins with file templates, frontmatter specs (name, description, model), triggering examples, system prompts, and best practices.
Le multiplayer est le domaine le plus complexe du game dev. Ce skill couvre les choix architecturaux et les patterns implémentation par moteur.
Type de jeu
├── RTS / fighting / lockstep tactical
│ └── DETERMINISTIC LOCKSTEP (Photon Quantum, custom)
│ ✅ Sync parfait, peu de bandwidth
│ ❌ Rollback complexe, désync = bug fatal
│
├── FPS / action competitive (CS-like, Valorant, Apex)
│ └── CLIENT-SERVER + Client-side prediction + Server reconciliation + Lag compensation
│ ✅ Anti-cheat possible (server authoritative)
│ ❌ Coût serveur, complexité prediction
│
├── Co-op PvE / mid-scale (Among Us, Fall Guys)
│ ├── CLIENT-SERVER hosted (dedicated)
│ └── PEER-TO-PEER avec host elected (cheap)
│
├── MMO / persistent world
│ └── CLIENT-SERVER avec sharding + interest management
│
├── Turn-based / async
│ └── REST API + WebSocket pour notifications (pas de "vrai" netcode)
│
└── Local couch co-op
└── Pas de netcode du tout — local multi-input
Le client prédit immédiatement l'effet de ses inputs sans attendre le serveur. Donne une UX fluide.
// Unity NGO simplifié
public class PlayerController : NetworkBehaviour
{
private struct InputPayload {
public int tick;
public Vector3 inputVector;
}
private struct StatePayload {
public int tick;
public Vector3 position;
public Vector3 velocity;
}
private const int BUFFER_SIZE = 1024;
private InputPayload[] inputBuffer = new InputPayload[BUFFER_SIZE];
private StatePayload[] stateBuffer = new StatePayload[BUFFER_SIZE];
private void HandleClientTick(int currentTick) {
if (!IsOwner) return;
var input = new InputPayload {
tick = currentTick,
inputVector = GetInput()
};
inputBuffer[currentTick % BUFFER_SIZE] = input;
// Predict locally
StatePayload predictedState = ProcessMovement(input);
stateBuffer[currentTick % BUFFER_SIZE] = predictedState;
// Send to server
SendInputServerRpc(input);
}
}
Le serveur valide chaque input. Si la prédiction client diverge, le client reconcilie : revient à l'état serveur authoritative et rejoue ses inputs locaux non-confirmés.
[ClientRpc]
private void ReceiveServerStateClientRpc(StatePayload serverState) {
if (!IsOwner) return;
StatePayload predictedState = stateBuffer[serverState.tick % BUFFER_SIZE];
float positionError = Vector3.Distance(predictedState.position, serverState.position);
if (positionError > 0.001f) {
// Misprediction — reconcile
transform.position = serverState.position;
stateBuffer[serverState.tick % BUFFER_SIZE] = serverState;
// Replay all unconfirmed inputs
for (int tick = serverState.tick + 1; tick <= currentTick; tick++) {
stateBuffer[tick % BUFFER_SIZE] = ProcessMovement(inputBuffer[tick % BUFFER_SIZE]);
}
}
}
Quand le serveur reçoit un "I shot at this position" du client, il rewind l'état du monde au tick correspondant à la latence du client pour valider le tir.
T=100 | Server tick now
| Player A shoots at T=95 (50ms ping)
|
v
[T=95] Server rewinds enemies to T=95 positions, validates hit, applies damage
Sans lag compensation, on tire toujours "à côté" car l'ennemi a bougé entre le moment où on l'a vu et le moment où le serveur reçoit le shoot.
Pour les autres joueurs qu'on ne contrôle pas, on interpole entre les snapshots serveur au lieu de les téléporter. Latence visuelle de 100-150ms = mouvements fluides.
using Unity.Netcode;
public class HealthSystem : NetworkBehaviour
{
public NetworkVariable<int> currentHealth = new NetworkVariable<int>(
100,
readPerm: NetworkVariableReadPermission.Everyone,
writePerm: NetworkVariableWritePermission.Server
);
[ServerRpc]
public void TakeDamageServerRpc(int amount) {
if (!IsServer) return;
currentHealth.Value -= amount;
}
[ClientRpc]
private void PlayDeathEffectClientRpc() {
// VFX local sur tous les clients
}
private void OnEnable() {
currentHealth.OnValueChanged += OnHealthChanged;
}
}
Setup connection :
using Mirror;
public class Player : NetworkBehaviour
{
[SyncVar(hook = nameof(OnHealthChanged))]
private int health = 100;
[Command]
public void CmdTakeDamage(int amount) {
health -= amount;
}
[ClientRpc]
public void RpcPlayHitEffect() {
// VFX
}
private void OnHealthChanged(int oldValue, int newValue) {
UpdateHealthBar(newValue);
}
}
Avantages Mirror vs NGO :
# server.gd
extends Node
const PORT = 7777
const MAX_CLIENTS = 32
func _ready() -> void:
var peer := ENetMultiplayerPeer.new()
peer.create_server(PORT, MAX_CLIENTS)
multiplayer.multiplayer_peer = peer
multiplayer.peer_connected.connect(_on_peer_connected)
multiplayer.peer_disconnected.connect(_on_peer_disconnected)
func _on_peer_connected(id: int) -> void:
print("Peer %d connected" % id)
# Player.gd avec MultiplayerSynchronizer
extends CharacterBody2D
@export var sync_position: bool = true
@rpc("any_peer", "call_local", "reliable")
func take_damage(amount: int) -> void:
health -= amount
if health <= 0:
die.rpc()
@rpc("authority", "call_local", "reliable")
func die() -> void:
queue_free()
Le MultiplayerSynchronizer node sync automatiquement les properties cochées dans l'inspector. Le MultiplayerSpawner gère la création/destruction d'entités replicated.
Photon Fusion est une alternative payante mais très avancée :
public class PlayerNetworked : NetworkBehaviour
{
[Networked] public Vector3 NetworkedPosition { get; set; }
[Networked] public int NetworkedHealth { get; set; }
public override void FixedUpdateNetwork() {
if (GetInput(out NetInput input)) {
NetworkedPosition += input.movementVector * Runner.DeltaTime;
}
}
}
Pour les competitive games, Fusion est souvent le meilleur choix.
| Service | Use case |
|---|---|
| Steam Lobby + Steam Networking | Jeux Steam, gratuit, P2P relay |
| Epic Online Services (EOS) | Cross-platform, gratuit, lobby + matchmaking + voice |
| Unity Lobby + Relay | Unity-native, freemium |
| PlayFab | Microsoft, lobby + matchmaking + servers |
| GameLift (AWS) | Dedicated servers managed, scale auto |
| Hathora | Edge dedicated servers, simple pricing |
| Edgegap | Edge dedicated servers, distributed |
| Anti-cheat | Use case |
|---|---|
| Easy Anti-Cheat (EAC) | Standard PC + console, gratuit Epic |
| BattlEye | Standard PC + console, payant |
| Wellbia XIGNCODE3 | Asia market |
Règle de base : aucun anti-cheat ne remplace un server-authoritative design. Tout ce qui est calculé côté client est piratable. Toujours valider côté serveur.
Send to all clients au lieu de Area-of-Interest — bandwidth O(N²), inscalableunity-patterns (ce plugin)godot-patterns (ce plugin)realtime-websocket (atum-stack-backend)game-architect (ce plugin)