mirror of https://github.com/hykilpikonna/AquaDX
[+] Load png TabTitle
parent
0eec8dea05
commit
6580b78485
|
@ -308,7 +308,7 @@
|
|||
<Compile Include="UX\ExtendTimer.cs" />
|
||||
<Compile Include="UX\HideSelfMadeCharts.cs" />
|
||||
<Compile Include="UX\ImmediateSave.cs" />
|
||||
<Compile Include="UX\LoadJacketPng.cs" />
|
||||
<Compile Include="UX\LoadAssetsPng.cs" />
|
||||
<Compile Include="UX\LoadAssetBundleWithoutManifest.cs" />
|
||||
<Compile Include="UX\LoadLocalBga.cs" />
|
||||
<Compile Include="UX\QuickSkip.cs" />
|
||||
|
|
|
@ -22,8 +22,10 @@ SinglePlayer=true
|
|||
SkipToMusicSelection=false
|
||||
# Set the version string displayed at the top-right corner of the screen
|
||||
CustomVersionString=""
|
||||
# Deprecated: Use `LoadAssetsPng` instead
|
||||
# LoadJacketPng=true
|
||||
# Load Jacket image from folder "LocalAssets" and filename "{MusicID}.png" for self-made charts
|
||||
LoadJacketPng=true
|
||||
LoadAssetsPng=true
|
||||
# Use the png jacket above as BGA if BGA is not found for self-made charts
|
||||
# Use together with `LoadJacketPng`
|
||||
LoadLocalBga=true
|
||||
|
|
|
@ -22,8 +22,10 @@ SinglePlayer=true
|
|||
SkipToMusicSelection=false
|
||||
# 把右上角的版本更改为自定义文本
|
||||
CustomVersionString=""
|
||||
# 已弃用,请使用 LoadAssetsPng
|
||||
# LoadJacketPng=true
|
||||
# 通过游戏目录下 `LocalAssets\000000(歌曲 ID).png` 加载封面,自制谱用
|
||||
LoadJacketPng=true
|
||||
LoadAssetsPng=true
|
||||
# 如果没有 dat 格式的 BGA 的话,就用歌曲的封面做背景,而不是显示迪拉熊的笑脸
|
||||
# 请和 `LoadJacketPng` 一起用
|
||||
LoadLocalBga=true
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Tomlet.Attributes;
|
||||
|
||||
namespace AquaMai
|
||||
{
|
||||
|
@ -23,6 +24,7 @@ namespace AquaMai
|
|||
public bool SkipWarningScreen { get; set; }
|
||||
public bool SinglePlayer { get; set; }
|
||||
public bool SkipToMusicSelection { get; set; }
|
||||
public bool LoadAssetsPng { get; set; }
|
||||
public bool LoadJacketPng { get; set; }
|
||||
public bool LoadAssetBundleWithoutManifest { get; set; }
|
||||
public bool QuickSkip { get; set; }
|
||||
|
|
|
@ -73,6 +73,10 @@ namespace AquaMai
|
|||
// Read AquaMai.toml to load settings
|
||||
AppConfig = TomletMain.To<Config>(System.IO.File.ReadAllText("AquaMai.toml"));
|
||||
|
||||
// Migrate old settings
|
||||
AppConfig.UX.LoadAssetsPng = AppConfig.UX.LoadAssetsPng || AppConfig.UX.LoadJacketPng;
|
||||
AppConfig.UX.LoadJacketPng = false;
|
||||
|
||||
// Fixes that does not have side effects
|
||||
// These don't need to be configurable
|
||||
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using System.Text.RegularExpressions;
|
||||
using MAI2.Util;
|
||||
using Manager;
|
||||
using MelonLoader;
|
||||
using Monitor;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AquaMai.UX;
|
||||
|
||||
public class LoadAssetsPng
|
||||
{
|
||||
private static string[] imageExts = [".jpg", ".png", ".jpeg"];
|
||||
private static Dictionary<string, string> jacketPaths = new();
|
||||
private static Dictionary<string, string> tabTitlePaths = new();
|
||||
private static Dictionary<string, string> localAssetsContents = new();
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(DataManager), "LoadMusicBase")]
|
||||
public static void LoadMusicPostfix(List<string> ____targetDirs)
|
||||
{
|
||||
foreach (var aDir in ____targetDirs)
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(aDir, @"AssetBundleImages\jacket")))
|
||||
foreach (var file in Directory.GetFiles(Path.Combine(aDir, @"AssetBundleImages\jacket")))
|
||||
{
|
||||
if (!imageExts.Contains(Path.GetExtension(file).ToLowerInvariant())) continue;
|
||||
var idStr = Path.GetFileName(file).Substring("ui_jacket_".Length, 6);
|
||||
jacketPaths[idStr] = file;
|
||||
}
|
||||
|
||||
if (Directory.Exists(Path.Combine(aDir, @"Common\Sprites\Tab\Title")))
|
||||
foreach (var file in Directory.GetFiles(Path.Combine(aDir, @"Common\Sprites\Tab\Title")))
|
||||
{
|
||||
if (!imageExts.Contains(Path.GetExtension(file).ToLowerInvariant())) continue;
|
||||
tabTitlePaths[Path.GetFileNameWithoutExtension(file).ToLowerInvariant()] = file;
|
||||
}
|
||||
}
|
||||
|
||||
MelonLogger.Msg($"[LoadAssetsPng] Loaded {jacketPaths.Count} Jacket, {tabTitlePaths.Count} Tab Titles from AssetBundleImages.");
|
||||
|
||||
if (Directory.Exists(Path.Combine(Environment.CurrentDirectory, "LocalAssets")))
|
||||
foreach (var laFile in Directory.EnumerateFiles(Path.Combine(Environment.CurrentDirectory, "LocalAssets")))
|
||||
{
|
||||
if (!imageExts.Contains(Path.GetExtension(laFile).ToLowerInvariant())) continue;
|
||||
localAssetsContents[Path.GetFileNameWithoutExtension(laFile).ToLowerInvariant()] = laFile;
|
||||
}
|
||||
|
||||
MelonLogger.Msg($"[LoadAssetsPng] Loaded {localAssetsContents.Count} LocalAssets.");
|
||||
}
|
||||
|
||||
private static string GetJacketPath(string id)
|
||||
{
|
||||
return localAssetsContents.TryGetValue(id, out var laPath) ? laPath : jacketPaths.GetValueOrDefault(id);
|
||||
}
|
||||
|
||||
public static Texture2D GetJacketTexture2D(string id)
|
||||
{
|
||||
var path = GetJacketPath(id);
|
||||
if (path == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var texture = new Texture2D(1, 1);
|
||||
texture.LoadImage(File.ReadAllBytes(path));
|
||||
return texture;
|
||||
}
|
||||
|
||||
public static Texture2D GetJacketTexture2D(int id)
|
||||
{
|
||||
return GetJacketTexture2D($"{id:000000}");
|
||||
}
|
||||
|
||||
/*
|
||||
[HarmonyPatch]
|
||||
public static class TabTitleLoader
|
||||
{
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
{
|
||||
// Fxxk unity
|
||||
// game load tab title by call Resources.Load<Sprite> directly
|
||||
// patching Resources.Load<Sprite> need this stuff
|
||||
// var method = typeof(Resources).GetMethods(BindingFlags.Public | BindingFlags.Static).First(it => it.Name == "Load" && it.IsGenericMethod).MakeGenericMethod(typeof(Sprite));
|
||||
// return [method];
|
||||
// but it not work, game will blackscreen if add prefix or postfix
|
||||
//
|
||||
// patching AssetBundleManager.LoadAsset will lead game memory error
|
||||
// return [AccessTools.Method(typeof(AssetBundleManager), "LoadAsset", [typeof(string)], [typeof(Object)])];
|
||||
// and this is not work because game not using this
|
||||
//
|
||||
// we load them manually after game load and no need to hook the load progress
|
||||
}
|
||||
|
||||
public static bool Prefix(string path, ref Object __result)
|
||||
{
|
||||
if (!path.StartsWith("Common/Sprites/Tab/Title/")) return true;
|
||||
var filename = Path.GetFileNameWithoutExtension(path).ToLowerInvariant();
|
||||
var locPath = localAssetsContents.TryGetValue(filename, out var laPath) ? laPath : tabTitlePaths.GetValueOrDefault(filename);
|
||||
if (locPath is null) return true;
|
||||
|
||||
var texture = new Texture2D(1, 1);
|
||||
texture.LoadImage(File.ReadAllBytes(locPath));
|
||||
__result = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
|
||||
MelonLogger.Msg($"GetTabTitleSpritePrefix {locPath} {__result}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MusicSelectMonitor), "Initialize")]
|
||||
public static void TabTitleLoader(MusicSelectMonitor __instance, Dictionary<int, Sprite> ____genreSprite, Dictionary<int, Sprite> ____versionSprite)
|
||||
{
|
||||
var genres = Singleton<DataManager>.Instance.GetMusicGenres();
|
||||
foreach (var (id, genre) in genres)
|
||||
{
|
||||
if (____genreSprite.GetValueOrDefault(id) is not null) continue;
|
||||
var filename = genre.FileName.ToLowerInvariant();
|
||||
var locPath = localAssetsContents.TryGetValue(filename, out var laPath) ? laPath : tabTitlePaths.GetValueOrDefault(filename);
|
||||
if (locPath is null) continue;
|
||||
var texture = new Texture2D(1, 1);
|
||||
texture.LoadImage(File.ReadAllBytes(locPath));
|
||||
____genreSprite[id] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
var versions = Singleton<DataManager>.Instance.GetMusicVersions();
|
||||
foreach (var (id, version) in versions)
|
||||
{
|
||||
if (____versionSprite.GetValueOrDefault(id) is not null) continue;
|
||||
var filename = version.FileName.ToLowerInvariant();
|
||||
var locPath = localAssetsContents.TryGetValue(filename, out var laPath) ? laPath : tabTitlePaths.GetValueOrDefault(filename);
|
||||
if (locPath is null) continue;
|
||||
var texture = new Texture2D(1, 1);
|
||||
texture.LoadImage(File.ReadAllBytes(locPath));
|
||||
____versionSprite[id] = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch]
|
||||
public static class JacketLoader
|
||||
{
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
{
|
||||
var AM = typeof(AssetManager);
|
||||
return [AM.GetMethod("GetJacketThumbTexture2D", [typeof(string)]), AM.GetMethod("GetJacketTexture2D", [typeof(string)])];
|
||||
}
|
||||
|
||||
public static bool Prefix(string filename, ref Texture2D __result, AssetManager __instance)
|
||||
{
|
||||
var matches = Regex.Matches(filename, @"UI_Jacket_(\d+)(_s)?\.png");
|
||||
if (matches.Count < 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var id = matches[0].Groups[1].Value;
|
||||
|
||||
var texture = GetJacketTexture2D(id);
|
||||
__result = texture ?? __instance.LoadAsset<Texture2D>($"Jacket/UI_Jacket_{id}.png");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using System.Text.RegularExpressions;
|
||||
using Manager;
|
||||
using MelonLoader;
|
||||
|
||||
namespace AquaMai.UX
|
||||
{
|
||||
public class LoadJacketPng
|
||||
{
|
||||
[HarmonyPatch]
|
||||
public static class Loader
|
||||
{
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
{
|
||||
var AM = typeof(AssetManager);
|
||||
return new[] { AM.GetMethod("GetJacketThumbTexture2D", new[] { typeof(string) }), AM.GetMethod("GetJacketTexture2D", new[] { typeof(string) }) };
|
||||
}
|
||||
|
||||
public static bool Prefix(string filename, ref Texture2D __result, AssetManager __instance)
|
||||
{
|
||||
var matches = Regex.Matches(filename, @"UI_Jacket_(\d+)(_s)?\.png");
|
||||
if (matches.Count < 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var id = matches[0].Groups[1].Value;
|
||||
|
||||
var texture = GetJacketTexture2D(id);
|
||||
__result = texture ?? __instance.LoadAsset<Texture2D>($"Jacket/UI_Jacket_{id}.png");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] imageExts = [".jpg", ".png", ".jpeg"];
|
||||
private static Regex localAssetsJacketExt = new(@"(\d{6})\.(png|jpg|jpeg)");
|
||||
private static Dictionary<string, string> jacketPaths = new();
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(DataManager), "LoadMusicBase")]
|
||||
public static void LoadMusicPostfix(List<string> ____targetDirs)
|
||||
{
|
||||
foreach (var aDir in ____targetDirs)
|
||||
{
|
||||
if (!Directory.Exists(Path.Combine(aDir, @"AssetBundleImages\jacket"))) continue;
|
||||
foreach (var file in Directory.GetFiles(Path.Combine(aDir, @"AssetBundleImages\jacket")))
|
||||
{
|
||||
if (!imageExts.Contains(Path.GetExtension(file).ToLowerInvariant())) continue;
|
||||
var idStr = Path.GetFileName(file).Substring("ui_jacket_".Length, 6);
|
||||
jacketPaths[idStr] = file;
|
||||
}
|
||||
}
|
||||
|
||||
if (Directory.Exists(Path.Combine(Environment.CurrentDirectory, "LocalAssets")))
|
||||
foreach (var laFile in Directory.EnumerateFiles(Path.Combine(Environment.CurrentDirectory, "LocalAssets")))
|
||||
{
|
||||
var match = localAssetsJacketExt.Match(Path.GetFileName(laFile));
|
||||
if (!match.Success) continue;
|
||||
jacketPaths[match.Groups[1].Value] = laFile;
|
||||
}
|
||||
|
||||
MelonLogger.Msg($"[LoadJacketPng] Loaded {jacketPaths.Count} custom jacket images.");
|
||||
}
|
||||
|
||||
private static string GetJacketPath(string id)
|
||||
{
|
||||
return jacketPaths.GetValueOrDefault(id);
|
||||
}
|
||||
|
||||
public static Texture2D GetJacketTexture2D(string id)
|
||||
{
|
||||
var path = GetJacketPath(id);
|
||||
if (path == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var texture = new Texture2D(1, 1);
|
||||
texture.LoadImage(File.ReadAllBytes(path));
|
||||
return texture;
|
||||
}
|
||||
|
||||
public static Texture2D GetJacketTexture2D(int id)
|
||||
{
|
||||
return GetJacketTexture2D($"{id:000000}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ public class LoadLocalBga
|
|||
var moviePath = string.Format(Singleton<OptionDataManager>.Instance.GetMovieDataPath($"{music.movieName.id:000000}") + ".dat");
|
||||
if (!moviePath.Contains("dummy")) return;
|
||||
|
||||
var jacket = LoadJacketPng.GetJacketTexture2D(music.movieName.id);
|
||||
var jacket = LoadAssetsPng.GetJacketTexture2D(music.movieName.id);
|
||||
if (jacket is null)
|
||||
{
|
||||
MelonLogger.Msg("No jacket found for music " + music);
|
||||
|
|
Loading…
Reference in New Issue