private static IEnumerable <CodeInstruction> RefreshAstroBox_Transpiler(IEnumerable <CodeInstruction> instructions) { //Change: this.gameData.factoryCount //To: GetFactoryCount() //Change: this.gameData.factories[i].planetId //To: GetPlanetData(i).id //Change: this.gameData.factories[i].planet //To: GetPlanetData(i) try { instructions = ReplaceFactoryCount(instructions); CodeMatcher matcher = new CodeMatcher(instructions) .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.DeclaredPropertyGetter(typeof(PlanetFactory), nameof(PlanetFactory.planetId))) ) .Advance(-5); OpCode factoryIndexOp = matcher.InstructionAt(3).opcode; matcher.SetAndAdvance(factoryIndexOp, null) .InsertAndAdvance( new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UIStatisticsWindow_Transpiler), nameof(UIStatisticsWindow_Transpiler.GetPlanetData))), new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PlanetData), nameof(PlanetData.id))) ) .RemoveInstructions(5) .MatchForward(false, new CodeMatch(OpCodes.Callvirt, AccessTools.DeclaredPropertyGetter(typeof(PlanetFactory), nameof(PlanetFactory.planet))) ) .Advance(-5); factoryIndexOp = matcher.InstructionAt(3).opcode; matcher.SetAndAdvance(factoryIndexOp, null) .InsertAndAdvance( new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UIStatisticsWindow_Transpiler), nameof(UIStatisticsWindow_Transpiler.GetPlanetData))) ) .RemoveInstructions(5); return(matcher.InstructionEnumeration()); } catch { NebulaModel.Logger.Log.Error("RefreshAstroBox_Transpiler failed. Mod version not compatible with game version."); return(instructions); } }
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()); }
public static void ILSUpdateShipPos(StationComponent stationComponent, PlanetFactory factory, int timeGene, double dt, float shipSailSpeed, float shipWarpSpeed, int shipCarries, StationComponent[] gStationPool, AstroPose[] astroPoses, VectorLF3 relativePos, Quaternion relativeRot, bool starmap, int[] consumeRegister) { IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il) { // find begin of ship movement computation, c# 460 IL 2090 CodeMatcher matcher = new CodeMatcher(instructions, il); int indexStart = matcher .MatchForward(false, new CodeMatch(i => i.IsLdarg()), new CodeMatch(OpCodes.Ldc_R4), new CodeMatch(OpCodes.Div), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "Sqrt"), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldc_R4), new CodeMatch(OpCodes.Ble_Un)) .Pos; // cut out only that part of original function, but keep the first 5 IL lines (they create the 'bool flag' which is needed) for (matcher.Start().Advance(6); matcher.Pos < indexStart;) { matcher.SetAndAdvance(OpCodes.Nop, null); } // add null check at the beginning of the while(){} for gStationPool[shipData.otherGId] and if it is null skip this shipData until all data received from server matcher .MatchForward(true, new CodeMatch(OpCodes.Br), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), "workShipDatas")), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldelem, typeof(ShipData)), new CodeMatch(OpCodes.Stloc_S)); object jmpNextLoopIter = matcher.InstructionAt(-5).operand; matcher.CreateLabelAt(matcher.Pos + 1, out Label jmpNormalFlow); matcher .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_S, 7)) // gStationPool .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 60)) // shipData .InsertAndAdvance(new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "otherGId"))) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldelem, typeof(StationComponent))) .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, jmpNormalFlow)) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 59)) // j .InsertAndAdvance(new CodeInstruction(OpCodes.Ldc_I4_1)) .InsertAndAdvance(new CodeInstruction(OpCodes.Add)) .InsertAndAdvance(new CodeInstruction(OpCodes.Stloc_S, 59)) .InsertAndAdvance(new CodeInstruction(OpCodes.Br, jmpNextLoopIter)); // remove c# 502-525 (adding item from landing ship to station and modify remote order and shifitng those arrays AND j-- (as we end up in an endless loop if not)) indexStart = matcher .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "itemId")), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "itemCount")), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "inc")), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "AddItem")) .Pos; int indexEnd = matcher .MatchForward(true, new CodeMatch(OpCodes.Sub), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "Clear"), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(OpCodes.Sub), new CodeMatch(OpCodes.Stloc_S)) .Advance(1) .Pos; for (matcher.Start().Advance(indexStart); matcher.Pos < indexEnd;) { matcher.SetAndAdvance(OpCodes.Nop, null); } // c# 621 remove warp state entering as we do this triggered by host. client always messed up here for whatever reason so just tell him what to do. matcher .MatchForward(false, new CodeMatch(OpCodes.Ldloca_S), new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(ShipData), "warperCnt")), new CodeMatch(OpCodes.Dup), new CodeMatch(OpCodes.Ldind_I4), new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(OpCodes.Sub), new CodeMatch(OpCodes.Stind_I4), new CodeMatch(OpCodes.Ldloca_S), new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(ShipData), "warpState"))); for (int i = 0; i < 15; i++) { matcher.SetAndAdvance(OpCodes.Nop, null); } // remove c# 956 - 1054 (adding item from landing ship to station and modify remote order) indexStart = matcher .MatchForward(false, new CodeMatch(OpCodes.Ldarg_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "otherGId")), new CodeMatch(OpCodes.Ldelem_Ref), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), "storage")), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldarg_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "planetA"))) .Pos; indexEnd = matcher .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), "remotePairCount")), new CodeMatch(OpCodes.Rem), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Bne_Un)) .Pos; for (matcher.Start().Advance(indexStart); matcher.Pos <= indexEnd;) { matcher.SetAndAdvance(OpCodes.Nop, null); } // remove c# 1058 - 1093 (taking item from station and modify remote order) indexStart = matcher .MatchForward(false, new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "itemId")), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldarg_S), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldloca_S), new CodeMatch(OpCodes.Ldloca_S), new CodeMatch(OpCodes.Ldloca_S), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "TakeItem")) .Pos; indexEnd = matcher .MatchForward(true, new CodeMatch(OpCodes.Stind_I4), new CodeMatch(OpCodes.Leave), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Brfalse), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Call), new CodeMatch(OpCodes.Endfinally)) .Pos; for (matcher.Start().Advance(indexStart); matcher.Pos <= indexEnd;) { matcher.SetAndAdvance(OpCodes.Nop, null); } return(matcher.InstructionEnumeration()); } _ = Transpiler(null, null); }