Skip to content

Commit 9e44f69

Browse files
authored
Forced merge pull request #14 from MDMods/development
v4.1.2 bump
2 parents c2f9193 + 354af78 commit 9e44f69

10 files changed

Lines changed: 186 additions & 111 deletions

File tree

BmsLoader.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -655,16 +655,15 @@ private static float GetStartDelay(string prefab)
655655

656656
private static float GetAnimationDuration(string scene, string animation)
657657
{
658-
var resourceName =
659-
Singleton<ConfigManager>.instance.GetConfigStringValue("boss", "scene_name", "boss_name", scene);
660-
var controller = ResourcesManager.instance.LoadFromName<GameObject>(resourceName)
661-
.GetComponent<SpineActionController>();
658+
var controller = ResourcesManager.instance.LoadFromName<GameObject>(Boss.Instance.BossFestival($"{scene.Split("_")[1]}01_boss"))
659+
.GetComponent<SpineActionController>();
662660
var animations = controller.gameObject.GetComponent<SkeletonAnimation>().skeletonDataAsset
663661
.GetSkeletonData(true).Animations;
664-
662+
665663
var arr = new SkeletActionData[controller.actionData.Count];
666664
controller.actionData.CopyTo(arr, 0);
667665
var actionData = new List<SkeletActionData>(arr).Find(dd => dd.name == animation);
666+
668667
var animName = animation;
669668
if (actionData is { actionIdx: not null } && actionData.actionIdx.Length != 0)
670669
animName = actionData.actionIdx[0];

Data/Album.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.IO.Compression;
22
using CustomAlbums.Managers;
33
using CustomAlbums.Utilities;
4-
using Il2CppSystem.Runtime.Remoting.Messaging;
54
using UnityEngine;
65
using Logger = CustomAlbums.Utilities.Logger;
76

Data/CustomAlbumsSave.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,24 @@
33
public class CustomAlbumsSave
44
{
55
public string SelectedAlbum { get; set; } = string.Empty;
6+
public float Ability { get; set; } = 0;
67
public HashSet<string> UnlockedMasters { get; set; } = new();
78
public HashSet<string> Collections { get; set; } = new();
89
public HashSet<string> Hides { get; set; } = new();
910
public Queue<string> History { get; set; } = new();
1011
public Dictionary<string, Dictionary<int, CustomChartSave>> Highest { get; set; } = new();
1112
public Dictionary<string, List<int>> FullCombo { get; set; } = new();
13+
14+
internal bool IsEmpty()
15+
{
16+
return SelectedAlbum == string.Empty
17+
&& Ability == 0
18+
&& UnlockedMasters.Count == 0
19+
&& Collections.Count == 0
20+
&& Hides.Count == 0
21+
&& History.Count == 0
22+
&& Highest.Count == 0
23+
&& FullCombo.Count == 0;
24+
}
1225
}
1326
}

Managers/SaveManager.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ private static void RestoreBackup()
110110
{
111111
continue;
112112
}
113+
114+
// If our backup that we are trying to load is valid but empty, continue to try and find the last save with data in it
115+
if (SaveData.IsEmpty()) continue;
113116
Logger.Success($"Restored backup from {backup.LastWriteTime.DateTime}.");
114117
return;
115118
}

