dcsim-gameserver/Patchs/Agrandissement_Multi/README_AGRANDISSEMENT_MULTI.md

8.4 KiB

Agrandissement de salles — Synchronisation multijoueur

Ce que fait ce pack

Rend l'agrandissement de salle (clic [E] sur un panneau mural) synchrone entre tous les joueurs en multijoueur, tout en restant fonctionnel en solo.

Architecture

Client joueur clique [E]
    │
    ▼
PlayerInteraction.Ramasser()
    │
    ▼
agr.DemanderAgrandir()  ←─── [nouveau]
    │
    ▼
SynchronisationAgrandissement.DemanderAgrandissement(salleId, direction)
    │
    ├── Mode solo : execution directe locale
    │
    └── Mode multi :
            │
            ▼
        PlayerAgrandissementBridge.CmdDemanderAgrandissement  (sur le joueur local)
            │
            ▼
        Serveur : SynchronisationAgrandissement.TraiterDemandeServeur
            │
            ├── Valide (pas deja agrandi dans cette direction)
            ├── Ajoute a la SyncList des agrandissements effectues
            │
            ▼
        RpcLancerAgrandissement(salleId, direction)
            │
            ▼
        Chaque client + serveur : AgrandirLocal(false)
            │
            ▼
        Animation identique chez tous (meme parametres → meme geometrie)

Script 1 — SynchronisationAgrandissement.cs (NOUVEAU)

Contient deux classes :

  1. SynchronisationAgrandissement — singleton NetworkBehaviour, orchestre tout
  2. PlayerAgrandissementBridge — NetworkBehaviour a ajouter au prefab du joueur pour porter la [Command]

Script 2 — AgrandissementSalle.cs (MODIFIÉ)

Changements :

  • Nouvelle méthode DemanderAgrandir() : point d'entrée multi
  • Nouvelle méthode AgrandirLocal(bool instantane) : execute localement (avec ou sans anim)
  • Agrandir() conservée pour compat : équivaut à AgrandirLocal(false)
  • Toutes les coroutines d'animation (ConstruireSol, ConstruireMurs, ConstruirePlafond, ConstruireEclairage) acceptent un paramètre skipVisuel pour construire instantanément (rejeu client qui rejoint)
  • Gardes DedicatedServerMode.IsDedicatedServer sur la création de Material/TextMesh/debris
  • Layer Emplacement correctement appliqué aux emplacements de l'extension (il manquait dans l'original)

Script 3 — PlayerInteraction.cs (MODIFIÉ)

Un seul changement : ligne ~933, agr.Agrandir() remplacé par agr.DemanderAgrandir().

Étapes dans Unity

1. Remplacer les 3 scripts

