-
Notifications
You must be signed in to change notification settings - Fork 58
[+] 高仿旧框下一曲目随机图片提示功能 #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[+] 高仿旧框下一曲目随机图片提示功能 #111
Changes from all commits
de2037e
4b4c6ef
8585efb
55bc7b5
4fbd829
38ea467
1d91b39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,257 @@ | ||
| using AquaMai.Config.Attributes; | ||
| using AquaMai.Core.Attributes; | ||
| using AquaMai.Core.Helpers; | ||
| using HarmonyLib; | ||
| using MAI2.Util; | ||
| using Manager; | ||
| using MelonLoader; | ||
| using Monitor; | ||
| using Process; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.IO; | ||
| using UnityEngine; | ||
| using UnityEngine.UI; | ||
|
|
||
| namespace AquaMai.Mods.Fancy; | ||
|
|
||
| [ConfigSection( | ||
| "仿旧框下一曲目随机图像", | ||
| zh: "模仿旧框 FiNALE 在下一首曲目前显示随机提示图", | ||
| en: "Shows random tips image before next track, just like the good ol' FiNALE")] | ||
| [EnableGameVersion(22000)] | ||
| public class NextTrackTips | ||
| { | ||
| [ConfigEntry( | ||
| zh: "随机提示图目录,图像格式为 png", | ||
| en: "Tips image directory, only png images are supported")] | ||
| public static readonly string TipsDirectory = "LocalAssets/Tips"; | ||
|
|
||
| private static readonly List<Sprite> _nextTrackSprites = []; | ||
|
|
||
| private static bool _timeCounterChanged = false; | ||
|
|
||
| private static readonly CommonWindow[] _hackyWindows = new CommonWindow[2]; | ||
| private static IMessageMonitor[] _genericMonitorRefs = new IMessageMonitor[2]; | ||
|
|
||
| [HarmonyPrepare] | ||
| public static bool Initialize() | ||
| { | ||
| var resolvedDir = FileSystem.ResolvePath(TipsDirectory); | ||
| if (!Directory.Exists(resolvedDir)) | ||
| { | ||
| MelonLogger.Error($"[NextTrackTips] Tips directory does not exist: {resolvedDir}"); | ||
| return false; | ||
| } | ||
|
|
||
| var tipImgs = Directory.GetFiles(resolvedDir, "*.png", SearchOption.TopDirectoryOnly); | ||
|
|
||
| foreach (var tipImgPath in tipImgs) | ||
| { | ||
| try | ||
| { | ||
| var tex = new Texture2D(1, 1, TextureFormat.RGBA32, false); | ||
| tex.LoadImage(File.ReadAllBytes(tipImgPath)); | ||
| _nextTrackSprites.Add(Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f))); | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| MelonLogger.Warning($"[NextTrackTips] Failed to load image {tipImgPath}: {e}"); | ||
| } | ||
| } | ||
|
|
||
| if (_nextTrackSprites.Count < 1) | ||
| { | ||
| MelonLogger.Error($"[NextTrackTips] Tips directory seems empty or cannot load all images: {resolvedDir}"); | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(GenericProcess), "OnStart")] | ||
| public static void GenericProcess_OnStart_Postfix(GenericMonitor[] ____monitors) | ||
| { | ||
| _genericMonitorRefs = ____monitors; | ||
| } | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(GenericProcess), "OnRelease")] | ||
| public static void GenericProcess_OnRelease_Postfix() | ||
| { | ||
| _genericMonitorRefs = new IMessageMonitor[2]; | ||
| } | ||
|
|
||
| private static CommonWindow InitializeCommonWindowObject(CommonWindow prefab, Transform parent, int monitorIndex) | ||
| { | ||
| var window = UnityEngine.Object.Instantiate(prefab, parent); | ||
|
|
||
| window.Prepare( | ||
| _genericMonitorRefs[monitorIndex], | ||
| DB.WindowMessageID.NextTrackTips01, | ||
| DB.WindowPositionID.Middle, | ||
| Vector3.zero, | ||
| new WindowParam | ||
| { | ||
| changeSize = true, | ||
| sizeID = DB.WindowSizeID.LargeHorizontal, | ||
| hideTitle = true, | ||
| replaceText = true, | ||
| text = "", | ||
| directSprite = true, | ||
| sprite = _nextTrackSprites[UnityEngine.Random.Range(0, _nextTrackSprites.Count)] | ||
| } | ||
| ); | ||
|
|
||
| // Some hacks to force the layout and "fix" spacing | ||
| var winLayout = window.transform.Find("IMG_Window").GetComponent<HorizontalLayoutGroup>(); | ||
| winLayout.spacing = 0.0f; | ||
| winLayout.padding = new RectOffset(40, 40, 40, 40); | ||
|
|
||
| return window; | ||
| } | ||
|
|
||
| #region NextTrackProcess Patch | ||
| private static bool CheckNextTrackProcess(NextTrackProcess.NextTrackMode mode) | ||
| { | ||
| return mode != NextTrackProcess.NextTrackMode.FreedomTimeup && mode != NextTrackProcess.NextTrackMode.NeedAwake && mode != NextTrackProcess.NextTrackMode.GotoEnd; | ||
| } | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(NextTrackProcess), "ProcessingProcess")] | ||
| public static void ProcessingProcess_Postfix(NextTrackProcess.NextTrackMode ____mode, ref float ____timeCounter) | ||
| { | ||
| if (CheckNextTrackProcess(____mode) && !_timeCounterChanged) | ||
| { | ||
| ____timeCounter = 5f; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| _timeCounterChanged = true; | ||
| } | ||
| } | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(NextTrackProcess), "OnStart")] | ||
| public static void OnStart_Postfix(NextTrackMonitor[] ____monitors, NextTrackProcess.NextTrackMode ____mode) | ||
| { | ||
| if (!CheckNextTrackProcess(____mode)) | ||
| return; | ||
|
|
||
| var commonWindowPref = Resources.Load<GameObject>("Process/Generic/GenericProcess").transform.Find("Canvas/Main/MessageRoot/HorizontalSplitWindow").gameObject.GetComponent<CommonWindow>(); | ||
|
WUGqnwvMQPzl marked this conversation as resolved.
|
||
|
|
||
| for (int i = 0; i < ____monitors.Length; ++i) | ||
| { | ||
| var currUser = Singleton<UserDataManager>.Instance.GetUserData(i); | ||
| if (currUser == null || !currUser.IsActiveUser) | ||
| continue; | ||
|
|
||
| var mainCanvas = ____monitors[i].transform.Find("Canvas/Main"); | ||
| _hackyWindows[i] = InitializeCommonWindowObject(commonWindowPref, mainCanvas.transform, i); | ||
|
|
||
| // Play the sound effects and voice line | ||
| SoundManager.PlaySE(Mai2.Mai2Cue.Cue.JINGLE_NEXT_TRACK, i); | ||
|
|
||
| Mai2.Voice_Partner_000001.Cue nextTrackVoice = UnityEngine.Random.Range(0, 2) == 0 ? Mai2.Voice_Partner_000001.Cue.VO_000151 : Mai2.Voice_Partner_000001.Cue.VO_000152; | ||
| if (GameManager.MusicTrackNumber + 1U == GameManager.GetMaxTrackCount()) | ||
| nextTrackVoice = Mai2.Voice_Partner_000001.Cue.VO_000153; | ||
| SoundManager.PlayPartnerVoice(nextTrackVoice, i); | ||
| } | ||
| } | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(NextTrackProcess), "OnLateUpdate")] | ||
| public static void OnLateUpdate_Postfix(NextTrackMonitor[] ____monitors) | ||
| { | ||
| for (int i = 0; i < ____monitors.Length; ++i) | ||
| _hackyWindows[i]?.UpdateView(GameManager.GetGameMSecAdd()); | ||
| } | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(NextTrackProcess), "StartFadeIn")] | ||
| public static void StartFadeIn_Postfix(NextTrackMonitor[] ____monitors) | ||
| { | ||
| for (int i = 0; i < ____monitors.Length; ++i) | ||
| _hackyWindows[i]?.Close(); | ||
| } | ||
|
|
||
| [HarmonyPrefix] | ||
| [HarmonyPatch(typeof(NextTrackProcess), "OnRelease")] | ||
| public static void OnRelease_Prefix(NextTrackMonitor[] ____monitors) | ||
| { | ||
| for (int i = 0; i < ____monitors.Length; ++i) | ||
| { | ||
| if (_hackyWindows[i] != null) | ||
| { | ||
| UnityEngine.Object.Destroy(_hackyWindows[i]); | ||
| _hackyWindows[i] = null; | ||
| } | ||
| } | ||
|
|
||
| _timeCounterChanged = false; | ||
| } | ||
| #endregion | ||
|
|
||
| #region KaleidxScopeFadeProcess Patch | ||
|
WUGqnwvMQPzl marked this conversation as resolved.
|
||
| [EnableGameVersion(25000, 26499, noWarn: true)] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 据我所知,这里的内容大概会在这个类加载的时候被 jit 解析,让我验证一下这么写到底会不会有问题 |
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(KaleidxScopeFadeProcess), "OnStart")] | ||
| public static void KS_OnStart_Postfix(ProcessBase ___toProcess, List<KaleidxScopeFadeController> ___mainControllerList) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The window-creation, sound-effect, and voice-line logic is duplicated almost verbatim between Prompt for AI agents |
||
| { | ||
| if (___toProcess.GetType() != typeof(MusicSelectProcess) || GameManager.MusicTrackNumber < 2) // WTF SBGA??? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| return; | ||
|
|
||
| var commonWindowPref = Resources.Load<GameObject>("Process/Generic/GenericProcess").transform.Find("Canvas/Main/MessageRoot/HorizontalSplitWindow").gameObject.GetComponent<CommonWindow>(); | ||
|
|
||
| // WTF SBGA? | ||
| for (int i = 0; i < ___mainControllerList.Count; ++i) | ||
| { | ||
| var currUser = Singleton<UserDataManager>.Instance.GetUserData(i); | ||
| if (currUser == null || !currUser.IsActiveUser) | ||
| continue; | ||
|
|
||
| _hackyWindows[i] = InitializeCommonWindowObject(commonWindowPref, ___mainControllerList[i].transform, i); | ||
|
|
||
| // Play the sound effects and voice line | ||
| SoundManager.PlaySE(Mai2.Mai2Cue.Cue.JINGLE_NEXT_TRACK, i); | ||
|
|
||
| Mai2.Voice_Partner_000001.Cue nextTrackVoice = UnityEngine.Random.Range(0, 2) == 0 ? Mai2.Voice_Partner_000001.Cue.VO_000151 : Mai2.Voice_Partner_000001.Cue.VO_000152; | ||
| // WTF SBGA?? | ||
| if (GameManager.MusicTrackNumber == GameManager.GetMaxTrackCount()) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Inconsistent last-track voice condition: Prompt for AI agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ask SBGA |
||
| nextTrackVoice = Mai2.Voice_Partner_000001.Cue.VO_000153; | ||
| SoundManager.PlayPartnerVoice(nextTrackVoice, i); | ||
| } | ||
| } | ||
|
|
||
| [EnableGameVersion(25000, 26499, noWarn: true)] | ||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(KaleidxScopeFadeProcess), "OnLateUpdate")] | ||
| public static void KS_OnLateUpdate_Postfix(List<KaleidxScopeFadeController> ___mainControllerList, KaleidxScopeFadeState ___stateMachine) | ||
| { | ||
| for (int i = 0; i < ___mainControllerList.Count; ++i) | ||
| _hackyWindows[i]?.UpdateView(GameManager.GetGameMSecAdd()); | ||
| } | ||
|
|
||
| [EnableGameVersion(25000, 26499, noWarn: true)] | ||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(KaleidxScopeFadeProcess), "StartFadeIn")] | ||
| public static void KS_StartFadeIn_Postfix(List<KaleidxScopeFadeController> ___mainControllerList) | ||
| { | ||
| for (int i = 0; i < ___mainControllerList.Count; ++i) | ||
| _hackyWindows[i]?.Close(); | ||
| } | ||
|
|
||
| [EnableGameVersion(25000, 26499, noWarn: true)] | ||
| [HarmonyPrefix] | ||
| [HarmonyPatch(typeof(KaleidxScopeFadeProcess), "OnRelease")] | ||
| public static void KS_OnRelease_Prefix(List<KaleidxScopeFadeController> ___mainControllerList) | ||
| { | ||
| for (int i = 0; i < ___mainControllerList.Count; ++i) | ||
| { | ||
| if (_hackyWindows[i] != null) | ||
| { | ||
| UnityEngine.Object.Destroy(_hackyWindows[i]); | ||
| _hackyWindows[i] = null; | ||
| } | ||
| } | ||
| } | ||
| #endregion | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.