From 55f1f51949fa01428fa907993e16dd5563fa7204 Mon Sep 17 00:00:00 2001
From: starfish <50672801+starfi5h@users.noreply.github.com>
Date: Mon, 5 Feb 2024 04:26:49 +0800
Subject: [PATCH] Update Turrent packets

---
 .../Factory/Turret/TurretPhaseUpdatePacket.cs | 17 +++++
 .../Factory/Turret/TurretSuperNovaPacket.cs   |  8 ++-
 .../Turret/TurretGroupUpdateProcessor.cs      | 14 +++-
 .../Turret/TurretPhaseUpdateProcessor.cs      | 33 +++++++++
 .../Turret/TurretSuperNovaProcessor.cs        | 36 +++++++---
 .../Patches/Dynamic/UITurretWindow_Patch.cs   | 70 +++++++++++++++----
 6 files changed, 151 insertions(+), 27 deletions(-)
 create mode 100644 NebulaModel/Packets/Factory/Turret/TurretPhaseUpdatePacket.cs
 create mode 100644 NebulaNetwork/PacketProcessors/Factory/Turret/TurretPhaseUpdateProcessor.cs

diff --git a/NebulaModel/Packets/Factory/Turret/TurretPhaseUpdatePacket.cs b/NebulaModel/Packets/Factory/Turret/TurretPhaseUpdatePacket.cs
new file mode 100644
index 000000000..7cf25305c
--- /dev/null
+++ b/NebulaModel/Packets/Factory/Turret/TurretPhaseUpdatePacket.cs
@@ -0,0 +1,17 @@
+namespace NebulaModel.Packets.Factory.Turret;
+
+public class TurretPhaseUpdatePacket
+{
+    public TurretPhaseUpdatePacket() { }
+
+    public TurretPhaseUpdatePacket(int turretId, int phasePos, int planetId)
+    {
+        TurretId = turretId;
+        PhasePos = phasePos;
+        PlanetId = planetId;
+    }
+
+    public int TurretId { get; set; }
+    public int PhasePos { get; set; }
+    public int PlanetId { get; set; }
+}
diff --git a/NebulaModel/Packets/Factory/Turret/TurretSuperNovaPacket.cs b/NebulaModel/Packets/Factory/Turret/TurretSuperNovaPacket.cs
index 722585c3e..9affcbb63 100644
--- a/NebulaModel/Packets/Factory/Turret/TurretSuperNovaPacket.cs
+++ b/NebulaModel/Packets/Factory/Turret/TurretSuperNovaPacket.cs
@@ -4,14 +4,16 @@ public class TurretSuperNovaPacket
 {
     public TurretSuperNovaPacket() { }
 
-    public TurretSuperNovaPacket(int turretIndex, bool inSuperNova, int planetId)
+    public TurretSuperNovaPacket(int turretIndex, int brustModeIndex, bool setSuperNova, int planetId)
     {
         TurretIndex = turretIndex;
-        InSuperNova = inSuperNova;
+        BrustModeIndex = brustModeIndex;
+        SetSuperNova = setSuperNova;
         PlanetId = planetId;
     }
 
     public int TurretIndex { get; set; }
-    public bool InSuperNova { get; set; }
+    public int BrustModeIndex { get; set; }
+    public bool SetSuperNova { get; set; }
     public int PlanetId { get; set; }
 }
diff --git a/NebulaNetwork/PacketProcessors/Factory/Turret/TurretGroupUpdateProcessor.cs b/NebulaNetwork/PacketProcessors/Factory/Turret/TurretGroupUpdateProcessor.cs
index 475ad89b2..a706afaf1 100644
--- a/NebulaNetwork/PacketProcessors/Factory/Turret/TurretGroupUpdateProcessor.cs
+++ b/NebulaNetwork/PacketProcessors/Factory/Turret/TurretGroupUpdateProcessor.cs
@@ -19,10 +19,22 @@ protected override void ProcessPacket(TurretGroupUpdatePacket packet, NebulaConn
         {
             return;
         }
-        var turret = pool.buffer[packet.TurretIndex];
+        ref var turret = ref pool.buffer[packet.TurretIndex];
         if (turret.id != -1)
         {
             turret.SetGroup(packet.Group);
         }
+
+        // Refresh UI if viewing on the same turret
+        var uiTurret = UIRoot.instance.uiGame.turretWindow;
+        if (uiTurret.factory == null || uiTurret.factory.planetId != packet.PlanetId || uiTurret.turretId != packet.TurretIndex)
+        {
+            return;
+        }
+        for (var i = 0; i < uiTurret.groupSelectionBtns.Length; i++)
+        {
+            var uibutton = uiTurret.groupSelectionBtns[i];
+            uibutton.highlighted = uibutton.data == (int)turret.group;
+        }
     }
 }