Patches/AnalyticsPatch.cs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using CustomAlbums.Managers;
2+
using HarmonyLib;
3+
using Il2CppAssets.Scripts.Database;
4+
using Il2CppAssets.Scripts.Structs.Modules;
5+
using Il2CppPeroPeroGames.DataStatistics;
6+
using System.Reflection;
7+
using UnityEngine;
8+
using Logger = CustomAlbums.Utilities.Logger;
9+
10+
namespace CustomAlbums.Patches
11+
{
12+
internal class AnalyticsPatch
13+
{
14+
internal static readonly Logger Logger = new(nameof(AnalyticsPatch));
15+
16+
/// <summary>
17+
/// Blocks tag analytics from being sent if tag is CustomAlbums.
18+
/// </summary>
19+
[HarmonyPatch(typeof(ThinkingDataPeripheralHelper), nameof(ThinkingDataPeripheralHelper.CommonSendString))]
20+
internal class CommonSendStringPatch
21+
{
22+
private static bool Prefix(string eventName, string propertyName, string info)
23+
{
24+
var runCond = info != AlbumManager.Languages["ChineseS"];
25+
if (!runCond) Logger.Msg("Blocked custom albums tag analytics.");
26+
return runCond;
27+
}
28+
}
29+
30+
/// <summary>
31+
/// Blocks chart analytics from being sent if the chart is custom.
32+
/// </summary>
33+
[HarmonyPatch(typeof(ThinkingDataBattleHelper))]
34+
internal class SendMDPatch
35+
{
36+
private static IEnumerable<MethodBase> TargetMethods()
37+
{
38+
return typeof(ThinkingDataBattleHelper).GetMethods(BindingFlags.Instance | BindingFlags.Public)
39+
.Where(method => method.Name.StartsWith("Send"));
40+
}
41+
42+
private static bool Prefix()
43+
{
44+
var runCond = !BattleHelper.MusicInfo().uid.StartsWith($"{AlbumManager.Uid}-");
45+
if (!runCond) Logger.Msg("Blocked sending analytics of custom chart.");
46+
return runCond;
47+
}
48+
}
49+
50+
51+
/// <summary>
52+
/// Prevents the game from sending any analytics if the musicInfo is custom.
53+
/// </summary>
54+
[HarmonyPatch(typeof(ThinkingDataPeripheralHelper), nameof(ThinkingDataPeripheralHelper.PostToThinkingData))]
55+
internal class PostToThinkingDataPatch
56+
{
57+
private static bool Prefix(string dataStatisticsEventDefinesName, MusicInfo musicInfo)
58+
{
59+
var runCond = !musicInfo.uid.StartsWith($"{AlbumManager.Uid}-");
60+
if (!runCond) Logger.Msg("Blocked thinking data post of custom chart.");
61+
return runCond;
62+
}
63+
}
64+
65+
/// <summary>
66+
/// Prevents the game from sending any analytics if the favorited chart is custom.
67+
/// </summary>
68+
[HarmonyPatch(typeof(ThinkingDataPeripheralHelper),
69+
nameof(ThinkingDataPeripheralHelper.SendFavoriteMusicBehavior))]
70+
internal class SendFavoriteMusicBehaviorPatch
71+
{
72+
private static bool Prefix(string dataStatisticsEventDefinesNameMusicInfo, MusicInfo musicInfo)
73+
{
74+
var runCond = !musicInfo.uid.StartsWith($"{AlbumManager.Uid}-");
75+
if (!runCond) Logger.Msg("Blocked sending favorite chart analytics of custom chart.");
76+
return runCond;
77+
}
78+
}
79+
80+
81+
/// <summary>
82+
/// Prevents the game from sending any analytics if the musicInfo is custom.
83+
/// </summary>
84+
[HarmonyPatch(typeof(ThinkingDataPeripheralHelper), nameof(ThinkingDataPeripheralHelper.PostMusicChooseInfo))]
85+
internal class PostMusicChooseInfoPatch
86+
{
87+
private static bool Prefix(Vector2Int diffValue, string chooseMusicType, string searchName, MusicInfo musicInfo)
88+
{
89+
var runCond = !musicInfo.uid.StartsWith($"{AlbumManager.Uid}-");
90+
if (!runCond) Logger.Msg("Blocked sending chosen music from search analytics of custom chart.");
91+
return runCond;
92+
}
93+
}
94+
95+
/// <summary>
96+
/// Cleans search result analytics of custom charts.
97+
/// </summary>
98+
[HarmonyPatch(typeof(ThinkingDataPeripheralHelper), nameof(ThinkingDataPeripheralHelper.GetSearchResultInfo))]
99+
internal class GetSearchResultInfoPatch
100+
{
101+
102+
private static bool Prefix(MusicInfo musicInfo)
103+
{
104+
var runCond = !musicInfo.uid.StartsWith($"{AlbumManager.Uid}-");
105+
if (runCond) return true;
106+
107+
Logger.Msg("Blocking custom album from being added to search analytics.");
108+
return false;
109+
}
110+
}
111+
}
112+
}

