static IEnumerable <CodeInstruction> SaveCurrentGame_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iLGenerator) { /* BinaryWriter binaryWriter = new BinaryWriter(fileStream); => Create lzstream and replace binaryWriter. * set PerformanceMonitor.BeginStream to lzstream. * fileStream.Seek(6L, SeekOrigin.Begin); binaryWriter.Write(position); => Disable seek&write function. * binaryWriter.Dispose(); => Dispose lzstream before fileStream close. */ try { var matcher = new CodeMatcher(instructions, iLGenerator) .MatchForward(false, new CodeMatch(OpCodes.Newobj, AccessTools.Constructor(typeof(BinaryWriter), new Type[] { typeof(FileStream) }))) .Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "CreateBinaryWriter")) .MatchForward(false, new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(PerformanceMonitor), "BeginStream"))) .Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "MonitorStream")) .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IO.Stream), "Seek"))) .Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "FileLengthWrite0")) .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(BinaryWriter), "Write", new Type[] { typeof(long) }))) .Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "FileLengthWrite1")) .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IDisposable), "Dispose"))) .Advance(1) .Insert(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "DisposeLzstream"))); EnableCompress = true; return(matcher.InstructionEnumeration()); } catch (Exception ex) { SaveUtil.logger.LogError("SaveCurrentGame_Transpiler failed. Mod version not compatible with game version."); SaveUtil.logger.LogError(ex); } 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()); }
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 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> AllowBuildingWithLockedRecipes(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_1), new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(GameHistoryData), nameof(GameHistoryData.RecipeUnlocked))) ) .Repeat(codeMatcher => { codeMatcher.Advance(-1).SetOpcodeAndAdvance(OpCodes.Nop) .SetOpcodeAndAdvance(OpCodes.Nop) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Ldc_I4_1)); }); matcher.Start().MatchForward(false, new CodeMatch(OpCodes.Ldarg_3), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Ldelem_I4), new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(GameHistoryData), nameof(GameHistoryData.ItemUnlocked))) ) .Advance(-1).SetOpcodeAndAdvance(OpCodes.Nop) .SetOpcodeAndAdvance(OpCodes.Nop) .SetOpcodeAndAdvance(OpCodes.Nop) .SetOpcodeAndAdvance(OpCodes.Nop) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Ldc_I4_1)); return(matcher.InstructionEnumeration()); }
internal static CodeMatcher Print(this CodeMatcher codeMatcher, int before, int after) { #if DEBUG for (int i = -before; i <= after; ++i) { int currentOffset = i; int index = codeMatcher.Pos + currentOffset; if (index <= 0) { continue; } if (index >= codeMatcher.Length) { break; } try { var line = codeMatcher.InstructionAt(currentOffset); Log.LogTrace($"[{currentOffset}] " + line.ToString()); } catch (Exception e) { Log.LogError(e.Message); } } #endif return(codeMatcher); }
static IEnumerable <CodeInstruction> Transpiler1(IEnumerable <CodeInstruction> instructions) { var custominstruc = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(l => l.opcode == OpCodes.Call && l.Calls(AccessTools.Method(typeof(SceneEdit), "InitMenuNative")))) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .Insert( new CodeInstruction(OpCodes.Ldarg_0), Transpilers.EmitDelegate <Action>(() => { Debug.Log("Calling your control test coroutine."); @this2.StartCoroutine(InitMenuNative()); }), new CodeInstruction(OpCodes.Pop) ) .InstructionEnumeration(); return(custominstruc); }
static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il) { CodeMatcher matcher = new CodeMatcher(instructions, il) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "get_controller"), new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(PlayerController), "cmd")), new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(CommandState), "stage"))); if (matcher.IsInvalid) { NebulaModel.Logger.Log.Error("BuildTool_Path.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version."); return(instructions); } return(matcher .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return SimulatedWorld.Initialized && (FactoryManager.EventFromServer || FactoryManager.EventFromClient) && FactoryManager.PacketAuthor != LocalPlayer.PlayerId; })) .CreateLabelAt(matcher.Pos + 19, out Label jmpLabel) .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, jmpLabel)) .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.Call, AccessTools.PropertyGetter(typeof(BuildTool), nameof(BuildTool.buildPreviews))), new CodeMatch(OpCodes.Callvirt)) .Advance(1) .InsertAndAdvance(Transpilers.EmitDelegate <Action <BuildTool_Inserter> >(tool => { if (UndoManager.IgnoreAllEvents.Value) { return; } if (NebulaModAPI.IsMultiplayerActive) { if (NebulaModAPI.MultiplayerSession.LocalPlayer.IsClient) { return; } } IEnumerable <int> objectIds = tool.buildPreviews.Select(preview => preview.objId); PlayerUndo data = UndoManager.GetCurrentPlayerData(); data.AddUndoItem(new UndoBuild(data, objectIds)); })) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)); return(matcher.InstructionEnumeration()); }
private static IEnumerable <CodeInstruction> Transpiler1(IEnumerable <CodeInstruction> instructions) { IEnumerable <CodeInstruction> custominstruc = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(l => l.opcode == OpCodes.Call && l.Calls(AccessTools.Method(typeof(SceneEdit), "InitMenuNative")))) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .Insert( new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldarg_0), Transpilers.EmitDelegate <Action <SceneEdit> >((lthis) => { @this = lthis; Main.logger.LogDebug("Calling your modified CoRoutine"); @this.StartCoroutine(InitMenuNative()); }), new CodeInstruction(OpCodes.Pop) ) .InstructionEnumeration(); return(custominstruc); }
private static IEnumerable <CodeInstruction> _OnUpdate_Transpiler(IEnumerable <CodeInstruction> instructions) { // Replace: if (cargoPath.TryInsertItem(Mathf.Max(4, beltComponent.segIndex + beltComponent.segPivotOffset - 20), this.player.inhandItemId, 1, (byte)num)) // To: if (this.traffic.PutItemOnBelt(spraycoaterComponent.cargoBeltId, this.player.inhandItemId, (byte)num)) try { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(CargoPath), nameof(CargoPath.TryInsertItem)))) .InsertAndAdvance( new CodeInstruction(OpCodes.Ldarg_0), HarmonyLib.Transpilers.EmitDelegate <Func <byte, UISpraycoaterWindow, bool> >((foo, window) => { // Recalculate itemInc here because the argument is not reliable int itemInc = (window.player.inhandItemInc > 0) ? (window.player.inhandItemInc / window.player.inhandItemCount) : 0; itemInc = ((itemInc > 10) ? 10 : itemInc); int itemId = window.player.inhandItemId; int cargoBeltId = window.traffic.spraycoaterPool[window.spraycoaterId].cargoBeltId; return(window.traffic.PutItemOnBelt(cargoBeltId, itemId, (byte)itemInc)); })) .RemoveInstruction() .Advance(-17) .RemoveInstructions(14); // remove #81~94, leave only (byte)num return(matcher.InstructionEnumeration()); } catch { NebulaModel.Logger.Log.Error("UISpraycoaterWindow._OnUpdate_Transpiler failed. Mod version not compatible with game version."); return(instructions); } }
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()); }
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> 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> 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> 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()); }
public static IEnumerable <CodeInstruction> CargoContainer_Expand2x_Patch(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldloc_0), new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(CargoContainer), nameof(CargoContainer.poolCapacity))) ) .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(Transpilers.EmitDelegate <Action <CargoContainer> >((CargoContainer __instance) => { if (executeNow) { UpdateCargoBuffer(__instance); } else { expandedCargos.Add(__instance); } })) .InsertAndAdvance(new CodeInstruction(OpCodes.Ret)); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> ChangeFunction(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .End() .MatchBack(false, new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(OpCodes.Add) ) .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactoryStorage), nameof(FactoryStorage.tankPool)))) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 4)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldelema, typeof(TankComponent))) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_0)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 5)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldelema, typeof(AnimData))) .InsertAndAdvance(Transpilers.EmitDelegate <RefAction <TankComponent, AnimData> >((ref TankComponent tank, ref AnimData anim) => { if (tank.fluidCapacity > 11000) { anim.time = InverseFunction(anim.time); } })); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> SetFilterToEntity_Transpiler(IEnumerable <CodeInstruction> instructions) { instructions = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldloc_2), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Ldelema), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Stfld)) .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_2), new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UISlotPicker), "outputSlotId")), new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UISlotPicker), "selectedIndex"))) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <SetSlot>((StationComponent stationComponent, int outputSlotId, int selectedIndex) => { if (!SimulatedWorld.Initialized) { return(0); } LocalPlayer.SendPacketToLocalStar(new ILSUpdateSlotData(stationComponent.planetId, stationComponent.id, stationComponent.gid, outputSlotId, selectedIndex)); return(0); })) .Insert(new CodeInstruction(OpCodes.Pop)) .InstructionEnumeration(); return(instructions); }
private static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il) { CodeMatcher matcher = new CodeMatcher(instructions, il) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "get_controller"), new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(PlayerController), nameof(PlayerController.cmd))), new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(CommandState), nameof(CommandState.stage)))); if (matcher.IsInvalid) { NebulaModel.Logger.Log.Error("BuildTool_Path.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version."); return(instructions); } return(matcher .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return Multiplayer.IsActive && Multiplayer.Session.Factories.IsIncomingRequest.Value && Multiplayer.Session.Factories.PacketAuthor != Multiplayer.Session.LocalPlayer.Id; })) .CreateLabelAt(matcher.Pos + 19 + 22, out Label jmpLabel) .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, jmpLabel)) .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()); }
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); }
private static IEnumerable <CodeInstruction> IsPlanetPhysicsColliderDirty_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il) { CodeMatcher codeMatcher = new CodeMatcher(instructions, il) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(i => i.opcode == OpCodes.Ldfld && i.operand?.ToString() == "PlanetData planet"), new CodeMatch(i => i.opcode == OpCodes.Ldfld && i.operand?.ToString() == "PlanetPhysics physics"), new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(i => i.opcode == OpCodes.Stfld && i.operand?.ToString() == "System.Boolean isPlanetPhysicsColliderDirty")); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("CargoTraffic_IsPlanetPhysicsColliderDirty_Transpiler failed. Mod version not compatible with game version."); return(instructions); } return(codeMatcher .Repeat(matcher => { matcher .CreateLabelAt(matcher.Pos + 5, out Label end) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return Multiplayer.IsActive && Multiplayer.Session.Factories.IsIncomingRequest.Value; })) .Insert(new CodeInstruction(OpCodes.Brtrue, end)) .Advance(5); }) .InstructionEnumeration()); }
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); } }
static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldc_R4), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "GetVeinsInAreaNonAlloc")) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Ldloc_3)) .InsertAndAdvance( Transpilers.EmitDelegate <Func <BuildPreview, float> >(preview => DSPAdvancedMiner.getMinerRadius(preview.desc) + 4) ).MatchForward(true, new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(Vector3), nameof(Vector3.Dot))), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldc_R4)) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Ldloc_3)) .InsertAndAdvance( Transpilers.EmitDelegate <Func <BuildPreview, float> >(preview => { float radius = DSPAdvancedMiner.getMinerRadius(preview.desc); return(radius * radius); }) ); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> ClickReform(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(x => x.IsLdloc()), new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(BuildTool_Reform), nameof(BuildTool_Click.castGroundPos))) ) .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(Transpilers.EmitDelegate <Action <BuildTool_Reform> >(tool => { currentGridData.snapGrid = new Vector2(tool.brushSize, tool.brushSize); float longitude = 0; float latitude = 0; BlueprintUtils.GetLongitudeLatitudeRad(tool.castGroundPos.normalized, ref longitude, ref latitude); if (isLockedLongitude) { longitude = lockLongitude; } if (isLockedLatitude) { latitude = lockLatitude; } tool.castGroundPos = BlueprintUtils.GetDir(longitude, latitude) * tool.castGroundPos.magnitude; })); return(matcher.InstructionEnumeration()); }
static IEnumerable <CodeInstruction> DysonSphereSegmentRenderer_DrawModels_Patch(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(DysonSphereSegmentRenderer), nameof(DysonSphereSegmentRenderer.dysonSphere))), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(DysonSphere), nameof(DysonSphere.layersIdBased))) ) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(DysonSphereSegmentRenderer), nameof(DysonSphereSegmentRenderer.dysonSphere))), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(DysonSphere), nameof(DysonSphere.layersIdBased))) ) .SetOpcodeAndAdvance(OpCodes.Nop) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) .Advance(1) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .SetInstructionAndAdvance(Transpilers.EmitDelegate <Func <uint, DysonSphereSegmentRenderer, DysonSphereLayer> >((uint index, DysonSphereSegmentRenderer renderer) => { if (hideDysonSphereMesh.Value && DysonSphere.renderPlace == ERenderPlace.Universe) { return(null); } return(renderer.dysonSphere.layersIdBased[(int)((UIntPtr)index)]); })); return(matcher.InstructionEnumeration()); }
static IEnumerable <CodeInstruction> Transpiler1(IEnumerable <CodeInstruction> instructions) { var custominstruc = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(l => l.opcode == OpCodes.Call && l.Calls(AccessTools.Method(typeof(SceneEdit), "InitMenuNative")))) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) .SetAndAdvance(OpCodes.Nop, null) //.SetAndAdvance(OpCodes.Nop, null) .Insert( new CodeInstruction(OpCodes.Ldarg_0), Transpilers.EmitDelegate <Action>(() => { Debug.Log("Calling your test coroutine."); //InitMenuNativeRe(); //@this2.StartCoroutine(test2()); //Task.Factory.StartNew(new Action(() => InitialBackgroundWorker())); @this2.StartCoroutine(InitialBackgroundWorker()); //@this2.StartCoroutine(MenuLoaderWorker()); //test2(); }), new CodeInstruction(OpCodes.Pop) ) //.Insert(new CodeInstruction (OpCodes.Call, AccessTools.Method(typeof(Main), "InitMenuNativeRe"))) .InstructionEnumeration(); return(custominstruc); }
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()); }
static IEnumerable <CodeInstruction> CodeTranspiler(IEnumerable <CodeInstruction> instructions) { var custominstruc = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Ceq), new CodeMatch(OpCodes.Stfld), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Ceq), new CodeMatch(OpCodes.Stfld), new CodeMatch(OpCodes.Br) ) .Insert( new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PropMyItem), "_isVisible")), Transpilers.EmitDelegate <Action <bool> >((vis) => { Main.PMIUIStatus = vis; }) ) .InstructionEnumeration(); return(custominstruc); }