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());
        }
Ejemplo n.º 2
0
        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());
        }
Ejemplo n.º 3
0
        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());
        }
Ejemplo n.º 4
0
        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());
        }
Ejemplo n.º 5
0
    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);
    }
        private static IEnumerable <CodeInstruction> OnGameTick_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator il)
        {
            try
            {
                CodeMatcher codeMatcher = new CodeMatcher(instructions, il)
                                          .MatchForward(false,
                                                        new CodeMatch(OpCodes.Ldarg_0),
                                                        new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "gameData"),
                                                        new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "factories"),
                                                        new CodeMatch(i => i.IsLdloc()),
                                                        new CodeMatch(OpCodes.Ldelem_Ref)
                                                        );

                CodeInstruction factoryIdInstruction   = codeMatcher.InstructionAt(3);
                CodeInstruction generatorIdInstruction = codeMatcher.InstructionAt(7);

                return(codeMatcher
                       .CreateLabel(out Label label)
                       .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0))
                       .InsertAndAdvance(factoryIdInstruction)
                       .InsertAndAdvance(generatorIdInstruction)
                       .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <ACH_BroadcastStar, int, int, bool> >((instance, factoryId, generatorId) =>
                {
                    if (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost)
                    {
                        return true;
                    }

                    if (instance.gameData.factories[factoryId]?.powerSystem?.genPool[generatorId] == null || instance.gameData.factories[factoryId].index == -1)
                    {
                        return false;
                    }

                    return true;
                }))
                       .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, label))
                       .InsertAndAdvance(new CodeInstruction(OpCodes.Ret))
                       .InstructionEnumeration());
            }
            catch
            {
                NebulaModel.Logger.Log.Error("ACH_BroadcastStar.OnGameTick_Transpiler failed. Mod version not compatible with game version.");
                return(instructions);
            }
        }
        public static IEnumerable <CodeInstruction> _OnUpdate_Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            try {
                int         pos1, pos2;
                CodeMatcher matcher = new CodeMatcher(instructions);

                matcher.MatchForward(false, new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(DysonNode), "color")));
                pos1 = matcher.Pos;
                matcher.MatchBack(false, new CodeMatch(OpCodes.Ldloc_S));
                pos2 = matcher.Pos;
                matcher.Advance(pos1 - pos2 + 1)
                .Insert(
                    new CodeInstruction(matcher.InstructionAt(pos2 - pos1 - 1)),
                    new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UIDysonBrush_Paint_Transpiler), "SendNodePacket"))
                    );

                matcher.MatchForward(false, new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(DysonFrame), "color")));
                pos1 = matcher.Pos;
                matcher.MatchBack(false, new CodeMatch(OpCodes.Ldloc_S));
                pos2 = matcher.Pos;
                matcher.Advance(pos1 - pos2 + 1)
                .Insert(
                    new CodeInstruction(matcher.InstructionAt(pos2 - pos1 - 1)),
                    new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UIDysonBrush_Paint_Transpiler), "SendFramePacket"))
                    );

                matcher.MatchForward(false, new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(DysonShell), "color")));
                pos1 = matcher.Pos;
                matcher.MatchBack(false, new CodeMatch(OpCodes.Ldloc_S));
                pos2 = matcher.Pos;
                matcher.Advance(pos1 - pos2 + 1)
                .Insert(
                    new CodeInstruction(matcher.InstructionAt(pos2 - pos1 - 1)),
                    new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UIDysonBrush_Paint_Transpiler), "SendShellPacket"))
                    );

                return(matcher.InstructionEnumeration());
            }
            catch
            {
                NebulaModel.Logger.Log.Error("UIDysonBrush_Paint._OnUpdate_Transpiler failed. Mod version not compatible with game version.");
                return(instructions);
            }
        }