Patches/SavePatch.cs

Lines changed: 38 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System.Reflection;
22
using System.Runtime.CompilerServices;
33
using System.Runtime.InteropServices;
4-
using System.Text.Json.Nodes;
4+
using CustomAlbums.Data;
55
using CustomAlbums.Managers;
66
using CustomAlbums.Utilities;
77
using HarmonyLib;
@@ -13,7 +13,6 @@
1313
using Il2CppAssets.Scripts.PeroTools.Commons;
1414
using Il2CppAssets.Scripts.PeroTools.Platforms.Steam;
1515
using Il2CppAssets.Scripts.Structs;
16-
using Il2CppAssets.Scripts.UI.Panels;
1716
using Il2CppInterop.Common;
1817
using Il2CppPeroPeroGames.DataStatistics;
1918
using MelonLoader.NativeUtils;
@@ -53,7 +52,7 @@ internal static class SavePatch
5352
/// <param name="panel">The PnlRecord instance to set.</param>
5453
/// <param name="data">The custom chart data.</param>
5554
/// <param name="isFullCombo">If the selected chart has been FCed.</param>
56-
private static void SetPanelWithData(PnlRecord panel, JsonNode data, bool isFullCombo)
55+
private static void SetPanelWithData(PnlRecord panel, CustomChartSave data, bool isFullCombo)
5756
{
5857
// Enables the FC icon if chart has been FCed
5958
// Also sets the combo text to a gold color if it has been FCed
@@ -64,13 +63,13 @@ private static void SetPanelWithData(PnlRecord panel, JsonNode data, bool isFull
6463
}
6564

6665
// Sets all the PnlRecord data to custom chart data.
67-
var evaluate = data["Evaluate"]!.GetValue<int>();
68-
panel.txtAccuracy.text = data["AccuracyStr"]!.GetValue<string>();
69-
panel.txtClear.text = data["Clear"]!.GetValue<float>().ToStringInvariant();
70-
panel.txtCombo.text = data["Combo"]!.GetValue<int>().ToStringInvariant();
66+
var evaluate = data.Evaluate;
67+
panel.txtAccuracy.text = data.AccuracyStr;
68+
panel.txtClear.text = data.Clear.ToStringInvariant();
69+
panel.txtCombo.text = data.Combo.ToStringInvariant();
7170
panel.txtGrade.text = EvalToGrade[evaluate];
7271
panel.txtGrade.color = panel.gradeColor[evaluate];
73-
panel.txtScore.text = data["Score"]!.GetValue<int>().ToStringInvariant();
72+
panel.txtScore.text = data.Score.ToStringInvariant();
7473
}
7574

