[RF] Move some patches to visual

This commit is contained in:
Clansty
2024-10-28 06:09:42 +08:00
parent 6945032077
commit 7933d49bb2
16 changed files with 127 additions and 126 deletions

View File

@@ -117,70 +117,11 @@ public class Config
""")]
public bool CustomFont { get; set; }
[ConfigComment(
en: """
Provide the ability to use custom skins (advanced feature)
Load skin textures from LocalAssets\Skins
""",
zh: """
提供自定义皮肤的能力(高级功能)
从 LocalAssets\Skins 中加载皮肤贴图
""")]
public bool CustomSkins { get; set; }
[ConfigComment(
en: """
More detailed judgment display
Requires CustomSkins to be enabled and the resource file to be downloaded
https://github.com/hykilpikonna/AquaDX/releases/download/nightly/JudgeDisplay4B.7z
""",
zh: """
更精细的判定表示
需开启 CustomSkins 并下载资源文件
https://github.com/hykilpikonna/AquaDX/releases/download/nightly/JudgeDisplay4B.7z
""")]
public bool JudgeDisplay4B { get; set; }
[ConfigComment(
en: """
Custom track start difficulty image (not really custom difficulty)
Requires CustomSkins to be enabled
Will load four image resources through custom skins: musicBase, musicTab, musicLvBase, musicLvText
""",
zh: """
自定义在歌曲开始界面上显示的难度贴图 (并不是真的自定义难度)
需要启用自定义皮肤功能
会通过自定义皮肤加载四个图片资源: musicBase, musicTab, musicLvBase, musicLvText
""")]
public bool CustomTrackStartDiff { get; set; }
[ConfigComment(
en: "Map touch actions to buttons",
zh: "映射触摸操作至实体按键")]
public bool TouchToButtonInput { get; set; }
[ConfigComment(
en: """
Delayed the animation of the song start screen
For recording chart confirmation
""",
zh: """
推迟了歌曲开始界面的动画
录制谱面确认用
""")]
public bool TrackStartProcessTweak { get; set; }
[ConfigComment(
en: """
Disable the TRACK X text, DX/Standard display box, and the derakkuma at the bottom of the screen in the song start screen
For recording chart confirmation
""",
zh: """
在歌曲开始界面, 把 TRACK X 字样, DX/标准谱面的显示框, 以及画面下方的滴蜡熊隐藏掉
录制谱面确认用
""")]
public bool DisableTrackStartTabs { get; set; }
[ConfigComment(
en: "Cannot be used together with HanabiFix",
zh: """

View File

@@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using HarmonyLib;
using Monitor;
using Process;
using UnityEngine;
using UnityEngine.UI;
namespace AquaMai.UX;
public class CustomLogo
{
private static List<Sprite> segaLogo = new();
private static List<Sprite> allNetLogo = new();
public static void DoCustomPatch(HarmonyLib.Harmony h)
{
EnumSprite(segaLogo, Path.Combine(Environment.CurrentDirectory, "LocalAssets", "SegaLogo"));
EnumSprite(allNetLogo, Path.Combine(Environment.CurrentDirectory, "LocalAssets", "AllNetLogo"));
}
private static void EnumSprite(List<Sprite> collection, string path)
{
if (!Directory.Exists(path)) return;
foreach (var file in Directory.EnumerateFiles(path, "*.png"))
{
var data = File.ReadAllBytes(file);
var texture2D = new Texture2D(1, 1, TextureFormat.RGBA32, false);
if (texture2D.LoadImage(data))
{
collection.Add(Sprite.Create(texture2D, new Rect(0f, 0f, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f)));
}
}
}
[HarmonyPatch(typeof(AdvertiseProcess), "OnStart")]
[HarmonyPostfix]
private static void AdvProcessPostFix(AdvertiseMonitor[] ____monitors)
{
if (segaLogo.Count > 0)
{
var logo = segaLogo[UnityEngine.Random.Range(0, segaLogo.Count)];
foreach (var monitor in ____monitors)
{
monitor.transform.Find("Canvas/Main/SegaAllNet_LOGO/NUL_ADT_SegaAllNet_LOGO/SegaLogo").GetComponent<Image>().sprite = logo;
}
}
if (allNetLogo.Count > 0)
{
var logo = allNetLogo[UnityEngine.Random.Range(0, allNetLogo.Count)];
foreach (var monitor in ____monitors)
{
monitor.transform.Find("Canvas/Main/SegaAllNet_LOGO/NUL_ADT_SegaAllNet_LOGO/AllNetLogo").GetComponent<Image>().sprite = logo;
}
}
}
}

