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> 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()); }
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> 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()); }
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()); }
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> 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); }
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()); }
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()); }
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()); }
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); } }
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> 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); } }
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> CheckConditions(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "desc"), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "hasBuildCollider"), new CodeMatch(OpCodes.Brfalse), new CodeMatch(OpCodes.Ldloc_S) ).Advance(1) .SetAndAdvance(OpCodes.Ldarg_0, null) .SetInstructionAndAdvance( Transpilers.EmitDelegate <Func <BuildPreview, BuildTool_Click, bool> >( (preview, _this) => { if (preview.item.ID == 2212) { if (_this.handPrefabDesc != null && _this.handPrefabDesc.modelIndex == GroundSubstation.firstSubstationId + 2) { return(false); } } return(preview.desc.hasBuildCollider); })); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> Replace10With1Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(instr => instr.opcode == OpCodes.Ldc_R4 && Mathf.Approximately((float)instr.operand, 10f))) .SetOperandAndAdvance(1f); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> ChangeCastDistance(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldc_R4, 800f) ) .SetInstruction(Transpilers.EmitDelegate <Func <float> >(() => GameCamera.instance.blueprintPoser.planetRadius * 2.4f)); return(matcher.InstructionEnumeration()); }
static IEnumerable <CodeInstruction> RedirectSaves(IEnumerable <CodeInstruction> instructions) { var codeMatch = new CodeMatcher(instructions); codeMatch = codeMatch.MatchForward(false, new CodeMatch(OpCodes.Ldstr, "save")); codeMatch = codeMatch.Repeat(matcher => { matcher.SetOperandAndAdvance(folderRedirect + matcher.Operand); }); return(codeMatch.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> ColorPatch(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(instr => instr.opcode == OpCodes.Ldc_I4_S && (sbyte)instr.operand == 12) ).Repeat(matcher2 => { matcher2.SetOperandAndAdvance(16); }); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> Update_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il) { CodeMatcher matcher = new CodeMatcher(instructions, il) // find for loop increment and exit condition .MatchForward(false, new CodeMatch(OpCodes.Stloc_0), new CodeMatch(OpCodes.Ldloc_0), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LogisticShipRenderer), "transport")), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GalacticTransport), "stationCursor")), new CodeMatch(OpCodes.Blt)) .Advance(-3) .CreateLabel(out Label jmpToForCompare) .Start() // find stationPool access (which produces IndexOutOfBounds in rare cases) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LogisticShipRenderer), "transport")), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GalacticTransport), "stationPool")), new CodeMatch(OpCodes.Ldloc_0)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LogisticShipRenderer), "transport"))) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(GalacticTransport), "stationPool"))) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_0)) .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <IsOutOfBounds>((StationComponent[] stationComponent, int index) => { if (index >= stationComponent.Length && Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsClient) { WarningManager.DisplayCriticalWarning("IndexOutOfBounds in LogisticShipRenderer. Consider reconnecting!"); } return(index < stationComponent.Length); })) .Insert(new CodeInstruction(OpCodes.Brfalse, jmpToForCompare)) // find start of our injected code .MatchBack(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LogisticShipRenderer), "transport")), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GalacticTransport), "stationPool")), new CodeMatch(OpCodes.Ldloc_0)) .CreateLabel(out Label jmpToOverflowCheck) .Start() // exchange loop start ptr with our index checking .MatchForward(true, new CodeMatch(OpCodes.Stloc_0), new CodeMatch(OpCodes.Ldloc_0), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LogisticShipRenderer), "transport")), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(GalacticTransport), "stationCursor")), new CodeMatch(OpCodes.Blt)) .SetOperandAndAdvance(jmpToOverflowCheck); return(matcher.InstructionEnumeration()); }
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()); }
static IEnumerable <CodeInstruction> FixMovement(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PlayerController), nameof(PlayerController.actionBuild))), new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(PlayerAction_Build), "get_blueprintMode")), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Cgt_Un) ).Advance(1) .InsertAndAdvance(Transpilers.EmitDelegate <Func <bool, bool> >(isBp => isBp && mode)); return(matcher.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()); }
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()); }
public static IEnumerable <CodeInstruction> Replace10With1Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(StationComponent), nameof(StationComponent.deliveryDrones)))) .MatchBack(false, new CodeMatch(instr => instr.opcode == OpCodes.Ldc_R4 && Mathf.Approximately((float)instr.operand, 10f))) .SetOperandAndAdvance(1f); matcher .MatchForward(false, new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(StationComponent), nameof(StationComponent.deliveryShips)))) .MatchBack(false, new CodeMatch(instr => instr.opcode == OpCodes.Ldc_R4 && Mathf.Approximately((float)instr.operand, 10f))) .SetOperandAndAdvance(1f); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldc_I4_S, (sbyte)122), new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(Input), nameof(Input.GetKeyDown), new [] { typeof(KeyCode) }))) .RemoveInstruction() .SetInstruction(Transpilers.EmitDelegate <Func <bool> >(() => { return(CustomKeyBindSystem.GetKeyBind("DSPTrashButton").keyValue); })); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> DontClearOpenPath(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldstr), new CodeMatch(OpCodes.Stfld) ) .SetOpcodeAndAdvance(OpCodes.Nop) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)) .SetInstructionAndAdvance(new CodeInstruction(OpCodes.Nop)); return(matcher.InstructionEnumeration()); }
public static IEnumerable <CodeInstruction> DontClearOpenPath(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Ldstr)) .SetInstruction(Transpilers.EmitDelegate <Func <string> >(() => { string currentPath = UIRoot.instance.uiGame.blueprintBrowser.openPath; return(BlueprintData.GenerateNewFileName(currentPath)); })); return(matcher.InstructionEnumeration()); }