7675
/// <summary>
@@ -114,37 +113,30 @@ private static bool InjectPnlPreparation(PnlPreparation __instance, bool forceRe
114113
{
115114
var currentMusicInfo = GlobalDataBase.s_DbMusicTag.CurMusicInfo();
116115

117-
// If the chart is not custom, run the original method, otherwise continue and don't run the original method
116+
// If the chart is not custom, run the original method; otherwise, run our modified one
118117
if (currentMusicInfo.albumJsonIndex != AlbumManager.Uid + 1) return true;
119118

120119
// Reset the panel to its default
121120
ClearAndRefreshPanels(__instance, forceReload);
122121
__instance.designerLongNameController?.Refresh();
122+
123123
if (!ModSettings.SavingEnabled) return false;
124124

125125
var recordPanel = __instance.pnlRecord;
126126
var currentChartData = SaveData.GetChartSaveDataFromUid(currentMusicInfo.uid);
127-
var highestExists = currentChartData.TryGetPropertyValue("Highest", out var currentChartHighest);
128127

129128
// If no highest data exists then early return
130-
if (!highestExists || currentChartHighest is null)
129+
if ((currentChartData.Highest?.Count ?? 0) == 0)
131130
{
132131
Logger.Msg($"No save data found for {currentMusicInfo.uid}, nothing to inject");
133132
return false;
134133
}
135134

136135
var difficulty = GetDifficulty(currentMusicInfo.uid);
137136

138-
currentChartData.TryGetPropertyValue("FullCombo", out var currentChartFullCombo);
139-
140-
// LINQ query to see if difficulty is in the full combo list
141-
// If currentChartFullCombo is null then there is no full combo so isFullCombo is false
142-
var isFullCombo = currentChartFullCombo?.AsArray().Any(x => (int)x == difficulty) ?? false;
143-
144-
// Get the highest score for the difficulty that is selected
145-
currentChartHighest = currentChartHighest[difficulty.ToString()];
137+
var isFullCombo = currentChartData.FullCombo?.Contains(difficulty) ?? false;
138+
var currentChartHighest = currentChartData.Highest.GetValueOrDefault(difficulty);
146139

147-
// If the current chart has no data for the selected difficulty then early return
148140
if (currentChartHighest is null)
149141
{
150142
Logger.Msg($"Save data was found for the chart, but not for difficulty {difficulty}");
@@ -210,7 +202,6 @@ private static void CleanCustomData()
210202

211203
if (ModSettings.SavingEnabled) SaveData.SelectedAlbum = AlbumManager.GetAlbumNameFromUid(DataHelper.selectedMusicUidFromInfoList);
212204
DataHelper.selectedMusicUidFromInfoList = "0-0";
213-
DataHelper.unlockMasters.RemoveAll((Il2CppSystem.Predicate<string>)(uid => uid.StartsWith($"{AlbumManager.Uid}-")));
214205
}
215206

216207
private static void InjectCustomData()
@@ -220,30 +211,44 @@ private static void InjectCustomData()
220211
DataHelper.hides.AddManagedRange(SaveData.Hides.GetAlbumUidsFromNames());
221212
DataHelper.history.AddManagedRange(SaveData.History.GetAlbumUidsFromNames());
222213
DataHelper.collections.AddManagedRange(SaveData.Collections.GetAlbumUidsFromNames());
223-
DataHelper.unlockMasters.AddManagedRange(SaveData.UnlockedMasters.GetAlbumUidsFromNames());
224214

225215
if (!SaveData.SelectedAlbum.StartsWith("album_")) return;
226216
DataHelper.selectedAlbumUid = "music_package_999";
227217
DataHelper.selectedAlbumTagIndex = 999;
228218
DataHelper.selectedMusicUidFromInfoList = AlbumManager.LoadedAlbums.TryGetValue(SaveData.SelectedAlbum, out var album) ? album.Uid : "0-0";
229219
}
230220

231-
// Dumb hack that fixes the chart appearing locked on game start even if it is unlocked
232-
[HarmonyPatch(typeof(PnlStage), nameof(PnlStage.Start))]
233-
internal class StartPatch
221+
[HarmonyPatch(typeof(DataHelper), nameof(DataHelper.CheckMusicUnlockMaster))]
222+
internal class CheckUnlockMasterPatch
234223
{
235-
private static void Postfix(PnlStage __instance)
224+
private static bool Prefix(MusicInfo musicInfo, ref bool __result)
236225
{
237-
var uid = DataHelper.selectedMusicUid;
238-
if (!DataHelper.selectedMusicUid?.StartsWith($"{AlbumManager.Uid}-") ?? true) return;
226+
SaveData.Ability = Math.Max(SaveData.Ability, GlobalDataBase.dbUi.ability);
227+
var ability = GameAccountSystem.instance.IsLoggedIn() ? SaveData.Ability : 0;
228+
var uid = musicInfo?.uid;
239229

240-
var album = AlbumManager.GetByUid(uid);
230+
// If musicInfo or uid is null, run original
231+
if (uid is null) return true;
241232

242-
if (album == null || (!DataHelper.isUnlockAllMaster && !SaveData.UnlockedMasters.Contains(album!.AlbumName))) return;
233+
// Bugged vanilla state, do manual logic
234+
if (GlobalDataBase.dbUi.ability == 0 && ability != 0)
235+
{
236+
Logger.Msg("Fixing bugged vanilla state for master lock");
237+
var vanillaParse = Formatting.TryParseAsInt(musicInfo.difficulty3, out var difficulty);
238+
var cond = !vanillaParse || ability >= difficulty;
239+
__result = cond || DataHelper.unlockMasters.Contains(uid) || SaveData.UnlockedMasters.Contains(AlbumManager.GetAlbumNameFromUid(uid)) || (!AlbumManager.GetByUid(musicInfo.uid)?.IsPackaged ?? false);
240+
return false;
241+
}
243242

244-
__instance.difficulty3Lock.SetActive(false);
245-
__instance.difficulty3Master.SetActive(true);
246-
__instance.difficulty3.enabled = true;
243+
// Non-bugged vanilla case
244+
if (!uid.StartsWith($"{AlbumManager.Uid}-")) return true;
245+
246+
// Non-bugged custom case
247+
var successParse = Formatting.TryParseAsInt(musicInfo.difficulty3, out var diffNum);
248+
var abilityConditionOrGimmick = !successParse || ability >= diffNum;
249+
250+
__result = abilityConditionOrGimmick || SaveData.UnlockedMasters.Contains(AlbumManager.GetAlbumNameFromUid(uid)) || !AlbumManager.GetByUid(musicInfo.uid).IsPackaged;
251+
return false;
247252
}
248253
}
249254

@@ -395,24 +400,6 @@ private static void Postfix(string musicUid, int musicDifficulty, string charact
395400
}
396401
}
397402