View File

@@ -1,388 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using HarmonyLib;
using MelonLoader;
using Monitor;
using Monitor.Game;
using Process;
using UnityEngine;
namespace AquaMai.UX;
public class CustomSkins
{
private static readonly List<string> ImageExts = [".png", ".jpg", ".jpeg"];
private static readonly List<string> SlideFanFields = ["_normalSlideFan", "_eachSlideFan", "_breakSlideFan", "_breakSlideFanEff"];
private static readonly List<string> CustomTrackStartFields = ["_musicBase", "_musicTab", "_musicLvBase", "_musicLvText"];
private static Sprite customOutline;
private static Sprite[,] customSlideFan = new Sprite[4, 11];
public static readonly Sprite[,] CustomJudge = new Sprite[2, ((int)NoteJudge.ETiming.End + 1)];
public static readonly Sprite[,,,] CustomJudgeSlide = new Sprite[2, 3, 2, ((int)NoteJudge.ETiming.End + 1)];
public static readonly Texture2D[] CustomTrackStart = new Texture2D[4];
private static bool LoadIntoGameNoteImageContainer(string fieldName, int? idx1, int? idx2, Texture2D texture)
{
// 先确定确实有这个 Field, 如果没有的话可以直接跳过这个文件
var fieldTraverse = Traverse.Create(typeof(GameNoteImageContainer)).Field(fieldName);
if (!fieldTraverse.FieldExists())
{
MelonLogger.Msg($"[CustomNoteSkin] Cannot found field {fieldName}");
return false;
}
var fieldType = fieldTraverse.GetValueType();
if (!idx1.HasValue)
{
// 目标 Field 应当是单个 Sprite
if (fieldType != typeof(Sprite))
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} is a {fieldType.Name}, not a Sprite");
return false;
}
var target = fieldTraverse.GetValue<Sprite>();
var pivot = new Vector2(target.pivot.x / target.rect.width, target.pivot.y / target.rect.height);
var custom = Sprite.Create(
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
0, SpriteMeshType.Tight, target.border
);
fieldTraverse.SetValue(custom);
}
else if (!idx2.HasValue)
{
// 目标 Field 是一维数组
if (fieldType != typeof(Sprite[]))
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} is a {fieldType.Name}, not a Sprite[]");
return false;
}
var targetArray = fieldTraverse.GetValue<Sprite[]>();
var target = targetArray[idx1.Value];
var pivot = new Vector2(target.pivot.x / target.rect.width, target.pivot.y / target.rect.height);
var custom = Sprite.Create(
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
0, SpriteMeshType.Tight, target.border
);
targetArray[idx1.Value] = custom;
}
else
{
// 目标 Field 是二维数组
if (fieldType != typeof(Sprite[,]))
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} is a {fieldType.Name}, not a Sprite[,]");
return false;
}
var targetArray = fieldTraverse.GetValue<Sprite[,]>();
var target = targetArray[idx1.Value, idx2.Value];
var pivot = new Vector2(target.pivot.x / target.rect.width, target.pivot.y / target.rect.height);
var custom = Sprite.Create(
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
0, SpriteMeshType.Tight, target.border
);
targetArray[idx1.Value, idx2.Value] = custom;
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameNotePrefabContainer), "Initialize")]
private static void LoadNoteSkin()
{
if (!Directory.Exists(Path.Combine(Environment.CurrentDirectory, "LocalAssets", "Skins"))) return;
foreach (var laFile in Directory.EnumerateFiles(Path.Combine(Environment.CurrentDirectory, "LocalAssets", "Skins")))
{
if (!ImageExts.Contains(Path.GetExtension(laFile).ToLowerInvariant())) continue;
var texture = new Texture2D(1, 1, TextureFormat.RGBA32, false);
texture.LoadImage(File.ReadAllBytes(laFile));
var name = Path.GetFileNameWithoutExtension(laFile);
var args = name.Split('_');
// 文件名的格式是 XXXXXXXX_A_B 表示 GameNoteImageContainer._XXXXXXXX[A, B]
// 视具体情况, A, B 可能不存在
var fieldName = '_' + args[0];
int? idx1 = (args.Length < 2) ? null : (int.TryParse(args[1], out var temp) ? temp : null);
int? idx2 = (args.Length < 3) ? null : (int.TryParse(args[2], out temp) ? temp : null);
int? idx3 = (args.Length < 4) ? null : (int.TryParse(args[3], out temp) ? temp : null);
Traverse traverse;
if (CustomTrackStartFields.Contains(fieldName))
{
var i = CustomTrackStartFields.IndexOf(fieldName);
CustomTrackStart[i] = texture;
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (fieldName == "_outline")
{
customOutline = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), 1f);
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (fieldName == "_judgeNormal" || fieldName == "_judgeBreak")
{
if (!idx1.HasValue)
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
continue;
}
var i = (fieldName == "_judgeBreak") ? 1 : 0;
CustomJudge[i, idx1.Value] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), 1f);
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (fieldName == "_judgeSlideNormal" || fieldName == "_judgeSlideBreak")
{
if (!idx1.HasValue || !idx2.HasValue || !idx3.HasValue)
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs 3 indices");
continue;
}
var i = (fieldName == "_judgeSlideBreak") ? 1 : 0;
Vector2 pivot;
switch (idx1.Value)
{
case 0 when idx2.Value == 0:
pivot = new Vector2(0f, 0.5f);
break;
case 0 when idx2.Value == 1:
pivot = new Vector2(1f, 0.5f);
break;
case 1 when idx2.Value == 0:
pivot = new Vector2(0f, 0.3f);
break;
case 1 when idx2.Value == 1:
pivot = new Vector2(1f, 0.3f);
break;
case 2 when idx2.Value == 0:
pivot = new Vector2(0.5f, 0.8f);
break;
case 2 when idx2.Value == 1:
pivot = new Vector2(0.5f, 0.2f);
break;
default:
pivot = new Vector2(0.5f, 0.5f);
break;
}
CustomJudgeSlide[i, idx1.Value, idx2.Value, idx3.Value] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f);
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (SlideFanFields.Contains(fieldName))
{
if (!idx1.HasValue)
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
continue;
}
var i = SlideFanFields.IndexOf(fieldName);
customSlideFan[i, idx1.Value] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(1f, 0.5f), 1f);
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (fieldName == "_touchJust")
{
traverse = Traverse.Create(GameNotePrefabContainer.TouchTapB);
var noticeObject = traverse.Field<GameObject>("NoticeObject").Value;
var target = noticeObject.GetComponent<SpriteRenderer>();
var pivot = new Vector2(
target.sprite.pivot.x / target.sprite.rect.width,
target.sprite.pivot.y / target.sprite.rect.height
);
var custom = Sprite.Create(
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
0, SpriteMeshType.Tight, target.sprite.border
);
target.sprite = custom;
traverse = Traverse.Create(GameNotePrefabContainer.TouchTapC);
noticeObject = traverse.Field<GameObject>("NoticeObject").Value;
noticeObject.GetComponent<SpriteRenderer>().sprite = custom;
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (fieldName == "_touchHold")
{
if (!idx1.HasValue)
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
continue;
}
traverse = Traverse.Create(GameNotePrefabContainer.TouchHoldC);
var target = traverse.Field<SpriteRenderer[]>("ColorsObject").Value;
var renderer = target[idx1.Value];
var pivot = new Vector2(
renderer.sprite.pivot.x / renderer.sprite.rect.width,
renderer.sprite.pivot.y / renderer.sprite.rect.height
);
var custom = Sprite.Create(
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
0, SpriteMeshType.Tight, renderer.sprite.border
);
renderer.sprite = custom;
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (fieldName == "_normalTouchBorder")
{
if (!idx1.HasValue)
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
continue;
}
traverse = Traverse.Create(GameNotePrefabContainer.TouchReserve);
var target = traverse.Field<Sprite[]>("_reserveSingleSprite").Value;
var targetSprite = target[idx1.Value - 2];
var pivot = new Vector2(
targetSprite.pivot.x / targetSprite.rect.width,
targetSprite.pivot.y / targetSprite.rect.height
);
target[idx1.Value - 2] = Sprite.Create(
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
0, SpriteMeshType.Tight, targetSprite.border
);
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (fieldName == "_eachTouchBorder")
{
if (!idx1.HasValue)
{
MelonLogger.Msg($"[CustomNoteSkin] Field {fieldName} needs a index");
continue;
}
traverse = Traverse.Create(GameNotePrefabContainer.TouchReserve);
var target = traverse.Field<Sprite[]>("_reserveEachSprite").Value;
var targetSprite = target[idx1.Value - 2];
var pivot = new Vector2(
targetSprite.pivot.x / targetSprite.rect.width,
targetSprite.pivot.y / targetSprite.rect.height
);
target[idx1.Value - 2] = Sprite.Create(
texture, new Rect(0, 0, texture.width, texture.height), pivot, 1f,
0, SpriteMeshType.Tight, targetSprite.border
);
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
continue;
}
if (LoadIntoGameNoteImageContainer(fieldName, idx1, idx2, texture))
{
MelonLogger.Msg($"[CustomNoteSkin] Successfully loaded {name}");
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameCtrl), "Initialize")]
private static void ChangeOutlineTexture(GameObject ____guideEndPointObj)
{
if (____guideEndPointObj != null && customOutline != null)
{
____guideEndPointObj.GetComponent<SpriteRenderer>().sprite = customOutline;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(SlideFan), "Initialize")]
private static void ChangeFanTexture(
SpriteRenderer[] ____spriteLines, SpriteRenderer[] ____effectSprites, bool ___BreakFlag, bool ___EachFlag
)
{
Vector3 position;
Sprite sprite;
if (___BreakFlag)
{
for (var i = 0; i < 11; i++)
{
sprite = customSlideFan[2, i];
if (sprite != null)
{
____spriteLines[2 * i].sprite = sprite;
position = ____spriteLines[2 * i].transform.localPosition;
____spriteLines[2 * i].transform.localPosition = new Vector3(0, position.y, position.z);
____spriteLines[2 * i].color = Color.white;
____spriteLines[2 * i + 1].sprite = sprite;
position = ____spriteLines[2 * i + 1].transform.localPosition;
____spriteLines[2 * i + 1].transform.localPosition = new Vector3(0, position.y, position.z);
____spriteLines[2 * i + 1].color = Color.white;
}
sprite = customSlideFan[3, i];
if (sprite != null)
{
____effectSprites[2 * i].sprite = sprite;
position = ____effectSprites[2 * i].transform.localPosition;
____effectSprites[2 * i].transform.localPosition = new Vector3(0, position.y, position.z);
____effectSprites[2 * i].color = Color.white;
____effectSprites[2 * i + 1].sprite = sprite;
position = ____effectSprites[2 * i + 1].transform.localPosition;
____effectSprites[2 * i + 1].transform.localPosition = new Vector3(0, position.y, position.z);
____effectSprites[2 * i + 1].color = Color.white;
}
}
}
else if (___EachFlag)
{
for (var i = 0; i < 11; i++)
{
sprite = customSlideFan[1, i];
if (sprite != null)
{
____spriteLines[2 * i].sprite = sprite;
position = ____spriteLines[2 * i].transform.localPosition;
____spriteLines[2 * i].transform.localPosition = new Vector3(0, position.y, position.z);
____spriteLines[2 * i].color = Color.white;
____spriteLines[2 * i + 1].sprite = sprite;
position = ____spriteLines[2 * i + 1].transform.localPosition;
____spriteLines[2 * i + 1].transform.localPosition = new Vector3(0, position.y, position.z);
____spriteLines[2 * i + 1].color = Color.white;
}
}
}
else
{
for (var i = 0; i < 11; i++)
{
sprite = customSlideFan[0, i];
if (sprite != null)
{
____spriteLines[2 * i].sprite = sprite;
position = ____spriteLines[2 * i].transform.localPosition;
____spriteLines[2 * i].transform.localPosition = new Vector3(0, position.y, position.z);
____spriteLines[2 * i].color = Color.white;
____spriteLines[2 * i + 1].sprite = sprite;
position = ____spriteLines[2 * i + 1].transform.localPosition;
____spriteLines[2 * i + 1].transform.localPosition = new Vector3(0, position.y, position.z);
____spriteLines[2 * i + 1].color = Color.white;
}
}
}
}
}

