Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MaiChartManager.GenClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
var psi = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/c pnpm exec ts-node genClient.ts",
Arguments = "/c pnpm exec tsx genClient.ts",
WorkingDirectory = frontDir,
UseShellExecute = false,
};
Expand Down
4 changes: 4 additions & 0 deletions MaiChartManager/Browser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ private void webView21_CoreWebView2InitializationCompleted(object sender, CoreWe
webView21.CoreWebView2.PermissionRequested += WebViewHelper.OnPermissionRequested;
webView21.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
webView21.CoreWebView2.WebMessageReceived += OnWebMessageReceived;

#if DEBUG
WindowState = FormWindowState.Minimized;
#endif
}

private async void CoreWebView2_NewWindowRequested(object? sender, CoreWebView2NewWindowRequestedEventArgs e)
Expand Down
4 changes: 2 additions & 2 deletions MaiChartManager/Controllers/App/OobeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ public IActionResult DeleteGamePathHistory([FromBody] string path)
}

[HttpPost]
public void InitializeGameData()
public async Task InitializeGameData()
{
settings.InitializeGameData();
await settings.InitializeGameData();
}

[HttpGet]
Expand Down
6 changes: 3 additions & 3 deletions MaiChartManager/Controllers/AssetDir/AssetDirController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public void PutAssetDirTxtValue([FromBody] PutAssetDirTxtValueRequest req)
}

[HttpPost]
public void RequestLocalImportDir()
public async Task RequestLocalImportDir()
{
var dialog = new FolderBrowserDialog
{
Expand Down Expand Up @@ -133,7 +133,7 @@ public void RequestLocalImportDir()
var dest = Path.Combine(StaticSettings.StreamingAssets, destName);
logger.LogInformation("Src: {src} Dest: {dest}", src, dest);
FileSystem.CopyDirectory(src, dest, UIOption.AllDialogs);
settings.RescanAll();
await settings.RescanAll();
}

public record UploadAssetDirResult(string DirName);
Expand Down Expand Up @@ -181,7 +181,7 @@ public async Task<UploadAssetDirResult> UploadAssetDir(string? destName)
section = await reader.ReadNextSectionAsync();
}

settings.RescanAll();
await settings.RescanAll();

return new UploadAssetDirResult(destName);
}
Expand Down
4 changes: 2 additions & 2 deletions MaiChartManager/Controllers/AssetDir/MusicListController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public IEnumerable<MusicXmlWithABJacket> GetMusicList()
}

[HttpPost]
public void ReloadAll()
public async Task ReloadAll()
{
settings.RescanAll();
await settings.RescanAll();
}
}
98 changes: 17 additions & 81 deletions MaiChartManager/Controllers/Mod/ConfigurationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,91 +12,25 @@ namespace MaiChartManager.Controllers.Mod;

