private static void InjectIL(TypeDefinition type, ModuleDefinition module)
        {
            // internal DataManager.FileLoadRequest CreateFileRequest(BattleTechResourceType resourceType, string identifier, PrewarmRequest prewarm, bool allowRequestStacking)
            const string targetMethod = "CreateFileRequest";

            // From class -> JsonLoadRequest -> StringDataLoadRequest
            MethodDefinition method =
                type.GetMethods().FirstOrDefault(m => m.Name == targetMethod);

            if (method == null)
            {
                CecilManager.WriteError($"Can't find method: {targetMethod}\n");
                return;
            }

            ILProcessor ilProcessor = method.Body.GetILProcessor();
            Instruction methodStart = method.Body.Instructions[0];

            List <Instruction> newInstructions = CreateInstructions(ilProcessor, methodStart, module);

            newInstructions.Reverse();

            foreach (Instruction instruction in newInstructions)
            {
                ilProcessor.InsertBefore(method.Body.Instructions[0], instruction);
            }
        }
        public void Inject(Dictionary <string, TypeDefinition> typeTable, ModuleDefinition module)
        {
            if (!Mod.Settings.Patch.DataManager)
            {
                return;
            }

            if (typeTable.TryGetValue(_baseType, out TypeDefinition type))
            {
                CecilManager.WriteLog($"Found baseType: {_baseType}");

                foreach (TypeDefinition nestedType in type.NestedTypes)
                {
                    if (_targetType.Equals(nestedType.FullName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        CecilManager.WriteLog($"Found target nestedType: {nestedType.FullName}");
                        InjectIL(nestedType, module);
                    }
                }
            }
            else
            {
                CecilManager.WriteError($"Can't find target type: {_targetType}");
            }
        }
        public void Inject(Dictionary <string, TypeDefinition> typeTable, ModuleDefinition module)
        {
            if (!Mod.Settings.Patch.Vanilla)
            {
                return;
            }

            if (typeTable.TryGetValue(_targetType, out TypeDefinition type))
            {
                InjectIL(type, module);
                return;
            }

            CecilManager.WriteError($"Can't find type: {_targetType}");
        }
        public void Inject(Dictionary <string, TypeDefinition> typeTable, ModuleDefinition module)
        {
            if (!Mod.Settings.Patch.DataManager)
            {
                return;
            }

            if (typeTable.TryGetValue(_targetType, out TypeDefinition type))
            {
                CecilManager.WriteError($"Injecting IL for targetType: {_targetType}");
                InjectIL(type, module);
            }
            else
            {
                CecilManager.WriteError($"Can't find target type: {_targetType}");
            }
        }
 static void Main(string[] args)
 {
     CecilManager.Init();
 }
        private static void InjectIL(TypeDefinition type, ModuleDefinition module)
        {
            const string targetMethod = "Load";

            // From class -> JsonLoadRequest -> StringDataLoadRequest
            TypeDefinition   baseType = type.BaseType.Resolve().BaseType.Resolve();
            MethodDefinition method   =
                baseType.GetMethods().FirstOrDefault(m => m.Name == targetMethod);

            if (method == null)
            {
                CecilManager.WriteError($"Can't find method: {targetMethod}\n");
                return;
            }

            ILProcessor ilProcessor = method.Body.GetILProcessor();

            // Add a enew reference to an importable method call for AsyncJsonLoadRequest.Load()
            TypeReference ajlr_TR = module.ImportReference(typeof(AsyncJsonLoadRequest));
            TypeReference taskTR  = module.ImportReference(typeof(Task));

            MethodReference ajlr_lr_MR = new MethodReference("LoadResource", taskTR, ajlr_TR);
            TypeReference   stringTR   = module.ImportReference(typeof(string));

            ajlr_lr_MR.Parameters.Add(new ParameterDefinition(stringTR));

            TypeReference actionStringTR = module.ImportReference(typeof(Action <string>));

            ajlr_lr_MR.Parameters.Add(new ParameterDefinition(actionStringTR));
            ajlr_lr_MR.ReturnType = taskTR;

            MethodReference ajlr_lr_Imported_MR = module.ImportReference(ajlr_lr_MR);

            // Walk the instructions to find the target. Don't mutate as we go, so we can use insertAfter later.
            int targetIdx = -1;

            for (int i = 0; i < method.Body.Instructions.Count - 1; i++)
            {
                Instruction instruction = method.Body.Instructions[i];
                if (instruction.OpCode == OpCodes.Callvirt &&
                    instruction.Operand is MethodDefinition methodDef)
                {
                    //CecilManager.WriteLog($"Found methodDef: {methodDef.FullName}");

                    if (methodDef.FullName.StartsWith("System.Void HBS.Data.DataLoader::LoadResource"))
                    {
                        CecilManager.WriteLog($"Found injection point: {methodDef.FullName}\n");
                        targetIdx = i;
                    }
                }
            }
            if (targetIdx != -1)
            {
                // Replace callvirt for dataManager.dataLoader.LoadResource with call to AsyncJsonLoadRequest
                method.Body.Instructions[targetIdx] = ilProcessor.Create(OpCodes.Call, ajlr_lr_Imported_MR);

                // Elminate references to dataLoader (no longer used)
                method.Body.Instructions[targetIdx - 9].OpCode  = OpCodes.Nop;
                method.Body.Instructions[targetIdx - 9].Operand = null;

                method.Body.Instructions[targetIdx - 8].OpCode  = OpCodes.Nop;
                method.Body.Instructions[targetIdx - 8].Operand = null;

                method.Body.Instructions[targetIdx - 7].OpCode  = OpCodes.Nop;
                method.Body.Instructions[targetIdx - 7].Operand = null;

                // Add a pop to remove the async Task (to eliminate dnSpy decompile err)
                Instruction popInst = ilProcessor.Create(OpCodes.Pop);
                ilProcessor.InsertAfter(method.Body.Instructions[targetIdx], popInst);
            }
        }