View File

@@ -1,66 +0,0 @@
using System.Collections.Generic;
using HarmonyLib;
using Monitor;
using UI;
using UnityEngine;
using UnityEngine.UI;
namespace AquaMai.UX;
public class CustomTrackStartDiff
{
// 自定义在歌曲开始界面上显示的难度 (并不是真的自定义难度)
// 需要启用自定义皮肤功能
// 会加载四个图片资源: musicBase, musicTab, musicLvBase, musicLvText
[HarmonyPostfix]
[HarmonyPatch(typeof(TrackStartMonitor), "SetTrackStart")]
private static void DisableTabs(
MultipleImage ____musicBaseImage,
MultipleImage ____musicTabImage,
SpriteCounter ____difficultySingle,
SpriteCounter ____difficultyDouble,
Image ____levelTextImage,
List<ResultMonitor.SpriteSheet> ____musicLevelSpriteSheets,
TimelineRoot ____musicDetail
)
{
var texture = CustomSkins.CustomTrackStart[0];
if (texture != null)
{
____musicBaseImage.MultiSprites[6] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), 100f);
____musicBaseImage.ChangeSprite(6);
}
texture = CustomSkins.CustomTrackStart[1];
if (texture != null)
{
____musicTabImage.MultiSprites[6] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), 100f);
____musicTabImage.ChangeSprite(6);
}
texture = CustomSkins.CustomTrackStart[2];
if (texture != null)
{
var lvBase = Traverse.Create(____musicDetail).Field<MultipleImage>("_lv_Base").Value;
lvBase.MultiSprites[6] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), 100f);
lvBase.ChangeSprite(6);
}
texture = CustomSkins.CustomTrackStart[3];
if (texture != null)
{
var original = ____musicLevelSpriteSheets[0].Sheet;
var sheet = new Sprite[original.Length];
for (var i = 0; i < original.Length; i++)
{
var sprite = original[i];
sheet[i] = Sprite.Create(texture, sprite.textureRect, new Vector2(0.5f, 0.5f), 100f);
}
____difficultySingle.SetSpriteSheet(sheet);
____difficultyDouble.SetSpriteSheet(sheet);
____levelTextImage.sprite = sheet[14];
}
}
}