diff --git a/NebulaNetwork/PacketProcessors/Factory/Turret/TurretPhaseUpdateProcessor.cs b/NebulaNetwork/PacketProcessors/Factory/Turret/TurretPhaseUpdateProcessor.cs
new file mode 100644
index 000000000..b8c7e548a
--- /dev/null
+++ b/NebulaNetwork/PacketProcessors/Factory/Turret/TurretPhaseUpdateProcessor.cs
@@ -0,0 +1,33 @@
+#region
+
+using NebulaAPI.Packets;
+using NebulaModel.Networking;
+using NebulaModel.Packets;
+using NebulaModel.Packets.Factory.Turret;
+
+#endregion
+
+namespace NebulaNetwork.PacketProcessors.Factory.Turret;
+
+[RegisterPacketProcessor]
+internal class TurretPhaseUpdateProcessor : PacketProcessor<TurretPhaseUpdatePacket>
+{
+    protected override void ProcessPacket(TurretPhaseUpdatePacket packet, NebulaConnection conn)
+    {
+        var pool = GameMain.galaxy.PlanetById(packet.PlanetId)?.factory?.defenseSystem.turrets;
+        if (pool == null || packet.TurretId < 0 || packet.TurretId >= pool.buffer.Length)
+        {
+            return;
+        }
+        ref var turret = ref pool.buffer[packet.TurretId];
+        turret.phasePos = packet.PhasePos;
+
+        // Refresh UI if viewing on the same turret
+        var uiTurret = UIRoot.instance.uiGame.turretWindow;
+        if (uiTurret.factory == null || uiTurret.factory.planetId != packet.PlanetId || uiTurret.turretId != packet.TurretId)
+        {
+            return;
+        }
+        uiTurret.phaseText.text = (turret.phasePos / 60f).ToString("0.##");
+    }
+}
diff --git a/NebulaNetwork/PacketProcessors/Factory/Turret/TurretSuperNovaProcessor.cs b/NebulaNetwork/PacketProcessors/Factory/Turret/TurretSuperNovaProcessor.cs
index 5bd172743..2e20504a5 100644
--- a/NebulaNetwork/PacketProcessors/Factory/Turret/TurretSuperNovaProcessor.cs
+++ b/NebulaNetwork/PacketProcessors/Factory/Turret/TurretSuperNovaProcessor.cs
@@ -4,6 +4,7 @@
 using NebulaModel.Networking;
 using NebulaModel.Packets;
 using NebulaModel.Packets.Factory.Turret;
+using NebulaWorld;
 
 #endregion
 
@@ -14,23 +15,29 @@ internal class TurretSuperNovaProcessor : PacketProcessor<TurretSuperNovaPacket>
 {
     protected override void ProcessPacket(TurretSuperNovaPacket packet, NebulaConnection conn)
     {
-        var defenseSystem = GameMain.galaxy.PlanetById(packet.PlanetId)?.factory?.defenseSystem;
+        var planet = GameMain.galaxy.PlanetById(packet.PlanetId);
+        var defenseSystem = planet?.factory?.defenseSystem;
         var pool = defenseSystem?.turrets;
         if (pool == null || packet.TurretIndex == -1 || packet.TurretIndex >= pool.buffer.Length ||
             pool.buffer[packet.TurretIndex].id == -1)
         {
             return;
         }
-        //TODO: Evaluate in PR, should I count on other packet, or should I pass through?
-        var burstModeIndex = UITurretWindow.burstModeIndex;
-        var inSuperNova = packet.InSuperNova;
 
-        var refTurret = pool.buffer[packet.TurretIndex];
+        if (IsHost)
+        {
+            // Broadcast supernova events to other players in the system
+            var starId = planet.star.id;
+            Multiplayer.Session.Network.SendPacketToStar(packet, starId);
+        }
 
-        switch (burstModeIndex)
+        var setSuperNova = packet.SetSuperNova;
+        UITurretWindow.burstModeIndex = packet.BrustModeIndex; // Leave a mark in UI
+        ref var refTurret = ref pool.buffer[packet.TurretIndex];
+        switch (packet.BrustModeIndex)
         {
             case 1:
-                if (inSuperNova)
+                if (setSuperNova)
                 {
                     refTurret.SetSupernova();
                 }
@@ -40,7 +47,7 @@ protected override void ProcessPacket(TurretSuperNovaPacket packet, NebulaConnec
                 }
                 break;
             case 2:
-                if (inSuperNova)
+                if (setSuperNova)
                 {
                     defenseSystem.SetGroupTurretsSupernova(refTurret.group);
                 }
@@ -50,7 +57,7 @@ protected override void ProcessPacket(TurretSuperNovaPacket packet, NebulaConnec
                 }
                 break;
             case 3:
-                if (inSuperNova)
+                if (setSuperNova)
                 {
                     defenseSystem.SetGlobalTurretsSupernova();
                 }
@@ -60,5 +67,16 @@ protected override void ProcessPacket(TurretSuperNovaPacket packet, NebulaConnec
                 }
                 break;
         }
+
+        var uiTurret = UIRoot.instance.uiGame.turretWindow;
+        if (uiTurret.factory == null || uiTurret.factory.planetId != packet.PlanetId || uiTurret.turretId != packet.TurretIndex)
+        {
+            return;
+        }
+        uiTurret.supernovaWait = packet.SetSuperNova;
+        if (refTurret.inSupernova)
+        {
+            GameMain.gameScenario.NotifyOnSupernovaUITriggered();
+        }
     }
 }
