private static IEnumerable <CodeInstruction> TryPlayCustomTopicAdvTpl(IEnumerable <CodeInstruction> instructions) { var matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldstr, "話題を振る")) .MatchForward(true, new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(TalkScene), nameof(TalkScene.isNPC)))) .Advance(1) .ThrowIfNotMatch("Brtrue not found", new CodeMatch(OpCodes.Brtrue)); var startPos = matcher.Pos; // Figure out where the if else ends so we can jump there if we want to skip it // First go to the start of else, then step back and get the label at the end of if that skips over the else var elseLabel = ((Label)matcher.Operand); matcher.MatchForward(false, new CodeMatch(instruction => instruction.labels.Contains(elseLabel))) .Advance(-1) .ThrowIfNotMatch("Br not found", new CodeMatch(OpCodes.Br)); var skipIfelseLabel = matcher.Operand; // Go back to the start of the if matcher.Advance(startPos - matcher.Pos).ThrowIfNotMatch("Brtrue not found 2", new CodeMatch(OpCodes.Brtrue)); // Go back to the first if, then insert our if before it // Copy the `this` load instead of hardcoding it just in case (isNPC takes it) matcher.Advance(-2); var loadInstrCopy = new CodeInstruction(matcher.Opcode, matcher.Operand); matcher.Advance(1).Insert( new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(TopicHooks), nameof(TryPlayCustomTopicAdvHook))), new CodeInstruction(OpCodes.Brtrue, skipIfelseLabel), loadInstrCopy); return(matcher.Instructions()); }
public static IEnumerable <CodeInstruction> GameTick_Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PlayerControlGizmo), "player")), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_controller"), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_modelVisible"), new CodeMatch(OpCodes.Brfalse)); var jmpPos = matcher.Operand; matcher.Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <PlayerControlGizmo, bool> >((PlayerControlGizmo _this) => { return(Multiplayer.IsActive && _this.player.navigation.indicatorAstroId > 100000); })) .Insert(new CodeInstruction(OpCodes.Brtrue, jmpPos)); matcher.MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PlayerControlGizmo), "player")), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_navigation"), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_indicatorAstroId"), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Ble)); jmpPos = matcher.Operand; matcher.Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <PlayerControlGizmo, bool> >((PlayerControlGizmo _this) => { return(Multiplayer.IsActive && _this.player.navigation.indicatorAstroId > 100000); })) .Insert(new CodeInstruction(OpCodes.Brtrue, jmpPos)); matcher.MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PlayerControlGizmo), "player")), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_navigation"), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_indicatorAstroId"), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Ble)); jmpPos = matcher.Operand; matcher.Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <PlayerControlGizmo, bool> >((PlayerControlGizmo _this) => { return(Multiplayer.IsActive && _this.player.navigation.indicatorAstroId > 100000); })) .Insert(new CodeInstruction(OpCodes.Brtrue, jmpPos)); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> CargoPathPatch(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(CargoPath), nameof(CargoPath.chunks))), new CodeMatch(OpCodes.Ldloc_S) ); matcher.MatchForward(false, new CodeMatch(OpCodes.Stloc_S)); object beginArg = matcher.Operand; matcher.Advance(1).MatchForward(false, new CodeMatch(OpCodes.Stloc_S)); object speedArg = matcher.Operand; matcher.MatchForward(false, new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Stloc_S)); matcher.Advance(2) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloca_S, beginArg)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloca_S, speedArg)) .InsertAndAdvance(Transpilers.EmitDelegate <RefAction <CargoPath, int, int> >((CargoPath path, ref int begin, ref int speed) => { // The change if (speed > 10) // If the speed is greater than 10, the length judgment process is performed to prevent crossing the boundary { for (int i = 10; i <= speed; i++) { if (begin + i + 10 >= path.bufferLength) // About to leave the end of the conveyor belt { speed = i; break; } if (path.buffer[begin + i] != 0) // Not empty within the speed range { speed = i; break; } } if (speed < 10) { speed = 10; // If the speed slows down to within a safe speed, set it to a safe speed } } })); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> MultiplyUnlockText(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(TechProto), nameof(TechProto.UnlockFunctions)))) .MatchForward(false, new CodeMatch(instr => instr.IsStloc())); OpCode typeStlocOpcode = matcher.Opcode.ToLoad(); object typeStlocOperand = matcher.Operand; matcher.MatchForward(false, new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(TechProto), nameof(TechProto.UnlockValues)))) .MatchForward(false, new CodeMatch(OpCodes.Stloc_S)); object arg = matcher.Operand; matcher.Advance(1) .InsertAndAdvance(new CodeInstruction(typeStlocOpcode, typeStlocOperand)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloca_S, arg)) .InsertAndAdvance(Transpilers.EmitDelegate <RefAction <int, int> >((int type, ref int value) => { if (type == 18) { value *= GigaStationsPlugin.droneCapacityMultiplier; } else if (type == 19) { value *= GigaStationsPlugin.vesselCapacityMultiplier; } })); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .End() .MatchBack(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.cursorTarget)))); CodeMatcher matcher2 = matcher.Clone().MatchForward(false, new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldc_I4_S) , new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(BuildPreview), nameof(BuildPreview.condition)))); object previewVariable = matcher2.Operand; matcher.Advance(1); while (matcher.Opcode != OpCodes.Stloc_S) { matcher.RemoveInstruction(); } matcher.InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, previewVariable)) .InsertAndAdvance(Transpilers.EmitDelegate <Func <BuildTool_BlueprintPaste, BuildPreview, Vector3> >((tool, preview) => preview.lpos.normalized * Mathf.Min(tool.planet.realRadius * 0.025f, 20f))); return(matcher.InstructionEnumeration()); }
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 IEnumerable <CodeInstruction> PowerSystem_RequestDysonSpherePower_Transpiler(IEnumerable <CodeInstruction> instructions) { //Prevent dysonSphere.energyReqCurrentTick from changing on the client side //Change: if (this.dysonSphere != null) //To: if (this.dysonSphere != null && (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost)) try { CodeMatcher codeMatcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PowerSystem), "dysonSphere")), new CodeMatch(OpCodes.Brfalse) //IL #93 ); object label = codeMatcher.Instruction.operand; codeMatcher.Advance(1) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return(!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost); })) .InsertAndAdvance(new CodeInstruction(OpCodes.Brfalse_S, label)); return(codeMatcher.InstructionEnumeration()); } catch { NebulaModel.Logger.Log.Error("PowerSystem.RequestDysonSpherePower_Transpiler failed. Mod version not compatible with game version."); return(instructions); } }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il) { var matcher = new CodeMatcher(instructions, il); // Search for the first time we check if the player has opened a chest, this happens when adding the items in the opened inventory to the dictionary matcher.MatchForward(false, new CodeMatch(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.player))), new CodeMatch(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.myPlayer))), new CodeMatch(OpCodes.Ldelem_Ref), new CodeMatch(OpCodes.Ldfld, typeof(Player).GetField(nameof(Player.chest))), new CodeMatch(OpCodes.Ldc_I4_M1), new CodeMatch(OpCodes.Beq)); matcher.Instruction.opcode = OpCodes.Nop; matcher.Instruction.operand = null; matcher.Advance(1); var getItemCode = new CodeInstruction[] { new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldloca_S, 1), new CodeInstruction(OpCodes.Ldloca_S, 2), new CodeInstruction(OpCodes.Call, typeof(StorageUI).GetMethod(nameof(StorageUI.DoWithdrawItemForCraft), new Type[] { typeof(Recipe), typeof(Item).MakeByRefType(), typeof(int).MakeByRefType() })), // The old instruction we destroyed new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.player))) }; matcher.InsertAndAdvance(getItemCode); return(matcher.InstructionEnumeration()); }
private static IEnumerable <CodeInstruction> PickupBeltItems_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL) { CodeMatcher codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(true, new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == nameof(CargoPath.TryPickItem)) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("CargoTraffic.PickupBeltItems_Transpiler failed. Mod version not compatible with game version."); return(instructions); } return(codeMatcher .Advance(2) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 5)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_3)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_2)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_3)) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Action <int, int, int, bool> >((item, cnt, belt, all) => { // Only pickup by hand needs to be synced if (Multiplayer.IsActive && !all) { Multiplayer.Session.Belts.RegisterBeltPickupUpdate(item, cnt, belt); } })) .InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> Get_nearestFactory_Transpiler(IEnumerable <CodeInstruction> instructions) { var matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldloc_3), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldelem_Ref), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Brfalse)); if (matcher.IsInvalid) { NebulaModel.Logger.Log.Error("Get_nearestFactory_Transpiler failed. Mod version not compatible with game version."); return(instructions); } var op = matcher.InstructionAt(5).operand; return(matcher .Advance(-1) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return LocalPlayer.IsMasterClient || !SimulatedWorld.Initialized; })) .Insert(new CodeInstruction(OpCodes.Brfalse, op)) .InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> Get_nearestFactory_Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldloc_3), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldelem_Ref), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Brfalse)); if (matcher.IsInvalid) { NebulaModel.Logger.Log.Error("Player.Get_nearestFactory_Transpiler failed. Mod version not compatible with game version."); return(instructions); } object op = matcher.InstructionAt(5).operand; return(matcher .Advance(-1) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return !Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost; })) .Insert(new CodeInstruction(OpCodes.Brfalse, op)) .InstructionEnumeration()); }
private static void MatchInserterEntityOnly(BuildTool_BlueprintPaste tool, BuildPreview bp) { IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldloca_S), new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(ColliderData), nameof(ColliderData.objType))) ) .MatchForward(false, new CodeMatch(OpCodes.Ldloca_S), new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(ColliderData), nameof(ColliderData.objType))) ); matcher.Opcode = OpCodes.Nop; matcher.Operand = null; matcher.Advance(1) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) .SetOpcodeAndAdvance(OpCodes.Br); return(matcher.InstructionEnumeration()); } // make compiler happy _ = Transpiler(null); }
static IEnumerable <CodeInstruction> InternalUpdateResearch_Transpiler(IEnumerable <CodeInstruction> instructions) { //Change: if (ts.hashUploaded >= ts.hashNeeded) //To: if (ts.hashUploaded >= ts.hashNeeded && (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost)) try { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(i => i.IsLdarg()), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(TechState), nameof(TechState.hashUploaded))), new CodeMatch(i => i.IsLdarg()), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(TechState), nameof(TechState.hashNeeded))), new CodeMatch(OpCodes.Blt) //IL 339 ); object label = matcher.Instruction.operand; matcher.Advance(1) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return(!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost); })) .InsertAndAdvance(new CodeInstruction(OpCodes.Brfalse_S, label)); return(matcher.InstructionEnumeration()); } catch { NebulaModel.Logger.Log.Error("LabComponent.InternalUpdateResearch_Transpiler failed. Mod version not compatible with game version."); return(instructions); } }
public static IEnumerable <CodeInstruction> Refresh_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL) { CodeMatcher codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(true, new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "userName") ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("UIVersionText.Refresh_Transpiler failed. Mod version not compatible with game version."); return(instructions); } return(codeMatcher .Advance(1) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <string, string> >((text) => { if (Multiplayer.IsActive) { text = $"{PluginInfo.PLUGIN_SHORT_NAME} {PluginInfo.PLUGIN_DISPLAY_VERSION}\r\n{text}"; } return text; })) .InstructionEnumeration()); }
static IEnumerable <CodeInstruction> PickupBeltItems_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL) { var codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(true, new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == nameof(CargoPath.TryPickItem)) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("CargoTraffic.PickupBeltItems_Transpiler failed. Mod version not compatible with game version."); return(instructions); } var itemId = codeMatcher.InstructionAt(3); var count = codeMatcher.InstructionAt(4); var beltId = new CodeInstruction(OpCodes.Ldarg_2); var segId = codeMatcher.InstructionAt(-6); return(codeMatcher .Advance(2) .InsertAndAdvance(itemId) .InsertAndAdvance(count) .InsertAndAdvance(beltId) .InsertAndAdvance(segId) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Action <int, int, int, int> >((item, cnt, belt, seg) => { if (SimulatedWorld.Initialized) { BeltManager.RegisterBeltPickupUpdate(item, cnt, belt, seg); } })) .InstructionEnumeration()); }
public static CodeMatcher MoveToLabel(this CodeMatcher matcher, Label label) { while (!matcher.Labels.Contains(label)) { matcher.Advance(1); } return(matcher); }
public static IEnumerable <CodeInstruction> _OnUpdate_Transpiler(IEnumerable <CodeInstruction> instructions) { try { int pos1, pos2; CodeMatcher matcher = new CodeMatcher(instructions); matcher.MatchForward(false, new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(DysonNode), "color"))); pos1 = matcher.Pos; matcher.MatchBack(false, new CodeMatch(OpCodes.Ldloc_S)); pos2 = matcher.Pos; matcher.Advance(pos1 - pos2 + 1) .Insert( new CodeInstruction(matcher.InstructionAt(pos2 - pos1 - 1)), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UIDysonBrush_Paint_Transpiler), "SendNodePacket")) ); matcher.MatchForward(false, new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(DysonFrame), "color"))); pos1 = matcher.Pos; matcher.MatchBack(false, new CodeMatch(OpCodes.Ldloc_S)); pos2 = matcher.Pos; matcher.Advance(pos1 - pos2 + 1) .Insert( new CodeInstruction(matcher.InstructionAt(pos2 - pos1 - 1)), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UIDysonBrush_Paint_Transpiler), "SendFramePacket")) ); matcher.MatchForward(false, new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(DysonShell), "color"))); pos1 = matcher.Pos; matcher.MatchBack(false, new CodeMatch(OpCodes.Ldloc_S)); pos2 = matcher.Pos; matcher.Advance(pos1 - pos2 + 1) .Insert( new CodeInstruction(matcher.InstructionAt(pos2 - pos1 - 1)), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UIDysonBrush_Paint_Transpiler), "SendShellPacket")) ); return(matcher.InstructionEnumeration()); } catch { NebulaModel.Logger.Log.Error("UIDysonBrush_Paint._OnUpdate_Transpiler failed. Mod version not compatible with game version."); return(instructions); } }
private static IEnumerable <CodeInstruction> FixedUpdate_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL) { CodeMatcher codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(true, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Player), "ApplyGamePauseState")), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GameMain), "_paused")), new CodeMatch(OpCodes.Brtrue) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("GameMain.FixedUpdate_Transpiler failed. Mod version not compatible with game version."); return(instructions); } object skipLabel1 = codeMatcher.Instruction.operand; codeMatcher .CreateLabelAt(codeMatcher.Pos + 1, out Label nextLabel1) .InsertAndAdvance( new CodeInstruction(OpCodes.Brfalse_S, nextLabel1), //_paused== false => enter loop new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), new CodeInstruction(OpCodes.Brfalse_S, skipLabel1), //_paused== true && Multiplayer.Session == null => can pause, skip loop new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), new CodeInstruction(OpCodes.Callvirt, AccessTools.DeclaredPropertyGetter(typeof(MultiplayerSession), nameof(MultiplayerSession.CanPause))) ) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GameMain), "_fullscreenPaused")), new CodeMatch(OpCodes.Brfalse) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("GameMain.FixedUpdate_Transpiler 2 failed. Mod version not compatible with game version."); return(instructions); } object skipLabel2 = codeMatcher.Instruction.operand; return(codeMatcher .Advance(1) .CreateLabel(out Label nextLabel2) //position of checking _fullscreenPausedUnlockOneFrame .InsertAndAdvance( new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), new CodeInstruction(OpCodes.Brfalse_S, nextLabel2), //_fullscreenPaused && Multiplayer.Session == null => can pause, jump to next check new CodeInstruction(OpCodes.Call, AccessTools.DeclaredPropertyGetter(typeof(Multiplayer), nameof(Multiplayer.Session))), new CodeInstruction(OpCodes.Callvirt, AccessTools.DeclaredPropertyGetter(typeof(MultiplayerSession), nameof(MultiplayerSession.CanPause))), new CodeInstruction(OpCodes.Brfalse_S, skipLabel2) //_fullscreenPaused && Multiplayer.Session.CanPause == fasle => can't pause, skip ) .InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> AddColors(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldloc_1), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BeltComponent), nameof(BeltComponent.speed))), new CodeMatch(OpCodes.Ldc_I4_1) ); CodeMatcher matcher2 = matcher.Clone(); matcher2.MatchForward(true, new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Stloc_S)); object arg = matcher2.Operand; matcher2.Advance(1); object label = matcher2.Operand; matcher.Advance(2) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, arg)) .SetInstruction(Transpilers.EmitDelegate <Func <int, int, int> >((speed, other) => { if (speed <= 1) { return(other); } if (speed <= 2) { other += 4; } else if (speed <= 5) { other += 8; } else if (speed <= 12) { other += 12; } return(other); })) .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Stloc_S, arg)) .SetInstruction(new CodeInstruction(OpCodes.Br, label)); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> OnPopulateFamiliars(IEnumerable <CodeInstruction> instructions, ILGenerator il) { var matcher = new CodeMatcher(instructions, il) .MatchForward(true, new CodeMatch(i => i.opcode == OpCodes.Blt)); // Patches the loop so it stops after all the vanilla familiars. var ret = matcher .Advance(-3) .RemoveInstructions(3) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldc_I4, 13)) .InstructionEnumeration(); return(ret); }
static IEnumerable <CodeInstruction> RemoveBrokenConnections(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BuildPreview), nameof(BuildPreview.bpgpuiModelId))), new CodeMatch(OpCodes.Ldc_I4_0) ).Advance(1); Label label = (Label)matcher.Instruction.operand; matcher.Advance(-2) .InsertAndAdvance(Transpilers.EmitDelegate <Func <BuildPreview, bool> >(bp => { if (!isEnabled && !NebulaModAPI.NebulaIsInstalled) { return(true); } if (bp.desc.multiLevel) { BuildPreview current = bp; while (current.input != null) { if (!current.input.IsGood()) { return(false); } current = current.input; } } if (bp.desc.isInserter) { if (bp.input != null && !bp.input.IsGood()) { return(bp.input.desc.isBelt); } if (bp.output != null && !bp.output.IsGood()) { return(bp.output.desc.isBelt); } } return(true); })) .InsertAndAdvance(new CodeInstruction(OpCodes.Brfalse, label)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_3)); return(matcher.InstructionEnumeration()); }
private static IEnumerable <CodeInstruction> InternalUpdate_Transpiler(IEnumerable <CodeInstruction> instructions) { // Store projectile data after sphere.AddDysonRocket(dysonRocket, autoDysonNode) if IsUpdateNeeded == true try { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(DysonSphere), nameof(DysonSphere.AddDysonRocket))) //IL#310 ); CodeInstruction loadInstruction = matcher.InstructionAt(-1); //autoDysonNode matcher.Advance(2) .InsertAndAdvance( new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(SiloComponent), nameof(SiloComponent.planetId))), new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(SiloComponent), nameof(SiloComponent.localPos))), loadInstruction, HarmonyLib.Transpilers.EmitDelegate <Action <int, Vector3, DysonNode> >((planetId, localPos, autoDysonNode) => { // If the dyson sphere has no subscribers anymore, skip this data if (!Multiplayer.IsActive || !Multiplayer.Session.Launch.Snapshots.ContainsKey(planetId / 100 - 1)) { return; } // Assume layerId < 16, nodeId < 4096 DysonLaunchData.Projectile data = new DysonLaunchData.Projectile { PlanetId = planetId, TargetId = (ushort)((autoDysonNode.layerId << 12) | (autoDysonNode.id & 0x0FFF)), LocalPos = localPos }; Multiplayer.Session.Launch.ProjectileBag.Add(data); }) ); return(matcher.InstructionEnumeration()); } catch { NebulaModel.Logger.Log.Error("SiloComponent.InternalUpdate_Transpiler failed. Mod version not compatible with game version."); return(instructions); } }
static IEnumerable <CodeInstruction> BoneArmor_Import_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iLGenerator) { try { var matcher = new CodeMatcher(instructions, iLGenerator) .MatchForward(false, new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(BoneArmor), "SetSize"))); if (matcher.IsValid) { //.MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(BinaryReader), "ReadInt32"))) matcher.Advance(3) .Set(OpCodes.Pop, null); } return(matcher.InstructionEnumeration()); } catch (Exception ex) { UnityEngine.Debug.LogError(ex.ToString()); } return(instructions); }
private static IEnumerable <CodeInstruction> PhPluginSceneInfoSaveTranspiler(IEnumerable <CodeInstruction> instructions) { var matcher = new CodeMatcher(instructions); matcher.MatchForward(false, new CodeMatch(OpCodes.Ldstr, "【PHStudio】")); var getWriterInstr = matcher.InstructionAt(-1); matcher.Advance(2); matcher.InsertAndAdvance( new CodeInstruction(OpCodes.Ldarg_0), getWriterInstr, CodeInstruction.Call(typeof(Hooks), nameof(SceneInfoSaveHook))); if (matcher.Instruction.opcode != OpCodes.Leave && matcher.Instruction.opcode != OpCodes.Leave_S) { throw new Exception("Failed to patch SceneInfo.Save"); } return(matcher.Instructions()); }
public static IEnumerable <CodeInstruction> PlayerActionMine_Transpiler(IEnumerable <CodeInstruction> instructions) { var codeMatcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Ldelema), new CodeMatch(OpCodes.Ldflda), new CodeMatch(OpCodes.Dup), new CodeMatch(OpCodes.Ldind_I4), new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(OpCodes.Sub), new CodeMatch(OpCodes.Stind_I4)); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("PlayerActionMine_Transpiler failed. Mod version not compatible with game version."); return(instructions); } return(codeMatcher .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <FetchVeinMineAmount>((PlayerAction_Mine _this) => { // do we need to check for the event here? its very unlikely that we call the GameTick() by hand... if (SimulatedWorld.Initialized && !PlanetManager.EventFromClient && !PlanetManager.EventFromServer) { LocalPlayer.SendPacketToLocalStar(new VegeMinedPacket(_this.player.planetId, _this.miningId, _this.player.factory.veinPool[_this.miningId].amount, true)); } return 0; })) .Insert(new CodeInstruction(OpCodes.Pop)) .InstructionEnumeration()); }
static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL) { var codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(true, new CodeMatch(i => i.opcode == OpCodes.Ldsfld && ((FieldInfo)i.operand).Name == "buildTargetAutoMove") ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("BuildTool_Click.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version."); return(instructions); } var label = codeMatcher.InstructionAt(1).operand; return(codeMatcher .Advance(2) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return SimulatedWorld.Initialized && (FactoryManager.EventFromServer || FactoryManager.EventFromClient) && FactoryManager.PacketAuthor != LocalPlayer.PlayerId; })) .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, label)) .InstructionEnumeration()); }
private static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL) { CodeMatcher codeMatcher = new CodeMatcher(instructions, iL) .MatchForward(true, new CodeMatch(i => i.opcode == OpCodes.Ldsfld && ((FieldInfo)i.operand).Name == "buildTargetAutoMove") ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("BuildTool_Click.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version."); return(instructions); } object label = codeMatcher.InstructionAt(1).operand; return(codeMatcher .Advance(2) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return Multiplayer.IsActive && Multiplayer.Session.Factories.IsIncomingRequest.Value && Multiplayer.Session.Factories.PacketAuthor != Multiplayer.Session.LocalPlayer.Id; })) .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, label)) .InstructionEnumeration()); }
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()); }
public static IEnumerable <CodeInstruction> _OnLateUpdate_Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIVirtualStarmap), "starPool")), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_Item"), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIVirtualStarmap.StarNode), "nameText")), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_gameObject"), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "SetActive"), new CodeMatch(OpCodes.Ldloc_S)); if (matcher.IsInvalid) { Log.Warn("UIVirtualStarmap transpiler could not find injection point, not patching!"); return(instructions); } matcher.Advance(1) .SetAndAdvance(OpCodes.Ldloc_2, null) // change 'if (flag2 && flag)' to 'if (flag2 && pressing)' .Advance(2); // now remove original logic in this if(){} for (int i = 0; i < 39; i++) { matcher.SetAndAdvance(OpCodes.Nop, null); } // add own logic matcher.InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldloc_S, 12), HarmonyLib.Transpilers.EmitDelegate <ShowSolarsystemDetails>((UIVirtualStarmap starmap, int starIndex) => { if (pressSpamProtector) { return; } pressSpamProtector = true; if (Multiplayer.Session != null && Multiplayer.Session.IsInLobby && starmap.clickText == "") { ClearStarmap(starmap); ShowSolarSystem(starmap, starIndex); } else if (Multiplayer.Session != null && Multiplayer.Session.IsInLobby && starmap.clickText != "") { string[] split = starmap.clickText.Split(' '); int starId = 0; starId = Convert.ToInt32(split[0]); StarData starData = starmap._galaxyData.StarById(starId); // no increment as we stored the actual id in there if (starData == null || starIndex == 0) // starIndex == 0 is the star in the middle, so we need to decrement by 1 below { return; } PlanetData pData = starData.planets[starIndex - 1]; if (pData == null) { return; } if (UIRoot.instance.uiGame.planetDetail.planet != null && UIRoot.instance.uiGame.planetDetail.planet.id == pData.id && pData.type != EPlanetType.Gas) { // clicked on planet and details already visible, so set as new birth planet starmap._galaxyData.birthStarId = starId; starmap._galaxyData.birthPlanetId = pData.id; GameMain.data.galaxy.birthStarId = starId; GameMain.data.galaxy.birthPlanetId = pData.id; customBirthStar = starData.id; customBirthPlanet = pData.id; Log.Info($"set birth planet{pData.id} {pData.displayName}"); Text text = GameObject.Find("UI Root/Overlay Canvas/Galaxy Select/start-button/start-text").GetComponent <Text>(); text.text = $"Start Game at {pData.displayName}"; text.horizontalOverflow = HorizontalWrapMode.Overflow; if (pData.data == null) { Button button = GameObject.Find("UI Root/Overlay Canvas/Galaxy Select/start-button").GetComponent <Button>(); button.interactable = false; EPlanetType planetType = pData.type; pData.type = EPlanetType.Gas; PlanetModelingManager.genPlanetReqList.Enqueue(pData); pData.onLoaded += (PlanetData planet) => { pData.type = planetType; button.interactable = true; }; } } starmap.clickText = split[0] + " " + starIndex.ToString(); UIRoot.instance.uiGame.SetPlanetDetail(pData); GameObject.Find("UI Root/Overlay Canvas/Galaxy Select/right-group")?.SetActive(false); UIRoot.instance.uiGame.planetDetail.gameObject.SetActive(true); UIRoot.instance.uiGame.planetDetail.gameObject.GetComponent <RectTransform>().parent.gameObject.SetActive(true); UIRoot.instance.uiGame.planetDetail.gameObject.GetComponent <RectTransform>().parent.gameObject.GetComponent <RectTransform>().parent.gameObject.SetActive(true); UIRoot.instance.uiGame.planetDetail._OnUpdate(); } })); // change for loop to start at 0 instead of 1 matcher.Start(); matcher.MatchForward(true, new CodeMatch(OpCodes.Stloc_2), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIVirtualStarmap), "clickText")), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "IsNullOrEmpty"), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Ceq), new CodeMatch(OpCodes.Stloc_3) ) .Advance(1) .SetInstruction(new CodeInstruction(OpCodes.Ldc_I4_0)); // mark the correct star as birth point matcher.Start(); matcher.MatchForward(true, new CodeMatch(OpCodes.Ldc_R4), new CodeMatch(OpCodes.Stloc_1), new CodeMatch(OpCodes.Br), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Stloc_1), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Stloc_0), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Brtrue) ) .Advance(-1) .SetAndAdvance(OpCodes.Nop, null) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 5)) .Insert(HarmonyLib.Transpilers.EmitDelegate <IsBirthStar>((UIVirtualStarmap starmap, int starIndex) => { return(starmap.starPool[starIndex].starData.id != starmap._galaxyData.birthStarId && starmap.starPool[starIndex].starData.id != starmap._galaxyData.birthPlanetId); })); // listen for general mouse clicks to deselect planet / solar system matcher.Start(); matcher.MatchForward(true, new CodeMatch(OpCodes.Br), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIVirtualStarmap), "starPool")), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_Item"), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIVirtualStarmap.StarNode), "active")), new CodeMatch(OpCodes.Brfalse), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldloc_0), new CodeMatch(OpCodes.Ceq) ) .Advance(3) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_0)) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <TrackPlayerClick>((UIVirtualStarmap starmap, int starIndex) => { bool pressing = VFInput.rtsConfirm.pressing; if ((pressing && !pressSpamProtector) && starIndex == -1) { if (starmap.clickText != "" && UIRoot.instance.uiGame.planetDetail.gameObject.activeSelf) // hide planet details { GameObject.Find("UI Root/Overlay Canvas/Galaxy Select/right-group").SetActive(true); UIRoot.instance.uiGame.planetDetail.gameObject.SetActive(false); } else if (starmap.clickText != "" && !UIRoot.instance.uiGame.planetDetail.gameObject.activeSelf) // hide solar system details { starmap.clickText = ""; starmap.OnGalaxyDataReset(); } pressSpamProtector = true; } })); return(matcher.InstructionEnumeration()); }
private static IEnumerable <CodeInstruction> OnBeltBuilt_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iLGenerator) { /* * Calls * Multiplayer.Session.Factories.OnNewSetInserterPickTarget(objId, pickTarget, inserterId, offset, pointPos); * After * this.factorySystem.SetInserterPickTarget(inserterId, num6, num5 - num7); */ CodeMatcher codeMatcher = new CodeMatcher(instructions, iLGenerator) .MatchForward(true, new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == nameof(FactorySystem.SetInserterPickTarget) ) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("PlanetFactory_Transpiler.OnBeltBuilt 1 failed. Mod version not compatible with game version."); return(instructions); } List <CodeInstruction> setInserterTargetInsts = codeMatcher.InstructionsWithOffsets(-5, -1); // inserterId, pickTarget, offset CodeInstruction objIdInst = codeMatcher.InstructionAt(-13); // objId List <CodeInstruction> pointPosInsts = codeMatcher.InstructionsWithOffsets(8, 10); // pointPos codeMatcher = codeMatcher .Advance(1) .InsertAndAdvance(setInserterTargetInsts.ToArray()) .InsertAndAdvance(objIdInst) .InsertAndAdvance(pointPosInsts.ToArray()) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Action <int, int, int, int, UnityEngine.Vector3> >((inserterId, pickTarget, offset, objId, pointPos) => { if (Multiplayer.IsActive) { Multiplayer.Session.Factories.OnNewSetInserterPickTarget(objId, pickTarget, inserterId, offset, pointPos); } })); /* * Calls * Multiplayer.Session.Factories.OnNewSetInserterInsertTarget(objId, pickTarget, inserterId, offset, pointPos); * After * this.factorySystem.SetInserterInsertTarget(inserterId, num9, num5 - num10); */ codeMatcher = codeMatcher .MatchForward(true, new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == nameof(FactorySystem.SetInserterInsertTarget) ) ); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("PlanetFactory_Transpiler.OnBeltBuilt 2 failed. Mod version not compatible with game version."); return(codeMatcher.InstructionEnumeration()); } setInserterTargetInsts = codeMatcher.InstructionsWithOffsets(-5, -1); // inserterId, pickTarget, offset objIdInst = codeMatcher.InstructionAt(-13); // objId pointPosInsts = codeMatcher.InstructionsWithOffsets(9, 11); // pointPos codeMatcher = codeMatcher .Advance(1) .InsertAndAdvance(setInserterTargetInsts.ToArray()) .InsertAndAdvance(objIdInst) .InsertAndAdvance(pointPosInsts.ToArray()) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Action <int, int, int, int, UnityEngine.Vector3> >((inserterId, pickTarget, offset, objId, pointPos) => { if (Multiplayer.IsActive) { Multiplayer.Session.Factories.OnNewSetInserterInsertTarget(objId, pickTarget, inserterId, offset, pointPos); } })); return(codeMatcher.InstructionEnumeration()); }