diff --git a/NebulaModel/Packets/Combat/DFRelay/DFRelayDirectionStateChangePacket.cs b/NebulaModel/Packets/Combat/DFRelay/DFRelayDirectionStateChangePacket.cs new file mode 100644 index 000000000..c22efbb91 --- /dev/null +++ b/NebulaModel/Packets/Combat/DFRelay/DFRelayDirectionStateChangePacket.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NebulaModel.Packets.Combat.DFRelay +{ + public class DFRelayDirectionStateChangePacket + { + public DFRelayDirectionStateChangePacket() { } + + public DFRelayDirectionStateChangePacket(in int relayId, in int hiveAstroId, in int stage, in int newDirection) + { + HiveAstroId = hiveAstroId; + RelayId = relayId; + Stage = stage; + NewDirection = newDirection; + } + + public int HiveAstroId { get; set; } + public int RelayId { get; set; } + public int Stage { get; set; } + public int NewDirection { get; set; } + } +} diff --git a/NebulaNetwork/PacketProcessors/Combat/DFRelay/DFRelayDirectionStateChangeProcessor.cs b/NebulaNetwork/PacketProcessors/Combat/DFRelay/DFRelayDirectionStateChangeProcessor.cs new file mode 100644 index 000000000..dde994e3f --- /dev/null +++ b/NebulaNetwork/PacketProcessors/Combat/DFRelay/DFRelayDirectionStateChangeProcessor.cs @@ -0,0 +1,42 @@ +using NebulaAPI.Packets; +using NebulaModel.Logger; +using NebulaModel.Networking; +using NebulaModel.Packets; +using NebulaModel.Packets.Combat.DFRelay; +using UnityEngine; + +namespace NebulaNetwork.PacketProcessors.Combat.DFRelay +{ + [RegisterPacketProcessor] + public class DFRelayDirectionStateChangeProcessor : PacketProcessor + { + protected override void ProcessPacket(DFRelayDirectionStateChangePacket packet, NebulaConnection conn) + { + var hiveSystem = GameMain.spaceSector.GetHiveByAstroId(packet.HiveAstroId); + if (hiveSystem == null) return; + + var dfRelayComponent = hiveSystem.relays.buffer[packet.RelayId]; + if (dfRelayComponent?.id != packet.RelayId) return; + + switch (packet.NewDirection) + { + case -1: //Relay is being sent home + dfRelayComponent.targetAstroId = 0; + dfRelayComponent.targetLPos = Vector3.zero; + dfRelayComponent.targetYaw = 0f; + dfRelayComponent.baseState = 0; + dfRelayComponent.baseId = 0; + dfRelayComponent.baseTicks = 0; + dfRelayComponent.baseEvolve = default(EvolveData); + dfRelayComponent.baseRespawnCD = 0; + dfRelayComponent.direction = -1; + dfRelayComponent.param0 = 0f; + + dfRelayComponent.stage = packet.Stage; + + Log.Debug($"Relay {dfRelayComponent.id} returning home"); + break; + } + } + } +} diff --git a/NebulaPatcher/Patches/Transpilers/EnemyDFRelayComponent_Transplier.cs b/NebulaPatcher/Patches/Transpilers/EnemyDFRelayComponent_Transplier.cs new file mode 100644 index 000000000..c70b416bc --- /dev/null +++ b/NebulaPatcher/Patches/Transpilers/EnemyDFRelayComponent_Transplier.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using HarmonyLib; +using System.Reflection.Emit; +using NebulaModel.Logger; +using NebulaModel.Packets.Combat.DFRelay; +using NebulaWorld; + +namespace NebulaPatcher.Patches.Transpilers +{ + [HarmonyPatch(typeof(DFRelayComponent))] + internal class EnemyDFRelayComponent_Transplier + { + [HarmonyTranspiler] + [HarmonyPatch(nameof(DFRelayComponent.RelaySailLogic))] + public static IEnumerable RelaySailLogic_Transpiler(IEnumerable instructions) + { + try + { + // Attempt to match anywhere where `direction = -1` is set. + // Change to: + // direction = -1 + // call UpdateRelayDirectionState(relayId, hive) + + var codeMatcher = new CodeMatcher(instructions); + codeMatcher.MatchForward(true, + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(OpCodes.Ldc_I4_M1), + new CodeMatch(i => i.opcode == OpCodes.Stfld && ((FieldInfo)i.operand).Name == "direction")); + + if (codeMatcher.IsInvalid) + { + Log.Error("Transpiler DFRelayComponent.RelaySailLogic matcher is not valid. Mod version not compatible with game version."); + return instructions; + } + + codeMatcher.Repeat(matcher => + { + matcher.InsertAndAdvance( + // Relay ID argument + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, + AccessTools.Field(typeof(DFRelayComponent), nameof(DFRelayComponent.id))), + + // Relay sail stage argument + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, + AccessTools.Field(typeof(DFRelayComponent), nameof(DFRelayComponent.stage))), + + // Hive Astro ID argument + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, + AccessTools.Field(typeof(DFRelayComponent), nameof(DFRelayComponent.hiveAstroId))), + + //Call our method + new CodeInstruction(OpCodes.Call, + AccessTools.Method(typeof(EnemyDFRelayComponent_Transplier), + nameof(ReplicateRelayDirectionChange)))); + }); + + return codeMatcher.InstructionEnumeration(); + } + catch (Exception e) + { + Log.Error("Transpiler DFRelayComponent.RelaySailLogic failed. Mod version not compatible with game version."); + Log.Error(e); + return instructions; + } + } + + static void ReplicateRelayDirectionChange(int relayId, int stage, int hiveAstroId) + { + if (!Multiplayer.IsActive) return; + if (!Multiplayer.Session.IsClient) + { + Multiplayer.Session.Network.SendPacket(new DFRelayDirectionStateChangePacket(relayId, hiveAstroId, stage, -1)); + } + } + } +}