View File

@@ -1,30 +0,0 @@
using System.Collections.Generic;
using HarmonyLib;
using Monitor;
using UI;
using UnityEngine;
using UnityEngine.UI;
namespace AquaMai.UX;
public class DisableTrackStartTabs
{
// 在歌曲开始界面, 把 TRACK X 字样, DX/标准谱面的显示框, 以及画面下方的滴蜡熊隐藏掉, 让他看起来不那么 sinmai, 更像是 majdata
[HarmonyPostfix]
[HarmonyPatch(typeof(TrackStartMonitor), "SetTrackStart")]
private static void DisableTabs(
SpriteCounter ____trackNumber, SpriteCounter ____bossTrackNumber, SpriteCounter ____utageTrackNumber,
MultipleImage ____musicTabImage, GameObject[] ____musicTabObj, GameObject ____derakkumaRoot
)
{
____trackNumber.transform.parent.gameObject.SetActive(false);
____bossTrackNumber.transform.parent.gameObject.SetActive(false);
____utageTrackNumber.transform.parent.gameObject.SetActive(false);
____musicTabImage.gameObject.SetActive(false);
____musicTabObj[0].gameObject.SetActive(false);
____musicTabObj[1].gameObject.SetActive(false);
____musicTabObj[2].gameObject.SetActive(false);
____derakkumaRoot.SetActive(false);
}
}

