mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-18 10:10:45 +08:00
fix: 统一 WpfGui 工作目录 (#14072)
* fix: 统一WpfGui工作目录 * chore: 漏了的cache目录 * chore: Auto update by pre-commit hooks [skip changelog] * fix: 多了一层相对目录 * feat: wpf 创建软连接 * feat: 添加 PathsHelper,提取通用地址 * feat: 提取通用目录 * fix: Combine * fix: 重构依赖后 MaaWpfGui 的 resource 路径丢失 (#14077) fix: mklink * chore: 删除弹窗 * chore: 自定义基建使用绝对路径 * perf: 简化命名 * fix: 遗漏的issue rp * fix: 基建 * perf: config.new * feat: 去除本地作业前缀 * chore: 怎么改名了 * rft: rename 添加一个Dir后缀, 直接using static * fix: remove不再使用的../../../resrouce * perf: 短点 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: uye <99072975+ABA2396@users.noreply.github.com> Co-authored-by: Status102 <102887808+status102@users.noreply.github.com>
This commit is contained in:
@@ -31,15 +31,14 @@ using Serilog;
|
||||
[assembly: PropertyChanged.FilterType("MaaWpfGui.Configuration.")]
|
||||
|
||||
namespace MaaWpfGui.Configuration.Factory;
|
||||
using static MaaWpfGui.Helper.PathsHelper;
|
||||
|
||||
public static class ConfigFactory
|
||||
{
|
||||
public const string ConfigFileName = "config/gui.new.json";
|
||||
private static readonly string _configurationFile = Path.Combine(Environment.CurrentDirectory, ConfigFileName);
|
||||
public static readonly string ConfigFile = Path.Combine(ConfigDir, "gui.new.json");
|
||||
|
||||
// TODO: write backup method. WIP: https://github.com/Cryolitia/MaaAssistantArknights/tree/config
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
private static readonly string _configurationBakFile = Path.Combine(Environment.CurrentDirectory, "config/gui.new.json.bak");
|
||||
private static readonly string _configBakFile = Path.Combine(ConfigDir, "gui.new.json.bak");
|
||||
|
||||
private static readonly ILogger _logger = Log.ForContext<ConfigurationHelper>();
|
||||
|
||||
@@ -59,21 +58,21 @@ public static class ConfigFactory
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (Directory.Exists("config") is false)
|
||||
if (Directory.Exists(ConfigDir) is false)
|
||||
{
|
||||
Directory.CreateDirectory("config");
|
||||
Directory.CreateDirectory(ConfigDir);
|
||||
}
|
||||
|
||||
Root? parsed = null;
|
||||
if (File.Exists(_configurationFile))
|
||||
if (File.Exists(ConfigFile))
|
||||
{
|
||||
try
|
||||
{
|
||||
parsed = JsonSerializer.Deserialize<Root>(File.ReadAllText(_configurationFile), _options);
|
||||
parsed = JsonSerializer.Deserialize<Root>(File.ReadAllText(ConfigFile), _options);
|
||||
if (parsed is null)
|
||||
{
|
||||
_logger.Warning("Failed to load configuration file, copying configuration file to error file");
|
||||
File.Copy(_configurationFile, _configurationFile + ".err", true);
|
||||
File.Copy(ConfigFile, ConfigFile + ".err", true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -82,21 +81,21 @@ public static class ConfigFactory
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed is null && File.Exists(_configurationBakFile))
|
||||
if (parsed is null && File.Exists(_configBakFile))
|
||||
{
|
||||
_logger.Information("trying to use backup file");
|
||||
try
|
||||
{
|
||||
parsed = JsonSerializer.Deserialize<Root>(File.ReadAllText(_configurationBakFile), _options);
|
||||
parsed = JsonSerializer.Deserialize<Root>(File.ReadAllText(_configBakFile), _options);
|
||||
if (parsed is not null)
|
||||
{
|
||||
_logger.Information("Backup file loaded successfully, copying backup file to configuration file");
|
||||
File.Copy(_configurationBakFile, _configurationFile, true);
|
||||
File.Copy(_configBakFile, ConfigFile, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warning("Failed to load backup file, copying backup file to error file");
|
||||
File.Copy(_configurationBakFile, _configurationBakFile + ".err", true);
|
||||
File.Copy(_configBakFile, _configBakFile + ".err", true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -152,13 +151,13 @@ public static class ConfigFactory
|
||||
SpecificConfigBind(keyValue.Key, keyValue.Value);
|
||||
}
|
||||
|
||||
if (Save(_configurationBakFile, parsed))
|
||||
if (Save(_configBakFile, parsed))
|
||||
{
|
||||
_logger.Information("{File} saved", _configurationBakFile);
|
||||
_logger.Information("{File} saved", _configBakFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warning("{File} save failed", _configurationBakFile);
|
||||
_logger.Warning("{File} save failed", _configBakFile);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
@@ -274,7 +273,7 @@ public static class ConfigFactory
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(file ?? _configurationFile, JsonSerializer.Serialize(root ?? Root, _options));
|
||||
File.WriteAllText(file ?? ConfigFile, JsonSerializer.Serialize(root ?? Root, _options));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -291,7 +290,7 @@ public static class ConfigFactory
|
||||
await _semaphore.WaitAsync();
|
||||
try
|
||||
{
|
||||
var filePath = file ?? _configurationFile;
|
||||
var filePath = file ?? ConfigFile;
|
||||
var jsonString = JsonSerializer.Serialize(Root, _options);
|
||||
await File.WriteAllTextAsync(filePath, jsonString);
|
||||
return true;
|
||||
@@ -313,11 +312,11 @@ public static class ConfigFactory
|
||||
{
|
||||
if (Save())
|
||||
{
|
||||
_logger.Information("{File} saved", _configurationFile);
|
||||
_logger.Information("{File} saved", ConfigFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warning("{File} save failed", _configurationFile);
|
||||
_logger.Warning("{File} save failed", ConfigFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,10 @@ namespace MaaWpfGui.Helper
|
||||
{
|
||||
public class ConfigurationHelper
|
||||
{
|
||||
public const string ConfigurationFile = "config/gui.json";
|
||||
private static readonly string _configurationFile = Path.Combine(Environment.CurrentDirectory, ConfigurationFile);
|
||||
private static readonly string _configurationBakFile = Path.Combine(Environment.CurrentDirectory, "config/gui.json.bak");
|
||||
private static readonly string _configurationErrorFile = Path.Combine(Environment.CurrentDirectory, "config/gui.error.json");
|
||||
public static readonly string ConfigFile = Path.Combine(PathsHelper.ConfigDir, "gui.json");
|
||||
public static readonly string ConfigBakFile = Path.Combine(PathsHelper.ConfigDir, "gui.json.bak");
|
||||
public static readonly string ConfigErrorFile = Path.Combine(PathsHelper.ConfigDir, "gui.error.json");
|
||||
|
||||
private static ConcurrentDictionary<string, ConcurrentDictionary<string, string>> _kvsMap;
|
||||
private static string _current = ConfigurationKeys.DefaultConfiguration;
|
||||
private static ConcurrentDictionary<string, string> _kvs;
|
||||
@@ -276,26 +276,26 @@ namespace MaaWpfGui.Helper
|
||||
|
||||
private static bool ParseConfig(out JObject parsed)
|
||||
{
|
||||
parsed = ParseJsonFile(_configurationFile);
|
||||
parsed = ParseJsonFile(ConfigFile);
|
||||
if (parsed is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (File.Exists(_configurationFile))
|
||||
if (File.Exists(ConfigFile))
|
||||
{
|
||||
_logger.Warning("Failed to load configuration file, copying configuration file to error file");
|
||||
File.Copy(_configurationFile, _configurationErrorFile, true);
|
||||
File.Copy(ConfigFile, ConfigErrorFile, true);
|
||||
}
|
||||
|
||||
if (File.Exists(_configurationBakFile))
|
||||
if (File.Exists(ConfigBakFile))
|
||||
{
|
||||
_logger.Information("trying to use backup file");
|
||||
parsed = ParseJsonFile(_configurationBakFile);
|
||||
parsed = ParseJsonFile(ConfigBakFile);
|
||||
if (parsed is not null)
|
||||
{
|
||||
_logger.Information("Backup file loaded successfully, copying backup file to configuration file");
|
||||
File.Copy(_configurationBakFile, _configurationFile, true);
|
||||
File.Copy(ConfigBakFile, ConfigFile, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -325,13 +325,13 @@ namespace MaaWpfGui.Helper
|
||||
}
|
||||
|
||||
SetKvOrMigrate(parsed);
|
||||
if (Save(_configurationBakFile))
|
||||
if (Save(ConfigBakFile))
|
||||
{
|
||||
_logger.Information("{File} saved", _configurationBakFile);
|
||||
_logger.Information("{File} saved", ConfigBakFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warning("{File} save failed", _configurationBakFile);
|
||||
_logger.Warning("{File} save failed", ConfigBakFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -396,7 +396,7 @@ namespace MaaWpfGui.Helper
|
||||
},
|
||||
Formatting.Indented);
|
||||
|
||||
File.WriteAllText(file ?? _configurationFile, jsonStr);
|
||||
File.WriteAllText(file ?? ConfigFile, jsonStr);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -490,11 +490,11 @@ namespace MaaWpfGui.Helper
|
||||
|
||||
if (Save())
|
||||
{
|
||||
_logger.Information("{File} saved", _configurationFile);
|
||||
_logger.Information("{File} saved", ConfigFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warning("{File} save failed", _configurationFile);
|
||||
_logger.Warning("{File} save failed", ConfigFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace MaaWpfGui.Helper
|
||||
|
||||
private static void LoadBattleData()
|
||||
{
|
||||
string filePath = Path.Combine(AsstProxy.MainResourcePath(), "resource/battle_data.json");
|
||||
string filePath = Path.Combine(PathsHelper.ResourceDir, "battle_data.json");
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return;
|
||||
@@ -124,8 +124,8 @@ namespace MaaWpfGui.Helper
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
var clientTags = ParseRecruit(Path.Combine(AsstProxy.MainResourcePath(), "resource", clientPath, "recruitment.json"));
|
||||
var displayTags = ParseRecruit(Path.Combine(AsstProxy.MainResourcePath(), "resource", displayPath, "recruitment.json"));
|
||||
var clientTags = ParseRecruit(Path.Combine(PathsHelper.ResourceDir, clientPath, "recruitment.json"));
|
||||
var displayTags = ParseRecruit(Path.Combine(PathsHelper.ResourceDir, displayPath, "recruitment.json"));
|
||||
|
||||
RecruitTags = clientTags.Keys
|
||||
.Select(key => new KeyValuePair<string, (string DisplayName, string ClientName)>(
|
||||
@@ -167,7 +167,7 @@ namespace MaaWpfGui.Helper
|
||||
private static void LoadMapData()
|
||||
{
|
||||
MapData = [];
|
||||
var path = Path.Combine(AsstProxy.MainResourcePath(), "resource", "Arknights-Tile-Pos", "overview.json");
|
||||
var path = Path.Combine(PathsHelper.ResourceDir, "Arknights-Tile-Pos", "overview.json");
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace MaaWpfGui.Helper
|
||||
{
|
||||
private static readonly ILogger _logger = Log.ForContext<ETagCache>();
|
||||
|
||||
private static readonly string _etagFile = Path.Combine(Environment.CurrentDirectory, "cache/etag.json");
|
||||
private static readonly string _lastModifiedFile = Path.Combine(Environment.CurrentDirectory, "cache/last_modified.json");
|
||||
private static readonly string _etagFile = Path.Combine(PathsHelper.CacheDir, "etag.json");
|
||||
private static readonly string _lastModifiedFile = Path.Combine(PathsHelper.CacheDir, "last_modified.json");
|
||||
private static Dictionary<string, string> _etagCache = [];
|
||||
private static Dictionary<string, DateTimeOffset> _lastModifiedCache = [];
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace MaaWpfGui.Helper
|
||||
|
||||
public static async Task<bool> SaveResponseToFileAsync(HttpResponseMessage? response, string saveTo, bool saveAndDeleteTmp = true)
|
||||
{
|
||||
saveTo = Path.Combine(Environment.CurrentDirectory, saveTo);
|
||||
saveTo = Path.Combine(PathsHelper.BaseDir, saveTo);
|
||||
|
||||
var tempFile = saveTo + ".tmp";
|
||||
if (File.Exists(tempFile))
|
||||
|
||||
@@ -40,14 +40,14 @@ namespace MaaWpfGui.Helper
|
||||
switch (language)
|
||||
{
|
||||
case "zh-cn":
|
||||
filename = Path.Combine(AsstProxy.MainResourcePath(), "resource", "item_index.json");
|
||||
filename = Path.Combine(PathsHelper.ResourceDir, "item_index.json");
|
||||
break;
|
||||
|
||||
case "pallas":
|
||||
break;
|
||||
|
||||
default:
|
||||
filename = Path.Combine(AsstProxy.MainResourcePath(), "resource", "global", DataHelper.ClientDirectoryMapper[language], "resource", "item_index.json");
|
||||
filename = Path.Combine(PathsHelper.ResourceDir, "global", DataHelper.ClientDirectoryMapper[language], "resource", "item_index.json");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace MaaWpfGui.Helper
|
||||
return cachedImage;
|
||||
}
|
||||
|
||||
var imagePath = Path.Combine(Environment.CurrentDirectory, $"resource/template/items/{itemId}.png");
|
||||
var imagePath = Path.Combine(PathsHelper.ResourceDir, $"template/items/{itemId}.png");
|
||||
if (!File.Exists(imagePath))
|
||||
{
|
||||
_imageCache.TryAdd(itemId, null);
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace MaaWpfGui.Helper
|
||||
{
|
||||
public static class JsonDataHelper
|
||||
{
|
||||
private static readonly string _dataDir = "data";
|
||||
private static readonly object _lock = new();
|
||||
private static readonly ILogger _logger = Log.ForContext("SourceContext", "JsonDataHelper");
|
||||
|
||||
@@ -36,7 +35,7 @@ namespace MaaWpfGui.Helper
|
||||
/// <returns>反序列化数据</returns>
|
||||
public static T? Get<T>(string key, T? defaultValue = default, string? dataDir = null)
|
||||
{
|
||||
var filePath = Path.Combine(dataDir ?? _dataDir, $"{key}.json");
|
||||
var filePath = Path.Combine(dataDir ?? PathsHelper.DataDir, $"{key}.json");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
@@ -70,13 +69,13 @@ namespace MaaWpfGui.Helper
|
||||
/// <returns>是否设置成功</returns>
|
||||
public static bool Set<T>(string key, T value, string? dataDir = null)
|
||||
{
|
||||
var filePath = Path.Combine(dataDir ?? _dataDir, $"{key}.json");
|
||||
var filePath = Path.Combine(dataDir ?? PathsHelper.DataDir, $"{key}.json");
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(_dataDir);
|
||||
Directory.CreateDirectory(PathsHelper.DataDir);
|
||||
var json = JsonConvert.SerializeObject(value, Formatting.Indented);
|
||||
File.WriteAllText(filePath, json);
|
||||
return true;
|
||||
@@ -96,7 +95,7 @@ namespace MaaWpfGui.Helper
|
||||
/// <returns>是否成功删除</returns>
|
||||
public static bool Delete(string key)
|
||||
{
|
||||
var filePath = Path.Combine(_dataDir, $"{key}.json");
|
||||
var filePath = Path.Combine(PathsHelper.DataDir, $"{key}.json");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -122,7 +121,7 @@ namespace MaaWpfGui.Helper
|
||||
/// <returns>是否存在</returns>
|
||||
public static bool Exists(string key)
|
||||
{
|
||||
var filePath = Path.Combine(_dataDir, $"{key}.json");
|
||||
var filePath = Path.Combine(PathsHelper.DataDir, $"{key}.json");
|
||||
return File.Exists(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
72
src/MaaWpfGui/Helper/PathsHelper.cs
Normal file
72
src/MaaWpfGui/Helper/PathsHelper.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
// <copyright file="PathsHelper.cs" company="MaaAssistantArknights">
|
||||
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
|
||||
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License v3.0 only as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY
|
||||
// </copyright>
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace MaaWpfGui.Helper;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for managing commonly used application paths.
|
||||
/// </summary>
|
||||
public static class PathsHelper
|
||||
{
|
||||
private static string? _base;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application's working directory (AppDomain.CurrentDomain.BaseDirectory).
|
||||
/// </summary>
|
||||
public static string BaseDir => _base ??= AppDomain.CurrentDomain.BaseDirectory;
|
||||
|
||||
private static string? _resource;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the resource directory under the working directory.
|
||||
/// </summary>
|
||||
public static string ResourceDir => _resource ??= Path.Combine(BaseDir, "resource");
|
||||
|
||||
private static string? _cache;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to the application's cache directory.
|
||||
/// </summary>
|
||||
public static string CacheDir => _cache ??= Path.Combine(BaseDir, "cache");
|
||||
|
||||
private static string? _config;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to the directory containing GUI configuration files for the application.
|
||||
/// </summary>
|
||||
public static string ConfigDir => _config ??= Path.Combine(BaseDir, "config");
|
||||
|
||||
private static string? _debug;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to the directory used for storing debug files.
|
||||
/// </summary>
|
||||
/// <remarks>The debug directory is located within the application's base directory and is named
|
||||
/// "debug". The directory may not exist until created by the application or related processes.</remarks>
|
||||
public static string DebugDir => _debug ??= Path.Combine(BaseDir, "debug");
|
||||
|
||||
private static string? _data;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to the application's data directory.
|
||||
/// </summary>
|
||||
/// <remarks>The data directory is located within the application's base directory under a folder
|
||||
/// named "data". This property returns the resolved path, creating the directory if it does not exist is the
|
||||
/// responsibility of the caller.</remarks>
|
||||
public static string DataDir => _data ??= Path.Combine(BaseDir, "data");
|
||||
}
|
||||
@@ -86,6 +86,17 @@ namespace MaaWpfGui.Main
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe bool AsstSetUserDir(string dirname)
|
||||
{
|
||||
fixed (byte* ptr = EncodeNullTerminatedUtf8(dirname))
|
||||
{
|
||||
_logger.Information("AsstSetUserDir dirame: {Dirname}", dirname);
|
||||
var ret = MaaService.AsstSetUserDir(ptr);
|
||||
_logger.Information("AsstSetUserDir ret: {Ret}", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe bool AsstLoadResource(string dirname)
|
||||
{
|
||||
fixed (byte* ptr = EncodeNullTerminatedUtf8(dirname))
|
||||
@@ -325,6 +336,8 @@ namespace MaaWpfGui.Main
|
||||
TaskSettingVisibilityInfo.Instance.CurrentTask = string.Empty;
|
||||
}
|
||||
};
|
||||
|
||||
AsstSetUserDir(PathsHelper.BaseDir);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -338,19 +351,6 @@ namespace MaaWpfGui.Main
|
||||
}
|
||||
}
|
||||
|
||||
public static string MainResourcePath()
|
||||
{
|
||||
var uiVersion = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion.Split('+')[0] ?? "0.0.1";
|
||||
if (uiVersion == "0.0.1")
|
||||
{
|
||||
return Directory.GetCurrentDirectory() + @"\..\..\..";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Directory.GetCurrentDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载全局资源。新版 core 全惰性加载资源,所以可以无脑调用
|
||||
/// </summary>
|
||||
@@ -360,11 +360,11 @@ namespace MaaWpfGui.Main
|
||||
_logger.Information("Load Resource");
|
||||
|
||||
string clientType = SettingsViewModel.GameSettings.ClientType;
|
||||
string mainRes = MainResourcePath();
|
||||
string mainRes = PathsHelper.ResourceDir;
|
||||
|
||||
string globalResource = mainRes + @"\resource\global\" + clientType;
|
||||
string mainCache = Directory.GetCurrentDirectory() + @"\cache";
|
||||
string globalCache = mainCache + @"\resource\global\" + clientType;
|
||||
string globalResource = Path.Combine(mainRes, "global", clientType);
|
||||
string mainCache = PathsHelper.CacheDir;
|
||||
string globalCache = Path.Combine(mainCache, "global", clientType);
|
||||
|
||||
bool loaded;
|
||||
if (clientType is "" or "Official" or "Bilibili")
|
||||
@@ -387,15 +387,23 @@ namespace MaaWpfGui.Main
|
||||
|
||||
static bool LoadResIfExists(string path)
|
||||
{
|
||||
const string Resource = @"\resource";
|
||||
if (!Directory.Exists(path + Resource))
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
_logger.Warning("Resource not found: {Path}", path + Resource);
|
||||
_logger.Warning("Resource not found: {Path}", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
_logger.Information("Load resource: {Path}", path + Resource);
|
||||
return AsstLoadResource(path);
|
||||
_logger.Information("Load resource: {Path}", path);
|
||||
|
||||
// AsstLoadResource 需要的是 resource 的上级目录
|
||||
var parent = Directory.GetParent(path)?.FullName ?? string.Empty;
|
||||
if (string.IsNullOrEmpty(parent))
|
||||
{
|
||||
_logger.Warning("Resource path invalid: {Path}", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return AsstLoadResource(parent);
|
||||
}
|
||||
|
||||
// 新的目录结构为 tasks/tasks.json,api 为了兼容,仍然存在 resource/tasks.json
|
||||
|
||||
@@ -60,10 +60,11 @@ namespace MaaWpfGui.Main
|
||||
|
||||
private static Mutex _mutex;
|
||||
private static bool _hasMutex;
|
||||
public const string UiLogFilename = "debug/gui.log";
|
||||
public const string UiLogBakFilename = "debug/gui.bak.log";
|
||||
public const string CoreLogFilename = "debug/asst.log";
|
||||
public const string CoreLogBakFilename = "debug/asst.bak.log";
|
||||
|
||||
public static readonly string UiLogFile = Path.Combine(PathsHelper.DebugDir, "gui.log");
|
||||
public static readonly string UiLogBakFile = Path.Combine(PathsHelper.DebugDir, "gui.bak.log");
|
||||
public static readonly string CoreLogFile = Path.Combine(PathsHelper.DebugDir, "asst.log");
|
||||
public static readonly string CoreLogBakFile = Path.Combine(PathsHelper.DebugDir, "asst.bak.log");
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern IntPtr LoadLibrary(string dllName);
|
||||
@@ -90,10 +91,9 @@ namespace MaaWpfGui.Main
|
||||
|
||||
var dllFiles = Directory.GetFiles(currentDirectory, "*.dll");
|
||||
|
||||
return dllFiles
|
||||
return [.. dllFiles
|
||||
.Select(Path.GetFileName)
|
||||
.Where(fileName => !maaDlls.Contains(fileName) && !fileName.Contains("maa", StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
.Where(fileName => !maaDlls.Contains(fileName) && !fileName.Contains("maa", StringComparison.OrdinalIgnoreCase))];
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -149,21 +149,21 @@ namespace MaaWpfGui.Main
|
||||
Directory.CreateDirectory("debug");
|
||||
}
|
||||
|
||||
if (File.Exists(UiLogFilename) && new FileInfo(UiLogFilename).Length > 4 * 1024 * 1024)
|
||||
if (File.Exists(UiLogFile) && new FileInfo(UiLogFile).Length > 4 * 1024 * 1024)
|
||||
{
|
||||
if (File.Exists(UiLogBakFilename))
|
||||
if (File.Exists(UiLogBakFile))
|
||||
{
|
||||
File.Delete(UiLogBakFilename);
|
||||
File.Delete(UiLogBakFile);
|
||||
}
|
||||
|
||||
File.Move(UiLogFilename, UiLogBakFilename);
|
||||
File.Move(UiLogFile, UiLogBakFile);
|
||||
}
|
||||
|
||||
// Bootstrap serilog
|
||||
var loggerConfiguration = new LoggerConfiguration()
|
||||
.WriteTo.Debug(outputTemplate: "[{Timestamp:HH:mm:ss}][{Level:u3}]{ClassName} <{ThreadId}> {Message:lj}{NewLine}{Exception}")
|
||||
.WriteTo.File(
|
||||
UiLogFilename,
|
||||
UiLogFile,
|
||||
outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}][{Level:u3}]{ClassName} <{ThreadId}> {Message:lj}{NewLine}{Exception}")
|
||||
.Enrich.With<ClassNameEnricher>()
|
||||
.Enrich.FromLogContext()
|
||||
@@ -181,8 +181,8 @@ namespace MaaWpfGui.Main
|
||||
loggerConfiguration = (maaEnv == "Debug" || withDebugFile)
|
||||
? loggerConfiguration.MinimumLevel.Verbose()
|
||||
: loggerConfiguration.MinimumLevel.Information();
|
||||
var currentDirectory = Directory.GetCurrentDirectory();
|
||||
var folderName = Path.GetFileName(currentDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
|
||||
var workingDirectory = PathsHelper.BaseDir;
|
||||
var folderName = Path.GetFileName(workingDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
|
||||
var isBuildOutputFolder =
|
||||
string.Equals(folderName, "Release", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(folderName, "Debug", StringComparison.OrdinalIgnoreCase) ||
|
||||
@@ -196,7 +196,7 @@ namespace MaaWpfGui.Main
|
||||
_logger.Information("Built at {BuiltDate:O}", builtDate);
|
||||
_logger.Information("Maa ENV: {MaaEnv}", maaEnv);
|
||||
_logger.Information("Command Line: {Join}", string.Join(' ', args));
|
||||
_logger.Information("User Dir {GetCurrentDirectory}", currentDirectory);
|
||||
_logger.Information("User Dir {BaseDirectory}", workingDirectory);
|
||||
if (withDebugFile)
|
||||
{
|
||||
_logger.Information("Start with DEBUG file");
|
||||
@@ -228,7 +228,7 @@ namespace MaaWpfGui.Main
|
||||
}
|
||||
|
||||
// 检查 resource 文件夹是否存在
|
||||
if (!Directory.Exists(Path.Combine(AsstProxy.MainResourcePath(), "resource")))
|
||||
if (!Directory.Exists(PathsHelper.ResourceDir))
|
||||
{
|
||||
throw new DirectoryNotFoundException("resource folder not found!");
|
||||
}
|
||||
@@ -275,7 +275,7 @@ namespace MaaWpfGui.Main
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsWritable(AppDomain.CurrentDomain.BaseDirectory))
|
||||
if (!IsWritable(PathsHelper.BaseDir))
|
||||
{
|
||||
Task.Run(() => MessageBoxHelper.Show(LocalizationHelper.GetString("SoftwareLocationWarning"), LocalizationHelper.GetString("Error"), MessageBoxButton.OK, MessageBoxImage.Error));
|
||||
}
|
||||
@@ -318,7 +318,7 @@ namespace MaaWpfGui.Main
|
||||
private static bool HandleMultipleInstances()
|
||||
{
|
||||
// 设置互斥量的名称
|
||||
string mutexName = "MAA_" + Directory.GetCurrentDirectory().Replace("\\", "_").Replace(":", string.Empty);
|
||||
string mutexName = "MAA_" + PathsHelper.BaseDir.Replace("\\", "_").Replace(":", string.Empty);
|
||||
_mutex = new Mutex(true, mutexName, out var isOnlyInstance);
|
||||
|
||||
try
|
||||
@@ -437,7 +437,14 @@ namespace MaaWpfGui.Main
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
// MessageBox.Show("O(∩_∩)O 拜拜");
|
||||
Instances.TaskQueueViewModel.ResetAllTemporaryVariable();
|
||||
try
|
||||
{
|
||||
Instances.TaskQueueViewModel.ResetAllTemporaryVariable();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Release();
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace MaaWpfGui.Models
|
||||
{
|
||||
DirectoryMerge(
|
||||
Path.Combine(basePath, folder),
|
||||
Path.Combine(Directory.GetCurrentDirectory(), folder));
|
||||
Path.Combine(PathsHelper.BaseDir, folder));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -287,7 +287,7 @@ namespace MaaWpfGui.Models
|
||||
|
||||
try
|
||||
{
|
||||
DirectoryMerge(ExtractFolder, Directory.GetCurrentDirectory());
|
||||
DirectoryMerge(ExtractFolder, PathsHelper.BaseDir);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace MaaWpfGui.Services
|
||||
[DllImport("MaaCore.dll")]
|
||||
public static extern bool AsstSetStaticOption(AsstStaticOptionKey key, [MarshalAs(UnmanagedType.LPUTF8Str)]string value);
|
||||
|
||||
[DllImport("MaaCore.dll")]
|
||||
public static extern unsafe bool AsstSetUserDir(byte* dirname);
|
||||
[DllImport("MaaCore.dll")]
|
||||
public static extern unsafe bool AsstLoadResource(byte* dirname);
|
||||
|
||||
|
||||
@@ -63,10 +63,10 @@ namespace MaaWpfGui.Services
|
||||
public async Task UpdateStageWeb()
|
||||
{
|
||||
// 清理旧的缓存文件
|
||||
const string CacheAllFileDownloadComplete = "cache/allFileDownloadComplete.json";
|
||||
const string LastUpdateTime = "cache/LastUpdateTime.json";
|
||||
const string StageAndTasksUpdateTime = "cache/stageAndTasksUpdateTime.json";
|
||||
var filesToClean = new[] { CacheAllFileDownloadComplete, LastUpdateTime, StageAndTasksUpdateTime };
|
||||
string cacheAllFileDownloadComplete = PathsHelper.CacheDir + "allFileDownloadComplete.json";
|
||||
string lastUpdateTime = PathsHelper.CacheDir + "LastUpdateTime.json";
|
||||
string stageAndTasksUpdateTime = PathsHelper.CacheDir + "stageAndTasksUpdateTime.json";
|
||||
var filesToClean = new[] { cacheAllFileDownloadComplete, lastUpdateTime, stageAndTasksUpdateTime };
|
||||
|
||||
foreach (var file in filesToClean)
|
||||
{
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace MaaWpfGui.Services.Web
|
||||
|
||||
public async Task<bool> DownloadFileAsync(Uri uri, string fileName, string? contentType = "application/octet-stream")
|
||||
{
|
||||
string fileDir = Directory.GetCurrentDirectory();
|
||||
string fileDir = PathsHelper.BaseDir;
|
||||
string fileNameWithTemp = fileName + ".temp";
|
||||
string fullFilePath = Path.Combine(fileDir, fileName);
|
||||
string fullFilePathWithTemp = Path.Combine(fileDir, fileNameWithTemp);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace MaaWpfGui.Services.Web
|
||||
{
|
||||
public class MaaApiService : IMaaApiService
|
||||
{
|
||||
private const string CacheDir = "cache/";
|
||||
private static readonly string CacheDir = PathsHelper.BaseDir + "/cache/";
|
||||
|
||||
public async Task<JObject?> RequestMaaApiWithCache(string api)
|
||||
{
|
||||
|
||||
@@ -139,8 +139,8 @@ namespace MaaWpfGui.ViewModels.UI
|
||||
|
||||
private static readonly string _announcementInFile = SettingsViewModel.GuiSettings.Language switch
|
||||
{
|
||||
"zh-cn" or "zh-tw" => Path.Combine(Environment.CurrentDirectory, "cache", "announcement.md"),
|
||||
_ => Path.Combine(Environment.CurrentDirectory, "cache", "announcement_en.md"),
|
||||
"zh-cn" or "zh-tw" => Path.Combine(PathsHelper.CacheDir, "announcement.md"),
|
||||
_ => Path.Combine(PathsHelper.CacheDir, "announcement_en.md"),
|
||||
};
|
||||
|
||||
private static string AnnouncementInFile
|
||||
|
||||
@@ -39,6 +39,7 @@ using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using Stylet;
|
||||
using static MaaWpfGui.Helper.CopilotHelper;
|
||||
using static MaaWpfGui.Helper.PathsHelper;
|
||||
using static MaaWpfGui.Models.AsstTasks.AsstCopilotTask;
|
||||
using DataFormats = System.Windows.Forms.DataFormats;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
@@ -64,9 +65,9 @@ namespace MaaWpfGui.ViewModels.UI
|
||||
/// </summary>
|
||||
private CopilotBase? _copilotCache;
|
||||
private const string CopilotIdPrefix = "maa://";
|
||||
private const string TempCopilotFile = "cache/_temp_copilot.json";
|
||||
private static readonly string TempCopilotFile = Path.Combine(CacheDir, "_temp_copilot.json");
|
||||
private static readonly string[] _supportExt = [".json", ".mp4", ".m4s", ".mkv", ".flv", ".avi"];
|
||||
private const string CopilotJsonDir = "config/copilot";
|
||||
private static readonly string CopilotJsonDir = Path.Combine(ConfigDir, "copilot");
|
||||
private const string StageNameRegex = @"(?:[a-z]{0,3})(?:\d{0,2})-(?:(?:A|B|C|D|EX|S|TR|MO)-?)?(?:\d{1,2})";
|
||||
private const string InvalidStageNameChars = @"[:',\.\(\)\|\[\]\?,。【】{};:]"; // 无效字符
|
||||
|
||||
@@ -647,6 +648,15 @@ namespace MaaWpfGui.ViewModels.UI
|
||||
int copilotId = 0;
|
||||
bool writeToCache = false;
|
||||
object? payload;
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
var resourceFile = Path.Combine(ResourceDir, "copilot", Path.GetFileName(filename));
|
||||
if (File.Exists(resourceFile))
|
||||
{
|
||||
filename = resourceFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(filename))
|
||||
{
|
||||
var fileSize = new FileInfo(filename).Length;
|
||||
@@ -1024,7 +1034,8 @@ namespace MaaWpfGui.ViewModels.UI
|
||||
|
||||
try
|
||||
{
|
||||
comboBox.ItemsSource = Directory.GetFiles(@".\resource\copilot\", "*.json");
|
||||
var files = Directory.GetFiles(Path.Combine(ResourceDir, "copilot"), "*.json");
|
||||
comboBox.ItemsSource = files.Select(Path.GetFileName).ToList();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
||||
@@ -203,7 +203,7 @@ public class VersionUpdateViewModel : Screen
|
||||
.ShowUpdateVersion(row: 2);
|
||||
}
|
||||
|
||||
string curDir = Directory.GetCurrentDirectory();
|
||||
string curDir = PathsHelper.BaseDir;
|
||||
string extractDir = Path.Combine(curDir, "NewVersionExtract"); // 新版本解压的路径
|
||||
string oldFileDir = Path.Combine(curDir, ".old");
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class AchievementSettingsUserControlModel : PropertyChangedBase
|
||||
public void BackupAchievements()
|
||||
{
|
||||
using var dialog = new FolderBrowserDialog();
|
||||
dialog.SelectedPath = Environment.CurrentDirectory;
|
||||
dialog.SelectedPath = PathsHelper.BaseDir;
|
||||
dialog.ShowNewFolderButton = true;
|
||||
|
||||
if (dialog.ShowDialog() != DialogResult.OK)
|
||||
@@ -75,7 +75,7 @@ public class AchievementSettingsUserControlModel : PropertyChangedBase
|
||||
var dlg = new Microsoft.Win32.OpenFileDialog
|
||||
{
|
||||
Filter = "JSON|*.json",
|
||||
InitialDirectory = Environment.CurrentDirectory,
|
||||
InitialDirectory = PathsHelper.BaseDir,
|
||||
};
|
||||
|
||||
if (dlg.ShowDialog() != true)
|
||||
|
||||
@@ -39,14 +39,12 @@ public class IssueReportUserControlModel : PropertyChangedBase
|
||||
}
|
||||
|
||||
private static readonly string[] _payloadFileNames = [
|
||||
Bootstrapper.UiLogFilename,
|
||||
Bootstrapper.UiLogBakFilename,
|
||||
Bootstrapper.CoreLogFilename,
|
||||
Bootstrapper.CoreLogBakFilename,
|
||||
ConfigurationHelper.ConfigurationFile,
|
||||
ConfigFactory.ConfigFileName];
|
||||
|
||||
private const string DebugDir = "debug";
|
||||
Bootstrapper.UiLogFile,
|
||||
Bootstrapper.UiLogBakFile,
|
||||
Bootstrapper.CoreLogFile,
|
||||
Bootstrapper.CoreLogBakFile,
|
||||
ConfigurationHelper.ConfigFile,
|
||||
ConfigFactory.ConfigFile];
|
||||
|
||||
public static IssueReportUserControlModel Instance { get; }
|
||||
|
||||
@@ -54,12 +52,12 @@ public class IssueReportUserControlModel : PropertyChangedBase
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(DebugDir))
|
||||
if (!Directory.Exists(PathsHelper.DebugDir))
|
||||
{
|
||||
Directory.CreateDirectory(DebugDir);
|
||||
Directory.CreateDirectory(PathsHelper.DebugDir);
|
||||
}
|
||||
|
||||
Process.Start("explorer.exe", DebugDir);
|
||||
Process.Start("explorer.exe", PathsHelper.DebugDir);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -73,7 +71,7 @@ public class IssueReportUserControlModel : PropertyChangedBase
|
||||
try
|
||||
{
|
||||
var reportFileName = $"report_{DateTimeOffset.Now:MM-dd_HH-mm-ss}.zip";
|
||||
string zipPath = Path.Combine(DebugDir, reportFileName);
|
||||
string zipPath = Path.Combine(PathsHelper.DebugDir, reportFileName);
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
string debugTempPath = Path.Combine(tempPath, "debug");
|
||||
string resourceTempPath = Path.Combine(tempPath, "resource");
|
||||
@@ -94,7 +92,7 @@ public class IssueReportUserControlModel : PropertyChangedBase
|
||||
continue;
|
||||
}
|
||||
|
||||
string relativePath = Path.GetRelativePath(Environment.CurrentDirectory, file);
|
||||
string relativePath = Path.GetRelativePath(PathsHelper.BaseDir, file);
|
||||
string dest = Path.Combine(tempPath, relativePath);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(dest)!);
|
||||
File.Copy(file, dest, overwrite: true);
|
||||
@@ -114,12 +112,12 @@ public class IssueReportUserControlModel : PropertyChangedBase
|
||||
}
|
||||
|
||||
// 遍历 cache 文件夹下的文件,复制到 tempPath/cache
|
||||
const string CacheResourceDir = "cache";
|
||||
if (Directory.Exists(CacheResourceDir))
|
||||
string cacheResourceDir = PathsHelper.CacheDir;
|
||||
if (Directory.Exists(cacheResourceDir))
|
||||
{
|
||||
foreach (var file in Directory.EnumerateFiles(CacheResourceDir, "*", SearchOption.AllDirectories))
|
||||
foreach (var file in Directory.EnumerateFiles(cacheResourceDir, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
string relativePath = Path.GetRelativePath(CacheResourceDir, file);
|
||||
string relativePath = Path.GetRelativePath(cacheResourceDir, file);
|
||||
string dest = Path.Combine(tempPath, "cache", relativePath);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(dest)!);
|
||||
File.Copy(file, dest, overwrite: true);
|
||||
|
||||
@@ -161,10 +161,10 @@ public class VersionUpdateSettingsUserControlModel : PropertyChangedBase
|
||||
{
|
||||
bool isDefaultClient = new HashSet<string> { string.Empty, "Official", "Bilibili" }.Contains(clientType);
|
||||
|
||||
string defaultJsonPath = Path.Combine(AsstProxy.MainResourcePath(), "resource/version.json");
|
||||
string defaultJsonPath = Path.Combine(PathsHelper.ResourceDir, "version.json");
|
||||
var jsonPath = isDefaultClient
|
||||
? defaultJsonPath
|
||||
: Path.Combine(AsstProxy.MainResourcePath(), $"resource/global/{clientType}/resource/version.json");
|
||||
: Path.Combine(PathsHelper.ResourceDir, $"global/{clientType}/resource/version.json");
|
||||
|
||||
string versionName;
|
||||
if (!File.Exists(defaultJsonPath) || (!isDefaultClient && !File.Exists(jsonPath)))
|
||||
|
||||
@@ -290,7 +290,7 @@ public class InfrastSettingsUserControlModel : TaskViewModel
|
||||
SetAndNotify(ref _defaultInfrast, value);
|
||||
if (_defaultInfrast != UserDefined)
|
||||
{
|
||||
CustomInfrastFile = @"resource\custom_infrast\" + value;
|
||||
CustomInfrastFile = Path.Combine(PathsHelper.ResourceDir, "custom_infrast", value);
|
||||
}
|
||||
|
||||
ConfigurationHelper.SetValue(ConfigurationKeys.DefaultInfrast, value);
|
||||
|
||||
Reference in New Issue
Block a user