static IEnumerable <CodeInstruction> FindNext_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL) { var codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(false, new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "serving"), new CodeMatch(i => i.IsLdloc()), new CodeMatch(OpCodes.Callvirt), new CodeMatch(OpCodes.Brtrue) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("MechaDroneLogic_Transpiler.FindNext failed. Mod version not compatible with game version."); return(instructions); } var target = codeMatcher.InstructionAt(1); var jump = codeMatcher.InstructionAt(3).operand; return(codeMatcher .Advance(4) .InsertAndAdvance(target) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <int, bool> >((targetId) => { return DroneManager.IsPendingBuildRequest(targetId); })) .Insert(new CodeInstruction(OpCodes.Brtrue, jump)) .InstructionEnumeration()); }
public static bool BuildFinally_Prefix(PlanetFactory __instance, Player player, int prebuildId) { if (!SimulatedWorld.Initialized) { return(true); } if (LocalPlayer.IsMasterClient) { if (!FactoryManager.ContainsPrebuildRequest(__instance.planetId, prebuildId)) { // This prevents duplicating the entity when multiple players trigger the BuildFinally for the same entity at the same time. // If it occurs in any other circumstances, it means that we have some desynchronization between clients and host prebuilds buffers. Log.Warn($"BuildFinally was called without having a corresponding PrebuildRequest for the prebuild {prebuildId} on the planet {__instance.planetId}"); return(false); } // Remove the prebuild request from the list since we will now convert it to a real building FactoryManager.RemovePrebuildRequest(__instance.planetId, prebuildId); } if (LocalPlayer.IsMasterClient || !FactoryManager.IsIncomingRequest) { LocalPlayer.SendPacket(new BuildEntityRequest(__instance.planetId, prebuildId, FactoryManager.PacketAuthor == FactoryManager.AUTHOR_NONE ? LocalPlayer.PlayerId : FactoryManager.PacketAuthor)); } if (!LocalPlayer.IsMasterClient && !FactoryManager.IsIncomingRequest && !DroneManager.IsPendingBuildRequest(-prebuildId)) { DroneManager.AddBuildRequestSent(-prebuildId); } return(LocalPlayer.IsMasterClient || FactoryManager.IsIncomingRequest); }
static IEnumerable <CodeInstruction> UpdateTargets_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL) { /* * Update search for new targets. Do not include targets that are already pending response from server. * Change: * if (!this.serving.Contains(num4) && (prebuildPool[i].itemRequired == 0 || prebuildPool[i].itemRequired <= this.player.package.GetItemCount((int)prebuildPool[i].protoId))) * * To: * if (!this.serving.Contains(num4) && !DroneManager.IsPendingBuildRequest(num4) && (prebuildPool[i].itemRequired == 0 || prebuildPool[i].itemRequired <= this.player.package.GetItemCount((int)prebuildPool[i].protoId))) */ var codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(true, new CodeMatch(i => i.IsLdarg()), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "serving"), new CodeMatch(i => i.IsLdloc()), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "Contains"), new CodeMatch(OpCodes.Brtrue) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("MechaDroneLogic_Transpiler.UpdateTargets_Transpiler 1 failed. Mod version not compatible with game version."); return(instructions); } var num4Instruction = codeMatcher.InstructionAt(-2); var jumpInstruction = codeMatcher.Instruction; codeMatcher = codeMatcher .Advance(1) .InsertAndAdvance(num4Instruction) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <int, bool> >((num4) => { return(DroneManager.IsPendingBuildRequest(num4)); })) .InsertAndAdvance(jumpInstruction); /* * Make sure targets are only chosen if player is closest to the build preview * Change: * if (a.sqrMagnitude > this.sqrMinBuildAlt && sqrMagnitude <= num2) * To: * if (DroneManager.AmIClosestPlayer(ref a) && a.sqrMagnitude > this.sqrMinBuildAlt && sqrMagnitude <= num2) */ codeMatcher = codeMatcher .MatchForward(false, new CodeMatch(i => i.IsLdloc()), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "get_sqrMagnitude"), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "sqrMinBuildAlt"), new CodeMatch(OpCodes.Ble_Un) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("MechaDroneLogic_Transpiler.UpdateTargets_Transpiler 2 failed. Mod version not compatible with game version."); return(codeMatcher.InstructionEnumeration()); } var aOperand = codeMatcher.Instruction.operand; var jumpOperand = codeMatcher.InstructionAt(4).operand; codeMatcher = codeMatcher .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, aOperand)) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <Vector3, bool> >((aVar) => { return(DroneManager.AmIClosestPlayer(ref aVar)); })) .InsertAndAdvance(new CodeInstruction(OpCodes.Brfalse, jumpOperand)); /* * Insert * DroneManager.BroadcastDroneOrder(droneId, entityId, stage); * After * this.serving.Add(num3); */ codeMatcher = codeMatcher .MatchForward(true, new CodeMatch(i => i.IsLdarg()), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "serving"), new CodeMatch(i => i.IsLdloc()), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "Add"), new CodeMatch(OpCodes.Pop) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("MechaDroneLogic_Transpiler.UpdateTargets_Transpiler 3 failed. Mod version not compatible with game version."); return(codeMatcher.InstructionEnumeration()); } // The index from drones[j] var droneIdInstruction = codeMatcher.InstructionAt(-8); // num3 from this.serving.Add(num3); var entityIdInstruction = codeMatcher.InstructionAt(-2); // drones[j].stage = 1; var stageInstruction = new CodeInstruction(OpCodes.Ldc_I4_1); return(codeMatcher .Advance(1) .InsertAndAdvance(droneIdInstruction) .InsertAndAdvance(entityIdInstruction) .InsertAndAdvance(stageInstruction) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Action <int, int, int> >((droneId, entityId, stage) => { DroneManager.BroadcastDroneOrder(droneId, entityId, stage); })) .InstructionEnumeration()); }