diff --git a/NebulaPatcher/Patches/Dynamic/UITurretWindow_Patch.cs b/NebulaPatcher/Patches/Dynamic/UITurretWindow_Patch.cs
index 397a04128..f88ad3c5d 100644
--- a/NebulaPatcher/Patches/Dynamic/UITurretWindow_Patch.cs
+++ b/NebulaPatcher/Patches/Dynamic/UITurretWindow_Patch.cs
@@ -11,6 +11,30 @@ namespace NebulaPatcher.Patches.Dynamic;
 [HarmonyPatch(typeof(UITurretWindow))]
 internal class UITurretWindow_Patch
 {
+    [HarmonyPostfix]
+    [HarmonyPatch(nameof(UITurretWindow.OnTurretShiftValueChange))]
+    public static void OnTurretShiftValueChange_Postfix(UITurretWindow __instance)
+    {
+        //Notify about manual bullet inserting / withdrawing change
+        if (!Multiplayer.IsActive || __instance is null)
+        {
+            return;
+        }
+
+        if (__instance._turretId == 0 || __instance.factory == null || __instance.player == null)
+        {
+            return;
+        }
+        ref var turret = ref __instance.defenseSystem.turrets.buffer[__instance.turretId];
+        if (turret.id != __instance.turretId || turret.type != ETurretType.Disturb)
+        {
+            return;
+        }
+
+        Multiplayer.Session.Network.SendPacketToLocalStar(new TurretPhaseUpdatePacket(
+            turret.id, turret.phasePos, __instance.factory.planetId));
+    }
+
     [HarmonyPostfix]
     [HarmonyPatch(nameof(UITurretWindow.OnHandFillAmmoButtonClick))]
     public static void OnHandFillAmmoButtonClick_Postfix(UITurretWindow __instance)
@@ -50,9 +74,6 @@ public static void AmmoButtonClick_Postfix(UITurretWindow __instance)
 
         Multiplayer.Session.Network.SendPacketToLocalStar(new TurretStorageUpdatePacket(turret,
             GameMain.localPlanet?.id ?? -1));
-
-        //Multiplayer.Session.Network.SendPacketToLocalStar(new TurretStorageUpdatePacket(__instance.turretId,
-        // turret.itemId, turret.itemCount, turret.itemInc, GameMain.localPlanet?.id ?? -1));
     }
 
 
@@ -99,19 +120,40 @@ public static void OnSetBurstMode_Postfix(UITurretWindow __instance, int obj)
             GameMain.localPlanet?.id ?? -1));
     }
 
-    //TODO: Work In Progress on SuperNova
-    //[HarmonyPostfix]
-    //[HarmonyPatch(nameof(UITurretWindow.SuperNovaBtn_onClick))]
-    //public static void OnSetSuperNova_Postfix(UITurretWindow __instance, int obj)
-    //{
-    //    if (!Multiplayer.IsActive)
-    //        return;
+    [HarmonyPrefix]
+    [HarmonyPatch(nameof(UITurretWindow.SuperNovaBtn_onClick))]
+    public static bool OnSetSuperNova_Prefix(UITurretWindow __instance)
+    {
+        if (!Multiplayer.IsActive)
+        {
+            return true;
+        }
 
-    //    bool superNovaOn = __instance.defenseSystem.turrets.buffer[__instance.turretId].inSupernova;
+        if (__instance.turretId == 0 || __instance.factory == null || __instance.player == null)
+        {
+            return false;
+        }
+        ref var turret = ref __instance.defenseSystem.turrets.buffer[__instance.turretId];
+        if (turret.id != __instance.turretId)
+        {
+            return false;
+        }
+        var packet = new TurretSuperNovaPacket(__instance.turretId,
+            UITurretWindow.burstModeIndex, !turret.inSupernova, __instance.factory.planetId);
 
-    //    Multiplayer.Session.Network.SendPacketToLocalStar(new TurretSuperNovaPacket(__instance.turretId, superNovaOn,
-    //        GameMain.localPlanet?.id ?? -1));
-    //}
+        if (Multiplayer.Session.IsClient)
+        {
+            // Client will wait for server to authorize
+            Multiplayer.Session.Network.SendPacket(packet);
+            __instance.supernovaWait &= !turret.inSupernova;
+            return false;
+        }
+        else
+        {
+            Multiplayer.Session.Network.SendPacketToLocalStar(packet);
+            return true;
+        }
+    }
 
 
     [HarmonyPostfix]