using HarmonyLib; using MAI2.Util; using Manager; using Monitor; using System; using System.Collections.ObjectModel; using static NoteJudge; using MelonLoader; namespace SinmaiAssist.Cheat { public class AutoPlay { public enum AutoPlayMode { None, Critical, Perfect, Great, Good, Random, RandomAllPerfect, RandomFullComboPlus, RandomFullCombo } private static readonly ReadOnlyCollection RandCriticalTiming = Array.AsReadOnly(new NoteJudge.ETiming[5] { NoteJudge.ETiming.FastPerfect2nd, NoteJudge.ETiming.FastPerfect, NoteJudge.ETiming.Critical, NoteJudge.ETiming.LatePerfect, NoteJudge.ETiming.LatePerfect2nd }); private static readonly ReadOnlyCollection RandomJudgeTiming = Array.AsReadOnly(new NoteJudge.ETiming[] { NoteJudge.ETiming.Critical, NoteJudge.ETiming.FastPerfect, NoteJudge.ETiming.FastPerfect2nd, NoteJudge.ETiming.LatePerfect, NoteJudge.ETiming.LatePerfect2nd, NoteJudge.ETiming.LateGreat2nd, NoteJudge.ETiming.FastGreat2nd, NoteJudge.ETiming.LateGood, NoteJudge.ETiming.FastGood, NoteJudge.ETiming.TooLate }); public static AutoPlayMode autoPlayMode = AutoPlayMode.None; public static bool DisableUpdate = false; public static bool IsAutoPlay() { return autoPlayMode != AutoPlayMode.None; } [HarmonyPrefix] [HarmonyPatch(typeof(GameManager), "IsAutoPlay")] public static bool SetIsAutoPlay(ref bool __result) { __result = IsAutoPlay(); return false; } [HarmonyPostfix] [HarmonyPatch(typeof(GameManager), "set_AutoPlay")] public static void AutoPlayUpdate() { var mode = GameManager.AutoPlay; if (DisableUpdate) return; autoPlayMode = (AutoPlayMode)mode; } [HarmonyPostfix] [HarmonyPatch(typeof(GameManager), "AutoJudge")] public static void AutoJudge(ref NoteJudge.ETiming __result) { var random = UnityEngine.Random.Range(0, 1000); var random2 = 2; if (random < 350) { random2 += UnityEngine.Random.Range(-2, 3); } switch (autoPlayMode) { case AutoPlayMode.Critical: __result = NoteJudge.ETiming.Critical; break; case AutoPlayMode.Perfect: __result = UnityEngine.Random.Range(0, 2) == 0 ? NoteJudge.ETiming.LatePerfect2nd : NoteJudge.ETiming.FastPerfect2nd; break; case AutoPlayMode.Great: __result = UnityEngine.Random.Range(0, 2) == 0 ? NoteJudge.ETiming.LateGreat : NoteJudge.ETiming.FastGreat; break; case AutoPlayMode.Good: __result = UnityEngine.Random.Range(0, 2) == 0 ? NoteJudge.ETiming.LateGood : NoteJudge.ETiming.FastGood; break; case AutoPlayMode.Random: __result = RandomJudgeTiming[UnityEngine.Random.Range(0, RandomJudgeTiming.Count)]; break; case AutoPlayMode.RandomAllPerfect: __result = RandCriticalTiming[random2]; break; case AutoPlayMode.RandomFullComboPlus: if (random >= 10) { __result = RandCriticalTiming[random2]; } else { __result = UnityEngine.Random.Range(0, 2) == 1 ? NoteJudge.ETiming.LateGreat : NoteJudge.ETiming.FastGreat; } break; case AutoPlayMode.RandomFullCombo: if (random >= 80) { __result = RandCriticalTiming[random2]; } else if (random >= 20) { __result = UnityEngine.Random.Range(0, 2) == 1 ? NoteJudge.ETiming.LateGreat : NoteJudge.ETiming.FastGreat; } else { __result = UnityEngine.Random.Range(0, 2) == 1 ? NoteJudge.ETiming.LateGood : NoteJudge.ETiming.FastGood; } break; default: __result = NoteJudge.ETiming.TooFast; break; } } [HarmonyPrefix] [HarmonyPatch(typeof(NoteBase), "SetAutoPlayJudge")] public static bool NoteBaseAutoPlayJudge(NoteBase __instance) { if (!IsAutoPlay()) return true; var appearMsec = (float)AccessTools.Field(typeof(NoteBase), "AppearMsec").GetValue(__instance); var isExNote = (bool)AccessTools.Field(typeof(NoteBase), "IsExNote").GetValue(__instance); var playJudgeSeMethod = AccessTools.Method(typeof(NoteBase), "PlayJudgeSe"); if (NotesManager.GetCurrentMsec() > appearMsec - 4.1666665f && IsAutoPlay()) { if ((autoPlayMode == AutoPlayMode.RandomAllPerfect || autoPlayMode == AutoPlayMode.RandomFullCombo || autoPlayMode == AutoPlayMode.RandomFullComboPlus) && isExNote) { AccessTools.Field(typeof(NoteBase), "JudgeResult").SetValue(__instance, NoteJudge.ETiming.Critical); } else { AccessTools.Field(typeof(Monitor.NoteBase), "JudgeResult").SetValue(__instance, GameManager.AutoJudge()); } playJudgeSeMethod.Invoke(__instance, null); } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(SlideRoot), "Judge")] public static bool SlideRootJudge(SlideRoot __instance, ref bool __result) { if (!IsAutoPlay()) return true; // 检查是否进入判定窗口 var isNoteCheckTimeStartMethod = AccessTools.Method(typeof(SlideRoot), "IsNoteCheckTimeStart"); bool isNoteCheckTimeStart = (bool)isNoteCheckTimeStartMethod.Invoke( __instance, new object[] { Singleton.Instance.GetGameScore(__instance.MonitorId).UserOption.GetJudgeTimingFrame() } ); if (!isNoteCheckTimeStart) { __result = false; return false; } // ★ 强制所有 Slide 判定为 Critical var judgeResultField = AccessTools.Field(typeof(SlideRoot), "JudgeResult"); judgeResultField.SetValue(__instance, NoteJudge.ETiming.Critical); __result = true; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(TouchNoteB), "Judge")] public static bool TouchNoteBJudge(TouchNoteB __instance, ref bool __result) { if (!IsAutoPlay()) return true; var isNoteCheckTimeStartMethod = AccessTools.Method(typeof(NoteBase), "IsNoteCheckTimeStart"); bool isNoteCheckTimeStart = (bool)isNoteCheckTimeStartMethod.Invoke(__instance, new object[] { Singleton.Instance.GetGameScore(__instance.MonitorId).UserOption.GetJudgeTimingFrame() }); if (isNoteCheckTimeStart) { __result = false; return false; } var judgeTimingDiffMsecField = AccessTools.Field(typeof(NoteBase), "JudgeTimingDiffMsec"); var judgeResultField = AccessTools.Field(typeof(NoteBase), "JudgeResult"); var appearMsecField = AccessTools.Field(typeof(NoteBase), "AppearMsec"); var judgeTypeField = AccessTools.Field(typeof(NoteBase), "JudgeType"); var buttonIdField = AccessTools.Field(typeof(NoteBase), "ButtonId"); var TouchAreaField = AccessTools.Field(typeof(TouchNoteB), "TouchArea"); var playJudgeSeMethod = AccessTools.Method(typeof(TouchNoteB), "PlayJudgeSe"); var judgeTimingDiffMsec = NotesManager.GetCurrentMsec() - (float)appearMsecField.GetValue(__instance); judgeTimingDiffMsecField.SetValue(__instance, judgeTimingDiffMsec); ETiming judgeResult = (ETiming)judgeResultField.GetValue(__instance); judgeResult = NoteJudge.GetJudgeTiming(ref judgeTimingDiffMsec, Singleton.Instance.GetGameScore(__instance.MonitorId).UserOption.GetJudgeTimingFrame(), (EJudgeType)judgeTypeField.GetValue(__instance)); if (autoPlayMode == AutoPlayMode.RandomAllPerfect || autoPlayMode == AutoPlayMode.RandomFullComboPlus || autoPlayMode == AutoPlayMode.RandomFullCombo) { judgeResult = NoteJudge.ETiming.Critical; } judgeResultField.SetValue(__instance, judgeResult); TouchSensorType touchArea = (TouchSensorType)TouchAreaField.GetValue(__instance); if (judgeResult != NoteJudge.ETiming.End) { playJudgeSeMethod.Invoke(__instance, null); int buttonId = (int)buttonIdField.GetValue(__instance); if (touchArea == TouchSensorType.B) { InputManager.SetUsedThisFrame(__instance.MonitorId, (InputManager.TouchPanelArea)(8 + buttonId)); } else if (touchArea == TouchSensorType.E) { InputManager.SetUsedThisFrame(__instance.MonitorId, (InputManager.TouchPanelArea)(26 + buttonId)); } else if (touchArea == TouchSensorType.A) { InputManager.SetUsedThisFrame(__instance.MonitorId, (InputManager.TouchPanelArea)(0 + buttonId)); } else if (touchArea == TouchSensorType.D) { InputManager.SetUsedThisFrame(__instance.MonitorId, (InputManager.TouchPanelArea)(18 + buttonId)); } else if (touchArea == TouchSensorType.C) { InputManager.SetUsedThisFrame(__instance.MonitorId, InputManager.TouchPanelArea.C1); InputManager.SetUsedThisFrame(__instance.MonitorId, InputManager.TouchPanelArea.C2); } __result = true; return false; } return false; } [HarmonyPostfix] [HarmonyPatch(typeof(TouchNoteB), "NoteCheck")] public static void NoteCheck(TouchNoteB __instance) { if (!IsAutoPlay()) return; var judgeResultField = AccessTools.Field(typeof(NoteBase), "JudgeResult"); var playJudgeSeMethod = AccessTools.Method(typeof(TouchNoteB), "PlayJudgeSe"); float appearMsec = (float)AccessTools.Field(typeof(NoteBase), "AppearMsec").GetValue(__instance); if ((autoPlayMode == AutoPlayMode.RandomAllPerfect || autoPlayMode == AutoPlayMode.RandomFullComboPlus || autoPlayMode == AutoPlayMode.RandomFullCombo) && NotesManager.GetCurrentMsec() > appearMsec - 4.1666665f && IsAutoPlay()) { judgeResultField.SetValue(__instance, NoteJudge.ETiming.Critical); playJudgeSeMethod.Invoke(__instance, null); } } } }