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()); }
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()); }
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.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()); }
public static IEnumerable <CodeInstruction> ChaControl_SetShapeBodyValue_RemoveHeightLock(IEnumerable <CodeInstruction> instructions) { var cm = new CodeMatcher(instructions); // find branch that overrides the male height cm.MatchForward(false, new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(ChaInfo), nameof(ChaInfo.sex)))) .MatchForward(false, new CodeMatch(c => c.Branches(out _))); // turn it into an unconditional jump cm.InsertAndAdvance(new CodeInstruction(OpCodes.Pop)) .SetOpcodeAndAdvance(OpCodes.Br); return(cm.Instructions()); }
public static IEnumerable <CodeInstruction> ChaControl_Initialize_RemoveHeightLock(IEnumerable <CodeInstruction> instructions) { var cm = new CodeMatcher(instructions); // find branch that overrides the male height cm.MatchForward(false, new CodeMatch(OpCodes.Ldc_R4, 0.6f)) .MatchBack(false, new CodeMatch(OpCodes.Call)) .MatchBack(false, new CodeMatch(c => c.Branches(out _))); // turn it into an unconditional jump cm.InsertAndAdvance(new CodeInstruction(OpCodes.Pop)) .SetOpcodeAndAdvance(OpCodes.Br); return(cm.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)); var findRecipesCode = new CodeInstruction[] { new CodeInstruction(OpCodes.Ldloca_S, 6), new CodeInstruction(OpCodes.Call, typeof(MagicStoragePlus).GetMethod(nameof(MagicStoragePlus.FindRecipesPatch), new Type[] { typeof(Dictionary <int, int>).MakeByRefType() })) }; matcher.InsertAndAdvance(findRecipesCode); return(matcher.InstructionEnumeration()); }
private static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il) { /* * Inserts * if(!Multiplayer.IsActive) * Before trying to take items, so that all prebuilds are assumed to require items while in MP */ CodeMatcher matcher = new CodeMatcher(instructions, il) .MatchForward(true, new CodeMatch(i => i.IsLdloc()), // count new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(OpCodes.Ceq), new CodeMatch(OpCodes.Brfalse) ); if (matcher.IsInvalid) { NebulaModel.Logger.Log.Error("BuildTool_BlueprintPaste.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version."); return(instructions); } object jumpOperand = matcher.Instruction.operand; matcher = matcher .MatchBack(false, new CodeMatch(i => i.IsLdloc()), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "item"), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "ID"), new CodeMatch(i => i.IsStloc()) ); if (matcher.IsInvalid) { NebulaModel.Logger.Log.Error("BuildTool_BlueprintPaste.CreatePrebuilds_Transpiler 2 failed. Mod version not compatible with game version."); return(instructions); } return(matcher .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() => { return Multiplayer.IsActive; })) .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, jumpOperand)) .InstructionEnumeration()); }
static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions) { // Set int count = 1 before trying to use hand items or take tail items so that it passes if player did not generate event var codeMatcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(i => i.IsLdarg()), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "get_player"), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_inhandItemId")); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("BuildTool_Common.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version."); return(instructions); } return(codeMatcher .InsertAndAdvance(new CodeInstruction(OpCodes.Ldc_I4_1)) .InstructionEnumeration()); }
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()); }
static IEnumerable <CodeInstruction> FactorySystem_DrawModels_Patch(IEnumerable <CodeInstruction> instructions) { CodeMatcher matcher = new CodeMatcher(instructions); matcher .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.ejectorCursor))) ); // replace the code logic with the same logic wrapped in a meaningful lock for thread safety and return matcher .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(Transpilers.EmitDelegate <Action <FactorySystem> >(factorySystem => { if (factorySystem.factory.dysonSphere != null) { lock (factorySystem.factory.dysonSphere) { DysonSphereRelatedGameTick(factorySystem); } } else { DysonSphereRelatedGameTick(factorySystem); } })) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .InsertAndAdvance(Transpilers.EmitDelegate <Action <FactorySystem> >(factorySystem => { lock (GameMain.history) { TechRelatedGameTick(factorySystem); } })) .InsertAndAdvance(new CodeInstruction(OpCodes.Ret)); return(matcher.InstructionEnumeration()); }
static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions) { var codeMatcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(i => i.IsLdarg()), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "get_player"), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "get_inhandItemId")); if (codeMatcher.IsInvalid) { NebulaModel.Logger.Log.Error("BuildTool_Common.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version."); return(instructions); } // num = 1; from within the if statement var numInstruction = codeMatcher.InstructionAt(11); return(codeMatcher .InsertAndAdvance(new CodeInstruction(OpCodes.Ldc_I4_1)) .InsertAndAdvance(numInstruction) .InstructionEnumeration()); }
static void PatchHighlightInRedConstructionObstacles(CodeMatcher codeMatcherCursor, ILGenerator generator) { codeMatcherCursor.Start(); codeMatcherCursor.MatchForward(true, new CodeMatch(OpCodes.Ldloc_3), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(List <GameObject>), "Item")), new CodeMatch(OpCodes.Stloc_S) ); if (codeMatcherCursor.IsValid) { var obstacleLocal = (LocalBuilder)codeMatcherCursor.Operand; codeMatcherCursor.MatchForward(false, new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(typeof(Builder), nameof(Builder.obstaclesBuffer))), new CodeMatch(OpCodes.Ldloc_S), // Renderer new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(typeof(Builder), nameof(Builder.builderObstacleMaterial))), new CodeMatch(OpCodes.Ldloc_S), // int new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(CommandBuffer), nameof(CommandBuffer.DrawRenderer), new Type[] { typeof(Renderer), typeof(Material), typeof(int) })) ); if (codeMatcherCursor.IsValid) { var rendererLocal = (LocalBuilder)codeMatcherCursor.Advance(1).Operand; var submeshIndexLocal = (LocalBuilder)codeMatcherCursor.Advance(2).Operand; codeMatcherCursor.Advance(-3); // Check if obstacle destroying is enabled var disabledDestroyObstaclesLabel = generator.DefineLabel(); codeMatcherCursor .InsertAndAdvance( new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Config), nameof(Config.Instance))), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(Config), nameof(Config.destroyLargerObstaclesOnConstruction))), new CodeInstruction(OpCodes.Brfalse_S, disabledDestroyObstaclesLabel) ); // Then check if construction obstacle var notConstructionObstacleLabel = generator.DefineLabel(); codeMatcherCursor .InsertAndAdvance( new CodeInstruction(OpCodes.Ldloc_S, obstacleLocal), new CodeInstruction(OpCodes.Call, AccessTools.Method($"{typeof(UpdateAllowedPatch)}:{nameof(IsConstructionObstacle)}", new Type[] { typeof(GameObject) })), new CodeInstruction(OpCodes.Brfalse_S, notConstructionObstacleLabel) ); // Then define destroy material codeMatcherCursor .InsertAndAdvance( new CodeInstruction(OpCodes.Call, AccessTools.Method($"{typeof(UpdateAllowedPatch)}:{nameof(DefineDestroyMaterialIfNot)}")) ); // And then highlight in red codeMatcherCursor .InsertAndAdvance( new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(Builder), nameof(Builder.obstaclesBuffer))), new CodeInstruction(OpCodes.Ldloc_S, rendererLocal), // Renderer new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(UpdateAllowedPatch), nameof(destroyableObstacleMat))), new CodeInstruction(OpCodes.Ldloc_S, submeshIndexLocal), // int new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(typeof(CommandBuffer), nameof(CommandBuffer.DrawRenderer), new Type[] { typeof(Renderer), typeof(Material), typeof(int) })) ); // Then jump over instructions within "else" block var isConstructionObstacleLabel = generator.DefineLabel(); codeMatcherCursor .InsertAndAdvance( new CodeInstruction(OpCodes.Br_S, isConstructionObstacleLabel) ); // Or else highlight in default (yellow) codeMatcherCursor.Instruction.WithLabels(disabledDestroyObstaclesLabel, notConstructionObstacleLabel); codeMatcherCursor.Advance(5); codeMatcherCursor.Instruction.WithLabels(isConstructionObstacleLabel); } } }
static void PatchClearFromConstructionObstacles(CodeMatcher codeCursor, ILGenerator generator) { codeCursor.Start(); codeCursor.MatchForward(false, new CodeMatch(OpCodes.Ldloc_1), new CodeMatch(OpCodes.Ldloc_3), new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(List <GameObject>), nameof(List <GameObject> .Count))), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Ceq), new CodeMatch(OpCodes.And), new CodeMatch(OpCodes.Stloc_1) ); if (codeCursor.IsValid) { // Remove boolean result assignent as we are "moving" it to after obstacle highlighting block var labels = codeCursor.Instruction.ExtractLabels(); codeCursor.RemoveInstructions(7); codeCursor.AddLabels(labels); codeCursor.MatchForward(true, new CodeMatch(OpCodes.Ldloc_3), new CodeMatch(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(List <GameObject>), nameof(List <GameObject> .Count))), new CodeMatch(OpCodes.Ldc_I4_0), new CodeMatch(OpCodes.Ble) ); if (codeCursor.IsValid) { var countCondBranchOperand = (Label)codeCursor.Operand; codeCursor.MatchForward(false, new CodeMatch(instruction => instruction.labels.Contains(countCondBranchOperand))); if (codeCursor.IsValid) { labels = codeCursor.Instruction.ExtractLabels(); // Make it to allow construction by clearing contruction obstacles for boolean result assignment if destroying obstacles is enabled var disabledDestroyObstaclesLabel = generator.DefineLabel(); codeCursor.InsertAndAdvance( new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Config), nameof(Config.Instance))).WithLabels(labels), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(Config), nameof(Config.destroyLargerObstaclesOnConstruction))), new CodeInstruction(OpCodes.Brfalse_S, disabledDestroyObstaclesLabel) ); codeCursor.InsertAndAdvance( new CodeInstruction(OpCodes.Ldloc_3), new CodeInstruction(OpCodes.Call, AccessTools.Method($"{typeof(UpdateAllowedPatch)}:{nameof(ClearConstructionObstacles)}", new Type[] { typeof(List <GameObject>) })) ); // Assign boolean result here (was before highlighting block) codeCursor.InsertAndAdvance( new CodeInstruction(OpCodes.Ldloc_1).WithLabels(disabledDestroyObstaclesLabel), new CodeInstruction(OpCodes.Ldloc_3), new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(List <GameObject>), nameof(List <GameObject> .Count))), new CodeInstruction(OpCodes.Ldc_I4_0), new CodeInstruction(OpCodes.Ceq), new CodeInstruction(OpCodes.And), new CodeInstruction(OpCodes.Stloc_1) ); } } } }
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()); }
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> Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il) { var matcher = new CodeMatcher(instructions, il); // Search for the first 4 consecative Ldc_I4 instructions (a Color constructor after if statements which move the trash can in other conditions) matcher.MatchForward(false, new CodeMatch(OpCodes.Ldc_I4, 150), new CodeMatch(OpCodes.Ldc_I4, 150), new CodeMatch(OpCodes.Ldc_I4, 150), new CodeMatch(OpCodes.Ldc_I4, 150), new CodeMatch(OpCodes.Newobj)); matcher.Instruction.opcode = OpCodes.Nop; matcher.Instruction.operand = null; matcher.Advance(1); Label bailOut; matcher.CreateLabelAt(matcher.Pos, out bailOut); var trashOffsetCode = new CodeInstruction[] { new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.playerInventory))), new CodeInstruction(OpCodes.Brfalse_S, bailOut), new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.player))), new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.myPlayer))), new CodeInstruction(OpCodes.Ldelem_Ref), new CodeInstruction(OpCodes.Callvirt, typeof(Player).GetMethod("GetModPlayer", new Type[] { }).MakeGenericMethod(typeof(StoragePlayer))), new CodeInstruction(OpCodes.Ldfld, typeof(StoragePlayer).GetField(nameof(StoragePlayer.StorageAccess))), new CodeInstruction(OpCodes.Ldfld, typeof(Point16).GetField(nameof(Point16.X))), new CodeInstruction(OpCodes.Ldc_I4_0), new CodeInstruction(OpCodes.Blt_S, bailOut), new CodeInstruction(OpCodes.Ldloc_0), new CodeInstruction(OpCodes.Ldsflda, typeof(UI).GetField(nameof(UI.TrashSlotOffset))), new CodeInstruction(OpCodes.Ldfld, typeof(Point16).GetField(nameof(Point16.X))), new CodeInstruction(OpCodes.Add), new CodeInstruction(OpCodes.Stloc_0), new CodeInstruction(OpCodes.Ldloc_1), new CodeInstruction(OpCodes.Ldsflda, typeof(UI).GetField(nameof(UI.TrashSlotOffset))), new CodeInstruction(OpCodes.Ldfld, typeof(Point16).GetField(nameof(Point16.Y))), new CodeInstruction(OpCodes.Add), new CodeInstruction(OpCodes.Stloc_1), new CodeInstruction(OpCodes.Ldc_R4, 0.755f), new CodeInstruction(OpCodes.Stsfld, typeof(Main).GetField(nameof(Main.inventoryScale))) }; matcher.InsertAndAdvance(trashOffsetCode); matcher.Advance(1); matcher.InsertAndAdvance(new CodeInstruction(OpCodes.Ldc_I4, 150)); matcher.MatchForward(true, new CodeMatch(OpCodes.Call, typeof(ChestUI).GetMethod("Draw", new Type[] { typeof(Microsoft.Xna.Framework.Graphics.SpriteBatch) }))); matcher.MatchForward(true, new CodeMatch(OpCodes.Ldsfld), new CodeMatch(OpCodes.Ldsfld), new CodeMatch(OpCodes.Ldelem_Ref), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Ldc_I4_M1), new CodeMatch(OpCodes.Bne_Un), new CodeMatch(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.npcShop))), new CodeMatch(OpCodes.Brtrue)); var iconsLabel = matcher.Instruction.operand; matcher.Advance(1); var icon1Code = new CodeInstruction[] { new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.player))), new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.myPlayer))), new CodeInstruction(OpCodes.Ldelem_Ref), new CodeInstruction(OpCodes.Callvirt, typeof(Player).GetMethod("GetModPlayer", new Type[] { }).MakeGenericMethod(typeof(StoragePlayer))), new CodeInstruction(OpCodes.Ldfld, typeof(StoragePlayer).GetField(nameof(StoragePlayer.StorageAccess))), new CodeInstruction(OpCodes.Ldfld, typeof(Point16).GetField(nameof(Point16.X))), new CodeInstruction(OpCodes.Ldc_I4_0), new CodeInstruction(OpCodes.Bgt, iconsLabel) }; matcher.InsertAndAdvance(icon1Code); matcher.MatchForward(true, new CodeMatch(OpCodes.Callvirt, typeof(Player).GetMethod("QuickStackAllChests"))); var quickStackCode = new CodeInstruction[] { new CodeInstruction(OpCodes.Ldc_I4_0), new CodeInstruction(OpCodes.Call, typeof(StorageUI).GetMethod("TryQuickStack", new Type[] { typeof(bool) })), new CodeInstruction(OpCodes.Pop) }; matcher.InsertAndAdvance(quickStackCode); matcher.MatchForward(true, new CodeMatch(OpCodes.Ldsfld), new CodeMatch(OpCodes.Ldsfld), new CodeMatch(OpCodes.Ldelem_Ref), new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Ldc_I4_M1), new CodeMatch(OpCodes.Bne_Un), new CodeMatch(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.npcShop))), new CodeMatch(OpCodes.Brtrue)); iconsLabel = matcher.Instruction.operand; matcher.Advance(1); var icon2Code = new CodeInstruction[] { new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.player))), new CodeInstruction(OpCodes.Ldsfld, typeof(Main).GetField(nameof(Main.myPlayer))), new CodeInstruction(OpCodes.Ldelem_Ref), new CodeInstruction(OpCodes.Callvirt, typeof(Player).GetMethod("GetModPlayer", new Type[] { }).MakeGenericMethod(typeof(StoragePlayer))), new CodeInstruction(OpCodes.Ldfld, typeof(StoragePlayer).GetField(nameof(StoragePlayer.StorageAccess))), new CodeInstruction(OpCodes.Ldfld, typeof(Point16).GetField(nameof(Point16.X))), new CodeInstruction(OpCodes.Ldc_I4_0), new CodeInstruction(OpCodes.Bgt, iconsLabel) }; matcher.InsertAndAdvance(icon2Code); return(matcher.InstructionEnumeration()); }