Skip to content

Commit

Permalink
[+] Slide related visual feature (#81)
Browse files Browse the repository at this point in the history
New Features:
1. Invert the Slide hierarchy
2. Slide Track shrinking animation

Changes:
1. Improve the visual effect of Break-Slide judge blink
2. `DisableTrackStartTabs` now also hide user's best achievement
  • Loading branch information
Minepig authored Nov 6, 2024
1 parent 11beb66 commit 85dd802
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 4 deletions.
5 changes: 2 additions & 3 deletions AquaMai/Visual/BreakSlideJudgeBlink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ public class BreakSlideJudgeBlink
[HarmonyPostfix]
[HarmonyPatch(typeof(SlideJudge), "UpdateBreakEffectAdd")]
private static void FixBreakSlideJudgeBlink(
SpriteRenderer ___SpriteRenderAdd, SpriteRenderer ___SpriteRender,
SlideJudge.SlideJudgeType ____judgeType, SlideJudge.SlideAngle ____angle
SpriteRenderer ___SpriteRenderAdd, int ____addEffectCount
)
{
if (!___SpriteRenderAdd.gameObject.activeSelf) return;
float num = ___SpriteRenderAdd.color.r;
float num = (____addEffectCount & 0b10) >> 1;
___SpriteRenderAdd.color = new Color(num, num, num, 1f);
}
}
20 changes: 20 additions & 0 deletions AquaMai/Visual/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,24 @@ 这个 Patch 让 BreakSlide 的 Critical 判定也可以像 BreakTap 一样闪
推荐与自定义皮肤一起使用 (否则视觉效果可能并不好)
""")]
public bool BreakSlideJudgeBlink { get; set; }

[ConfigComment(
en: """
Make the Slide Track disappear with an inward-shrinking animation, similar to AstroDX
""",
zh: """
使 Slide Track 消失时有类似 AstroDX 一样的向内缩入的动画
""")]
public bool SlideArrowAnimation { get; set; }

[ConfigComment(
en: """
Invert the Slide hierarchy, so that the new Slide appears on top like Maimai classic
Enable to support color changing effects achieved by overlaying multiple stars
""",
zh: """
反转 Slide 层级, 使新出现的 Slide 像旧框一样显示在上层
启用以支持通过叠加多个星星达成的变色效果
""")]
public bool SlideLayerReverse { get; set; }
}
14 changes: 13 additions & 1 deletion AquaMai/Visual/DisableTrackStartTabs.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using HarmonyLib;
using Monitor;
using TMPro;
using UI;
using UnityEngine;

Expand All @@ -13,7 +14,8 @@ public class DisableTrackStartTabs
[HarmonyPatch(typeof(TrackStartMonitor), "SetTrackStart")]
private static void DisableTabs(
SpriteCounter ____trackNumber, SpriteCounter ____bossTrackNumber, SpriteCounter ____utageTrackNumber,
MultipleImage ____musicTabImage, GameObject[] ____musicTabObj, GameObject ____derakkumaRoot
MultipleImage ____musicTabImage, GameObject[] ____musicTabObj, GameObject ____derakkumaRoot,
TimelineRoot ____musicDetail
)
{
____trackNumber.transform.parent.gameObject.SetActive(false);
Expand All @@ -24,5 +26,15 @@ private static void DisableTabs(
____musicTabObj[1].gameObject.SetActive(false);
____musicTabObj[2].gameObject.SetActive(false);
____derakkumaRoot.SetActive(false);
var traverse = Traverse.Create(____musicDetail);
traverse.Field<MultipleImage>("_achivement_Base").Value.ChangeSprite(1);
traverse.Field<MultipleImage>("_clearRank_Base").Value.ChangeSprite(1);
traverse.Field<TextMeshProUGUI>("_achivement_Text").Value.gameObject.SetActive(false);
traverse.Field<TextMeshProUGUI>("_achivement_decimal_Text").Value.gameObject.SetActive(false);
traverse.Field<TextMeshProUGUI>("_achivement_percent_Text").Value.gameObject.SetActive(false);
traverse.Field<MultipleImage>("_clearRank_Image").Value.gameObject.SetActive(false);
traverse.Field<GameObject>("_deluxScore_Obj").Value.SetActive(false);
traverse.Field<MultipleImage>("_comboRank_Image").Value.ChangeSprite(0);
traverse.Field<MultipleImage>("_syncRank_Image").Value.ChangeSprite(0);
}
}
115 changes: 115 additions & 0 deletions AquaMai/Visual/SlideArrowAnimation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using HarmonyLib;
using Manager;
using Monitor;
using Monitor.Game;
using Process;
using UnityEngine;

namespace AquaMai.Visual;

public class SlideArrowAnimation
{
private static List<SpriteRenderer> _animatingSpriteRenderers = [];

[HarmonyTranspiler]
[HarmonyPatch(typeof(SlideRoot), "NoteCheck")]
private static IEnumerable<CodeInstruction> GetUnVisibleColorHook(IEnumerable<CodeInstruction> instructions)
{
var methodGetUnVisibleColor = AccessTools.Method(typeof(SlideRoot), "GetUnVisibleColor");

var oldInstList = new List<CodeInstruction>(instructions);
var newInstList = new List<CodeInstruction>();

for (var i = 0; i < oldInstList.Count; i++)
{
var inst = oldInstList[i];
if (inst.Calls(methodGetUnVisibleColor))
{
// 现在栈上应该有: SpriteRenderer, SlideRoot(this)
// 这一条 IL 会消耗 this, 调用 GetUnVisibleColor(), 推一个 Color 到栈上
// 然后接下来的一条 IL 是调用 SpriteRenderer.color 的 setter 把 SpriteRenderer 和 Color 一起消耗掉
// 我们现在直接用一个 static method 消耗掉 SpriteRenderer 和 this
// 所以要忽略当前 IL, 再忽略下一条 IL, 然后构造一个 Call

// ReSharper disable once ConvertClosureToMethodGroup
var redirect = CodeInstruction.Call((SpriteRenderer r, SlideRoot s) => OnSlideArrowDisable(r, s));
newInstList.Add(redirect);
i++; // 跳过下一条 IL
}
else
{
newInstList.Add(inst);
}
}
return newInstList;
}

public static void OnSlideArrowDisable(SpriteRenderer renderer, SlideRoot slideRoot)
{
_animatingSpriteRenderers.Add(renderer);
}

[HarmonyPostfix]
[HarmonyPatch(typeof(SlideRoot), "SetArrowObject")]
private static void RemoveArrowAnimation(GameObject arrowobj)
{
var spriteRenderer = arrowobj.GetComponent<SpriteRenderer>();
spriteRenderer.transform.localScale = Vector3.one;
if (_animatingSpriteRenderers.Contains(spriteRenderer))
{
_animatingSpriteRenderers.Remove(spriteRenderer);
}
}

[HarmonyPostfix]
[HarmonyPatch(typeof(SlideRoot), "SetBreakArrowObject")]
private static void RemoveBreakArrowAnimation(GameObject breakArrowobj)
{
var breakSlideObj = breakArrowobj.GetComponent<BreakSlide>();
breakSlideObj.SpriteRender.transform.localScale = Vector3.one;
if (_animatingSpriteRenderers.Contains(breakSlideObj.SpriteRender))
{
_animatingSpriteRenderers.Remove(breakSlideObj.SpriteRender);
}
}

[HarmonyPostfix]
[HarmonyPatch(typeof(GameCtrl), "UpdateNotes")]
private static void OnGameCtrlUpdateNotesLast()
{
for (var num = _animatingSpriteRenderers.Count - 1; num >= 0; num--)
{
var spriteRenderer = _animatingSpriteRenderers[num];
if (spriteRenderer == null)
{
_animatingSpriteRenderers.RemoveAt(num);
}
else
{
var localScale = spriteRenderer.transform.localScale;
var scale = localScale.y - NotesManager.GetAddMSec() / 150f;
if (scale <= 0)
{
spriteRenderer.transform.localScale = new Vector3(1f, 0f, 1f);
spriteRenderer.color = new Color(1f, 1f, 1f, 0f);
_animatingSpriteRenderers.RemoveAt(num);
}
else
{
localScale.y = scale;
spriteRenderer.color = new Color(1f, 1f, 1f, Mathf.Sqrt(scale));
spriteRenderer.transform.localScale = localScale;
}
}
}
}

[HarmonyPrefix]
[HarmonyPatch(typeof(GameProcess), "SetRelease")]
private static void OnBeforeGameProcessSetRelease()
{
_animatingSpriteRenderers.Clear();
}
}
66 changes: 66 additions & 0 deletions AquaMai/Visual/SlideLayerReverse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Collections.Generic;
using HarmonyLib;
using Monitor;
using UnityEngine;

namespace AquaMai.Visual;

public class SlideLayerReverse
{
[HarmonyPostfix]
[HarmonyPatch(typeof(SlideRoot), "Initialize")]
private static void CalcArrowLayer(
bool ___BreakFlag, List<SpriteRenderer> ____spriteRenders, List<BreakSlide> ____breakSpriteRenders,
int ___SlideIndex, int ____baseArrowSortingOrder
)
{
// 原本的 sortingOrder 是 -(SlideIndex + _baseArrowSortingOrder + index)
// 令 orderBase = SlideIndex + _baseArrowSortingOrder
// 分配给这条 slide 的 sortingOrder 范围是 -(orderBase + count - 1) ~ -(orderBase)
// 现在要保留 slide 内部箭头顺序, 但使得 slide 间次序反转
// 范围会变成 orderBase ~ orderBase + count - 1
// 其中原本是 -(orderBase) 的箭头应该调整为 orderBase + count - 1

var orderBase = ___SlideIndex + ____baseArrowSortingOrder; // SlideIndex + _baseArrowSortingOrder
if (!___BreakFlag)
{
var lastIdx = ____spriteRenders.Count - 1;
for (var index = 0; index < ____spriteRenders.Count; index++)
{
var renderer = ____spriteRenders[index];
renderer.sortingOrder = -32700 + orderBase + lastIdx - index;
}
}
else
{
var lastIdx = ____breakSpriteRenders.Count - 1;
for (var index = 0; index < ____breakSpriteRenders.Count; index++)
{
var breakSlide = ____breakSpriteRenders[index];
breakSlide.SetSortingOrder(-32700 + orderBase + lastIdx - index);
}
}
}

[HarmonyPostfix]
[HarmonyPatch(typeof(SlideFan), "Initialize")]
private static void CalcFanArrowLayer(
SpriteRenderer[] ____spriteLines, SpriteRenderer[] ____effectSprites,
int ___SlideIndex, int ____baseArrowSortingOrder
)
{
var orderBase = ___SlideIndex + ____baseArrowSortingOrder; // SlideIndex + _baseArrowSortingOrder
var lastIdx = ____spriteLines.Length - 1;
for (var index = 0; index < ____spriteLines.Length; index++)
{
var renderer = ____spriteLines[index];
renderer.sortingOrder = -32700 + orderBase + lastIdx - index;
}
lastIdx = ____effectSprites.Length - 1;
for (var index = 0; index < ____effectSprites.Length; index++)
{
var renderer = ____effectSprites[index];
renderer.sortingOrder = 1000 + orderBase + lastIdx - index;
}
}
}

0 comments on commit 85dd802

Please sign in to comment.