private static IEnumerable <CodeInstruction> TryPlayCustomTopicAdvTpl(IEnumerable <CodeInstruction> instructions) { var matcher = new CodeMatcher(instructions) .MatchForward(true, new CodeMatch(OpCodes.Ldstr, "話題を振る")) .MatchForward(true, new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(TalkScene), nameof(TalkScene.isNPC)))) .Advance(1) .ThrowIfNotMatch("Brtrue not found", new CodeMatch(OpCodes.Brtrue)); var startPos = matcher.Pos; // Figure out where the if else ends so we can jump there if we want to skip it // First go to the start of else, then step back and get the label at the end of if that skips over the else var elseLabel = ((Label)matcher.Operand); matcher.MatchForward(false, new CodeMatch(instruction => instruction.labels.Contains(elseLabel))) .Advance(-1) .ThrowIfNotMatch("Br not found", new CodeMatch(OpCodes.Br)); var skipIfelseLabel = matcher.Operand; // Go back to the start of the if matcher.Advance(startPos - matcher.Pos).ThrowIfNotMatch("Brtrue not found 2", new CodeMatch(OpCodes.Brtrue)); // Go back to the first if, then insert our if before it // Copy the `this` load instead of hardcoding it just in case (isNPC takes it) matcher.Advance(-2); var loadInstrCopy = new CodeInstruction(matcher.Opcode, matcher.Operand); matcher.Advance(1).Insert( new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(TopicHooks), nameof(TryPlayCustomTopicAdvHook))), new CodeInstruction(OpCodes.Brtrue, skipIfelseLabel), loadInstrCopy); return(matcher.Instructions()); }
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()); }
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()); }