Ejemplo n.º 8
0
        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);
            }
        }
        private static IEnumerable <CodeInstruction> InternalUpdate_Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            // Store projectile data after swarm.AddBullet(sailBullet, orbitId) if IsUpdateNeeded == true
            try
            {
                CodeMatcher matcher = new CodeMatcher(instructions)
                                      .MatchForward(false,
                                                    new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(SailBullet), nameof(SailBullet.lBegin))) //IL#638
                                                    );
                CodeInstruction loadInstruction = matcher.InstructionAt(-1);
                matcher.MatchForward(false,
                                     new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(DysonSwarm), nameof(DysonSwarm.AddBullet))) //IL#679
                                     )
                .Advance(2)
                .InsertAndAdvance(
                    new CodeInstruction(OpCodes.Ldarg_0),
                    new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(EjectorComponent), nameof(EjectorComponent.planetId))),
                    loadInstruction,
                    new CodeInstruction(OpCodes.Ldarg_0),
                    new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(EjectorComponent), nameof(EjectorComponent.orbitId))),
                    HarmonyLib.Transpilers.EmitDelegate <Action <int, Vector3, int> >((planetId, localPos, orbitId) =>
                {
                    // If the dyson sphere has no subscribers anymore, skip this data
                    if (!Multiplayer.IsActive || !Multiplayer.Session.Launch.Snapshots.ContainsKey(planetId / 100 - 1))
                    {
                        return;
                    }

                    // Assume orbitId < 65536
                    DysonLaunchData.Projectile data = new DysonLaunchData.Projectile
                    {
                        PlanetId = planetId,
                        TargetId = (ushort)orbitId,
                        LocalPos = localPos
                    };
                    Multiplayer.Session.Launch.ProjectileBag.Add(data);
                })
                    );
                return(matcher.InstructionEnumeration());
            }
            catch
            {
                NebulaModel.Logger.Log.Error("EjectorComponent.InternalUpdate_Transpiler failed. Mod version not compatible with game version.");
                return(instructions);
            }
        }
Ejemplo n.º 10
0
        private static IEnumerable <CodeInstruction> InternalUpdate_Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            // Store projectile data after sphere.AddDysonRocket(dysonRocket, autoDysonNode) if IsUpdateNeeded == true
            try
            {
                CodeMatcher matcher = new CodeMatcher(instructions)
                                      .MatchForward(false,
                                                    new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(DysonSphere), nameof(DysonSphere.AddDysonRocket))) //IL#310
                                                    );
                CodeInstruction loadInstruction = matcher.InstructionAt(-1);                                                                                     //autoDysonNode
                matcher.Advance(2)
                .InsertAndAdvance(
                    new CodeInstruction(OpCodes.Ldarg_0),
                    new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(SiloComponent), nameof(SiloComponent.planetId))),
                    new CodeInstruction(OpCodes.Ldarg_0),
                    new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(SiloComponent), nameof(SiloComponent.localPos))),
                    loadInstruction,
                    HarmonyLib.Transpilers.EmitDelegate <Action <int, Vector3, DysonNode> >((planetId, localPos, autoDysonNode) =>
                {
                    // If the dyson sphere has no subscribers anymore, skip this data
                    if (!Multiplayer.IsActive || !Multiplayer.Session.Launch.Snapshots.ContainsKey(planetId / 100 - 1))
                    {
                        return;
                    }

                    // Assume layerId < 16, nodeId < 4096
                    DysonLaunchData.Projectile data = new DysonLaunchData.Projectile
                    {
                        PlanetId = planetId,
                        TargetId = (ushort)((autoDysonNode.layerId << 12) | (autoDysonNode.id & 0x0FFF)),
                        LocalPos = localPos
                    };
                    Multiplayer.Session.Launch.ProjectileBag.Add(data);
                })
                    );
                return(matcher.InstructionEnumeration());
            }
            catch
            {
                NebulaModel.Logger.Log.Error("SiloComponent.InternalUpdate_Transpiler failed. Mod version not compatible with game version.");
                return(instructions);
            }
        }
Ejemplo n.º 11
0
            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> 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());
        }
Ejemplo n.º 13
0
        public static IEnumerable <CodeInstruction> Free_Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            CodeMatcher matcher = new CodeMatcher(instructions)
                                  .MatchForward(true,
                                                new CodeMatch(OpCodes.Ldarg_0),
                                                new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "get_controller"),
                                                new CodeMatch(OpCodes.Ldnull),
                                                new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "op_Inequality"),
                                                new CodeMatch(OpCodes.Brfalse)
                                                );

            if (matcher.IsInvalid)
            {
                NebulaModel.Logger.Log.Error("Player.Free_Transpiler failed. Mod version not compatible with game version.");
                return(instructions);
            }

            object jumpOperand = matcher.InstructionAt(4).operand;

            return(matcher
                   .SetOperandAndAdvance(jumpOperand)
                   .InstructionEnumeration());
        }