[ApiController]
[Route("MaiChartManagerServlet/[action]Api")]
public class ConfigurationController(StaticSettings settings, ILogger<ConfigurationController> logger) : ControllerBase
public class ConfigurationController : ControllerBase
{
public class UnsupportedConfigApiVersionException() : Exception(Locale.UnsupportedConfigVersion);
private readonly StaticSettings settings;
private readonly ILogger<ConfigurationController> logger;
private readonly ModConfigService modConfigService;

public class ConfigCorruptedException() : Exception(Locale.AquaMaiConfigCorrupted);

public class AquaMaiNotInstalledException() : Exception(Locale.AquaMaiNotInstalled);

public class AquaMaiSignatureVerificationFailedException() : Exception("AquaMaiSignatureVerificationFailed");

[NonAction]
private static void CheckConfigApiVersion(HeadlessConfigInterface configInterface)
{
var currentSupportedApiVersion = new Version(1, 1);
var configApiVersion = new Version(configInterface.ApiVersion);
if (currentSupportedApiVersion.Major != configApiVersion.Major)
{
throw new UnsupportedConfigApiVersionException();
}

if (currentSupportedApiVersion.Minor > configApiVersion.Minor)
{
throw new UnsupportedConfigApiVersionException();
}
}

[NonAction]
public static IConfig GetCurrentAquaMaiConfig(bool forceDefault = false, bool skipSignatureCheck = false)
public ConfigurationController(StaticSettings settings, ILogger<ConfigurationController> logger, ModConfigService modConfigService)
{
if (!System.IO.File.Exists(ModPaths.AquaMaiDllInstalledPath))
{
throw new AquaMaiNotInstalledException();
}

var binary = System.IO.File.ReadAllBytes(ModPaths.AquaMaiDllInstalledPath);
if (!skipSignatureCheck)
{
var sigResult = AquaMaiSignatureV2.VerifySignature(binary);
if (sigResult.Status != AquaMaiSignatureV2.VerifyStatus.Valid)
{
throw new AquaMaiSignatureVerificationFailedException();
}
}
var configInterface = HeadlessConfigLoader.LoadFromPacked(binary);
var config = configInterface.CreateConfig();
CheckConfigApiVersion(configInterface);
if (System.IO.File.Exists(ModPaths.AquaMaiConfigPath) && !forceDefault)
{
try
{
var view = configInterface.CreateConfigView(System.IO.File.ReadAllText(ModPaths.AquaMaiConfigPath));
var migrationManager = configInterface.GetConfigMigrationManager();

if (migrationManager.GetVersion(view) != migrationManager.LatestVersion)
{
Console.WriteLine("Migrating AquaMai config from {0} to {1}", migrationManager.GetVersion(view), migrationManager.LatestVersion);
view = migrationManager.Migrate(view);
}

var parser = configInterface.GetConfigParser();
parser.Parse(config, view);
StaticSettings.UpdateAssetPathsFromAquaMaiConfig(config);
}
catch (Exception ex)
{
Console.WriteLine("无法加载 AquaMai 配置");
Console.WriteLine(ex);
if (ex.Message.Contains("Could not migrate the config"))
{
// 这个应该是,AquaMai 未安装或需要更新
throw;
}
// 这个的提示是 AquaMai 配置文件损坏
throw new ConfigCorruptedException();
}
}

return config;
this.settings = settings;
this.logger = logger;
this.modConfigService = modConfigService;
}

[HttpGet]
public AquaMaiConfigDto.ConfigDto GetAquaMaiConfig(bool forceDefault = false, bool skipSignatureCheck = false)
public async Task<AquaMaiConfigDto.ConfigDto> GetAquaMaiConfig(bool forceDefault = false, bool skipSignatureCheck = false)
{
var dllPath = await modConfigService.GetAquaMaiDllPath();
Dictionary<string, string[]>? configSort = null;
using (var stream = new FileStream(ModPaths.AquaMaiDllInstalledPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var stream = new FileStream(dllPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var asm = ModuleDefinition.ReadModule(stream);
var configSortRes = asm.Resources.FirstOrDefault(it => it is EmbeddedResource { Name: "configSort.yaml.compressed" } or EmbeddedResource { Name: "configSort.yaml" });
Expand All @@ -108,7 +42,8 @@ public AquaMaiConfigDto.ConfigDto GetAquaMaiConfig(bool forceDefault = false, bo
configSort = deserializer.Deserialize<Dictionary<string, string[]>>(yaml);
}
}
var config = GetCurrentAquaMaiConfig(forceDefault, skipSignatureCheck);
var shouldSkipSignatureCheck = skipSignatureCheck || !string.Equals(dllPath, ModPaths.AquaMaiDllInstalledPath, StringComparison.OrdinalIgnoreCase);
var config = await modConfigService.GetCurrentAquaMaiConfig(forceDefault, shouldSkipSignatureCheck);
return new AquaMaiConfigDto.ConfigDto(
config.ReflectionManager.Sections.Select(section =>
{
Expand All @@ -124,11 +59,12 @@ public AquaMaiConfigDto.ConfigDto GetAquaMaiConfig(bool forceDefault = false, bo
[HttpPut]
public async Task SetAquaMaiConfig(AquaMaiConfigDto.ConfigSaveDto config)
{
var dllPath = await modConfigService.GetAquaMaiDllPath();
var jsonOptions = new JsonSerializerOptions();
jsonOptions.Converters.Add(new JsonStringEnumConverter());

var configInterface = HeadlessConfigLoader.LoadFromPacked(ModPaths.AquaMaiDllInstalledPath);
CheckConfigApiVersion(configInterface);
var configInterface = HeadlessConfigLoader.LoadFromPacked(dllPath);
modConfigService.CheckConfigApiVersion(configInterface);
var configEdit = configInterface.CreateConfig();

foreach (var section in configEdit.ReflectionManager.Sections)
Expand Down Expand Up @@ -183,4 +119,4 @@ public async Task SetAquaMaiConfig(AquaMaiConfigDto.ConfigSaveDto config)
// 可能修改了歌曲封面目录
settings.ScanMusicList();
}
}
}
81 changes: 78 additions & 3 deletions MaiChartManager/Controllers/Mod/InstallationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace MaiChartManager.Controllers.Mod;

[ApiController]
[Route("MaiChartManagerServlet/[action]Api")]
public class InstallationController(StaticSettings settings, ILogger<InstallationController> logger) : ControllerBase
public class InstallationController(StaticSettings settings, ILogger<InstallationController> logger, MuModService muModService) : ControllerBase
{
private static string judgeDisplay4BPath = Path.Combine(StaticSettings.exeDir, "Resources", "JudgeDisplay4B");

Expand All @@ -35,7 +35,12 @@ public record GameModInfo(
bool IsHidConflictExist,
AquaMaiSignatureV2.VerifyResult? Signature,
bool IsAdxHidIoModAbsent,
bool IsMmlLegacyLibsInstalled
bool IsMmlLegacyLibsInstalled,
bool MuModInstalled,
string? MuModVersion,
string? MuModChannel,
string? MuModCacheVersion,
bool IsBothModsPresent
);

[HttpGet]
Expand All @@ -50,11 +55,25 @@ public GameModInfo GetGameModInfo()

var aquaMaiBuiltinVersion = FileVersionInfo.GetVersionInfo(ModPaths.AquaMaiDllBuiltinPath).ProductVersion;

var muModInstalled = muModService.IsMuModInstalled();

AquaMaiSignatureV2.VerifyResult? sig = null;
if (aquaMaiInstalled)
{
sig = AquaMaiSignatureV2.VerifySignature(System.IO.File.ReadAllBytes(ModPaths.AquaMaiDllInstalledPath));
}
else if (muModInstalled)
{
sig = AquaMaiSignatureV2.VerifySignature(System.IO.File.ReadAllBytes(ModPaths.MuModDllInstalledPath));
}
var muModVersion = muModInstalled ? muModService.GetMuModVersion() : null;
string? muModChannel = null;
string? muModCacheVersion = null;
if (muModInstalled)
{
try { muModChannel = muModService.ReadConfig().Channel; } catch { }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

GetGameModInfo 方法中,使用了空的 catch 块来静默处理读取 MuMod 配置失败时可能发生的异常。虽然这可以防止程序崩溃,但完全吞掉异常会使调试变得困难,因为无法得知读取失败的原因(例如,文件被占用、权限问题或格式错误)。建议至少在 catch 块中记录一条警告或调试日志,以便于追踪潜在问题。

            try { muModChannel = muModService.ReadConfig().Channel; } catch (Exception e) { logger.LogWarning(e, "Failed to read MuMod config channel."); }

muModCacheVersion = muModService.GetCacheInfo();
}

return new GameModInfo(
IsMelonInstalled(),
Expand All @@ -65,7 +84,12 @@ public GameModInfo GetGameModInfo()
GetIsHidConflictExist(),
sig,
GetIsAdxHidIoModAbsent(),
GetIsMmlLegacyLibsInstalled()
GetIsMmlLegacyLibsInstalled(),
muModInstalled,
muModVersion,
muModChannel,
muModCacheVersion,
aquaMaiInstalled && muModInstalled
);
}

Expand Down Expand Up @@ -198,6 +222,10 @@ public void InstallAquaMai()
var src = Path.Combine(StaticSettings.exeDir, "AquaMai.dll");
var dest = Path.Combine(StaticSettings.GamePath, @"Mods\AquaMai.dll");
CopyFile(src, dest);
if (System.IO.File.Exists(ModPaths.MuModDllInstalledPath))
{
System.IO.File.Delete(ModPaths.MuModDllInstalledPath);
}
}

[HttpPost]
Expand Down Expand Up @@ -265,11 +293,58 @@ public async Task InstallAquaMaiOnline(InstallAquaMaiOnlineDto req)
var dest = Path.Combine(StaticSettings.GamePath, @"Mods\AquaMai.dll");
Directory.CreateDirectory(Path.GetDirectoryName(dest));
await System.IO.File.WriteAllBytesAsync(dest, data);
if (System.IO.File.Exists(ModPaths.MuModDllInstalledPath))
{
System.IO.File.Delete(ModPaths.MuModDllInstalledPath);
}
return;
}
throw new InvalidOperationException("Failed to download AquaMai from all urls", lastException);
}

[HttpPost]
public async Task InstallMuMod()
{
CopyFile(ModPaths.MuModDllBuiltinPath, ModPaths.MuModDllInstalledPath);

if (System.IO.File.Exists(ModPaths.AquaMaiDllInstalledPath))
{
System.IO.File.Delete(ModPaths.AquaMaiDllInstalledPath);
}

if (!System.IO.File.Exists(ModPaths.MuModConfigPath))
{
System.IO.File.WriteAllText(ModPaths.MuModConfigPath, "Channel = \"slow\"\nCachePath = \"LocalAssets\\\\MuMod.cache\"\n");
}

try
{
await muModService.EnsureCache(CancellationToken.None);
}
catch (Exception e)
{
logger.LogError(e, "Failed to download MuMod cache during install, but DLL was installed successfully");
}
}

[HttpPost]
public void DeleteAquaMai()
{
if (System.IO.File.Exists(ModPaths.AquaMaiDllInstalledPath))
{
FileSystem.DeleteFile(ModPaths.AquaMaiDllInstalledPath, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
}
}

[HttpPost]
public void DeleteMuMod()
{
if (System.IO.File.Exists(ModPaths.MuModDllInstalledPath))
{
FileSystem.DeleteFile(ModPaths.MuModDllInstalledPath, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
}
}

[HttpPost]
public void KillGameProcess()
{
Expand Down
Loading