Files
Sinmai-Assist/Cheat/AutoPlay.cs
2025-10-13 18:18:32 +08:00

284 lines
12 KiB
C#

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<NoteJudge.ETiming> 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<NoteJudge.ETiming> 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<GamePlayManager>.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<GamePlayManager>.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<GamePlayManager>.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);
}
}
}
}