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}");
// v7.1 : enregistrer le cable dans le gestionnaire pour le rejoin des clients
if (GestionnaireCablesReseau.Instance != null)
{
GestionnaireCablesReseau.Instance.EnregistrerCableRJ45(
equipSourceNetId, portSourceIndex, equipDestNetId, portDestIndex, couleur, longueur);
}
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é");
// v7.1 : desinscrire du gestionnaire
if (GestionnaireCablesReseau.Instance != null)
{
GestionnaireCablesReseau.Instance.OublierCableRJ45(
equipSourceNetId, portSourceIndex, equipDestNetId, portDestIndex);
}
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);
}
// v7.1 : enregistrer le cable dans le gestionnaire pour le rejoin des clients
if (GestionnaireCablesReseau.Instance != null)
{
GestionnaireCablesReseau.Instance.EnregistrerCableAlim(
pduNetId, indexPrise, equipNetId, indexPortAlim, couleur);
}
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é");
// v7.1 : desinscrire du gestionnaire
if (GestionnaireCablesReseau.Instance != null)
{
GestionnaireCablesReseau.Instance.OublierCableAlim(
pduNetId, indexPrise, equipNetId, indexPortAlim);
}
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
// ════════════════════════════════════════════════════════════
private PortRJ45 TrouverPortRJ45(uint equipNetId, int portIndex)
{
if (!NetworkClient.spawned.ContainsKey(equipNetId)) return null;
GameObject equipGO = NetworkClient.spawned[equipNetId].gameObject;
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)
{
if (!NetworkClient.spawned.ContainsKey(pduNetId)) return null;
GameObject pduGO = NetworkClient.spawned[pduNetId].gameObject;
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)
{
if (!NetworkClient.spawned.ContainsKey(equipNetId)) return null;
GameObject equipGO = NetworkClient.spawned[equipNetId].gameObject;
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;
}
}