Ejemplo n.º 14
0
        private static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL)
        {
            CodeMatcher codeMatcher = new CodeMatcher(instructions, iL)
                                      .MatchForward(true,
                                                    new CodeMatch(i => i.opcode == OpCodes.Ldsfld && ((FieldInfo)i.operand).Name == "buildTargetAutoMove")
                                                    );

            if (codeMatcher.IsInvalid)
            {
                NebulaModel.Logger.Log.Error("BuildTool_Click.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version.");
                return(instructions);
            }

            object label = codeMatcher.InstructionAt(1).operand;

            return(codeMatcher
                   .Advance(2)
                   .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() =>
            {
                return Multiplayer.IsActive && Multiplayer.Session.Factories.IsIncomingRequest.Value && Multiplayer.Session.Factories.PacketAuthor != Multiplayer.Session.LocalPlayer.Id;
            }))
                   .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, label))
                   .InstructionEnumeration());
        }
        static IEnumerable <CodeInstruction> CreatePrebuilds_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iL)
        {
            var codeMatcher = new CodeMatcher(instructions, iL)
                              .MatchForward(true,
                                            new CodeMatch(i => i.opcode == OpCodes.Ldsfld && ((FieldInfo)i.operand).Name == "buildTargetAutoMove")
                                            );

            if (codeMatcher.IsInvalid)
            {
                NebulaModel.Logger.Log.Error("BuildTool_Click.CreatePrebuilds_Transpiler failed. Mod version not compatible with game version.");
                return(instructions);
            }

            var label = codeMatcher.InstructionAt(1).operand;

            return(codeMatcher
                   .Advance(2)
                   .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() =>
            {
                return SimulatedWorld.Initialized && (FactoryManager.EventFromServer || FactoryManager.EventFromClient) && FactoryManager.PacketAuthor != LocalPlayer.PlayerId;
            }))
                   .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, label))
                   .InstructionEnumeration());
        }
Ejemplo n.º 16
0
        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);
        }
        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());
        }
Ejemplo n.º 18
0
        private static IEnumerable <CodeInstruction> ComputePowerTab_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iLGenerator)
        {
            /* This is fix for the power statistics.
             * Originally, this function is iterating through all factories and manually summing up "energyStored" values from their PowerSystems.
             * Since client does not have all factories loaded it would cause exceptions.
             * This fix is basically replacing this:
             *
             *  PowerSystem powerSystem = this.gameData.factories[i].powerSystem;
             *                  int netCursor = powerSystem.netCursor;
             *                  PowerNetwork[] netPool = powerSystem.netPool;
             *                  for (int j = 1; j < netCursor; j++)
             *                  {
             *                          num2 += netPool[j].energyStored;
             *                  }
             *
             *  With: Multiplayer.Session.Statistics.UpdateTotalChargedEnergy(factoryIndex);
             *
             * In the UpdateTotalChargedEnergy(), the total energyStored value is being calculated no clients based on the data received from the server. */
            CodeMatcher matcher = new CodeMatcher(instructions, iLGenerator)
                                  .MatchForward(false,
                                                new CodeMatch(OpCodes.Ldarg_0),
                                                new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "gameData"),
                                                new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "factories"),
                                                new CodeMatch(i => i.IsLdarg()),
                                                new CodeMatch(OpCodes.Conv_Ovf_I),
                                                new CodeMatch(OpCodes.Ldelem_Ref),
                                                new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "powerSystem"),
                                                new CodeMatch(OpCodes.Dup),
                                                new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "netCursor"),
                                                new CodeMatch(i => i.IsStloc()),
                                                new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "netPool"),
                                                new CodeMatch(i => i.IsStloc()),
                                                new CodeMatch(OpCodes.Ldc_I4_1),
                                                new CodeMatch(i => i.IsStloc()),
                                                new CodeMatch(OpCodes.Br)
                                                );

            if (matcher.IsInvalid)
            {
                NebulaModel.Logger.Log.Error("UIStatisticsWindow_Transpiler.ComputePowerTab_Transpiler failed. Mod version not compatible with game version.");
                return(instructions);
            }

            int currentPos = matcher.Pos;

            CodeInstruction storeNum2Instruction        = matcher.InstructionAt(-1);
            CodeInstruction loadFactoryIndexInstruction = matcher.InstructionAt(3);

            return(matcher.MatchForward(true,
                                        new CodeMatch(OpCodes.Blt)
                                        )
                   .Advance(1)
                   .CreateLabel(out Label endLabel)
                   .Start()
                   .Advance(currentPos)
                   .InsertAndAdvance(loadFactoryIndexInstruction)
                   .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <long, long> >((factoryIndex) =>
            {
                if (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost)
                {
                    return 0L;
                }

                return Multiplayer.Session.Statistics.UpdateTotalChargedEnergy((int)factoryIndex);
            }))
                   .InsertAndAdvance(storeNum2Instruction)
                   .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Func <bool> >(() =>
            {
                return Multiplayer.IsActive && !Multiplayer.Session.LocalPlayer.IsHost;
            }))
                   .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, endLabel))
                   .InstructionEnumeration());
        }