Copier dans Assets/Scripts/ :

  • SynchronisationAgrandissement.cs (nouveau fichier)
  • AgrandissementSalle.cs (remplace l'existant)
  • PlayerInteraction.cs (remplace l'existant)

2. Ajouter SynchronisationAgrandissement à la scène

Dans Datacenter_01 :

  1. Sélectionner le GameObject qui porte le NetworkManager
  2. Add ComponentSynchronisationAgrandissement
  3. S'assurer que ce GameObject a un NetworkIdentity ; la plupart du temps le NetworkManager n'en a pas lui-même. Créer un enfant SyncAgrandissement_Holder avec un NetworkIdentity + le script si besoin.

Important : pour que Mirror synchronise le SyncList, ce GameObject doit être spawné sur le réseau. Deux options :

  • Option A (simple) : le mettre dans NetworkManager.spawnPrefabs et le spawner au OnStartServer via un petit bootstrap
  • Option B (scène) : garder le GameObject dans la scène. Mirror va automatiquement le traiter comme un objet de scène avec NetworkIdentity. Dans ce cas, s'assurer que l'objet porte un NetworkIdentity et qu'il est présent dès l'ouverture de la scène.

L'option B est ce que je recommande pour ton cas : Datacenter_01 est une scène fixe, tu ajoutes SynchronisationAgrandissement + NetworkIdentity sur un GameObject dédié, et Mirror le gère tout seul.

3. Ajouter PlayerAgrandissementBridge au prefab du joueur

  1. Ouvrir le prefab du joueur (celui qui est dans NetworkManager.playerPrefab)
  2. Add ComponentPlayerAgrandissementBridge
  3. Sauver le prefab

Sans ce composant sur le joueur, les clients ne pourront pas envoyer leur CmdDemanderAgrandissement vers le serveur.

4. Rebuild

  • Client Windows (pour tester avec deux joueurs)
  • Dedicated Server Linux (pour déployer sur la Debian)

Test à faire

Test 1 — Mode solo

  1. Lancer en éditeur (play mode normal, pas host)
  2. Cliquer [E] sur un panneau d'agrandissement
  3. Attendu : l'animation se lance comme avant, salle agrandie à la fin

Test 2 — Mode host + client

  1. Lancer l'éditeur en Host
  2. Lancer un build client et le connecter
  3. Host clique [E] sur un panneau
  4. Attendu : les deux voient la même animation en même temps, les nouveaux emplacements apparaissent des deux côtés

Test 3 — Client déclencheur

  1. Host + client
  2. Client clique [E] sur un panneau
  3. Attendu : les deux voient l'animation, la SyncList côté serveur contient l'entrée

Test 4 — Dedicated + 2 clients

  1. Lancer le dedicated sur la Debian
  2. Connecter 2 clients Windows
  3. Un des clients clique [E]
  4. Attendu : les 2 clients voient l'animation synchrone, le serveur logue la création de l'extension

Test 5 — Rejoin

  1. Dedicated + 1 client
  2. Le client déclenche l'agrandissement
  3. Un 2e client se connecte APRÈS
  4. Attendu : le 2e client voit l'extension instantanément (pas d'animation), l'état est cohérent

Points d'attention

GameEconomy

Ton GameEconomy est en mode sandbox, donc les TenterAchat passent toujours. La validation économique serveur n'est pas implémentée dans ce pack, elle le sera quand tu sortiras du sandbox.

Emplacements de baies

Les EmplacementBaie de l'extension sont créés localement sur chaque instance (pas via NetworkServer.Spawn). C'est cohérent avec le pattern actuel de SalleDatacenter.GenererEmplacementsBaies() qui fonctionne déjà en multi.

Les baies qui seront placées dessus continueront d'utiliser le flux CmdPlacerBaie qui spawne bien via NetworkServer.Spawn dans BoutiqueReseau.TraiterPlacementBaieServeur.

Colliders sol + murs

Ils sont créés partout (serveur et clients) car ils sont nécessaires pour :

  • Le CharacterController du joueur (marcher dans la nouvelle zone)
  • La physique des objets posés
  • Les raycasts d'interaction

Pas de risque de "tomber dans le vide" côté serveur.

Néons

Sur le dedicated server, les Light ne sont pas créées (gain CPU + logs plus propres). Les clients les créent normalement. C'est sans impact gameplay.

Workflow de debug

Côté serveur dedicated, les logs à surveiller :

[SyncAgrandissement] Agrandissement valide : 1_Nord (total : 1)

Côté client :

[SyncAgrandissement] Rpc recu, execution agrandissement : salle 1 direction Nord
AgrandissementSalle: PHASE 3 - Début construction sol
AgrandissementSalle: PHASE 7 - Construction complète !

Si tu vois :

[SyncAgrandissement] Mur introuvable : salle 1 direction Nord

Ça veut dire que le salleId ou la direction ne correspondent à aucun mur dans la scène. Vérifier que SalleDatacenter.salleId est bien = 1 (ou que le fallback "n'importe quel mur dans la bonne direction" trouve un match).

Si tu vois :

[PlayerAgrandissementBridge] Instance SynchronisationAgrandissement introuvable cote serveur !

Ça veut dire que le GameObject qui porte SynchronisationAgrandissement n'a pas bien été spawné côté serveur. Vérifier qu'il est présent dans la scène au démarrage (option B) ou dans NetworkManager.spawnPrefabs + spawné au OnStartServer (option A).

Bugs connus limités

  1. Chat spam si plusieurs clients déclenchent en même temps : si 2 clients cliquent [E] sur le même panneau dans la même frame, le serveur validera le premier et rejettera le second (log warning "deja agrandi"). Pas grave pour les joueurs.

  2. Anim qui démarre décalée : la latence réseau entre Cmd et Rpc peut faire que les clients voient l'animation avec ~50-200ms de retard entre eux. Acceptable en coop standard.

  3. Animation coupée si un client disconnect pendant l'anim : comme c'est local sur chaque client, ça ne casse rien pour les autres. Le joueur qui reconnect verra l'extension déjà construite via le rejeu.

À implémenter plus tard (pas dans ce pack)

  • Validation économique serveur-side (quand tu sortiras du sandbox)
  • Persistence des agrandissements dans le SaveManager
  • Support multi-salles pour l'agrandissement (actuellement SynchronisationAgrandissement trouve FindObjectOfType<SalleDatacenter>(), donc ça ciblera toujours la salle 1 ; à affiner quand tu auras plusieurs salles agrandissables)