View File

@@ -1,75 +0,0 @@
using HarmonyLib;
using Manager;
using Monitor;
using UnityEngine;
namespace AquaMai.UX;
public class JudgeDisplay4B
{
// 精确到子判定的自定义判定显示, 需要启用自定义皮肤功能 (理论上不启用自定义皮肤不会崩游戏, 只不过此时这个功能显然不会生效)
[HarmonyPostfix]
[HarmonyPatch(typeof(SlideJudge), "Initialize")]
private static void SlideJudgeDisplay4B(
SpriteRenderer ___SpriteRenderAdd, SpriteRenderer ___SpriteRender,
SlideJudge.SlideJudgeType ____judgeType, SlideJudge.SlideAngle ____angle,
NoteJudge.ETiming judge, float msec, bool isBreak
)
{
var i = isBreak ? 1 : 0;
Sprite sprite = CustomSkins.CustomJudgeSlide[i, (int)____judgeType, (int)____angle, (int)judge];
if (sprite != null) {
___SpriteRender.sprite = sprite;
}
if (isBreak && judge == NoteJudge.ETiming.Critical)
{
sprite = CustomSkins.CustomJudgeSlide[i, (int)____judgeType, (int)____angle, (int) NoteJudge.ETiming.End];
if (sprite != null)
{
___SpriteRenderAdd.sprite = sprite;
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(JudgeGrade), "Initialize")]
private static void JudgeGradeDisplay4B(
SpriteRenderer ___SpriteRender,
NoteJudge.ETiming judge, float msec, NoteJudge.EJudgeType type
)
{
var i = (type == NoteJudge.EJudgeType.Break) ? 1 : 0;
Sprite sprite = CustomSkins.CustomJudge[i, (int)judge];
if (sprite != null) {
___SpriteRender.sprite = sprite;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(JudgeGrade), "InitializeBreak")]
private static void JudgeGradeBreakDisplay4B(
SpriteRenderer ___SpriteRenderAdd,
NoteJudge.ETiming judge, float msec, NoteJudge.EJudgeType type
)
{
if (judge == NoteJudge.ETiming.Critical)
{
var sprite = CustomSkins.CustomJudge[1, (int) NoteJudge.ETiming.End];
if (sprite != null)
{
___SpriteRenderAdd.sprite = sprite;
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(JudgeGrade), "InitializeBreak")]
private static void InitializeBreakFix(ref NoteJudge.EJudgeType type)
{
type = NoteJudge.EJudgeType.Break;
}
}

View File

@@ -1,71 +0,0 @@
using System.Collections.Generic;
using HarmonyLib;
using Monitor;
using Process;
using UI;
using UnityEngine;
using UnityEngine.UI;
namespace AquaMai.UX;
public class TrackStartProcessTweak
{
// 总之这个 Patch 没啥用, 是我个人用 sinmai 录谱面确认时用得到, 顺手也写进来了
// 具体而言就是推迟了歌曲开始界面的动画便于后期剪辑
[HarmonyPrefix]
[HarmonyPatch(typeof(TrackStartProcess), "OnUpdate")]
private static bool DelayAnimation(
TrackStartProcess.TrackStartSequence ____state,
ref float ____timeCounter,
ProcessDataContainer ___container
)
{
if (____state == TrackStartProcess.TrackStartSequence.Wait)
{
// 将开始动画(就是“噔噔, 噔 噔噔”)推迟
float temp = ____timeCounter + Time.deltaTime;
if (____timeCounter < 1.0f && temp >= 1.0f)
{
// 这是用来让转场动画继续播放的, 原本就是这个时候 notify 的同时开始播放开始动画
// 现在把开始动画往后延
___container.processManager.NotificationFadeIn();
}
____timeCounter = temp;
if (____timeCounter >= 3.0f)
{
return true;
// 原 method 的逻辑是这样
// case TrackStartProcess.TrackStartSequence.Wait:
// this._timeCounter += Time.deltaTime;
// if ((double) this._timeCounter >= 1.0)
// {
// this._timeCounter = 0.0f;
// this._state = TrackStartProcess.TrackStartSequence.Disp;
// /* 一些开始播放开始动画的代码 */
// this.container.processManager.NotificationFadeIn();
// break;
// }
// break;
// 所以只要在 prefix 里面等到 timeCounter 达到我们想要的值以后再执行原 method 就好
// 这里有个细节: NotificationFadeIn() 会被执行两遍, 这其实不好, 是个潜在 bug
// 不过由于此处把开始动画往后推了 2s, 转场动画已经结束把 Process 释放掉了, 所以第二遍会找不到 Process 就没效果
}
return false;
}
else if (____state == TrackStartProcess.TrackStartSequence.DispEnd)
{
// 将开始动画结束以后的转场动画推迟
____timeCounter += Time.deltaTime; // timeCounter 会在先前由原本的 method 归零
if (____timeCounter >= 1.0f)
{
return true;
}
return false;
}
return true;
}
}