Ejemplo n.º 19
0
        private static IEnumerable <CodeInstruction> OnBeltBuilt_Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator iLGenerator)
        {
            /*
             * Calls
             * Multiplayer.Session.Factories.OnNewSetInserterPickTarget(objId, pickTarget, inserterId, offset, pointPos);
             * After
             * this.factorySystem.SetInserterPickTarget(inserterId, num6, num5 - num7);
             */
            CodeMatcher codeMatcher = new CodeMatcher(instructions, iLGenerator)
                                      .MatchForward(true,
                                                    new CodeMatch(i => i.opcode == OpCodes.Callvirt &&
                                                                  ((MethodInfo)i.operand).Name == nameof(FactorySystem.SetInserterPickTarget)
                                                                  )
                                                    );

            if (codeMatcher.IsInvalid)
            {
                NebulaModel.Logger.Log.Error("PlanetFactory_Transpiler.OnBeltBuilt 1 failed. Mod version not compatible with game version.");
                return(instructions);
            }

            List <CodeInstruction> setInserterTargetInsts = codeMatcher.InstructionsWithOffsets(-5, -1); // inserterId, pickTarget, offset
            CodeInstruction        objIdInst     = codeMatcher.InstructionAt(-13);                       // objId
            List <CodeInstruction> pointPosInsts = codeMatcher.InstructionsWithOffsets(8, 10);           // pointPos

            codeMatcher = codeMatcher
                          .Advance(1)
                          .InsertAndAdvance(setInserterTargetInsts.ToArray())
                          .InsertAndAdvance(objIdInst)
                          .InsertAndAdvance(pointPosInsts.ToArray())
                          .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Action <int, int, int, int, UnityEngine.Vector3> >((inserterId, pickTarget, offset, objId, pointPos) =>
            {
                if (Multiplayer.IsActive)
                {
                    Multiplayer.Session.Factories.OnNewSetInserterPickTarget(objId, pickTarget, inserterId, offset, pointPos);
                }
            }));

            /*
             * Calls
             * Multiplayer.Session.Factories.OnNewSetInserterInsertTarget(objId, pickTarget, inserterId, offset, pointPos);
             * After
             * this.factorySystem.SetInserterInsertTarget(inserterId, num9, num5 - num10);
             */
            codeMatcher = codeMatcher
                          .MatchForward(true,
                                        new CodeMatch(i => i.opcode == OpCodes.Callvirt &&
                                                      ((MethodInfo)i.operand).Name == nameof(FactorySystem.SetInserterInsertTarget)
                                                      )
                                        );

            if (codeMatcher.IsInvalid)
            {
                NebulaModel.Logger.Log.Error("PlanetFactory_Transpiler.OnBeltBuilt 2 failed. Mod version not compatible with game version.");
                return(codeMatcher.InstructionEnumeration());
            }

            setInserterTargetInsts = codeMatcher.InstructionsWithOffsets(-5, -1); // inserterId, pickTarget, offset
            objIdInst     = codeMatcher.InstructionAt(-13);                       // objId
            pointPosInsts = codeMatcher.InstructionsWithOffsets(9, 11);           // pointPos

            codeMatcher = codeMatcher
                          .Advance(1)
                          .InsertAndAdvance(setInserterTargetInsts.ToArray())
                          .InsertAndAdvance(objIdInst)
                          .InsertAndAdvance(pointPosInsts.ToArray())
                          .InsertAndAdvance(HarmonyLib.Transpilers.EmitDelegate <Action <int, int, int, int, UnityEngine.Vector3> >((inserterId, pickTarget, offset, objId, pointPos) =>
            {
                if (Multiplayer.IsActive)
                {
                    Multiplayer.Session.Factories.OnNewSetInserterInsertTarget(objId, pickTarget, inserterId, offset, pointPos);
                }
            }));

            return(codeMatcher.InstructionEnumeration());
        }