398-
/// <summary>
399-
/// Stops the game from sending analytics of custom charts.
400-
/// </summary>
401-
[HarmonyPatch(typeof(ThinkingDataBattleHelper))]
402-
internal class SendMDPatch
403-
{
404-
private static MethodInfo[] TargetMethods()
405-
{
406-
return typeof(ThinkingDataBattleHelper).GetMethods(BindingFlags.Instance | BindingFlags.Public)
407-
.Where(method => method.Name.StartsWith("Send")).ToArray();
408-
}
409-
410-
private static bool Prefix()
411-
{
412-
return !BattleHelper.MusicInfo().uid.StartsWith($"{AlbumManager.Uid}-");
413-
}
414-
}
415-
416403
/// <summary>
417404
/// Enables the PnlVictory screen logic when the chart is custom.
418405
/// </summary>

Patches/TreeItemPatch.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,6 @@
11
using Il2Cpp;
2-
using Il2CppAssets.Scripts.UI.Panels.PnlMusicTag;
3-
using Il2CppSuperScrollView;
4-
using System;
5-
using System.Collections.Generic;
6-
using System.Linq;
7-
using System.Reflection;
8-
using System.Text;
9-
using System.Threading.Tasks;
102
using CustomAlbums.Utilities;
113
using HarmonyLib;
12-
using MelonLoader.NativeUtils;
13-
using System.Runtime.InteropServices;
14-
using Il2CppInterop.Common;
15-
using System.Runtime.CompilerServices;
16-
using CustomAlbums.Managers;
17-
using Il2CppInterop.Runtime;
18-
using Il2CppAssets.Scripts.Database;
19-
using static MelonLoader.MelonLogger;
204

215
namespace CustomAlbums.Patches
226
{

0 commit comments

Comments
 (0)