using UnityEngine; using System.Collections.Generic; using Mirror; /// /// CablageReseau.cs - v6.7 Multijoueur /// /// v6.7 : sync longueur toron /// - CmdSyncLongueurToron : met à jour la SyncVar longueur sur le serveur /// après consommation ou restitution de câble. Propage automatiquement /// à tous les clients via le hook de ToronNetworkSync. /// /// v6.4 : sync câbles RJ45 + alimentation + interrupteur prise /// /// SETUP : Ajouter sur le prefab PlayerCapsule. /// public class CablageReseau : NetworkBehaviour { // ════════════════════════════════════════════════════════════ // CÂBLES RJ45 // ════════════════════════════════════════════════════════════ [Command] public void CmdCreerCableRJ45(uint equipSourceNetId, int portSourceIndex, uint equipDestNetId, int portDestIndex, Color couleur, float longueur) { Debug.Log($"[Serveur] Câble RJ45 créé : equip {equipSourceNetId} port {portSourceIndex} → equip {equipDestNetId} port {portDestIndex}"); RpcCreerCableRJ45(equipSourceNetId, portSourceIndex, equipDestNetId, portDestIndex, couleur, longueur); } [ClientRpc] void RpcCreerCableRJ45(uint equipSourceNetId, int portSourceIndex, uint equipDestNetId, int portDestIndex, Color couleur, float longueur) { if (isLocalPlayer) return; PortRJ45 portSource = TrouverPortRJ45(equipSourceNetId, portSourceIndex); PortRJ45 portDest = TrouverPortRJ45(equipDestNetId, portDestIndex); if (portSource == null || portDest == null) { Debug.LogWarning($"[CablageReseau] Ports introuvables pour câble RJ45 distant"); return; } List chemin = ConstruireCheminAutoLocal( portSource.GetPointConnexion(), portDest.GetPointConnexion()); string nom = "Cable_" + portSource.nomPort + "_vers_" + portDest.nomPort + "_distant"; GameObject cableObj = new GameObject(nom); CableRJ45 cable = cableObj.AddComponent(); cable.Initialiser(portSource, portDest, chemin, couleur, longueur, null); portSource.Connecter(portDest, cable); portDest.Connecter(portSource, cable); Debug.Log($"[CablageReseau] Câble RJ45 distant créé : {portSource.nomPort} → {portDest.nomPort}"); } [Command] public void CmdSupprimerCableRJ45(uint equipSourceNetId, int portSourceIndex, uint equipDestNetId, int portDestIndex) { Debug.Log($"[Serveur] Câble RJ45 supprimé"); RpcSupprimerCableRJ45(equipSourceNetId, portSourceIndex, equipDestNetId, portDestIndex); } [ClientRpc] void RpcSupprimerCableRJ45(uint equipSourceNetId, int portSourceIndex, uint equipDestNetId, int portDestIndex) { if (isLocalPlayer) return; PortRJ45 portSource = TrouverPortRJ45(equipSourceNetId, portSourceIndex); PortRJ45 portDest = TrouverPortRJ45(equipDestNetId, portDestIndex); if (portSource != null && portSource.cable != null) { portSource.cable.SupprimerComplet(); } else if (portDest != null && portDest.cable != null) { portDest.cable.SupprimerComplet(); } Debug.Log("[CablageReseau] Câble RJ45 distant supprimé"); } // ════════════════════════════════════════════════════════════ // SYNC LONGUEUR TORON (v6.7) // ════════════════════════════════════════════════════════════ /// /// v6.7 : Met à jour la SyncVar longueur du toron côté serveur. /// Appelé par CableManager après consommation ou restitution de câble. /// La SyncVar de ToronNetworkSync propage automatiquement la nouvelle /// longueur à TOUS les clients via le hook. /// [Command] public void CmdSyncLongueurToron(uint toronNetId, float longueurRestante, float longueurTotale) { if (!NetworkServer.spawned.ContainsKey(toronNetId)) return; var obj = NetworkServer.spawned[toronNetId]; if (obj == null) return; ToronNetworkSync sync = obj.GetComponent(); if (sync != null) { sync.ServerSetLongueur(longueurTotale, longueurRestante); Debug.Log($"[Serveur] Longueur toron sync : {obj.name} → {longueurRestante:F1}m / {longueurTotale:F1}m"); } } // ════════════════════════════════════════════════════════════ // CÂBLES ALIMENTATION // ════════════════════════════════════════════════════════════ [Command] public void CmdCreerCableAlim(uint pduNetId, int indexPrise, uint equipNetId, int indexPortAlim, Color couleur) { Debug.Log($"[Serveur] Câble alim créé : PDU {pduNetId} prise {indexPrise} → equip {equipNetId} port {indexPortAlim}"); PriseC13 prise = TrouverPriseC13(pduNetId, indexPrise); PortAlimentation port = TrouverPortAlimentation(equipNetId, indexPortAlim); if (prise != null && port != null && !prise.estConnectee) { GameObject cableObj = new GameObject("CableAlim_serveur"); CableAlimentation cable = cableObj.AddComponent(); cable.couleurCable = couleur; cable.Initialiser(prise, port); prise.Connecter(cable, port); port.Connecter(cable, prise); } RpcCreerCableAlim(pduNetId, indexPrise, equipNetId, indexPortAlim, couleur); } [ClientRpc] void RpcCreerCableAlim(uint pduNetId, int indexPrise, uint equipNetId, int indexPortAlim, Color couleur) { if (isLocalPlayer) return; PriseC13 prise = TrouverPriseC13(pduNetId, indexPrise); PortAlimentation port = TrouverPortAlimentation(equipNetId, indexPortAlim); if (prise == null || port == null) { Debug.LogWarning("[CablageReseau] Prise/Port introuvables pour câble alim distant"); return; } GameObject cableObj = new GameObject("CableAlim_distant"); CableAlimentation cable = cableObj.AddComponent(); cable.couleurCable = couleur; cable.Initialiser(prise, port); prise.Connecter(cable, port); port.Connecter(cable, prise); Debug.Log($"[CablageReseau] Câble alim distant créé : PDU prise #{indexPrise} → {port.nomPort}"); } [Command] public void CmdSupprimerCableAlim(uint pduNetId, int indexPrise, uint equipNetId, int indexPortAlim) { Debug.Log($"[Serveur] Câble alim supprimé"); PriseC13 prise = TrouverPriseC13(pduNetId, indexPrise); if (prise != null && prise.cableBranche != null) prise.cableBranche.Supprimer(); RpcSupprimerCableAlim(pduNetId, indexPrise, equipNetId, indexPortAlim); } [ClientRpc] void RpcSupprimerCableAlim(uint pduNetId, int indexPrise, uint equipNetId, int indexPortAlim) { if (isLocalPlayer) return; PriseC13 prise = TrouverPriseC13(pduNetId, indexPrise); if (prise != null && prise.cableBranche != null) { prise.cableBranche.Supprimer(); } else { PortAlimentation port = TrouverPortAlimentation(equipNetId, indexPortAlim); if (port != null && port.cableBranche != null) port.cableBranche.Supprimer(); } Debug.Log("[CablageReseau] Câble alim distant supprimé"); } // ════════════════════════════════════════════════════════════ // INTERRUPTEUR PRISE // ════════════════════════════════════════════════════════════ [Command] public void CmdBasculerPrise(uint pduNetId, int indexPrise) { PriseC13 prise = TrouverPriseC13(pduNetId, indexPrise); if (prise != null) prise.BasculerInterrupteur(); RpcBasculerPrise(pduNetId, indexPrise); } [ClientRpc] void RpcBasculerPrise(uint pduNetId, int indexPrise) { if (isLocalPlayer) return; PriseC13 prise = TrouverPriseC13(pduNetId, indexPrise); if (prise != null) prise.BasculerInterrupteur(); } // ════════════════════════════════════════════════════════════ // HELPERS — Recherche de composants par netId + index // ════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════ // HELPER UNIVERSEL : trouver un NetworkIdentity spawned // Utilise NetworkServer.spawned cote serveur (dedicated inclus), // NetworkClient.spawned cote client. Les deux sont remplis en mode Host. // Sans ce helper, les [Command] executees sur un dedicated server ne // trouvaient aucun objet car NetworkClient.spawned est vide sans client local. // ════════════════════════════════════════════════════════════ private static GameObject TrouverGameObjectNetId(uint netId) { if (Mirror.NetworkServer.active && Mirror.NetworkServer.spawned.TryGetValue(netId, out var ni1) && ni1 != null) return ni1.gameObject; if (Mirror.NetworkClient.active && Mirror.NetworkClient.spawned.TryGetValue(netId, out var ni2) && ni2 != null) return ni2.gameObject; return null; } private PortRJ45 TrouverPortRJ45(uint equipNetId, int portIndex) { GameObject equipGO = TrouverGameObjectNetId(equipNetId); if (equipGO == null) return null; PortRJ45[] ports = equipGO.GetComponentsInChildren(); foreach (var port in ports) { if (port.numeroPort == portIndex) return port; } if (portIndex >= 0 && portIndex < ports.Length) return ports[portIndex]; return null; } private PriseC13 TrouverPriseC13(uint pduNetId, int indexPrise) { GameObject pduGO = TrouverGameObjectNetId(pduNetId); if (pduGO == null) return null; PDU pdu = pduGO.GetComponent(); if (pdu != null && indexPrise >= 0 && indexPrise < pdu.prises.Count) return pdu.prises[indexPrise]; PriseC13[] prises = pduGO.GetComponentsInChildren(); foreach (var p in prises) if (p.indexPrise == indexPrise) return p; return null; } private PortAlimentation TrouverPortAlimentation(uint equipNetId, int indexPort) { GameObject equipGO = TrouverGameObjectNetId(equipNetId); if (equipGO == null) return null; PortAlimentation[] ports = equipGO.GetComponentsInChildren(); if (indexPort >= 0 && indexPort < ports.Length) return ports[indexPort]; return null; } private List ConstruireCheminAutoLocal(Vector3 posSource, Vector3 posDest) { List chemin = new List(); PointAccroche[] tousPoints = FindObjectsOfType(); if (tousPoints.Length == 0) return chemin; PointAccroche ptDepart = null; float bestDistDepart = 3f; foreach (var p in tousPoints) { float d = Vector3.Distance(posSource, p.GetPosition()); if (d < bestDistDepart) { bestDistDepart = d; ptDepart = p; } } PointAccroche ptArrivee = null; float bestDistArrivee = 3f; foreach (var p in tousPoints) { float d = Vector3.Distance(posDest, p.GetPosition()); if (d < bestDistArrivee) { bestDistArrivee = d; ptArrivee = p; } } if (ptDepart == null || ptArrivee == null) return chemin; if (ptDepart == ptArrivee) { chemin.Add(ptDepart); return chemin; } float distanceVoisinage = 1.5f; Dictionary gScore = new Dictionary(); Dictionary cameFrom = new Dictionary(); HashSet closedSet = new HashSet(); List openSet = new List(); gScore[ptDepart] = 0; openSet.Add(ptDepart); int maxIter = 500; int iter = 0; while (openSet.Count > 0 && iter < maxIter) { iter++; PointAccroche current = null; float bestF = float.MaxValue; foreach (var n in openSet) { float g = gScore.ContainsKey(n) ? gScore[n] : float.MaxValue; float f = g + Vector3.Distance(n.GetPosition(), ptArrivee.GetPosition()); if (f < bestF) { bestF = f; current = n; } } if (current == null) break; if (current == ptArrivee) { List result = new List { current }; while (cameFrom.ContainsKey(current)) { current = cameFrom[current]; result.Insert(0, current); } return result; } openSet.Remove(current); closedSet.Add(current); foreach (var autre in tousPoints) { if (autre == current || closedSet.Contains(autre)) continue; if (Vector3.Distance(current.GetPosition(), autre.GetPosition()) > distanceVoisinage) continue; float tentG = gScore[current] + Vector3.Distance(current.GetPosition(), autre.GetPosition()); if (!openSet.Contains(autre)) openSet.Add(autre); else if (gScore.ContainsKey(autre) && tentG >= gScore[autre]) continue; cameFrom[autre] = current; gScore[autre] = tentG; } } chemin.Add(ptDepart); chemin.Add(ptArrivee); return chemin; } // ════════════════════════════════════════════════════════════ // HELPERS PUBLICS // ════════════════════════════════════════════════════════════ public static uint GetEquipNetId(PortRJ45 port) { if (port == null) return 0; NetworkIdentity netId = port.GetComponentInParent(); return netId != null ? netId.netId : 0; } public static uint GetPDUNetId(PriseC13 prise) { if (prise == null || prise.pduParent == null) return 0; NetworkIdentity netId = prise.pduParent.GetComponent(); return netId != null ? netId.netId : 0; } public static uint GetEquipNetIdFromPortAlim(PortAlimentation port) { if (port == null || port.equipement == null) return 0; NetworkIdentity netId = port.equipement.GetComponent(); return netId != null ? netId.netId : 0; } public static int GetPortAlimIndex(PortAlimentation port) { if (port == null || port.equipement == null) return 0; PortAlimentation[] ports = port.equipement.GetComponentsInChildren(); for (int i = 0; i < ports.Length; i++) if (ports[i] == port) return i; return 0; } }