diff --git a/Dedicated_Server_Linux/DatacenterSim.x86_64 b/Dedicated_Server_Linux/DatacenterSim.x86_64
new file mode 100755
index 0000000..9021e73
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim.x86_64 differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/Plugins/lib_burst_generated.so b/Dedicated_Server_Linux/DatacenterSim_Data/Plugins/lib_burst_generated.so
new file mode 100644
index 0000000..9c188d5
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/Plugins/lib_burst_generated.so differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/Resources/UnityPlayer.png b/Dedicated_Server_Linux/DatacenterSim_Data/Resources/UnityPlayer.png
new file mode 100644
index 0000000..43897cf
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/Resources/UnityPlayer.png differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/Resources/unity default resources b/Dedicated_Server_Linux/DatacenterSim_Data/Resources/unity default resources
new file mode 100644
index 0000000..7cf4261
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/Resources/unity default resources differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/Resources/unity_builtin_extra b/Dedicated_Server_Linux/DatacenterSim_Data/Resources/unity_builtin_extra
new file mode 100644
index 0000000..5b39231
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/Resources/unity_builtin_extra differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/RuntimeInitializeOnLoads.json b/Dedicated_Server_Linux/DatacenterSim_Data/RuntimeInitializeOnLoads.json
new file mode 100644
index 0000000..e648b56
--- /dev/null
+++ b/Dedicated_Server_Linux/DatacenterSim_Data/RuntimeInitializeOnLoads.json
@@ -0,0 +1 @@
+{"root":[{"assemblyName":"Assembly-CSharp","nameSpace":"Mirror","className":"GeneratedNetworkCode","methodName":"InitReadWriters","loadTypes":1,"isUnityClass":false},{"assemblyName":"Cinemachine","nameSpace":"Cinemachine","className":"CinemachineStoryboard","methodName":"InitializeModule","loadTypes":0,"isUnityClass":false},{"assemblyName":"Cinemachine","nameSpace":"Cinemachine","className":"CinemachineCore","methodName":"InitializeModule","loadTypes":0,"isUnityClass":false},{"assemblyName":"Cinemachine","nameSpace":"Cinemachine","className":"UpdateTracker","methodName":"InitializeModule","loadTypes":0,"isUnityClass":false},{"assemblyName":"Cinemachine","nameSpace":"Cinemachine","className":"CinemachineImpulseManager","methodName":"InitializeModule","loadTypes":0,"isUnityClass":false},{"assemblyName":"Cinemachine","nameSpace":"Cinemachine.PostFX","className":"CinemachineVolumeSettings","methodName":"InitializeModule","loadTypes":0,"isUnityClass":false},{"assemblyName":"glTFast","nameSpace":"","className":"$BurstDirectCallInitializer","methodName":"Initialize","loadTypes":2,"isUnityClass":false},{"assemblyName":"Mirror.Authenticators","nameSpace":"Mirror.Authenticators","className":"UniqueNameAuthenticator","methodName":"ResetStatics","loadTypes":0,"isUnityClass":false},{"assemblyName":"Mirror.Authenticators","nameSpace":"Mirror","className":"GeneratedNetworkCode","methodName":"InitReadWriters","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror.Components","nameSpace":"Mirror","className":"GeneratedNetworkCode","methodName":"InitReadWriters","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"NetworkClient","methodName":"Shutdown","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"NetworkDiagnostics","methodName":"ResetStatics","loadTypes":0,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"NetworkIdentity","methodName":"ResetStatics","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"NetworkLoop","methodName":"ResetStatics","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"NetworkLoop","methodName":"RuntimeInitializeOnLoad","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"NetworkManager","methodName":"ResetStatics","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"NetworkServer","methodName":"Shutdown","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"NetworkTime","methodName":"ResetStatics","loadTypes":0,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"ThreadLog","methodName":"Initialize","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror","nameSpace":"Mirror","className":"GeneratedNetworkCode","methodName":"InitReadWriters","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror.Examples","nameSpace":"Mirror.Examples.MultipleMatch","className":"CanvasController","methodName":"ResetStatics","loadTypes":1,"isUnityClass":false},{"assemblyName":"Mirror.Examples","nameSpace":"Mirror","className":"GeneratedNetworkCode","methodName":"InitReadWriters","loadTypes":1,"isUnityClass":false},{"assemblyName":"Unity.Burst","nameSpace":"","className":"$BurstDirectCallInitializer","methodName":"Initialize","loadTypes":2,"isUnityClass":true},{"assemblyName":"Unity.Collections","nameSpace":"","className":"$BurstDirectCallInitializer","methodName":"Initialize","loadTypes":2,"isUnityClass":true},{"assemblyName":"Unity.InputSystem","nameSpace":"UnityEngine.InputSystem","className":"InputSystem","methodName":"RunInitializeInPlayer","loadTypes":4,"isUnityClass":true},{"assemblyName":"Unity.InputSystem","nameSpace":"UnityEngine.InputSystem","className":"InputSystem","methodName":"RunInitialUpdate","loadTypes":1,"isUnityClass":true},{"assemblyName":"Unity.InputSystem","nameSpace":"UnityEngine.InputSystem.UI","className":"InputSystemUIInputModule","methodName":"ResetDefaultActions","loadTypes":4,"isUnityClass":true},{"assemblyName":"Unity.RenderPipelines.Core.Runtime","nameSpace":"UnityEngine.Experimental.Rendering","className":"XRSystem","methodName":"XRSystemInit","loadTypes":3,"isUnityClass":true},{"assemblyName":"Unity.RenderPipelines.Core.Runtime","nameSpace":"UnityEngine.Rendering","className":"DebugUpdater","methodName":"RuntimeInit","loadTypes":0,"isUnityClass":true},{"assemblyName":"Unity.VisualScripting.Core","nameSpace":"Unity.VisualScripting","className":"RuntimeVSUsageUtility","methodName":"RuntimeInitializeOnLoadBeforeSceneLoad","loadTypes":1,"isUnityClass":true}]}
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/ScriptingAssemblies.json b/Dedicated_Server_Linux/DatacenterSim_Data/ScriptingAssemblies.json
new file mode 100644
index 0000000..c32c357
--- /dev/null
+++ b/Dedicated_Server_Linux/DatacenterSim_Data/ScriptingAssemblies.json
@@ -0,0 +1 @@
+{"names":["UnityEngine.dll","UnityEngine.AIModule.dll","UnityEngine.AccessibilityModule.dll","UnityEngine.AndroidJNIModule.dll","UnityEngine.AnimationModule.dll","UnityEngine.AssetBundleModule.dll","UnityEngine.AudioModule.dll","UnityEngine.ClothModule.dll","UnityEngine.ClusterInputModule.dll","UnityEngine.ClusterRendererModule.dll","UnityEngine.ContentLoadModule.dll","UnityEngine.CoreModule.dll","UnityEngine.CrashReportingModule.dll","UnityEngine.DSPGraphModule.dll","UnityEngine.DirectorModule.dll","UnityEngine.GIModule.dll","UnityEngine.GameCenterModule.dll","UnityEngine.GridModule.dll","UnityEngine.HotReloadModule.dll","UnityEngine.IMGUIModule.dll","UnityEngine.ImageConversionModule.dll","UnityEngine.InputModule.dll","UnityEngine.InputLegacyModule.dll","UnityEngine.JSONSerializeModule.dll","UnityEngine.LocalizationModule.dll","UnityEngine.ParticleSystemModule.dll","UnityEngine.PerformanceReportingModule.dll","UnityEngine.PhysicsModule.dll","UnityEngine.Physics2DModule.dll","UnityEngine.ProfilerModule.dll","UnityEngine.PropertiesModule.dll","UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll","UnityEngine.ScreenCaptureModule.dll","UnityEngine.SharedInternalsModule.dll","UnityEngine.SpriteMaskModule.dll","UnityEngine.SpriteShapeModule.dll","UnityEngine.StreamingModule.dll","UnityEngine.SubstanceModule.dll","UnityEngine.SubsystemsModule.dll","UnityEngine.TLSModule.dll","UnityEngine.TerrainModule.dll","UnityEngine.TerrainPhysicsModule.dll","UnityEngine.TextCoreFontEngineModule.dll","UnityEngine.TextCoreTextEngineModule.dll","UnityEngine.TextRenderingModule.dll","UnityEngine.TilemapModule.dll","UnityEngine.UIModule.dll","UnityEngine.UIElementsModule.dll","UnityEngine.UmbraModule.dll","UnityEngine.UnityAnalyticsModule.dll","UnityEngine.UnityAnalyticsCommonModule.dll","UnityEngine.UnityConnectModule.dll","UnityEngine.UnityCurlModule.dll","UnityEngine.UnityTestProtocolModule.dll","UnityEngine.UnityWebRequestModule.dll","UnityEngine.UnityWebRequestAssetBundleModule.dll","UnityEngine.UnityWebRequestAudioModule.dll","UnityEngine.UnityWebRequestTextureModule.dll","UnityEngine.UnityWebRequestWWWModule.dll","UnityEngine.VFXModule.dll","UnityEngine.VRModule.dll","UnityEngine.VehiclesModule.dll","UnityEngine.VideoModule.dll","UnityEngine.VirtualTexturingModule.dll","UnityEngine.WindModule.dll","UnityEngine.XRModule.dll","Assembly-CSharp.dll","glTFast.dots.dll","Unity.RenderPipelines.Core.Runtime.dll","Unity.ProBuilder.Stl.dll","Unity.ProBuilder.Csg.dll","Unity.RenderPipelines.Universal.Config.Runtime.dll","Unity.VisualScripting.Flow.dll","Telepathy.dll","glTFast.Newtonsoft.dll","Unity.RenderPipelines.Core.ShaderLibrary.dll","Mirror.Examples.dll","Unity.Collections.dll","Unity.ProBuilder.Poly2Tri.dll","glTFast.Documentation.Examples.dll","Unity.TextMeshPro.dll","kcp2k.dll","Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll","Unity.RenderPipelines.Universal.Runtime.dll","Unity.Burst.dll","Unity.ProBuilder.dll","Mirror.dll","Unity.VisualScripting.Core.dll","Mirror.Transports.dll","UnityEngine.UI.dll","Mirror.Components.dll","glTFast.Export.dll","Unity.RenderPipelines.Universal.2D.Internal.dll","Unity.RenderPipeline.Universal.ShaderLibrary.dll","Unity.Timeline.dll","Unity.InputSystem.dll","SimpleWebTransport.dll","Unity.InputSystem.ForUI.dll","Mirror.Authenticators.dll","glTFast.dll","Unity.ProBuilder.KdTree.dll","Unity.Mathematics.dll","Unity.RenderPipelines.Universal.Shaders.dll","Unity.VisualScripting.State.dll","Cinemachine.dll","Unity.Collections.LowLevel.ILSupport.dll","Mirror.BouncyCastle.Cryptography.dll","Unity.VisualScripting.Antlr3.Runtime.dll","Unity.Burst.Unsafe.dll","Newtonsoft.Json.dll"],"types":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16]}
\ No newline at end of file
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/app.info b/Dedicated_Server_Linux/DatacenterSim_Data/app.info
new file mode 100644
index 0000000..7a89685
--- /dev/null
+++ b/Dedicated_Server_Linux/DatacenterSim_Data/app.info
@@ -0,0 +1,2 @@
+MAURO Stéphane
+DatacenterSim_Alpha
\ No newline at end of file
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/boot.config b/Dedicated_Server_Linux/DatacenterSim_Data/boot.config
new file mode 100644
index 0000000..131647a
--- /dev/null
+++ b/Dedicated_Server_Linux/DatacenterSim_Data/boot.config
@@ -0,0 +1,6 @@
+gfx-enable-gfx-jobs=1
+gfx-enable-native-gfx-jobs=1
+wait-for-native-debugger=0
+hdr-display-enabled=0
+gc-max-time-slice=3
+build-guid=dda67375c968463c8faf660d4f2e44c6
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/globalgamemanagers b/Dedicated_Server_Linux/DatacenterSim_Data/globalgamemanagers
new file mode 100644
index 0000000..781e066
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/globalgamemanagers differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/globalgamemanagers.assets b/Dedicated_Server_Linux/DatacenterSim_Data/globalgamemanagers.assets
new file mode 100644
index 0000000..78c0e7b
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/globalgamemanagers.assets differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/il2cpp_data/Metadata/global-metadata.dat b/Dedicated_Server_Linux/DatacenterSim_Data/il2cpp_data/Metadata/global-metadata.dat
new file mode 100644
index 0000000..023191b
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/il2cpp_data/Metadata/global-metadata.dat differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/il2cpp_data/Resources/mscorlib.dll-resources.dat b/Dedicated_Server_Linux/DatacenterSim_Data/il2cpp_data/Resources/mscorlib.dll-resources.dat
new file mode 100644
index 0000000..6d144fc
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/il2cpp_data/Resources/mscorlib.dll-resources.dat differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/level0 b/Dedicated_Server_Linux/DatacenterSim_Data/level0
new file mode 100644
index 0000000..0307471
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/level0 differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/resources.assets b/Dedicated_Server_Linux/DatacenterSim_Data/resources.assets
new file mode 100644
index 0000000..fa2e8b7
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/resources.assets differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/sharedassets0.assets b/Dedicated_Server_Linux/DatacenterSim_Data/sharedassets0.assets
new file mode 100644
index 0000000..1b4f488
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/sharedassets0.assets differ
diff --git a/Dedicated_Server_Linux/DatacenterSim_Data/sharedassets0.resource b/Dedicated_Server_Linux/DatacenterSim_Data/sharedassets0.resource
new file mode 100644
index 0000000..465cf10
Binary files /dev/null and b/Dedicated_Server_Linux/DatacenterSim_Data/sharedassets0.resource differ
diff --git a/Dedicated_Server_Linux/GameAssembly.so b/Dedicated_Server_Linux/GameAssembly.so
new file mode 100644
index 0000000..05bbfcc
Binary files /dev/null and b/Dedicated_Server_Linux/GameAssembly.so differ
diff --git a/Dedicated_Server_Linux/UnityPlayer.so b/Dedicated_Server_Linux/UnityPlayer.so
new file mode 100644
index 0000000..50b14d6
Binary files /dev/null and b/Dedicated_Server_Linux/UnityPlayer.so differ
diff --git a/Patchs/dcsim_patches_v4.zip b/Patchs/dcsim_patches_v4.zip
deleted file mode 100644
index 021f288..0000000
Binary files a/Patchs/dcsim_patches_v4.zip and /dev/null differ
diff --git a/Patchs/v4/README_PATCHES_V4.md b/Patchs/v4/README_PATCHES_V4.md
new file mode 100644
index 0000000..8d67ba2
--- /dev/null
+++ b/Patchs/v4/README_PATCHES_V4.md
@@ -0,0 +1,100 @@
+# Patches v4 - VRAI fix du BoutonPower sur dedicated server
+
+## ⚠️ Remplace les patches v3 qui étaient partiellement corrects
+
+La v3 (patch de CableAlimentation + CableRJ45) n'était PAS la cause racine.
+Le patch de v3 reste valide (évite des WARNINGS visuels), mais le vrai bug
+était ailleurs.
+
+## 🎯 La vraie cause racine
+
+`CablageReseau.TrouverPortAlimentation()` cherchait les équipements dans
+**`NetworkClient.spawned`** au lieu de `NetworkServer.spawned`.
+
+Sur un dedicated server (serveur pur, pas host), `NetworkClient` n'est pas
+actif, donc `NetworkClient.spawned` est **vide**. Résultat :
+- `TrouverPortAlimentation()` retournait toujours `null`
+- La condition `if (prise != null && port != null && ...)` était fausse
+- `port.Connecter()` n'était JAMAIS appelé
+- `port.estConnecte` restait à `false`
+- `BoutonPower` refusait d'allumer l'équipement
+
+Le message `[Serveur] Câble alim créé` était trompeur parce qu'il apparaît
+AVANT la vérification, juste au moment de l'entrée dans la méthode.
+
+## ✅ Le fix
+
+Ajout d'un helper universel `TrouverGameObjectNetId(netId)` dans `CablageReseau.cs`
+qui cherche dans le bon dictionnaire selon le contexte :
+- `NetworkServer.spawned` si on est serveur (dedicated OU host)
+- `NetworkClient.spawned` si on est purement client
+- `null` sinon
+
+Les 3 helpers `TrouverPortRJ45`, `TrouverPriseC13`, `TrouverPortAlimentation`
+utilisent maintenant ce helper universel.
+
+## 📄 Script patché (1)
+
+- **`CablageReseau.cs`** — helper universel + refacto des 3 méthodes Trouver*
+
+## 🚀 Actions à faire
+
+### 1. Remplacer le script dans Unity
+
+Copie `Scripts_Modifies/CablageReseau.cs` dans `Assets/Scripts/`, écrase
+l'existant.
+
+### 2. Rebuild Dedicated Server
+
+File → Build Settings → Dedicated Server Linux → Build.
+
+⚠️ **Astuce** : si tu veux t'assurer que le build prend bien les derniers
+scripts, supprime le contenu du dossier de build avant de rebuilder. Unity
+fait parfois du cache agressif.
+
+### 3. Redéploie sur la Debian
+
+```bash
+# Arrêter le service
+sudo systemctl stop datacentersim-server
+
+# Remplacer le dossier
+# (ou scp -r depuis ton Windows)
+
+# Relancer
+sudo systemctl start datacentersim-server
+sudo journalctl -u datacentersim-server -f
+```
+
+### 4. Test
+
+1. Commande PDU + serveur 1U
+2. Branche l'alim PDU → serveur (même procédure qu'avant)
+3. Appuie sur Power → **DOIT S'ALLUMER** ✅
+
+Attendu dans les logs serveur : plus de `BoutonPower: aucun câble
+d'alimentation branché !`.
+
+## 🐛 Bug annexe détecté (pour plus tard)
+
+Les câbles RJ45 ne font RIEN côté serveur actuellement (la méthode
+`CmdCreerCableRJ45` broadcast juste aux clients sans créer d'état serveur).
+
+Conséquence : les logiques type "flux de paquets", "consommation bande
+passante", etc. ne tourneront pas si elles dépendent de l'existence des
+câbles RJ45 côté serveur. À réfléchir dans une future refonte quand tu
+implémenteras ce genre de features.
+
+Pour l'instant c'est OK, le multi fonctionne et les câbles s'affichent
+bien chez tous les clients via le Rpc.
+
+## 🖥️ Rappel Ctrl+C qui ne marche pas
+
+Ajoute `-batchmode -nographics` aux arguments quand tu lances manuellement :
+
+```bash
+./DatacenterSim.x86_64 -server -port 7777 -batchmode -nographics
+```
+
+Ces flags forcent Unity à gérer proprement SIGINT. Ton service systemd les
+utilise déjà (ils sont dans `datacentersim-server.service`).
diff --git a/Patchs/v4/Scripts_Modifies/CablageReseau.cs b/Patchs/v4/Scripts_Modifies/CablageReseau.cs
new file mode 100644
index 0000000..d699087
--- /dev/null
+++ b/Patchs/v4/Scripts_Modifies/CablageReseau.cs
@@ -0,0 +1,420 @@
+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;
+ }
+}
\ No newline at end of file