using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using HarmonyLib; using NitroxClient.MonoBehaviours.Cyclops; using NitroxModel.Helper; namespace NitroxPatcher.Patches.Dynamic; /// /// Registers the local player in the cyclops it enters. /// public sealed partial class SubRoot_OnPlayerEntered_Patch : NitroxPatch, IDynamicPatch { private static readonly MethodInfo TARGET_METHOD = Reflect.Method((SubRoot t) => t.OnPlayerEntered(default(Player))); private static readonly OpCode START_INJECTION_CODE = OpCodes.Ldarg_0; private static readonly OpCode START_INJECTION_CODE_INVINCIBLE = OpCodes.Stfld; private static readonly FieldInfo LIVEMIXIN_INVINCIBLE = Reflect.Field((LiveMixin t) => t.invincible); /* There is a bug, where Subroot.live is not loaded when starting in a cyclops. Therefore this codepiece needs to check that and jump accordingly if not present * * For this change * * this.live.invincible = false * * to * * if (this.live != null) * { * this.live.invincible = false * } */ public static IEnumerable Transpiler(MethodBase original, IEnumerable instructions, ILGenerator generator) { List instructionList = instructions.ToList(); int injectionPoint = 0; Label newJumpPoint = generator.DefineLabel(); for (int i = 3; i < instructionList.Count; i++) { if (instructionList[i].opcode == START_INJECTION_CODE_INVINCIBLE && Equals(instructionList[i].operand, LIVEMIXIN_INVINCIBLE)) { if (instructionList[i - 3].opcode == START_INJECTION_CODE) { instructionList[i + 1].labels.Add(newJumpPoint); injectionPoint = i - 3; } } } if (injectionPoint != 0) { MethodInfo op_inequality_method = typeof(UnityEngine.Object).GetMethod("op_Inequality"); List injectedInstructions = new() { new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, Reflect.Field((SubRoot t) => t.live)), new CodeInstruction(OpCodes.Ldnull), new CodeInstruction(OpCodes.Call, op_inequality_method), new CodeInstruction(OpCodes.Brfalse, newJumpPoint) }; instructionList.InsertRange(injectionPoint, injectedInstructions); } return instructionList; } public static void Postfix(SubRoot __instance) { if (__instance.TryGetComponent(out NitroxCyclops nitroxCyclops)) { nitroxCyclops.OnLocalPlayerEnter(); } } }