static IEnumerable <CodeInstruction> PatchTranspile(IEnumerable <CodeInstruction> instructions) { var codes = new List <CodeInstruction>(instructions); var searchCode = new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(typeof(StationaryWeapon), "get_OperatorPosition")); int searchIndex = -1; for (var i = 0; i < codes.Count; i++) { if (codes[i].opcode == searchCode.opcode && codes[i].operand == searchCode.operand) { searchIndex = i; break; } } // Patch failed if (searchIndex == -1) { PatchLogger.LogTranspileSearchError(MethodBase.GetCurrentMethod()); return(instructions); } // Look ahead and search for a bgt instruction (should be within the next 10 lines) and get its operand. We want the same label to jump to // for our code below. Label jumpToLabel = default(Label); bool labelFound = false; for (var i = searchIndex; i < codes.Count; i++) { if (codes[i].opcode == OpCodes.Bgt_S) { jumpToLabel = (Label)codes[i].operand; break; } labelFound = true; } if (!labelFound) { Debug.LogError("Label not found."); return(instructions); } // This is start of the instruction that we are interested in. searchIndex -= 2; List <CodeInstruction> newCodes = CodeGenerator.GenerateInstructions(new List <Code>() { new Code(OpCodes.Ldloc_3), new Code(OpCodes.Ldfld, typeof(StationaryWeaponLink), "Weapon"), new Code(OpCodes.Ldnull), new Code(OpCodes.Ceq), new Code(OpCodes.Brtrue_S, jumpToLabel) }); codes.InsertRange(searchIndex, newCodes); return(codes.AsEnumerable()); }
//Define the event handlers. private static void OnChanged(object source, FileSystemEventArgs e) { var logger = new PatchLogger(SERVICE_NAME); var deploymentSet = new DeploymentSet(Directory.GetFiles(Constants.POLL_DIRECTORY)); if (deploymentSet.IsValid()) { //Move files from POLL to PROCESSING directory FileMover.MoveFiles(Constants.POLL_DIRECTORY, Constants.INPROCESS_DIRECTORY); //Create FilesToProcess.txt FileWriter.WriteFilesToProcess(deploymentSet.AllFiles); //Run PatchBuilder.NET to create package RunPatchBuilder(@"C:\PRODUCTION\", "ServiceDeployment"); //Move files from PROCESSING directory to patchfile FileMover.MoveFiles(Constants.INPROCESS_DIRECTORY, Constants.PATCH_FILES_DIRECTORY); //Execute DeployPatch.bat if (System.IO.File.Exists(Constants.BATCH_FILE_NAME)) { RunBatchFile(@"C:\PRODUCTION\"); } } else { logger.EventLog.WriteEntry("Deployment set is invalid. Nothing deployed.", EventLogEntryType.Error); } }
static IEnumerable <CodeInstruction> PatchTranspile(ILGenerator generator, IEnumerable <CodeInstruction> instructions) { var codes = new List <CodeInstruction>(instructions); // Search for code where backend.Session.getProfile() is called. var searchCode = new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(PatcherConstants.SessionInterfaceType, "get_Profile")); int searchIndex = -1; for (var i = 0; i < codes.Count; i++) { if (codes[i].opcode == searchCode.opcode && codes[i].operand == searchCode.operand) { searchIndex = i; break; } } // Patch failed. if (searchIndex == -1) { PatchLogger.LogTranspileSearchError(MethodBase.GetCurrentMethod()); return(instructions); } // Move back by 4. This is the start of this method call. // Note that we don't actually want to replace the code at searchIndex (which is a Ldloc0) since there is a branch // instruction prior to this instruction that leads to it and we can reuse a Ldloc0 instruction here. searchIndex -= 4; Label brFalseLabel = generator.DefineLabel(); Label brLabel = generator.DefineLabel(); List <CodeInstruction> newCodes = CodeGenerator.GenerateInstructions(new List <Code>() { new Code(OpCodes.Ldarg_0), new Code(OpCodes.Ldfld, typeof(ClientApplication), "_backEnd"), new Code(OpCodes.Callvirt, PatcherConstants.BackendInterfaceType, "get_Session"), new Code(OpCodes.Ldarg_0), new Code(OpCodes.Ldfld, typeof(MainApplication), "esideType_0"), new Code(OpCodes.Ldc_I4_0), new Code(OpCodes.Ceq), new Code(OpCodes.Brfalse, brFalseLabel), new Code(OpCodes.Callvirt, PatcherConstants.SessionInterfaceType, "get_Profile"), new Code(OpCodes.Br, brLabel), new CodeWithLabel(OpCodes.Callvirt, brFalseLabel, PatcherConstants.SessionInterfaceType, "get_ProfileOfPet"), new CodeWithLabel(OpCodes.Stfld, brLabel, typeof(MainApplication).GetNestedTypes(BindingFlags.NonPublic).Single(IsTargetNestedType), "profile") }); codes.RemoveRange(searchIndex + 1, 5); codes.InsertRange(searchIndex + 1, newCodes); return(codes.AsEnumerable()); }
static IEnumerable <CodeInstruction> PatchTranspile(ILGenerator generator, IEnumerable <CodeInstruction> instructions) { var codes = new List <CodeInstruction>(instructions); // Search for code where backend.Session.getProfile() is called. var searchCode = new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(PatcherConstants.SessionInterfaceType, "get_Profile")); int searchIndex = -1; for (var i = 0; i < codes.Count; i++) { if (codes[i].opcode == searchCode.opcode && codes[i].operand == searchCode.operand) { searchIndex = i; break; } } // Patch failed. if (searchIndex == -1) { PatchLogger.LogTranspileSearchError(MethodBase.GetCurrentMethod()); return(instructions); } // Move back by 3. This is the start of IL chain that we're interested in. searchIndex -= 3; Label brFalseLabel = generator.DefineLabel(); Label brLabel = generator.DefineLabel(); List <CodeInstruction> newCodes = CodeGenerator.GenerateInstructions(new List <Code>() { new Code(OpCodes.Ldloc_1), new Code(OpCodes.Ldfld, typeof(ClientApplication), "_backEnd"), new Code(OpCodes.Callvirt, PatcherConstants.BackendInterfaceType, "get_Session"), new Code(OpCodes.Ldloc_1), new Code(OpCodes.Ldfld, typeof(MainApplication), "esideType_0"), new Code(OpCodes.Ldc_I4_0), new Code(OpCodes.Ceq), new Code(OpCodes.Brfalse, brFalseLabel), new Code(OpCodes.Callvirt, PatcherConstants.SessionInterfaceType, "get_Profile"), new Code(OpCodes.Br, brLabel), new CodeWithLabel(OpCodes.Callvirt, brFalseLabel, PatcherConstants.SessionInterfaceType, "get_ProfileOfPet"), new CodeWithLabel(OpCodes.Ldc_I4_1, brLabel) }); codes.RemoveRange(searchIndex, 5); codes.InsertRange(searchIndex, newCodes); return(codes.AsEnumerable()); }
static IEnumerable <CodeInstruction> PatchTranspile(ILGenerator generator, IEnumerable <CodeInstruction> instructions) { var codes = new List <CodeInstruction>(instructions); var searchCode = new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(PatcherConstants.ExfilPointManagerType, "EligiblePoints", new System.Type[] { typeof(Profile) })); int searchIndex = -1; for (var i = 0; i < codes.Count; i++) { if (codes[i].opcode == searchCode.opcode && codes[i].operand == searchCode.operand) { searchIndex = i; break; } } // Patch failed. if (searchIndex == -1) { PatchLogger.LogTranspileSearchError(MethodBase.GetCurrentMethod()); return(instructions); } searchIndex -= 3; Label brFalseLabel = generator.DefineLabel(); Label brLabel = generator.DefineLabel(); List <CodeInstruction> newCodes = CodeGenerator.GenerateInstructions(new List <Code>() { new Code(OpCodes.Ldarg_0), new Code(OpCodes.Call, PatcherConstants.LocalGameType.BaseType, "get_Profile_0"), new Code(OpCodes.Ldfld, typeof(Profile), "Info"), new Code(OpCodes.Ldfld, PatcherConstants.ProfileInfoType, "Side"), new Code(OpCodes.Ldc_I4_4), new Code(OpCodes.Ceq), new Code(OpCodes.Brfalse, brFalseLabel), new Code(OpCodes.Call, PatcherConstants.ExfilPointManagerType, "get_Instance"), new Code(OpCodes.Ldarg_0), new Code(OpCodes.Ldfld, PatcherConstants.LocalGameType.BaseType, "gparam_0"), new Code(OpCodes.Box, typeof(PlayerOwner)), new Code(OpCodes.Callvirt, typeof(PlayerOwner), "get_Player"), new Code(OpCodes.Callvirt, typeof(Player), "get_Position"), new Code(OpCodes.Ldarg_0), new Code(OpCodes.Call, PatcherConstants.LocalGameType.BaseType, "get_Profile_0"), new Code(OpCodes.Ldfld, typeof(Profile), "Id"), new Code(OpCodes.Callvirt, PatcherConstants.ExfilPointManagerType, "ScavExfiltrationClaim", new System.Type[] { typeof(Vector3), typeof(string) }), new Code(OpCodes.Call, PatcherConstants.ExfilPointManagerType, "get_Instance"), new Code(OpCodes.Call, PatcherConstants.ExfilPointManagerType, "get_Instance"), new Code(OpCodes.Ldarg_0), new Code(OpCodes.Call, PatcherConstants.LocalGameType.BaseType, "get_Profile_0"), new Code(OpCodes.Ldfld, typeof(Profile), "Id"), new Code(OpCodes.Callvirt, PatcherConstants.ExfilPointManagerType, "GetScavExfiltrationMask"), new Code(OpCodes.Ldarg_0), new Code(OpCodes.Call, PatcherConstants.LocalGameType.BaseType, "get_Profile_0"), new Code(OpCodes.Ldfld, typeof(Profile), "Id"), new Code(OpCodes.Callvirt, PatcherConstants.ExfilPointManagerType, "ScavExfiltrationClaim", new System.Type[] { typeof(int), typeof(string) }), new Code(OpCodes.Br, brLabel), new CodeWithLabel(OpCodes.Call, brFalseLabel, PatcherConstants.ExfilPointManagerType, "get_Instance"), new Code(OpCodes.Ldarg_0), new Code(OpCodes.Call, PatcherConstants.LocalGameType.BaseType, "get_Profile_0"), new Code(OpCodes.Callvirt, PatcherConstants.ExfilPointManagerType, "EligiblePoints", new System.Type[] { typeof(Profile) }), new CodeWithLabel(OpCodes.Stloc_0, brLabel) }); codes.RemoveRange(searchIndex, 5); codes.InsertRange(searchIndex, newCodes); return(codes.AsEnumerable()); }
static IEnumerable <CodeInstruction> PatchTranspile(ILGenerator generator, IEnumerable <CodeInstruction> instructions) { var codes = new List <CodeInstruction>(instructions); // Search for code where this.Speaker is called for the first time. var searchCode = new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(Player), "Speaker")); int searchIndex = -1; for (var i = 0; i < codes.Count; i++) { if (codes[i].opcode == searchCode.opcode && codes[i].operand == searchCode.operand) { searchIndex = i; break; } } // Patch failed if (searchIndex == -1) { PatchLogger.LogTranspileSearchError(MethodBase.GetCurrentMethod()); return(instructions); } // We expected the next three callvirt instructions are the following. // TagBank Play // TaggedClip Match // Speaker Shut // We are interested in each. int callVirtCount = 0; int playIndex = -1, matchIndex = -1, lastCallIndex = -1; for (var i = searchIndex; i < codes.Count; i++) { if (codes[i].opcode == OpCodes.Callvirt) { switch (callVirtCount) { case 0: playIndex = i; break; case 1: matchIndex = i; break; case 2: lastCallIndex = i; break; default: Debug.LogError("Mismatched callvirt instruction count."); break; } searchIndex = i; callVirtCount++; if (callVirtCount > 2) { break; } } } if (playIndex == -1 || matchIndex == -1 || lastCallIndex == -1) { PatchLogger.LogPatchErrorWithMessage(MethodBase.GetCurrentMethod(), "Could not callvirt instructions."); return(instructions); } Label skipLabel = generator.DefineLabel(); Label playPostLabel = generator.DefineLabel(); Label matchPostLabel = generator.DefineLabel(); List <CodeInstruction> playCodes = GetCodes(ref playPostLabel, ref skipLabel); List <CodeInstruction> matchCodes = GetCodes(ref matchPostLabel, ref skipLabel); // If either of the first two calls returns null, we want to skip to the instruction after Speak Shut instruction. codes[playIndex + 1].labels.Add(playPostLabel); codes[matchIndex + 1].labels.Add(matchPostLabel); codes[lastCallIndex + 1].labels.Add(skipLabel); codes.InsertRange(playIndex + 1, playCodes); codes.InsertRange(matchIndex + playCodes.Count + 1, matchCodes); return(codes.AsEnumerable()); }