From ac535c70c76ec81a3b3d353105596f922e106d0a Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Tue, 30 Jun 2026 21:17:09 +0800 Subject: [PATCH 01/16] =?UTF-8?q?=E6=8B=86=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plain Craft Launcher 2/Application.xaml.cs | 2 +- .../Compatibility/ModBase.Declarations.cs | 632 +++ .../Compatibility/ModBase.LegacyFiles.cs | 872 ++++ .../Compatibility/ModBase.LegacyIni.cs | 157 + .../Compatibility/ModBase.LegacyLog.cs | 379 ++ .../Compatibility/ModBase.LegacySearch.cs | 205 + .../Compatibility/ModBase.LegacySystem.cs | 765 ++++ .../Compatibility/ModBase.LegacyText.cs | 453 ++ .../Compatibility/ModBase.LegacyUi.cs | 274 ++ Plain Craft Launcher 2/FormMain.xaml.cs | 22 +- .../Modules/Base/ModBase.cs | 3759 ----------------- .../Modules/Minecraft/ModLaunch.cs | 12 +- Plain Craft Launcher 2/Modules/ModMain.cs | 8 +- .../Modules/Network/Http/RequestSigning.cs | 4 +- .../Modules/Updates/UpdateManager.cs | 22 +- .../Pages/PageSetup/PageSetupAbout.xaml.cs | 6 +- .../Pages/PageSetup/PageSetupUpdate.xaml.cs | 8 +- .../Pages/PageSpeedLeft.xaml.cs | 4 +- .../Pages/PageTools/PageToolsGameLink.xaml.cs | 2 +- .../UI/Converters/AdditionConverter.cs | 35 + .../UI/Converters/InverseBooleanConverter.cs | 26 + .../InverseBooleanToVisibilityConverter.cs | 27 + .../UI/Converters/MultiplicationConverter.cs | 35 + 23 files changed, 3905 insertions(+), 3804 deletions(-) create mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs create mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs create mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs create mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs create mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs create mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs create mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs create mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs delete mode 100644 Plain Craft Launcher 2/Modules/Base/ModBase.cs create mode 100644 Plain Craft Launcher 2/UI/Converters/AdditionConverter.cs create mode 100644 Plain Craft Launcher 2/UI/Converters/InverseBooleanConverter.cs create mode 100644 Plain Craft Launcher 2/UI/Converters/InverseBooleanToVisibilityConverter.cs create mode 100644 Plain Craft Launcher 2/UI/Converters/MultiplicationConverter.cs diff --git a/Plain Craft Launcher 2/Application.xaml.cs b/Plain Craft Launcher 2/Application.xaml.cs index 8d7fb3ec2..2cc16f4e0 100644 --- a/Plain Craft Launcher 2/Application.xaml.cs +++ b/Plain Craft Launcher 2/Application.xaml.cs @@ -95,7 +95,7 @@ private static void _ApplicationStartup() _ = Config.Preference.Font; var updateBranchCfg = Config.Update.UpdateChannelConfig; if (updateBranchCfg.IsDefault()) - updateBranchCfg.SetValue(ModBase.versionBaseName.Contains("beta") + updateBranchCfg.SetValue(ModBase.VersionBaseName.Contains("beta") ? Core.App.UpdateChannel.Beta : Core.App.UpdateChannel.Release); diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs b/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs new file mode 100644 index 000000000..b27b65dde --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs @@ -0,0 +1,632 @@ +using System.IO; +using System.Windows.Media; +using PCL.Core.App; +using PCL.Core.Utils; +using Brush = System.Windows.Media.Brush; +using Color = System.Windows.Media.Color; +using ColorConverter = System.Windows.Media.ColorConverter; + +namespace PCL; + +public static partial class ModBase +{ + #region 声明 + + // 下列版本信息由更新器自动修改 + public static readonly string VersionBaseName = Basics.VersionName; + public static readonly string VersionStandardCode = Basics.Metadata.Version.StandardVersion; + public static readonly string UpstreamVersion = Basics.Metadata.Version.UpstreamVersion; + public static readonly string CommitHash = Basics.Metadata.Version.Commit; + public static readonly string CommitHashShort = Basics.Metadata.Version.CommitDigest; + public static readonly int VersionCode = Basics.VersionCode; + +#if DEBUG + public const string VersionBranchName = "Debug"; + public const string VersionBranchCode = "100"; +#elif DEBUGCI + public const string VersionBranchName = "CI"; + public const string VersionBranchCode = "50"; +#else + public const string VersionBranchName = "Publish"; + public const string VersionBranchCode = "0"; +#endif + /// + /// 主窗口句柄。 + /// + public static nint frmHandle; + + // 龙猫味石山小记: 用最不靠谱的实现写出能跑的代码 (AppDomain.CurrentDomain.SetupInformation.ApplicationBase 获取到的是当前工作目录而不是可执行文件所在目录) + /// + /// 程序可执行文件所在目录,以“\”结尾。 + /// + public static readonly string exePath = Basics.ExecutableDirectory.EndsWith(@"\") + ? Basics.ExecutableDirectory + : Basics.ExecutableDirectory + @"\"; + + /// + /// 程序内嵌图片文件夹路径,以“/”结尾。 + /// + public static readonly string pathImage = "pack://application:,,,/Plain Craft Launcher 2;component/Images/"; + + /// + /// 当前程序的语言。 + /// + public static string currentLang = "zh_CN"; + + /// + /// 设置对象。 + /// + public static ModSetup setup = new(); + + /// + /// 程序的打开计时。 + /// + public static long applicationStartTick = TimeUtils.GetTimeTick(); + + /// + /// 程序打开时的时间。 + /// + public static DateTime applicationOpenTime = DateTime.Now; + + /// + /// 程序是否已结束。 + /// + public static bool isProgramEnded = false; + + /// + /// 程序的缓存文件夹路径,以 \ 结尾。 + /// + public static string pathTemp = Paths.Temp + @"\"; + + /// + /// AppData 中的 PCL 文件夹路径,以 \ 结尾。 + /// + public static string pathAppdata = + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PCL") + @"\"; + + /// + /// AppData 中的 PCLCE 配置文件夹路径,以 \ 结尾。 + /// + public static string pathAppdataConfig = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + + (VersionBranchName == "Debug" ? @"\.pclcedebug\" : @"\.pclce\"); + + #endregion + + #region 自定义类 + + /// + /// 支持小数与常见类型隐式转换的颜色。 + /// + public class MyColor + { + public double a = 255d; + public double b; + public double g; + public double r; + + // 构造函数 + public MyColor() + { + } + + public MyColor(Color col) + { + a = col.A; + r = col.R; + g = col.G; + b = col.B; + } + + public MyColor(string hexString) + { + var stringColor = (Color)ColorConverter.ConvertFromString(hexString); + a = stringColor.A; + r = stringColor.R; + g = stringColor.G; + b = stringColor.B; + } + + public MyColor(double newA, MyColor col) + { + a = newA; + r = col.r; + g = col.g; + b = col.b; + } + + public MyColor(double newR, double newG, double newB) + { + a = 255d; + r = newR; + g = newG; + b = newB; + } + + public MyColor(double newA, double newR, double newG, double newB) + { + a = newA; + r = newR; + g = newG; + b = newB; + } + + public MyColor(Brush brush) + { + var color = ((SolidColorBrush)brush).Color; + a = color.A; + r = color.R; + g = color.G; + b = color.B; + } + + public MyColor(SolidColorBrush brush) + { + var color = brush.Color; + a = color.A; + r = color.R; + g = color.G; + b = color.B; + } + + public MyColor(object obj) + { + switch (obj) + { + case null: + a = 255d; + r = 255d; + g = 255d; + b = 255d; + break; + case SolidColorBrush brush: + { + // 避免反复获取 Color 对象造成性能下降 + var color = brush.Color; + a = color.A; + r = color.R; + g = color.G; + b = color.B; + break; + } + default: + a = Convert.ToDouble(((dynamic)obj).A); + r = Convert.ToDouble(((dynamic)obj).R); + g = Convert.ToDouble(((dynamic)obj).G); + b = Convert.ToDouble(((dynamic)obj).B); + break; + } + } + + // 类型转换 + public static implicit operator MyColor(string str) + { + return new MyColor(str); + } + + public static implicit operator MyColor(Color col) + { + return new MyColor(col); + } + + public static implicit operator Color(MyColor conv) + { + return Color.FromArgb( + MathByte(conv.a), + MathByte(conv.r), + MathByte(conv.g), + MathByte(conv.b)); + } + + public static implicit operator System.Drawing.Color(MyColor conv) + { + return System.Drawing.Color.FromArgb( + MathByte(conv.a), + MathByte(conv.r), + MathByte(conv.g), + MathByte(conv.b)); + } + + public static implicit operator MyColor(SolidColorBrush bru) + { + return new MyColor(bru.Color); + } + + public static implicit operator SolidColorBrush(MyColor conv) + { + return new SolidColorBrush(Color.FromArgb( + MathByte(conv.a), + MathByte(conv.r), + MathByte(conv.g), + MathByte(conv.b))); + } + + public static implicit operator MyColor(Brush bru) + { + return new MyColor(bru); + } + + public static implicit operator Brush(MyColor conv) + { + return new SolidColorBrush(Color.FromArgb( + MathByte(conv.a), + MathByte(conv.r), + MathByte(conv.g), + MathByte(conv.b))); + } + + // 颜色运算 + public static MyColor operator +(MyColor a, MyColor b) + { + return new MyColor { a = a.a + b.a, b = a.b + b.b, g = a.g + b.g, r = a.r + b.r }; + } + + public static MyColor operator -(MyColor a, MyColor b) + { + return new MyColor { a = a.a - b.a, b = a.b - b.b, g = a.g - b.g, r = a.r - b.r }; + } + + public static MyColor operator *(MyColor a, double b) + { + return new MyColor { a = a.a * b, b = a.b * b, g = a.g * b, r = a.r * b }; + } + + public static MyColor operator /(MyColor a, double b) + { + return new MyColor { a = a.a / b, b = a.b / b, g = a.g / b, r = a.r / b }; + } + + public static bool operator ==(MyColor a, MyColor b) + { + if (a is null && b is null) + return true; + if (a is null || b is null) + return false; + return a.a == b.a && a.r == b.r && a.g == b.g && a.b == b.b; + } + + public static bool operator !=(MyColor a, MyColor b) + { + if (a is null && b is null) + return false; + if (a is null || b is null) + return true; + return !(a.a == b.a && a.r == b.r && a.g == b.g && a.b == b.b); + } + + // HSL + public double Hue(double v1, double v2, double vH) + { + if (vH < 0d) + vH += 1d; + if (vH > 1d) + vH -= 1d; + if (vH < 0.16667d) + return v1 + (v2 - v1) * 6d * vH; + if (vH < 0.5d) + return v2; + if (vH < 0.66667d) + return v1 + (v2 - v1) * (4d - vH * 6d); + return v1; + } + + public MyColor FromHSL(double sH, double sS, double sL) + { + if (sS == 0d) + { + r = sL * 2.55d; + g = r; + b = r; + } + else + { + var h = sH / 360d; + var s = sS / 100d; + var l = sL / 100d; + s = l < 0.5d ? s * l + l : s * (1.0d - l) + l; + l = 2d * l - s; + r = 255d * Hue(l, s, h + 1d / 3d); + g = 255d * Hue(l, s, h); + b = 255d * Hue(l, s, h - 1d / 3d); + } + + a = 255d; + return this; + } + + public MyColor FromHSL2(double sH, double sS, double sL) + { + if (sS == 0d) + { + r = sL * 2.55d; + g = r; + b = r; + } + else + { + // 初始化 + sH = (sH + 3600000d) % 360d; + var cent = new[] + { + +0.1d, -0.06d, -0.3d, -0.19d, -0.15d, -0.24d, -0.32d, -0.09d, +0.18d, +0.05d, -0.12d, -0.02d, +0.1d, + -0.06d + }; // 0, 30, 60 + // 90, 120, 150 + // 180, 210, 240 + // 270, 300, 330 + // 最后两位与前两位一致,加是变亮,减是变暗 + // 计算色调对应的亮度片区 + var center = sH / 30.0d; + var intCenter = (int)Math.Round(Math.Floor(center)); // 亮度片区编号 + center = 50d - + ((1d - center + intCenter) * cent[intCenter] + (center - intCenter) * cent[intCenter + 1]) * + sS; + // center = 50 + (cent(intCenter) + (center - intCenter) * (cent(intCenter + 1) - cent(intCenter))) * sS + sL = (sL < center ? sL / center : 1d + (sL - center) / (100d - center)) * 50d; + FromHSL(sH, sS, sL); + } + + a = 255d; + return this; + } + + public MyColor Alpha(double sA) + { + a = sA; + return this; + } + + public override string ToString() + { + return "(" + a + "," + r + "," + g + "," + b + ")"; + } + + public override bool Equals(object obj) + { + return obj is MyColor other && a == other.a && r == other.r && g == other.g && b == other.b; + } + } + + /// + /// 支持负数与浮点数的矩形。 + /// + public class MyRect + { + // 构造函数 + public MyRect() + { + } + + public MyRect(double left, double top, double width, double height) + { + Left = left; + Top = top; + Width = width; + Height = height; + } + + // 属性 + public double Width { get; set; } + public double Height { get; set; } + public double Left { get; set; } + public double Top { get; set; } + } + + /// + /// 模块加载状态枚举。 + /// + public enum LoadState + { + Waiting, + Loading, + Finished, + Failed, + Aborted + } + + /// + /// 执行返回值。 + /// + public enum ProcessReturnValues + { + /// + /// 执行成功,或进程被中断。 + /// + Aborted = -1, + + /// + /// 执行成功。 + /// + Success = 0, + + /// + /// 执行失败。 + /// + Fail = 1, + + /// + /// 执行时出现未经处理的异常。 + /// + Exception = 2, + + /// + /// 执行超时。 + /// + Timeout = 3, + + /// + /// 取消执行。可能是由于不满足执行的前置条件。 + /// + Cancel = 4, + + /// + /// 任务成功完成。 + /// + TaskDone = 5 + } + + /// + /// 可以使用 Equals 和等号的 List。 + /// + public class EqualableList : List + { + public override bool Equals(object obj) + { + if (obj as List is null) + // 类型不同 + return false; + + // 类型相同 + var objList = (List)obj; + if (objList.Count != Count) + return false; + for (int i = 0, loopTo = objList.Count - 1; i <= loopTo; i++) + if (!objList[i].Equals(this[i])) + return false; + return true; + } + + public static bool operator ==(EqualableList left, EqualableList right) + { + return EqualityComparer>.Default.Equals(left, right); + } + + public static bool operator !=(EqualableList left, EqualableList right) + { + return !(left == right); + } + } + + #endregion + + #region 数学 + + /// + /// 2~65 进制的转换。 + /// + public static string RadixConvert(string input, int fromRadix, int toRadix) + { + const string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+="; + // 零与负数的处理 + if (string.IsNullOrEmpty(input)) + return "0"; + var isNegative = input.StartsWithF("-"); + if (isNegative) + input = input.TrimStart('-'); + // 转换为十进制 + var realNum = 0L; + var scale = 1L; + foreach (var digit in input.Reverse().Select(l => digits.IndexOfF(l.ToString()))) + { + realNum += digit * scale; + scale *= fromRadix; + } + + // 转换为指定进制 + var result = ""; + while (realNum > 0L) + { + var newNum = (int)(realNum % toRadix); + realNum = (long)Math.Round((realNum - newNum) / (double)toRadix); + result = digits[newNum] + result; + } + + // 负数的结束处理与返回 + return (isNegative ? "-" : "") + result; + } + + /// + /// 计算二阶贝塞尔曲线。 + /// + public static double MathBezier( + double x, + double x1, + double y1, + double x2, + double y2, + double acc = 0.01d) + { + switch (x) + { + case <= 0d or double.NaN: + return 0d; + case >= 1d: + return 1d; + } + + double b; + var a = x; + do + { + b = 3 * a * ((0.33333333 + x1 - x2) * a * a + (x2 - 2 * x1) * a + x1); + a += (x - b) * 0.5; + } while (!(Math.Abs(b - x) < acc)); // 精度 + + return 3 * a * ((0.33333333 + y1 - y2) * a * a + (y2 - 2 * y1) * a + y1); + } + + /// + /// 将一个数字限制为 0~255 的 Byte 值。 + /// + public static byte MathByte(double d) + { + if (d < 0d) + d = 0d; + if (d > 255d) + d = 255d; + return (byte)Math.Round(Math.Round(d)); + } + + /// + /// 提供 MyColor 类型支持的 Math.Round。 + /// + public static MyColor MathRound(MyColor col, int w = 0) + { + return new MyColor + { + a = Math.Round(col.a, w), + r = Math.Round(col.r, w), + g = Math.Round(col.g, w), + b = Math.Round(col.b, w) + }; + } + + /// + /// 获取两数间的百分比。小数点精确到 6 位。 + /// + /// + public static double MathPercent(double valueA, double valueB, double percent) + { + return Math.Round(valueA * (1d - percent) + valueB * percent, 6); // 解决 Double 计算错误 + } + + /// + /// 获取两颜色间的百分比,根据 RGB 计算。小数点精确到 6 位。 + /// + public static MyColor MathPercent(MyColor valueA, MyColor valueB, double percent) + { + return MathRound(valueA * (1d - percent) + valueB * percent, 6); // 解决Double计算错误 + } + + /// + /// 将数值限定在某个范围内。 + /// + public static double MathClamp(double value, double min, double max) + { + return Math.Max(min, Math.Min(max, value)); + } + + /// + /// 符号函数。 + /// + public static int MathSgn(double value) + { + return value switch + { + 0d => 0, + > 0d => 1, + _ => -1 + }; + } + + #endregion +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs new file mode 100644 index 000000000..dedc53b4a --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs @@ -0,0 +1,872 @@ +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; +using System.Text; +using PCL.Core.App.Localization; +using PCL.Core.Utils; +using PCL.Core.Utils.Codecs; +using PCL.Core.Utils.Hash; + +namespace PCL; + +public static partial class ModBase +{ + #region LegacyFiles + + // 路径处理 + /// + /// 从文件路径或者 Url 获取不包含文件名的路径,或获取文件夹的父文件夹路径。 + /// 取决于原路径格式,路径以 / 或 \ 结尾。 + /// 不包含路径将会抛出异常。 + /// + public static string GetPathFromFullPath(string filePath) + { + string getPathFromFullPathRet = default; + if (!(filePath.Contains(@"\") || filePath.Contains("/"))) + throw new Exception("不包含路径:" + filePath); + if (filePath.EndsWithF(@"\") || filePath.EndsWithF("/")) + { + // 是文件夹路径 + var isRight = filePath.EndsWithF(@"\"); + filePath = filePath[..^1]; + getPathFromFullPathRet = filePath[..filePath.LastIndexOfAny( + ['\\', '/'])] + (isRight ? @"\" : "/"); + } + else + { + // 是文件路径 + getPathFromFullPathRet = filePath[..(filePath.LastIndexOfAny(['\\', '/']) + 1)]; + if (string.IsNullOrEmpty(getPathFromFullPathRet)) + throw new Exception("不包含路径:" + filePath); + } + + return getPathFromFullPathRet; + } + + /// + /// 从文件路径或者 Url 获取不包含路径的文件名。不包含文件名将会抛出异常。 + /// + public static string GetFileNameFromPath(string filePath) + { + filePath = filePath.Replace("/", @"\"); + if (filePath.EndsWithF(@"\")) + throw new Exception("不包含文件名:" + filePath); + if (filePath.Contains('?')) + filePath = filePath[..filePath.IndexOfF("?")]; // 去掉网络参数后的 ? + if (filePath.Contains('\\')) + filePath = filePath[(filePath.LastIndexOfF(@"\") + 1)..]; + + var length = filePath.Length; + return length switch + { + 0 => throw new Exception("不包含文件名:" + filePath), + > 250 => throw new PathTooLongException("文件名过长:" + filePath), + _ => filePath + }; + } + + /// + /// 从文件路径或者 Url 获取不包含路径与扩展名的文件名。不包含文件名将会抛出异常。 + /// + public static string GetFileNameWithoutExtentionFromPath(string filePath) + { + return Path.GetFileNameWithoutExtension(filePath); + } + + /// + /// 从文件夹路径获取文件夹名。 + /// + public static string GetFolderNameFromPath(string folderPath) + { + if (folderPath.EndsWithF(@":\") || folderPath.EndsWithF(@":\\")) + return folderPath[..1]; + if (folderPath.EndsWithF(@"\") || folderPath.EndsWithF("/")) + folderPath = folderPath[..^1]; + return GetFileNameFromPath(folderPath); + } + + // 读取、写入、复制文件 + /// + /// 复制文件。会自动创建文件夹、会覆盖已有的文件。 + /// + public static void CopyFile(string fromPath, string toPath) + { + try + { + // 还原文件路径 + if (!fromPath.Contains(@":\")) + fromPath = exePath + fromPath; + if (!toPath.Contains(@":\")) + toPath = exePath + toPath; + // 如果复制同一个文件则跳过 + if ((fromPath ?? "") == (toPath ?? "")) + return; + // 确保目录存在 + Directory.CreateDirectory(GetPathFromFullPath(toPath)); + // 复制文件 + File.Copy(fromPath, toPath, true); + } + catch (Exception ex) + { + throw new Exception("复制文件出错:" + fromPath + " → " + toPath, ex); + } + } + + /// + /// 读取文件,如果失败则返回空数组。 + /// + public static byte[] ReadFileBytes(string filePath, Encoding encoding = null) + { + try + { + // 还原文件路径 + if (!filePath.Contains(@":\")) + filePath = exePath + filePath; + if (File.Exists(filePath)) + { + using var readStream = new FileStream( + filePath, + FileMode.Open, + FileAccess.Read, + FileShare.Read); + using var ms = new MemoryStream(); + readStream.CopyTo(ms); + return ms.ToArray(); + } + + Log("[System] 欲读取的文件不存在,已返回空内容:" + filePath); + return []; + } + catch (Exception ex) + { + Log(ex, "读取文件出错:" + filePath); + return []; + } + } + + /// + /// 读取文件,如果失败则返回空字符串。 + /// + /// 文件完整或相对路径。 + public static string ReadFile(string filePath, Encoding encoding = null) + { + var fileBytes = ReadFileBytes(filePath); + var readFileRet = encoding is null ? DecodeBytes(fileBytes) : encoding.GetString(fileBytes); + return readFileRet; + } + + /// + /// 读取流中的所有文本。 + /// + public static string ReadFile(Stream stream, Encoding encoding = null) + { + try + { + var readedContent = new MemoryStream(); + stream.CopyTo(readedContent); + var bts = readedContent.ToArray(); + return (encoding ?? EncodingDetector.DetectEncoding(bts)).GetString(bts); + } + catch (Exception ex) + { + Log(ex, "读取流出错"); + return ""; + } + } + + /// + /// 写入文件。 + /// + /// 文件完整或相对路径。 + /// 文件内容。 + /// 是否将文件内容追加到当前文件,而不是覆盖它。 + public static void WriteFile( + string filePath, + string text, + bool append = false, + Encoding? encoding = null) + { + // 处理相对路径 + if (!filePath.Contains(@":\")) + filePath = exePath + filePath; + // 确保目录存在 + Directory.CreateDirectory(GetPathFromFullPath(filePath)); + // 写入文件 + if (append) + // 追加目前文件 + { + using var writer = new StreamWriter( + filePath, + true, + encoding ?? EncodingDetector.DetectEncoding(ReadFileBytes(filePath))); + writer.Write(text); + } + else + { + // 直接写入字节 + var bytes = encoding is null + ? new UTF8Encoding(false).GetBytes(text) + : encoding.GetBytes(text); + var tempPath = filePath + ".pcltmp." + Guid.NewGuid().ToString("N"); + File.WriteAllBytes(tempPath, bytes); + File.Move(tempPath, filePath, true); + } + } + + /// + /// 写入文件。 + /// 如果 CanThrow 设置为 False,返回是否写入成功。 + /// + /// 文件完整或相对路径。 + /// 文件内容。 + /// 是否将文件内容追加到当前文件,而不是覆盖它。 + public static void WriteFile(string filePath, byte[] content, bool append = false) + { + // 处理相对路径 + if (!filePath.Contains(@":\")) + filePath = exePath + filePath; + // 确保目录存在 + Directory.CreateDirectory(GetPathFromFullPath(filePath)); + // 写入文件 + File.WriteAllBytes(filePath, content); + } + + /// + /// 将流写入文件。 + /// + /// 文件完整或相对路径。 + public static bool WriteFile(string filePath, Stream stream) + { + try + { + // 还原文件路径 + if (!filePath.Contains(@":\")) + filePath = exePath + filePath; + // 确保目录存在 + Directory.CreateDirectory(GetPathFromFullPath(filePath)); + // 读取流 + using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read); + fs.SetLength(0L); + stream.CopyTo(fs); + + return true; + } + catch (Exception ex) + { + Log(ex, "保存流出错"); + return false; + } + } + + /// + /// 解码 Bytes。 + /// + public static string DecodeBytes(byte[] bytes) + { + var length = bytes.Length; + if (length < 3) + return Encoding.UTF8.GetString(bytes); + // 根据 BOM 判断编码 + if (bytes[0] >= 0xEF) + { + // 有 BOM 类型 + if (bytes[0] == 0xEF && bytes[1] == 0xBB) + return Encoding.UTF8.GetString(bytes, 3, length - 3); + + if (bytes[0] == 0xFE && bytes[1] == 0xFF) + return Encoding.BigEndianUnicode.GetString(bytes, 3, length - 3); + + if (bytes[0] == 0xFF && bytes[1] == 0xFE) + return Encoding.Unicode.GetString(bytes, 3, length - 3); + + return Encoding.GetEncoding("GB18030").GetString(bytes, 3, length - 3); + } + + // 无 BOM 文件:GB18030(ANSI)或 UTF8 + var uTF8 = Encoding.UTF8.GetString(bytes); + var errorChar = Encoding.UTF8.GetString("\ufffd"u8.ToArray()).ToCharArray()[0]; + return uTF8.Contains(errorChar) + ? Encoding.GetEncoding("GB18030").GetString(bytes) + : uTF8; + } + + public static object GetHexString(Memory bytes) + { + var sb = new StringBuilder(bytes.Length * 2); + foreach (var c in bytes.Span) + sb.Append(c.ToString("x2")); + + return sb.ToString(); + } + + // 文件校验 + /// + /// 获取文件 MD5,若失败则返回空字符串。 + /// + public static string GetFileMD5(string filePath) + { + var retry = false; + Re: ; + + try + { + // 获取 MD5 + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + return (string)GetHexString(MD5Provider.Instance.ComputeHash(fs)); + } + catch (Exception ex) + { + if (retry || ex is FileNotFoundException) + { + Log(ex, "获取文件 MD5 失败:" + filePath); + return ""; + } + + retry = true; + Log(ex, "获取文件 MD5 可重试失败:" + filePath, LogLevel.Normal); + Thread.Sleep(RandomUtils.NextInt(200, 500)); + goto Re; + } + } + + /// + /// 获取文件 SHA512,若失败则返回空字符串。 + /// + public static string GetFileSHA512(string filePath) + { + var retry = false; + Re: ; + + try + { + // '检测该文件是否在下载中,若在下载则放弃检测 + // If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return "" + // 获取 SHA512 + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + return (string)GetHexString(SHA512Provider.Instance.ComputeHash(fs)); + } + catch (Exception ex) + { + if (retry || ex is FileNotFoundException) + { + Log(ex, "获取文件 SHA512 失败:" + filePath); + return ""; + } + + retry = true; + Log(ex, "获取文件 SHA512 可重试失败:" + filePath, LogLevel.Normal); + Thread.Sleep(RandomUtils.NextInt(200, 500)); + goto Re; + } + } + + /// + /// 获取文件 SHA256,若失败则返回空字符串。 + /// + public static string GetFileSHA256(string filePath) + { + var retry = false; + Re: ; + + try + { + // '检测该文件是否在下载中,若在下载则放弃检测 + // If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return "" + // 获取 SHA256 + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + return (string)GetHexString(SHA256Provider.Instance.ComputeHash(fs)); + } + catch (Exception ex) + { + if (retry || ex is FileNotFoundException) + { + Log(ex, "获取文件 SHA256 失败:" + filePath); + return ""; + } + + retry = true; + Log(ex, "获取文件 SHA256 可重试失败:" + filePath, LogLevel.Normal); + Thread.Sleep(RandomUtils.NextInt(200, 500)); + goto Re; + } + } + + /// + /// 获取文件 SHA1,若失败则返回空字符串。 + /// + public static string GetFileSHA1(string filePath) + { + var retry = false; + Re: ; + + try + { + // 获取 SHA1 + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + return (string)GetHexString(SHA1Provider.Instance.ComputeHash(fs)); + } + catch (Exception ex) + { + if (retry || ex is FileNotFoundException) + { + Log(ex, "获取文件 SHA1 失败:" + filePath); + return ""; + } + + retry = true; + Log(ex, "获取文件 SHA1 可重试失败:" + filePath, LogLevel.Normal); + Thread.Sleep(RandomUtils.NextInt(200, 500)); + goto Re; + } + } + + /// + /// 获取流的 SHA1,若失败则返回空字符串。 + /// + public static string GetAuthSHA1(Stream inputStream) + { + try + { + return (string)GetHexString(SHA1Provider.Instance.ComputeHash(inputStream)); + } + catch (Exception ex) + { + Log(ex, "获取流 SHA1 失败"); + return ""; + } + } + + /// + /// 文件的校验规则。 + /// + public class FileChecker + { + /// + /// 文件的准确大小。 + /// 不检查则为 -1。 + /// + public long actualSize = -1; + + /// + /// 是否可以使用已经存在的文件。 + /// + public bool canUseExistsFile = true; + + /// + /// 文件的 MD5、SHA1 或 SHA256。会根据输入字符串的长度自动判断种类。 + /// 不检查则为 Nothing。 + /// + public string hash; + + /// + /// 是否要求为 JSON 文件。 + /// 即,开头结尾必须为 {} 或 []。 + /// + public bool isJson; + + /// + /// 文件的最小大小。 + /// 不检查则为 -1。 + /// + public long minSize = -1; + + public FileChecker( + long minSize = -1, + long actualSize = -1, + string hash = null, + bool canUseExistsFile = true, + bool isJson = false) + { + this.actualSize = actualSize; + this.minSize = minSize; + this.hash = hash; + this.canUseExistsFile = canUseExistsFile; + this.isJson = isJson; + } + + /// + /// 检查文件。若成功则返回 Nothing,失败则返回错误的描述文本,描述文本不以句号结尾。不会抛出错误。 + /// + public string Check(string localPath) + { + try + { + Log($"[Checker] 开始校验文件 {localPath}", LogLevel.Developer); + var info = new FileInfo(localPath); + if (!info.Exists) + return "文件不存在:" + localPath; + var fileSize = info.Length; + var errorMessage = new List(); + var allowIgnore = false; // 允许相信哈希正确但是大小不正确 + if (!string.IsNullOrEmpty(hash)) + { + switch (hash.Length) + { + // MD5 + case < 35: + { + var computedHash = GetFileMD5(localPath); + if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) + errorMessage.Add("文件 MD5 应为 " + hash + ",实际为 " + computedHash); + break; + } + // SHA256 + case 64: + { + var computedHash = GetFileSHA256(localPath); + if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) + errorMessage.Add("文件 SHA256 应为 " + hash + ",实际为 " + computedHash); + break; + } + // SHA1 (40) + default: + { + var computedHash = GetFileSHA1(localPath); + if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) + errorMessage.Add("文件 SHA1 应为 " + hash + ",实际为 " + computedHash); + break; + } + } + + allowIgnore = errorMessage.Count == 0; + } + + if (actualSize >= 0L && actualSize != fileSize && !allowIgnore) // 不允许忽略大小不正确的情况 + errorMessage.Add($"文件大小应为 {actualSize} B,实际为 {fileSize} B" + + (fileSize < 2000L ? ",内容为" + ReadFile(localPath) : "")); + + if (minSize >= 0L && minSize > fileSize) + errorMessage.Add($"文件大小应大于 {minSize} B,实际为 {fileSize} B" + + (fileSize < 2000L ? ",内容为:" + ReadFile(localPath) : "")); + + if (isJson) + { + var content = ReadFile(localPath); + if (string.IsNullOrEmpty(content)) + throw new Exception("读取到的文件为空"); + try + { + GetJson(content); + } + catch (Exception ex) + { + throw new Exception(Lang.Text("Common.Error.InvalidJson"), ex); + } + } + + if (errorMessage.Count == 0) return null; + + errorMessage.Insert(0, $"实际校验地址:{localPath}"); + return errorMessage.Join(";"); + } + catch (Exception ex) + { + Log(ex, "检查文件出错"); + return ex.ToString(); + } + } + } + + /// + /// 等待文件就绪可读,在指定超时时间内轮询检查文件是否存在且内容非空。 + /// + /// 文件路径。 + /// 超时时间(毫秒)。 + public static void WaitForFileReady(string filePath, int timeoutMs = 2000) + { + WaitForFileReady(filePath, timeoutMs, false); + } + + /// + /// 等待文件就绪可读,在指定超时时间内轮询检查文件是否存在且内容非空。 + /// + /// 文件路径。 + /// 超时时间(毫秒)。 + /// 是否要求文件为合法 JSON。 + public static void WaitForFileReady(string filePath, int timeoutMs, bool requireJson) + { + filePath = filePath.Contains(@":\") ? filePath : exePath + filePath; + var start = Environment.TickCount; + long lastSize = -1; + while (Environment.TickCount - start < timeoutMs) + { + if (File.Exists(filePath)) + try + { + var info = new FileInfo(filePath); + var size = info.Length; + if (size <= 0) + continue; + if (!requireJson) + { + if (size == lastSize) + return; + lastSize = size; + } + else + { + var content = ReadFile(filePath); + if (!string.IsNullOrEmpty(content) && content.Trim().StartsWith("{")) + return; + } + } + catch (IOException) + { + } + + Thread.Sleep(50); + } + } + + /// + /// 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 Jar 以 zip 方式解压。 + /// 会尝试创建,但不会清空目标文件夹。 + /// + public static void ExtractFile(string compressFilePath, string destDirectory, Encoding encode = null, + Action progressIncrementHandler = null) + { + Directory.CreateDirectory(destDirectory); + destDirectory = Path.GetFullPath(destDirectory); + if (!destDirectory.EndsWith(Path.DirectorySeparatorChar.ToString())) + destDirectory += Path.DirectorySeparatorChar.ToString(); + if (compressFilePath.EndsWithF(".gz", true)) + // 以 gz 方式解压 + { + using var compressedFile = new FileStream(compressFilePath, FileMode.Open, FileAccess.Read); + using var decompressStream = new GZipStream(compressedFile, CompressionMode.Decompress); + using var extractFileStream = new FileStream( + Path.Combine( + destDirectory, + GetFileNameFromPath(compressFilePath) + .ToLower() + .Replace(".tar", "") + .Replace(".gz", "")), + FileMode.OpenOrCreate, FileAccess.Write); + decompressStream.CopyTo(extractFileStream); + } + else + // 以 zip 方式解压 + { + using var archive = ZipFile.Open(compressFilePath, ZipArchiveMode.Read, + encode ?? Encoding.GetEncoding("GB18030")); + var totalCount = archive.Entries.Count; + foreach (var entry in archive.Entries) + { + progressIncrementHandler?.Invoke(1d / totalCount); + var destinationPath = Path.GetFullPath(Path.Combine(destDirectory, entry.FullName)); + if (!destinationPath.StartsWithF(destDirectory)) + throw new Exception( + $"解压文件 {entry.FullName} 错误:解压文件路径 {destinationPath} 不在目标目录 {destDirectory} 内"); + if (destinationPath.EndsWithF(@"\") || destinationPath.EndsWithF("/")) continue; + Directory.CreateDirectory(GetPathFromFullPath(destinationPath)); + entry.ExtractToFile(destinationPath, true); + } + } + } + + /// + /// 删除文件夹,返回删除的文件个数。通过参数选择是否抛出异常。 + /// + public static int DeleteDirectory(string path, bool ignoreIssue = false) + { + if (!Directory.Exists(path)) + return 0; + var deletedCount = 0; + string[] files; + try + { + files = Directory.GetFiles(path); + } + catch (DirectoryNotFoundException ex) // #4549 + { + Log(ex, $"疑似为孤立符号链接,尝试直接删除({path})", LogLevel.Developer); + Directory.Delete(path); + return 0; + } + + foreach (var filePath in files) + { + var retriedFile = false; + RetryFile: ; + + try + { + File.Delete(filePath); + deletedCount += 1; + } + catch (Exception ex) + { + if (!retriedFile) + { + retriedFile = true; + Log(ex, $"删除文件失败,将在 0.3s 后重试({filePath})"); + Thread.Sleep(300); + goto RetryFile; + } + + if (ignoreIssue) + Log(ex, "删除单个文件可忽略地失败"); + else + throw; + } + } + + foreach (var str in Directory.GetDirectories(path)) + DeleteDirectory(str, ignoreIssue); + var retriedDir = false; + RetryDir: ; + + try + { + Directory.Delete(path, true); + } + catch (Exception ex) + { + if (!retriedDir && !RunInUi()) + { + retriedDir = true; + Log(ex, $"删除文件夹失败,将在 0.3s 后重试({path})"); + Thread.Sleep(300); + goto RetryDir; + } + + if (ignoreIssue) + Log(ex, "删除单个文件夹可忽略地失败"); + else + throw; + } + + return deletedCount; + } + + /// + /// 复制文件夹,失败会抛出异常。 + /// + public static void CopyDirectory(string fromPath, string toPath, Action progressIncrementHandler = null) + { + fromPath = fromPath.Replace("/", @"\"); + if (!fromPath.EndsWithF(@"\")) + fromPath += @"\"; + toPath = toPath.Replace("/", @"\"); + if (!toPath.EndsWithF(@"\")) + toPath += @"\"; + var allFiles = EnumerateFiles(fromPath).ToList(); + var fileCount = allFiles.Count; + foreach (var file in allFiles) + { + CopyFile(file.FullName, file.FullName.Replace(fromPath, toPath)); + if (progressIncrementHandler is not null) + progressIncrementHandler(1d / fileCount); + } + } + + /// + /// 遍历文件夹中的所有文件。 + /// + public static IEnumerable EnumerateFiles(string directory) + { + var info = new DirectoryInfo(ShortenPath(directory)); + if (!info.Exists) + return new List(); + return info.EnumerateFiles("*", SearchOption.AllDirectories); + } + + /// + /// 若路径长度大于指定值,则将长路径转换为短路径。 + /// + public static string ShortenPath(string longPath, int shortenThreshold = 247) + { + if (longPath.Length <= shortenThreshold) + return longPath; + var shortPath = new StringBuilder(260); + GetShortPathName(longPath, shortPath, 260); + return shortPath.ToString(); + } + + public static void MoveDirectory(string sourceDir, string targetDir) + { + if (!Directory.Exists(targetDir)) + Directory.CreateDirectory(targetDir); + foreach (var filePath in Directory.GetFiles(sourceDir)) + { + var fileName = GetFileNameFromPath(filePath); + File.Move(filePath, Path.Combine(targetDir, fileName)); + } + + foreach (var dirPath in Directory.GetDirectories(sourceDir)) + { + var dirName = GetFolderNameFromPath(dirPath); + MoveDirectory(dirPath, Path.Combine(targetDir, dirName)); + } + } + + [DllImport("kernel32", EntryPoint = "GetShortPathNameA")] + private static extern int GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer); + + public static void CreateSymbolicLink(string linkPath, string targetPath, int flags) + { + var cMDProcess = new Process(); + var linkDPath = ModLaunch.ExtractLinkD(); + { + var withBlock = cMDProcess.StartInfo; + withBlock.FileName = linkDPath; + withBlock.Arguments = $"\"{linkPath}\" \"{targetPath}\""; + withBlock.CreateNoWindow = true; + withBlock.UseShellExecute = false; + } + cMDProcess.Start(); + while (!cMDProcess.HasExited) + { + } + } + + + /// + /// 检查是否拥有某一文件夹的 I/O 权限。如果文件夹不存在,会返回 False。 + /// + public static bool CheckPermission(string path) + { + try + { + if (string.IsNullOrEmpty(path)) + return false; + if (!path.EndsWithF(@"\")) + path += @"\"; + if (path.EndsWithF(@":\System Volume Information\") || path.EndsWithF(@":\$RECYCLE.BIN\")) + return false; + if (!Directory.Exists(path)) + return false; + var fileName = "CheckPermission" + GetUuid(); + if (File.Exists(path + fileName)) + File.Delete(path + fileName); + File.Create(path + fileName).Dispose(); + File.Delete(path + fileName); + return true; + } + catch (Exception ex) + { + Log(ex, "没有对文件夹 " + path + " 的权限,请尝试以管理员权限运行 PCL"); + return false; + } + } + + /// + /// 检查是否拥有某一文件夹的 I/O 权限。如果出错,则抛出异常。 + /// + public static void CheckPermissionWithException(string path) + { + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentNullException("文件夹名不能为空!"); + if (!path.EndsWithF(@"\")) + path += @"\"; + if (!Directory.Exists(path)) + throw new DirectoryNotFoundException("文件夹不存在!"); + if (File.Exists(path + "CheckPermission")) + File.Delete(path + "CheckPermission"); + File.Create(path + "CheckPermission").Dispose(); + File.Delete(path + "CheckPermission"); + } + + #endregion +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs new file mode 100644 index 000000000..795431896 --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs @@ -0,0 +1,157 @@ +using System.Collections.Concurrent; +using System.IO; +using System.Text; + +namespace PCL; + +public static partial class ModBase +{ + #region LegacyIni + + // ============================= + // ini + // ============================= + + private static readonly ConcurrentDictionary> iniCache = new(); + + /// + /// 清除某 ini 文件的运行时缓存。 + /// + /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 + public static void IniClearCache(string fileName) + { + if (!fileName.Contains(@":\")) + fileName = $@"{exePath}PCL\{fileName}.ini"; + iniCache.Remove(fileName, out _); + } + + /// + /// 获取 ini 文件缓存。如果没有,则新读取 ini 文件内容。 + /// 在文件不存在或读取失败时返回 Nothing。 + /// + /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 + private static ConcurrentDictionary IniGetContent(string fileName) + { + try + { + // 还原文件路径 + if (!fileName.Contains(@":\")) + fileName = $@"{exePath}PCL\{fileName}.ini"; + // 检索缓存 + if (iniCache.TryGetValue(fileName, out var value)) + return value; + // 读取文件 + if (!File.Exists(fileName)) + return null; + var ini = new ConcurrentDictionary(); + foreach (var line in ReadFile(fileName) + .Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries)) + { + var index = line.IndexOfF(":"); + if (index > 0) + ini[line[..index]] = line[(index + 1)..]; // 可能会有重复键,见 #3616 + } + + iniCache[fileName] = ini; + return ini; + } + catch (Exception ex) + { + Log(ex, $"生成 ini 文件缓存失败({fileName})", LogLevel.Hint); + return null; + } + } + + /// + /// 读取 ini 文件。这可能会使用到缓存。 + /// + /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 + /// 键。 + /// 没有找到键时返回的默认值。 + public static string ReadIni(string fileName, string key, string defaultValue = "") + { + var content = IniGetContent(fileName); + if (content is null || !content.TryGetValue(key, out var value)) + return defaultValue; + return value; + } + + /// + /// 判断 ini 文件中是否包含某个键。这可能会使用到缓存。 + /// + public static bool HasIniKey(string fileName, string key) + { + var content = IniGetContent(fileName); + return content is not null && content.ContainsKey(key); + } + + /// + /// 从 ini 文件中移除某个键。这会更新缓存。 + /// + public static void DeleteIniKey(string fileName, string key) + { + WriteIni(fileName, key, null); + } + + /// + /// 写入 ini 文件,这会更新缓存。 + /// 若 Value 为 Nothing,则删除该键。 + /// + /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 + /// 键。 + /// 值。 + /// + public static void WriteIni(string fileName, string key, string value) + { + try + { + // 预处理 + if (key.Contains(':')) + throw new Exception($"尝试写入 ini 文件 {fileName} 的键名中包含了冒号:{key}"); + key = key.Replace("\r", "").Replace("\n", ""); + value = value?.Replace("\r", "").Replace("\n", ""); + // 防止争用 + lock (writeIniLock) + { + // 获取目前文件 + var content = IniGetContent(fileName) + ?? new ConcurrentDictionary(); + // 更新值 + if (value is null) + { + if (!content.ContainsKey(key)) + return; // 无需处理 + content.Remove(key, out _); + } + else + { + if (content.TryGetValue(key, out var value1) && (value1 ?? "") == (value ?? "")) + return; // 无需处理 + content[key] = value; + } + + // 写入文件 + var fileContent = new StringBuilder(); + foreach (var pair in content) + { + fileContent.Append(pair.Key); + fileContent.Append(':'); + fileContent.Append(pair.Value); + fileContent.Append("\r\n"); + } + + if (!fileName.Contains(@":\")) + fileName = $@"{exePath}PCL\{fileName}.ini"; + WriteFile(fileName, fileContent.ToString()); + } + } + catch (Exception ex) + { + Log(ex, $"写入文件失败({fileName} → {key}:{value})", LogLevel.Hint); + } + } + + private static readonly object writeIniLock = new(); + + #endregion +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs new file mode 100644 index 000000000..7b5918c7a --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs @@ -0,0 +1,379 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.VisualBasic; +using PCL.Core.App.Localization; +using PCL.Core.Logging; +using PCL.Core.Utils.OS; + +namespace PCL; + +public static partial class ModBase +{ + #region Debug + + public static bool modeDebug = false; + + // Log + public enum LogLevel + { + /// + /// 不提示,只记录日志。 + /// + Normal = 0, + + /// + /// 只提示开发者。 + /// + Developer = 1, + + /// + /// 只提示开发者与调试模式用户。 + /// + Debug = 2, + + /// + /// 弹出提示所有用户。 + /// + Hint = 3, + + /// + /// 弹窗,不要求反馈。 + /// + Msgbox = 4, + + /// + /// 弹窗,要求反馈。 + /// + Feedback = 5, + + /// + /// 弹出 Windows 原生弹窗,要求反馈。在无法保证 WPF 窗口能正常运行时使用此级别。 + /// 在第二次触发后会直接结束程序。 + /// + Critical = 6 + } + + private static bool isCriticalErrorTriggered; + + /// + /// 输出 Log。 + /// + /// 如果要求弹窗,指定弹窗的标题。 + public static void Log( + string text, + LogLevel level = LogLevel.Normal, + string? title = null, + string? userSummary = null) + { + // On Error Resume Next + // 放在最后会导致无法显示极端错误下的弹窗(如无法写入日志文件) + // 处理错误会导致再次调用 Log() 导致无限循环 + + // 输出日志 + if (new[] { LogLevel.Msgbox, LogLevel.Hint }.Contains(level)) + LogWrapper.Warn(text); + else + switch (level) + { + case LogLevel.Feedback: + LogWrapper.Error(text); + break; + case LogLevel.Critical: + LogWrapper.Fatal(text); + break; + case LogLevel.Debug: + LogWrapper.Debug(text); + break; + case LogLevel.Developer: + LogWrapper.Trace(text); + break; + default: + LogWrapper.Info(text); + break; + } + + if (isProgramEnded || level == LogLevel.Normal) + return; + + var userDetails = text.RegexReplace(@"\[[^\]]+?\] ", ""); + var userMessage = string.IsNullOrWhiteSpace(userSummary) + ? Lang.Text("SystemDialog.Error.UserVisible.Message", userDetails) + : userSummary; + var dialogTitle = _GetUserDialogTitle(title); + + switch (level) + { + case LogLevel.Developer: + break; + + case LogLevel.Debug: + if (modeDebug) + HintService.Hint("[调试模式] " + text, HintType.Info, false); + break; + + case LogLevel.Hint: + HintService.Hint(userMessage, HintType.Error, false); + break; + + case LogLevel.Msgbox: + ModMain.MyMsgBox(userMessage, dialogTitle, isWarn: true); + break; + + case LogLevel.Feedback: + _ShowFeedbackPrompt(userMessage, dialogTitle, false); + break; + + case LogLevel.Critical: + _ShowFeedbackPrompt(userMessage, dialogTitle, true); + break; + } + } + + /// + /// 输出错误信息。 + /// + /// 错误描述,仅用于日志和错误详情。 + /// 可选的本地化用户摘要;不会写入日志。 + public static void Log( + Exception ex, + string desc, + LogLevel level = LogLevel.Debug, + string? title = null, + string? userSummary = null) + { + // On Error Resume Next + if (ex is ThreadInterruptedException) + return; + + // 输出日志 + if (new[] { LogLevel.Msgbox, LogLevel.Hint }.Contains(level)) + LogWrapper.Warn(ex, desc); + else + switch (level) + { + case LogLevel.Feedback: + LogWrapper.Error(ex, desc); + break; + case LogLevel.Critical: + LogWrapper.Fatal(ex, desc); + break; + case LogLevel.Debug: + LogWrapper.Debug($"{desc}:{ex}"); + break; + case LogLevel.Developer: + LogWrapper.Trace($"{desc}:{ex}"); + break; + default: + LogWrapper.Error(ex, desc); + break; + } + + if (isProgramEnded) + return; + + var userMessage = _GetUserExceptionMessage(desc, ex, userSummary); + var dialogTitle = _GetUserDialogTitle(title); + + switch (level) + { + case LogLevel.Normal or LogLevel.Developer: + break; + + case LogLevel.Debug: + if (modeDebug) + HintService.Hint("[调试模式] " + desc + ":" + ex, HintType.Info, false); + break; + + case LogLevel.Hint: + HintService.Hint(userMessage, HintType.Error, false); + break; + + case LogLevel.Msgbox: + ModMain.MyMsgBox(userMessage, dialogTitle, isWarn: true); + break; + + case LogLevel.Feedback: + _ShowFeedbackPrompt(userMessage, dialogTitle, false); + break; + + case LogLevel.Critical: + _ShowFeedbackPrompt(userMessage, dialogTitle, true); + break; + } + } + + private static string _GetUserDialogTitle(string? title) + { + return string.IsNullOrWhiteSpace(title) + ? Lang.Text("SystemDialog.Error.Title") + : title; + } + + private static string _GetUserExceptionMessage( + string desc, + Exception ex, + string? userSummary) + { + if (!string.IsNullOrWhiteSpace(userSummary)) + return ExceptionDetails.Compose(userSummary, ex); + + return ex.GetType() == typeof(Win32Exception) + ? Lang.Text("SystemDialog.Error.OperationFailed.RuntimeMessage", desc, ex.ToString()) + : Lang.Text("SystemDialog.Error.OperationFailed.Message", desc, ex.ToString()); + } + + private static void _ShowFeedbackPrompt( + string userMessage, + string title, + bool isCritical) + { + switch (isCritical) + { + case true when isCriticalErrorTriggered: + FormMain.EndProgramForce(ProcessReturnValues.Exception); + return; + case true: + isCriticalErrorTriggered = true; + break; + } + + if (CanFeedback(false)) + { + var message = Lang.Text("Setup.Feedback.ErrorPrompt.Submit.Message", userMessage); + var shouldSend = isCritical + ? Interaction.MsgBox( + message, + (MsgBoxStyle)((int)MsgBoxStyle.Critical + (int)MsgBoxStyle.YesNo), + title) == MsgBoxResult.Yes + : ModMain.MyMsgBox( + message, + title, + Lang.Text("Setup.Feedback.ErrorPrompt.Submit.Action"), + Lang.Text("Common.Action.Cancel"), + isWarn: true) == 1; + + if (shouldSend) + Feedback(false, true); + return; + } + + var updateMessage = Lang.Text("Setup.Feedback.ErrorPrompt.Update.Message", userMessage); + if (isCritical) + Interaction.MsgBox(updateMessage, MsgBoxStyle.Critical, title); + else + ModMain.MyMsgBox(updateMessage, title, isWarn: true); + } + + public static string Base64Decode(string text) + { + if (string.IsNullOrWhiteSpace(text)) + return ""; + var decodedBytes = Convert.FromBase64String(text); + return Encoding.UTF8.GetString(decodedBytes); + } + + public static string Base64Encode(string text) + { + var bytes = Encoding.UTF8.GetBytes(text); + return Convert.ToBase64String(bytes); + } + + public static string Base64Encode(byte[] bytes) + { + return Convert.ToBase64String(bytes); + } + + // 反馈 + public static void Feedback(bool showMsgbox = true, bool forceOpenLog = false) + { + // On Error Resume Next + FeedbackInfo(); + var currentDate = DateTime.Now.ToString("yyyy-M-dd", CultureInfo.InvariantCulture); + + if (forceOpenLog || (showMsgbox && + ModMain.MyMsgBox( + Lang.Text("Setup.Feedback.Reminder.Message", currentDate), + Lang.Text("Setup.Feedback.Reminder.Title"), + Lang.Text("Common.Action.OpenFolder"), + Lang.Text("Setup.Feedback.Reminder.NotNeeded")) == + 1)) OpenExplorer(exePath + @"PCL\Log\"); + OpenWebsite("https://github.com/PCL-Community/PCL2-CE/issues/"); + } + + public static bool CanFeedback(bool showHint) + { + var stat = UpdateManager.GetVersionStatus(); + if (stat == UpdateEnums.VersionStatus.Latest) return true; + + if (!showHint) return false; + + if (ModMain.MyMsgBox( + stat == UpdateEnums.VersionStatus.NotLatest + ? Lang.Text("Setup.Feedback.Unavailable.NotLatest.Message") + : Lang.Text("Setup.Feedback.Unavailable.CheckFailed.Message"), + Lang.Text("Setup.Feedback.Unavailable.Title"), + stat == UpdateEnums.VersionStatus.NotLatest + ? Lang.Text("Setup.Feedback.Unavailable.NotLatest.Action") + : Lang.Text("Setup.Feedback.Unavailable.CheckFailed.Action"), + Lang.Text("Common.Action.Cancel")) == 1) + ModMain.frmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupUpdate); + + return false; + } + + /// + /// 在日志中输出系统诊断信息。 + /// + public static void FeedbackInfo() + { + try + { + // Get system memory info + var phyRam = KernelInterop.GetPhysicalMemoryBytes(); + + // Calculate memory and DPI scale + var availableMb = phyRam.Available / 1024 / 1024; + var totalMb = phyRam.Total / 1024 / 1024; + var dpiScale = Math.Round(dpi / 96.0, 2); + + // Build diagnostic information string + var info = $""" + [System] Diagnostic Information: + OS: {RuntimeInformation.OSDescription} (32-bit: {SystemInfo.Is32BitSystem}) + Memory: {availableMb} MB / {totalMb} MB + DPI: {dpi} ({dpiScale * 100}%) + MC Folder: {ModFolder.mcFolderSelected ?? "Nothing"} + Executable Path: {exePath} + """; + + LogWrapper.Info(info); + } + catch (Exception ex) + { + // Basic fail-safe to replace "On Error Resume Next" + LogWrapper.Error(ex, "Failed to collect feedback information"); + } + } + + // 断言 + public static void DebugAssert(bool exp) + { + if (!exp) + throw new Exception("断言命中"); + } + + // 获取当前的堆栈信息 + public static string GetStackTrace() + { + var stack = new StackTrace(); + return stack.GetFrames().Skip(1).Select(f => f.GetMethod()) + .Select(f => f.Name + "(" + f.GetParameters().Select(p => p.ToString()).ToList().Join(", ") + ") - " + + f.Module).ToList().Join("\r\n") + .Replace("\r\n" + "\r\n", "\r\n"); + } + + #endregion +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs new file mode 100644 index 000000000..8d5932937 --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs @@ -0,0 +1,205 @@ +namespace PCL; + +public static partial class ModBase +{ + #region 搜索 + + /// + /// 获取搜索文本的相似度。 + /// + /// 被搜索的长内容。 + /// 用户输入的搜索文本。 + private static double SearchSimilarity(string source, string query) + { + var qp = 0; + var lenSum = 0d; + source = source.ToLower().Replace(" ", ""); + query = query.ToLower().Replace(" ", ""); + var sourceLength = source.Length; + var queryLength = query.Length; // 用于计算最后因数的长度缓存 + while (qp < queryLength) + { + // 对 qp 作为开始位置计算 + var sp = 0; + var lenMax = 0; + var spMax = 0; + // 查找以 qp 为头的最大子串 + while (sp < source.Length) + { + // 对每个 sp 作为开始位置计算最大子串 + var len = 0; + while (qp + len < queryLength && sp + len < source.Length && source[sp + len] == query[qp + len]) + len += 1; + // 存储 len + if (len > lenMax) + { + lenMax = len; + spMax = sp; + } + + // 根据结果增加 sp + sp += Math.Max(1, len); + } + + if (lenMax > 0) + { + source = string.Concat(source.AsSpan(0, spMax), source.Length > spMax + lenMax + ? source[(spMax + lenMax)..] + : string.Empty); // 将源中的对应字段替换空 + // 存储 lenSum + var incWeight = Math.Pow(1.4d, 3 + lenMax) - 3.6d; // 根据长度加成 + incWeight *= 1d + 0.3d * Math.Max(0, 3 - Math.Abs(qp - spMax)); // 根据位置加成 + lenSum += incWeight; + } + + // 根据结果增加 qp + qp += Math.Max(1, lenMax); + } + + // 计算结果:重复字段量 × 源长度影响比例 + return lenSum / queryLength * (3d / Math.Pow(sourceLength + 15, 0.5d)) * + (queryLength <= 2 ? 3 - queryLength : 1); + } + + /// + /// 获取多段文本加权后的相似度。 + /// + private static double SearchSimilarityWeighted(List source, string query) + { + var totalWeight = 0d; + var sum = 0d; + foreach (var pair in source) + { + if (pair.aliases.Length != 0) + sum += pair.aliases.Max(a => SearchSimilarity(a, query)) * pair.weight; + totalWeight += pair.weight; + } + + return sum / totalWeight; + } + + /// + /// 用于搜索的项目。 + /// + public class SearchEntry + { + /// + /// 是否完全匹配。 + /// + public bool absoluteRight; + + /// + /// 该项目对应的源数据。 + /// + public T item; + + /// + /// 该项目用于搜索的文本源。 + /// 在搜索时,会对每个文本源单独加权,但单个文本源内的多个别名只取最高的一个的相似度。 + /// + public List searchSource; + + /// + /// 相似度。 + /// + public double similarity; + } + + /// + /// 单个用于搜索的文本源。 + /// + public class SearchSource + { + public string[] aliases; + public double weight; + + public SearchSource(string[] aliases, double weight = 1) + { + this.aliases = aliases; + this.weight = weight; + } + + public SearchSource(string text, double weight = 1) + { + aliases = [text]; + this.weight = weight; + } + } + + /// + /// 本地搜索返回的最大模糊结果数。 + /// + public const int MaxLocalSearchDepth = 25; + + /// + /// 进行多段文本加权搜索,获取相似度较高的数项结果。 + /// + /// 返回的最大模糊结果数。 + /// 返回结果要求的最低相似度。 + public static List> Search(List> entries, string query, int maxBlurCount = 5, + double minBlurSimilarity = 0.1d) + { + var resultList = new List>(); + + if (entries is null || entries.Count == 0) return resultList; + + // Preprocess query into parts + var queryParts = query.Split([' '], StringSplitOptions.RemoveEmptyEntries); + if (queryParts.Length == 0) + { + resultList.AddRange(entries); + return resultList; + } + + // Precompute query parts in lowercase for case-insensitive comparison + var queryPartsLower = queryParts.Select(q => q.ToLower()).ToArray(); + + // Process each entry to compute similarity and absolute match status + foreach (var entry in entries) + { + entry.similarity = SearchSimilarityWeighted(entry.searchSource, query); + + // Preprocess search source keys: remove spaces and convert to lowercase + var processedSources = entry.searchSource.Select(s => + { + for (var i = 0; i < s.aliases.Length; i++) + s.aliases[i] = s.aliases[i].Replace(" ", "").ToLower(); + return s.aliases; + }).ToList(); + + // Check if all query parts are matched exactly by at least one source + var isAbsoluteRight = queryPartsLower + .Select(qp => processedSources + .Any(ps => ps + .Any(p => p + .Contains(qp)))) + .All(found => found); + + entry.absoluteRight = isAbsoluteRight; + } + + // Sort by absolute match (descending), then by similarity (descending) + var sortedEntries = entries + .OrderByDescending(e => e.absoluteRight) + .ThenByDescending(e => e.similarity) + .ToList(); + + // Build the final result list + var blurCount = 0; + foreach (var entry in sortedEntries) + if (entry.absoluteRight) + { + resultList.Add(entry); + } + else + { + if (entry.similarity < minBlurSimilarity || blurCount >= maxBlurCount) break; + resultList.Add(entry); + blurCount += 1; + } + + return resultList; + } + + #endregion +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs new file mode 100644 index 000000000..67ecca863 --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs @@ -0,0 +1,765 @@ +using System.Collections; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Windows; +using System.Windows.Threading; +using Microsoft.VisualBasic; +using PCL.Core.App.Localization; +using PCL.Core.Logging; +using PCL.Core.Utils.OS; + +namespace PCL; + +public static partial class ModBase +{ + #region 系统 + + public static bool IsUtf8CodePage() + { + return Encoding.Default.CodePage == 65001; + } + + /// + /// 线程安全的 List。 + /// 通过在 For Each 循环中使用一个浅表副本规避多线程操作或移除自身导致的异常。 + /// + public class SafeList : IEnumerable, IDisposable, ICollection + { + private readonly List _internalList; + private readonly ReaderWriterLockSlim _lock = new(); + + public SafeList() + { + _internalList = []; + } + + public SafeList(IEnumerable data) + { + _internalList = new List(data); + } + + public T this[int index] + { + get => _internalList[index]; + set => _internalList[index] = value; + } + + public void Add(T item) + { + _lock.EnterWriteLock(); + try + { + _internalList.Add(item); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public bool Remove(T item) + { + _lock.EnterWriteLock(); + try + { + return _internalList.Remove(item); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public void Clear() + { + _lock.EnterWriteLock(); + try + { + _internalList.Clear(); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public int Count + { + get + { + _lock.EnterReadLock(); + try + { + return _internalList.Count; + } + finally + { + _lock.ExitReadLock(); + } + } + } + + public bool IsReadOnly => ((ICollection)_internalList).IsReadOnly; + + public bool Contains(T item) + { + return ((ICollection)_internalList).Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + ((ICollection)_internalList).CopyTo(array, arrayIndex); + } + + public void Dispose() + { + _lock.Dispose(); + } + + public IEnumerator GetEnumerator() + { + return ToList().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public List ToList() + { + _lock.EnterReadLock(); + try + { + return _internalList.ToList(); + } + finally + { + _lock.ExitReadLock(); + } + } + + public void RemoveAt(int index) + { + _lock.EnterWriteLock(); + try + { + _internalList.RemoveAt(index); + } + finally + { + _lock.ExitWriteLock(); + } + } + } + + /// + /// 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。 + /// + public static string pathPure = GetPureASCIIDir(); + + private static string GetPureASCIIDir() + { + if (exePath.IsASCII()) return exePath + @"PCL\"; + + if (pathAppdata.IsASCII()) return pathAppdata; + + if (pathTemp.IsASCII()) return pathTemp; + + return Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL"); + } + + /// + /// 指示接取到这个异常的函数进行重试。 + /// + public class RestartException : Exception + { + } + + /// + /// 指示用户手动取消了操作,或用户已知晓操作被取消的原因。 + /// + public class CancelledException : Exception + { + } + + /// + /// 判断对象是否为某个泛型类型的实例。 + /// + public static bool IsInstanceOfGenericType(this Type genericType, object obj) + { + if (obj is null) + return false; + var t = obj.GetType(); + while (t is not null) + { + if (t.IsGenericType && ReferenceEquals(t.GetGenericTypeDefinition(), genericType)) + return true; + t = t.BaseType; + } + + return false; + } + + private static int uuid = 1; + private static object uuidLock; + + /// + /// 获取一个全程序内不会重复的数字(伪 Uuid)。 + /// + public static int GetUuid() + { + uuidLock ??= new object(); + lock (uuidLock) + { + uuid += 1; + return uuid; + } + } + + /// + /// 将元素与 List 的混合体拆分为元素组。 + /// + public static List GetFullList(IList data) + { + List getFullListRet = default; + getFullListRet = []; + for (int i = 0, loopTo = data.Count - 1; i <= loopTo; i++) + if (data[i] is ICollection) + getFullListRet.AddRange((IEnumerable)data[i]); + else + getFullListRet.Add((T)data[i]); + + return getFullListRet; + } + + /// + /// 数组去重。 + /// + public static List Distinct(this ICollection arr, ComparisonBoolean isEqual) + { + var resultArray = new List(); + for (int i = 0, loopTo = arr.Count - 1; i <= loopTo; i++) + { + for (int ii = i + 1, loopTo1 = arr.Count - 1; ii <= loopTo1; ii++) + if (isEqual(arr.ElementAtOrDefault(i), arr.ElementAtOrDefault(ii))) + goto NextElement; + resultArray.Add(arr.ElementAtOrDefault(i)); + NextElement: ; + } + + return resultArray; + } + + /// + /// 对集合的每个元素执行指定操作。 + /// + public static IEnumerable ForEach(this IEnumerable collection, Action action) + { + foreach (var item in collection) + action(item); + return collection; + } + + /// + /// 用于储存 RaiseByMouse 的 EventArgs。 + /// + public sealed class RouteEventArgs(bool raiseByMouse = false) : EventArgs + { + public bool handled = false; + public bool raiseByMouse = raiseByMouse; + } + + /// + /// 前台运行文件。 + /// + /// 文件名。可以为“notepad”等缩写。 + /// 运行参数。 + public static void ShellOnly(string fileName, string arguments = "") + { + try + { + fileName = ShortenPath(fileName); + using var program = new Process(); + program.StartInfo.Arguments = arguments; + program.StartInfo.FileName = fileName; + program.StartInfo.UseShellExecute = true; + Log("[System] 执行外部命令:" + fileName + " " + arguments); + program.Start(); + } + catch (Exception ex) + { + Log( + ex, + "打开文件或程序失败:" + fileName, + LogLevel.Msgbox, + userSummary: Lang.Text("SystemDialog.File.OpenFailed.Message", fileName)); + } + } + + /// + /// 前台运行文件并返回返回值。 + /// + /// 文件名。可以为“notepad”等缩写。 + /// 运行参数。 + /// 等待该程序结束的最长时间(毫秒)。超时会返回 Result.Timeout。 + public static ProcessReturnValues ShellAndGetExitCode(string fileName, string arguments = "", int timeout = 1000000) + { + try + { + using var program = new Process(); + program.StartInfo.Arguments = arguments; + program.StartInfo.FileName = fileName; + Log("[System] 执行外部命令并等待返回码:" + fileName + " " + arguments); + program.Start(); + if (program.WaitForExit(timeout)) return (ProcessReturnValues)program.ExitCode; + + return ProcessReturnValues.Timeout; + } + catch (Exception ex) + { + Log(ex, "执行命令失败:" + fileName, LogLevel.Msgbox); + return ProcessReturnValues.Fail; + } + } + + /// + /// 静默运行文件并返回输出流字符串。执行失败会抛出异常。 + /// + /// 文件名。可以为“notepad”等缩写。 + /// 运行参数。 + /// 等待该程序结束的最长时间(毫秒)。超时会抛出错误。 + public static string ShellAndGetOutput(string fileName, string arguments = "", int timeout = 1000000, + string workingDirectory = null) + { + var info = new ProcessStartInfo + { + FileName = fileName, + Arguments = arguments, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true + }; + + // 设置工作目录(如果提供) + if (!string.IsNullOrEmpty(workingDirectory)) info.WorkingDirectory = workingDirectory.TrimEnd('\\'); + + Log("[System] 执行外部命令并等待返回结果:" + fileName + " " + arguments); + + using var program = new Process(); + program.StartInfo = info; + program.Start(); + + // 异步读取输出和错误流 + var outputTask = program.StandardOutput.ReadToEndAsync(); + var errorTask = program.StandardError.ReadToEndAsync(); + + // 等待进程退出或超时 + if (program.WaitForExit(timeout)) + { + // 确保异步读取完成 + Task.WaitAll(outputTask, errorTask); + } + else + { + // 超时后终止进程 + program.Kill(); + // 仍然尝试获取已输出的内容 + Task.WaitAll(outputTask, errorTask); + } + + // 合并结果并返回 + return outputTask.Result + errorTask.Result; + } + + /// + /// 在新的工作线程中执行代码。 + /// + public static Thread RunInNewThread( + Action action, + string name = null, + ThreadPriority priority = ThreadPriority.Normal) + { + var th = new Thread(() => + { + try + { + action(); + } + catch (ThreadInterruptedException ex) + { + Log(name + ":线程已中止"); + } + catch (Exception ex) + { + Log(ex, name + ":线程执行失败", LogLevel.Feedback); + } + }) { Name = name ?? "Runtime New Invoke " + GetUuid() + "#", Priority = priority }; + th.Start(); + return th; + } + + /// + /// 确保在 UI 线程中执行代码。 + /// 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。 + /// 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用! + /// + public static Output RunInUiWait(Func action) + { + return RunInUi() + ? action() + : System.Windows.Application.Current.Dispatcher.Invoke(action); + } + + /// + /// 确保在 UI 线程中执行代码。 + /// 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。 + /// 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用! + /// + public static void RunInUiWait(Action action) + { + if (System.Windows.Application.Current is null) + return; + if (RunInUi()) + action(); + else + System.Windows.Application.Current.Dispatcher.Invoke(action); + } + + /// + /// 确保在 UI 线程中执行代码,代码按触发顺序执行。 + /// 如果当前并非 UI 线程,也不阻断当前线程的执行。 + /// + public static void RunInUi(Action action, bool forceWaitUntilLoaded = false) + { + if (System.Windows.Application.Current is null) + return; + if (RunInUi()) + action(); + else + System.Windows.Application.Current.Dispatcher.InvokeAsync(action, + forceWaitUntilLoaded ? DispatcherPriority.Loaded : DispatcherPriority.Normal); + } + + /// + /// 确保在工作线程中执行代码。 + /// + public static void RunInThread(Action action) + { + if (RunInUi()) + RunInNewThread(action, "Runtime Invoke " + GetUuid() + "#"); + else + action(); + } + + /// + /// 使用优化的归并排序算法进行稳定排序。 + /// + /// 传入两个对象,若第一个对象应该排在前面,则返回 True。 + public static List Sort(this IList list, ComparisonBoolean sortRule) + { + // 创建原列表的副本以避免修改原始列表 + var tempList = new List(list); + if (tempList.Count <= 1) + return tempList; + + // 使用归并排序核心算法 + MergeSort_Sort(ref tempList, 0, tempList.Count - 1, sortRule); + return tempList; + } + + private static void MergeSort_Sort( + ref List array, + int left, + int right, + ComparisonBoolean comparator) + { + if (left >= right) + return; + + var mid = (left + right) / 2; + MergeSort_Sort(ref array, left, mid, comparator); + MergeSort_Sort(ref array, mid + 1, right, comparator); + MergeSort_Merge(ref array, left, mid, right, comparator); + } + + private static void MergeSort_Merge( + ref List array, + int left, + int mid, + int right, + ComparisonBoolean comparator) + { + var leftArray = new List(); + var rightArray = new List(); + + for (var i = left; i <= mid; i++) + leftArray.Add(array[i]); + + for (var j = mid + 1; j <= right; j++) + rightArray.Add(array[j]); + + var leftPtr = 0; + var rightPtr = 0; + var current = left; + + while (leftPtr < leftArray.Count && rightPtr < rightArray.Count) + { + // 保持稳定性的关键比较逻辑:当相等时优先取左数组元素 + if (comparator(leftArray[leftPtr], rightArray[rightPtr])) + { + array[current] = leftArray[leftPtr]; + leftPtr += 1; + } + else + { + array[current] = rightArray[rightPtr]; + rightPtr += 1; + } + + current += 1; + } + + while (leftPtr < leftArray.Count) + { + array[current] = leftArray[leftPtr]; + leftPtr += 1; + current += 1; + } + + while (rightPtr < rightArray.Count) + { + array[current] = rightArray[rightPtr]; + rightPtr += 1; + current += 1; + } + } + + public delegate bool ComparisonBoolean(T left, T right); + + /// + /// 返回列表的浅表副本。 + /// + public static IList Clone(this IList list) + { + return new List(list); + } + + /// + /// 尝试从字典中获取某项,如果该项不存在,则返回默认值。 + /// + public static TValue GetOrDefault(this Dictionary dict, TKey key, + TValue defaultValue = default) + { + return dict.GetValueOrDefault(key, defaultValue); + } + + /// + /// 将某项添加到以列表作为值的字典中。 + /// + public static void AddToList( + this Dictionary> dict, + TKey key, + TValue value) + { + if (dict.TryGetValue(key, out var value1)) + value1.Add(value); + else + dict.Add(key, [value]); + } + + /// + /// 获取程序启动参数。 + /// + /// 参数名。 + /// 默认值。 + public static object GetProgramArgument(string name, object defaultValue = null) + { + var allArguments = Interaction.Command().Split(" "); + for (int i = 0, loopTo = allArguments.Length - 1; i <= loopTo; i++) + if ((allArguments[i] ?? "") == ("-" + name ?? "")) + { + if (allArguments.Length == i + 1 || allArguments[i + 1].StartsWithF("-")) + return true; + return allArguments[i + 1]; + } + + return defaultValue; + } + + /// + /// 打开网页。 + /// + public static void OpenWebsite(string url) + { + try + { + if (!url.StartsWithF("http", true) && !url.StartsWithF("minecraft://", true)) + throw new Exception(url + " 不是一个有效的网址,它必须以 http 开头!"); + Log("[System] 正在打开网页:" + url); + var psi = new ProcessStartInfo(url) + { + UseShellExecute = true + }; + Process.Start(psi); + } + catch (Exception ex) + { + Log(ex, "无法打开网页(" + url + ")"); + ClipboardSet(url, false); + var message = ExceptionDetails.Compose( + Lang.Text("SystemDialog.Browser.OpenFailed.Message", url), + ex); + ModMain.MyMsgBox( + message, + Lang.Text("SystemDialog.Browser.OpenFailed.Title")); + } + } + + /// + /// 打开 explorer。 + /// 若不以 \ 结尾,则将视作文件路径,打开并选中此文件。 + /// + public static void OpenExplorer(string location) + { + try + { + location = ShortenPath(location.Replace("/", @"\").Trim(' ', '"')); + Log("[System] 正在打开资源管理器:" + location); + if (location.EndsWithF(@"\")) + ShellOnly(location); + else + ShellOnly("explorer", $"/select,\"{location}\""); + } + catch (Exception ex) + { + Log( + ex, + "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", + LogLevel.Msgbox, + userSummary: Lang.Text("SystemDialog.Folder.OpenFailed.Message", location)); + } + } + + /// + /// 设置剪贴板。将在另一线程运行,且不会抛出异常。 + /// + public static void ClipboardSet(string text, bool showSuccessHint = true) + { + RunInThread(() => + { + var success = false; + + for (var attempt = 0; attempt <= 5; attempt++) + try + { + RunInUi(() => Clipboard.SetText(text)); + success = true; + break; + } + catch (Exception ex) when (attempt < 5) + { + Thread.Sleep(20); + } + catch (Exception finalEx) + { + Log( + finalEx, + "剪贴板被占用,文本复制失败", + LogLevel.Hint, + userSummary: Lang.Text("Common.Hint.CopyFailed")); + } + + if (success && showSuccessHint) + RunInUi(() => HintService.Hint(Lang.Text("Common.Hint.Copied"), HintType.Success)); + }); + } + + /// + /// 从剪切板粘贴文件或文件夹 + /// + /// 目标文件夹 + /// 是否粘贴文件 + /// 是否粘贴文件夹 + /// 总共粘贴的数量 + public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool copyDir = true) + { + Log("[System] 从剪贴板粘贴文件到:" + dest); + try + { + var files = Clipboard.GetFileDropList(); + if (files.Count.Equals(0)) + { + Log("[System] 剪贴板内无文件可粘贴"); + return 0; + } + + var copiedFiles = 0; + var copiedFolders = 0; + foreach (var i in files) + { + if (copyFile && File.Exists(i)) // 文件 + try + { + var thisDest = dest + GetFileNameFromPath(i); + if (File.Exists(thisDest)) + { + Log("[System] 已存在同名文件:" + thisDest); + } + else + { + File.Copy(i, thisDest); + copiedFiles += 1; + } + } + catch (Exception ex) + { + Log(ex, "[System] 复制文件时出错"); + continue; + } + + if (copyDir && Directory.Exists(i)) // 文件夹 + try + { + var thisDest = dest + GetFolderNameFromPath(i); + if (Directory.Exists(thisDest)) + { + Log("[System] 已存在同名文件夹:" + thisDest); + } + else + { + CopyDirectory(i, thisDest); + copiedFolders += 1; + } + } + catch (Exception ex) + { + Log(ex, "[System] 复制文件时出错"); + } + } + + HintService.Hint(Lang.Text("Common.Hint.FilesPasted", copiedFiles, copiedFolders)); + } + catch (Exception ex) + { + Log(ex, "[System] 从剪切板粘贴文件失败", LogLevel.Hint); + } + + return 0; + } + + /// + /// 获取程序打包资源的输入流。该资源必须声明为 Resource 类型,否则将会报错,Images + /// 和 Resources 目录已默认声明该类型。 + /// + public static Stream GetResourceStream(string path) + { + var resourceInfo = + System.Windows.Application.GetResourceStream(new Uri($"pack://application:,,,/{path}", UriKind.Absolute)); + return resourceInfo?.Stream; + } + + #endregion +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs new file mode 100644 index 000000000..52b2b412b --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs @@ -0,0 +1,453 @@ +using System.Collections; +using System.Runtime.CompilerServices; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.VisualBasic; +using PCL.Core.App.Localization; +using PCL.Core.IO; +using PCL.Core.Utils; +using PCL.Core.Utils.Hash; + +namespace PCL; + +public static partial class ModBase +{ + #region 文本 + + public static char vbLq = Convert.ToChar(8220); + public static char vbRq = Convert.ToChar(8221); + + /// + /// 返回一个枚举对应的字符串。 + /// + /// 一个已经实例化的枚举类型。 + public static string GetStringFromEnum(Enum enumData) + { + return Enum.GetName(enumData.GetType(), enumData); + } + + /// + /// 将文件大小转化为适合的文本形式,如“1.28 M”。 + /// + /// 以字节为单位的大小表示。 + public static string GetString(long fileSize) + { + return ByteStream.GetReadableLength(fileSize, provider: Lang.Culture); + } + + /// + /// 获取 JSON 对象。 + /// + public static JsonNode GetJson(string data) + { + try + { + return JsonCompat.ParseNode(data); + } + catch (Exception ex) + { + var dataText = data ?? ""; + var length = dataText.Length; + throw new Exception("格式化 JSON 失败:" + (length > 2000 + ? string.Concat(dataText.AsSpan(0, 500), $"...(全长 {length} 个字符)...", dataText.AsSpan(length - 500)) + : dataText), ex); + } + } + + /// + /// 将第一个字符转换为大写,其余字符转换为小写。 + /// + public static string Capitalize(this string word) + { + if (string.IsNullOrEmpty(word)) + return word; + return word[..1].ToUpperInvariant() + word[1..].ToLowerInvariant(); + } + + /// + /// 将字符串统一至某个长度,过短则以 Code 将其右侧填充,过长则截取靠左的指定长度。 + /// + public static string StrFill(string str, string code, byte length) + { + return str.Length > length + ? str[..length] + : string.Concat(str.PadRight(length, code[0]).AsSpan(str.Length), str); + } + + /// + /// 将一个小数显示为固定的小数点后位数形式,将向零取整。 + /// 如 12 保留 2 位则输出 12.00,而 95.678 保留 2 位则输出 95.67。 + /// + public static string StrFillNum(double num, int length) + { + return Lang.Number(num, $"F{length}"); + } + + /// + /// 移除字符串首尾的标点符号、回车,以及括号中、冒号后的补充说明内容。 + /// + public static object StrTrim(string str, bool removeQuote = true) + { + if (removeQuote) + str = str.Split("(")[0].Split(":")[0].Split("(")[0].Split(":")[0]; + return str.Trim('.', '。', '!', ' ', '!', '?', '?', '\r', + '\n'); + } + + /// + /// 连接字符串。 + /// + public static string Join(this IEnumerable list, string split) + { + var builder = new StringBuilder(); + var isFirst = true; + foreach (var element in list) + { + if (isFirst) + isFirst = false; + else + builder.Append(split); + if (element is not null) + builder.Append(element); + } + + return builder.ToString(); + } + + /// + /// 分割字符串。 + /// + public static string[] Split(this string fullStr, string splitStr) + { + return splitStr.Length == 1 + ? fullStr.Split(splitStr[0]) + : fullStr.Split([splitStr], StringSplitOptions.None); + } + + /// + /// 获取字符串哈希值。 + /// + public static ulong GetHash(string str) + { + var getHashRet = 5381UL; + for (int i = 0, loopTo = str.Length - 1; i <= loopTo; i++) + getHashRet = (getHashRet << 5) ^ getHashRet ^ str[i]; + return getHashRet ^ 0xA98F501BC684032FUL; + } + + /// + /// 获取字符串 MD5。 + /// + public static string GetStringMD5(string str) + { + return (string)GetHexString(MD5Provider.Instance.ComputeHash(str)); + } + + /// + /// 检查字符串中的字符是否均为 ASCII 字符。 + /// + public static bool IsASCII(this string input) + { + return input.All(c => c < 128); + } + + /// + /// 获取在子字符串第一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024。 + /// 如果未找到子字符串则不裁切。 + /// + public static string BeforeFirst(this string str, string text, bool ignoreCase = false) + { + var pos = string.IsNullOrEmpty(text) + ? -1 + : str.IndexOfF(text, ignoreCase); + return pos >= 0 + ? str[..pos] + : str; + } + + /// + /// 获取在子字符串最后一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024/11。 + /// 如果未找到子字符串则不裁切。 + /// + public static string BeforeLast(this string str, string text, bool ignoreCase = false) + { + var pos = string.IsNullOrEmpty(text) ? -1 : str.LastIndexOfF(text, ignoreCase); + return pos >= 0 ? str[..pos] : str; + } + + /// + /// 获取在子字符串第一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 11/08。 + /// 如果未找到子字符串则不裁切。 + /// + public static string AfterFirst(this string str, string text, bool ignoreCase = false) + { + var pos = string.IsNullOrEmpty(text) ? -1 : str.IndexOfF(text, ignoreCase); + return pos >= 0 ? str[(pos + text.Length)..] : str; + } + + /// + /// 获取在子字符串最后一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 08。 + /// 如果未找到子字符串则不裁切。 + /// + public static string AfterLast(this string str, string text, bool ignoreCase = false) + { + var pos = string.IsNullOrEmpty(text) ? -1 : str.LastIndexOfF(text, ignoreCase); + return pos >= 0 ? str[(pos + text.Length)..] : str; + } + + /// + /// 获取处于两个子字符串之间的部分,裁切尽可能多的内容。 + /// 等效于 AfterLast 后接 BeforeFirst。 + /// 如果未找到子字符串则不裁切。 + /// + public static string Between(this string str, string after, string before, bool ignoreCase = false) + { + var startPos = string.IsNullOrEmpty(after) ? -1 : str.LastIndexOfF(after, ignoreCase); + if (startPos >= 0) + startPos += after.Length; + else + startPos = 0; + var endPos = string.IsNullOrEmpty(before) ? -1 : str.IndexOfF(before, startPos, ignoreCase); + if (endPos >= 0) return str.Substring(startPos, endPos - startPos); + + return startPos > 0 ? str[startPos..] : str; + } + + /// + /// 高速的 StartsWith。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool StartsWithF(this string str, string prefix, bool ignoreCase = false) + { + return str.StartsWith(prefix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + } + + /// + /// 高速的 EndsWith。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EndsWithF(this string str, string suffix, bool ignoreCase = false) + { + return str.EndsWith(suffix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + } + + /// + /// 支持可变大小写判断的 Contains。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsF(this string str, string subStr, bool ignoreCase = false) + { + return str.IndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0; + } + + /// + /// 高速的 IndexOf。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfF(this string str, string subStr, bool ignoreCase = false) + { + return str.IndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + } + + /// + /// 高速的 IndexOf。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfF(this string str, string subStr, int startIndex, bool ignoreCase = false) + { + return str.IndexOf(subStr, startIndex, + ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + } + + /// + /// 高速的 LastIndexOf。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOfF(this string str, string subStr, bool ignoreCase = false) + { + return str.LastIndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + } + + /// + /// 高速的 LastIndexOf。 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int LastIndexOfF(this string str, string subStr, int startIndex, bool ignoreCase = false) + { + return str.LastIndexOf(subStr, startIndex, + ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + } + + /// + /// 不会报错的 Val。 + /// 如果输入有误,返回 0。 + /// + public static double Val(object str) + { + try + { + return str is "&" ? 0d : Conversion.Val(str); + } + catch + { + return 0d; + } + } + + // 转义 + /// + /// 为字符串进行 XML 转义。 + /// + public static string EscapeXml(string str) + { + if (str.StartsWithF("{")) + str = "{}" + str; // #4187 + return str.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("'", "'") + .Replace("\"", """).Replace("\r\n", " "); + } + + /// + /// 为字符串进行 Like 关键字转义。 + /// + public static string EscapeLikePattern(string input) + { + var sb = new StringBuilder(); + foreach (var c in input) + switch (c) + { + case '[': + case ']': + case '*': + case '?': + case '#': + { + sb.Append('[').Append(c).Append(']'); + break; + } + + default: + { + sb.Append(c); + break; + } + } + + return sb.ToString(); + } + + // 正则 + /// + /// 搜索字符串中的所有正则匹配项。 + /// + public static List RegexSearch(this string str, string regex, RegexOptions options = RegexOptions.None) + { + List regexSearchRet; + try + { + regexSearchRet = []; + var regexSearchRes = new Regex(regex, options).Matches(str); + if (regexSearchRes is null) + return regexSearchRet; + foreach (Match item in regexSearchRes) + regexSearchRet.Add(item.Value); + } + catch (Exception ex) + { + Log(ex, "正则匹配全部项出错"); + return []; + } + + return regexSearchRet; + } + + /// + /// 搜索字符串中的所有正则匹配项。 + /// + /// 要搜索的字符串 + /// 正则表达式对象 + /// 所有匹配项的列表 + public static List RegexSearch(this string str, Regex regex) + { + try + { + var result = new List(); + foreach (Match item in regex.Matches(str)) result.Add(item.Value); + return result; + } + catch (Exception ex) + { + Log(ex, "正则匹配全部项出错"); + return []; + } + } + + /// + /// 获取字符串中的第一个正则匹配项,若无匹配则返回 Nothing。 + /// + public static string RegexSeek(this string str, string regex, RegexOptions options = RegexOptions.None) + { + try + { + var result = Regex.Match(str, regex, options).Value; + return string.IsNullOrEmpty(result) ? null : result; + } + catch (Exception ex) + { + Log(ex, "正则匹配第一项出错"); + return null; + } + } + + /// + /// 获取字符串中的第一个正则匹配项,若无匹配则返回 Nothing。 + /// + public static string RegexSeek(this string str, Regex regex, RegexOptions options = RegexOptions.None) + { + try + { + var result = regex.Match(str, (int)options).Value; + return string.IsNullOrEmpty(result) ? null : result; + } + catch (Exception ex) + { + Log(ex, "正则匹配第一项出错"); + return null; + } + } + + /// + /// 检查字符串是否匹配某正则模式。 + /// + public static bool RegexCheck(this string str, string regex, RegexOptions options = RegexOptions.None) + { + try + { + return Regex.IsMatch(str, regex, options); + } + catch (Exception ex) + { + Log(ex, "正则检查出错"); + return false; + } + } + + /// + /// 进行正则替换,会抛出错误。 + /// + public static string RegexReplace(this string allContents, string searchRegex, string replaceTo, + RegexOptions options = RegexOptions.None) + { + return Regex.Replace(allContents, searchRegex, replaceTo, options); + } + + /// + /// 对每个正则匹配分别进行替换,会抛出错误。 + /// + public static string RegexReplaceEach(this string allContents, string searchRegex, MatchEvaluator replaceTo, + RegexOptions options = RegexOptions.None) + { + return Regex.Replace(allContents, searchRegex, replaceTo, options); + } + + #endregion +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs new file mode 100644 index 000000000..6391a7ea6 --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs @@ -0,0 +1,274 @@ +using System.Drawing; +using System.IO; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Xaml; +using System.Xml.Linq; +using PCL.Core.App.Localization; +using Size = System.Windows.Size; + +namespace PCL; + +public static partial class ModBase +{ + #region UI + + public static void SetLaunchFont(string fontName = null) + { + try + { + LocalizationFontService.ApplyLaunchFont(fontName, LocalizationService.CurrentLanguage); + } + catch (Exception ex) + { + Log(ex, "设置字体失败", LogLevel.Hint); + } + } + + // 边距改变 + /// + /// 相对增减控件的左边距。 + /// + public static void DeltaLeft(FrameworkElement control, double newValue) + { + // 安全性检查 + DebugAssert(!double.IsNaN(newValue)); + DebugAssert(!double.IsInfinity(newValue)); + + if (control is Window window) + // 窗口改变 + window.Left += newValue; + else + // 根据 HorizontalAlignment 改变数值 + switch (control.HorizontalAlignment) + { + case HorizontalAlignment.Left: + case HorizontalAlignment.Stretch: + { + control.Margin = new Thickness(control.Margin.Left + newValue, control.Margin.Top, + control.Margin.Right, control.Margin.Bottom); + break; + } + case HorizontalAlignment.Right: + { + // control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, CType(control.Parent, Object).ActualWidth - control.ActualWidth - newValue, control.Margin.Bottom) + control.Margin = new Thickness(control.Margin.Left, control.Margin.Top, + control.Margin.Right - newValue, control.Margin.Bottom); + break; + } + + default: + { + DebugAssert(false); + break; + } + } + } + + /// + /// 设置控件的左边距。(仅针对置左控件) + /// + public static void SetLeft(FrameworkElement control, double newValue) + { + DebugAssert(control.HorizontalAlignment == HorizontalAlignment.Left); + control.Margin = new Thickness(newValue, control.Margin.Top, control.Margin.Right, control.Margin.Bottom); + } + + /// + /// 相对增减控件的上边距。 + /// + public static void DeltaTop(FrameworkElement control, double newValue) + { + // 安全性检查 + DebugAssert(!double.IsNaN(newValue)); + DebugAssert(!double.IsInfinity(newValue)); + + if (control is Window window) + // 窗口改变 + window.Top += newValue; + else + // 根据 VerticalAlignment 改变数值 + switch (control.VerticalAlignment) + { + case VerticalAlignment.Top: + { + control.Margin = new Thickness(control.Margin.Left, control.Margin.Top + newValue, + control.Margin.Right, control.Margin.Bottom); + break; + } + case VerticalAlignment.Bottom: + { + // control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, CType(control.Parent, Object).ActualWidth - control.ActualWidth - newValue, control.Margin.Bottom) + control.Margin = new Thickness(control.Margin.Left, control.Margin.Top, control.Margin.Right, + control.Margin.Bottom - newValue); + break; + } + + default: + { + DebugAssert(false); + break; + } + } + } + + /// + /// 设置控件的顶边距。(仅针对置上控件) + /// + public static void SetTop(FrameworkElement control, double newValue) + { + DebugAssert(control.VerticalAlignment == VerticalAlignment.Top); + control.Margin = new Thickness(control.Margin.Left, newValue, control.Margin.Right, control.Margin.Bottom); + } + + // DPI 转换 + public static readonly int dpi = (int)Math.Round(Graphics.FromHwnd(nint.Zero).DpiX); + + /// + /// 将经过 DPI 缩放的 WPF 尺寸转化为实际的像素尺寸。 + /// + public static double GetPixelSize(double wPFSize) + { + return wPFSize / 96d * dpi; + } + + /// + /// 将实际的像素尺寸转化为经过 DPI 缩放的 WPF 尺寸。 + /// + public static double GetWPFSize(double pixelSize) + { + return pixelSize * 96d / dpi; + } + + // UI 截图 + /// + /// 将某个控件的呈现转换为图片。 + /// + public static ImageBrush ControlBrush(FrameworkElement uI) + { + var width = uI.ActualWidth; + var height = uI.ActualHeight; + if (width < 1d || height < 1d) + return new ImageBrush(); + var bmp = new RenderTargetBitmap((int)Math.Round(GetPixelSize(width)), (int)Math.Round(GetPixelSize(height)), + dpi, dpi, PixelFormats.Pbgra32); + bmp.Render(uI); + return new ImageBrush(bmp); + } + + /// + /// 将某个控件的模拟呈现转换为图片。 + /// + public static ImageBrush ControlBrush(FrameworkElement uI, double width, double height, double left = 0d, + double top = 0d) + { + uI.Measure(new Size(width, height)); + uI.Arrange(new Rect(0d, 0d, width, height)); + var bmp = new RenderTargetBitmap((int)Math.Round(GetPixelSize(width)), (int)Math.Round(GetPixelSize(height)), + dpi, dpi, PixelFormats.Default); + bmp.Render(uI); + if (left != 0d || top != 0d) + uI.Arrange(new Rect(left, top, width, height)); + return new ImageBrush(bmp); + } + + /// + /// 将 UI 内容固定为图片并进行 Clear。 + /// + public static void ControlFreeze(Panel uI) + { + uI.Background = ControlBrush(uI); + uI.Children.Clear(); + } + + /// + /// 将 UI 内容固定为图片并进行 Clear。 + /// + public static void ControlFreeze(Border uI) + { + uI.Background = ControlBrush(uI); + uI.Child = null; + } + + /// + /// 将 XElement 转换为对应 UI 对象(不返回 XAML 清理结果)。 + /// + public static object GetObjectFromXML(XElement str) + { + return GetObjectFromXML(str.ToString()); + } + + /// + /// 将 XML 转换为对应 UI 对象。 + /// + public static object GetObjectFromXML(string str) + { + return GetObjectFromXML(str, out _); + } + + /// + /// 将 XML 转换为对应 UI 对象,并输出 XAML 清理结果。 + /// + public static object GetObjectFromXML(string str, out XamlEventSanitizer.SanitizeResult sanitizeResult) + { + str = str. // 兼容旧版自定义事件写法 + Replace("EventType=\"", "local:CustomEventService.EventType=\"") + .Replace("EventData=\"", "local:CustomEventService.EventData=\"") + .Replace("Property=\"EventType\"", "Property=\"local:CustomEventService.EventType\"") + .Replace("Property=\"EventData\"", "Property=\"local:CustomEventService.EventData\""); + // 修复因上述替换导致重复前缀的情况:local:CustomEventService.local:CustomEventService.EventType + str = str.Replace("local:CustomEventService.local:CustomEventService.", "local:CustomEventService."); + + sanitizeResult = XamlEventSanitizer.Sanitize(str); + str = sanitizeResult.SanitizedXaml; + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(str)); + // 类型检查 + using (var reader = new XamlXmlReader(stream)) + { + while (reader.Read()) + { + foreach (var blackListType in new[] + { + typeof(WebBrowser), typeof(Frame), typeof(MediaElement), typeof(ObjectDataProvider), + typeof(XamlReader), typeof(Window), typeof(XmlDataProvider) + }) + { + if (reader.Type is not null && blackListType.IsAssignableFrom(reader.Type.UnderlyingType)) + throw new UnauthorizedAccessException($"不允许使用 {blackListType.Name} 类型。"); + if (reader.Value is not null && Equals(reader.Value, blackListType.Name)) + throw new UnauthorizedAccessException($"不允许使用 {blackListType.Name} 值。"); + } + + foreach (var blackListMember in new[] { "Code", "FactoryMethod", "Static" }) + if (reader.Member is not null && (reader.Member.Name ?? "") == (blackListMember ?? "")) + throw new UnauthorizedAccessException($"不允许使用 {blackListMember} 成员。"); + } + } + + // 实际的加载 + stream.Position = 0L; + using (var writer = new StreamWriter(stream)) + { + writer.Write(str); + writer.Flush(); + stream.Position = 0L; + return System.Windows.Markup.XamlReader.Load(stream); + } + } + + private static readonly int uiThreadId = Environment.CurrentManagedThreadId; + + /// + /// 当前线程是否为主线程。 + /// + public static bool RunInUi() + { + return Environment.CurrentManagedThreadId == uiThreadId; + } + + #endregion +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/FormMain.xaml.cs b/Plain Craft Launcher 2/FormMain.xaml.cs index cb860d251..fd1f3d04f 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.cs +++ b/Plain Craft Launcher 2/FormMain.xaml.cs @@ -46,7 +46,7 @@ private void ShowUpdateLog() else changelog = Lang.Text("Main.UpdateLog.Empty"); if (ModMain.MyMsgBoxMarkdown(changelog, - Lang.Text("Main.UpdateLog.Title", ModBase.versionBranchName, ModBase.versionBaseName), Lang.Text("Common.Action.Confirm"), Lang.Text("Main.UpdateLog.FullChangelog")) == + Lang.Text("Main.UpdateLog.Title", ModBase.VersionBranchName, ModBase.VersionBaseName), Lang.Text("Common.Action.Confirm"), Lang.Text("Main.UpdateLog.FullChangelog")) == 2) ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases"); }, "UpdateLog Output"); } @@ -69,7 +69,7 @@ public FormMain() ModMain.frmLaunchRight = new PageLaunchRight(); // 版本号改变 var lastVersion = States.System.LastVersion; - if (lastVersion < ModBase.versionCode) + if (lastVersion < ModBase.VersionCode) { // 重新询问是否启用遥测数据收集 if (lastVersion <= 511) @@ -83,7 +83,7 @@ public FormMain() // 触发升级 UpgradeSub(lastVersion); } - else if (lastVersion > ModBase.versionCode) + else if (lastVersion > ModBase.VersionCode) // 触发降级 DowngradeSub(lastVersion); @@ -314,8 +314,8 @@ private void RunCountSub() // 升级与降级事件 private void UpgradeSub(int lastVersionCode) { - ModBase.Log("[Start] 版本号从 " + lastVersionCode + " 升高到 " + ModBase.versionCode); - States.System.LastVersion = ModBase.versionCode; + ModBase.Log("[Start] 版本号从 " + lastVersionCode + " 升高到 " + ModBase.VersionCode); + States.System.LastVersion = ModBase.VersionCode; // 检查有记录的最高版本号 int lowerVersionCode; #if BETA @@ -327,10 +327,10 @@ private void UpgradeSub(int lastVersionCode) } #else lowerVersionCode = States.System.LastAlphaVersion; - if (lowerVersionCode < ModBase.versionCode) + if (lowerVersionCode < ModBase.VersionCode) { - States.System.LastAlphaVersion = ModBase.versionCode; - ModBase.Log($"[Start] 最高版本号从 {lowerVersionCode} 升高到 {ModBase.versionCode}"); + States.System.LastAlphaVersion = ModBase.VersionCode; + ModBase.Log($"[Start] 最高版本号从 {lowerVersionCode} 升高到 {ModBase.VersionCode}"); } #endif // 被移除的窗口设置选项 (Commit 3161488 2026/1/23) @@ -342,15 +342,15 @@ private void UpgradeSub(int lastVersionCode) // 输出更新日志 if (lastVersionCode <= 0) return; - if (lowerVersionCode >= ModBase.versionCode) + if (lowerVersionCode >= ModBase.VersionCode) return; ShowUpdateLog(); } private void DowngradeSub(int lastVersionCode) { - ModBase.Log("[Start] 版本号从 " + lastVersionCode + " 降低到 " + ModBase.versionCode); - States.System.LastVersion = ModBase.versionCode; + ModBase.Log("[Start] 版本号从 " + lastVersionCode + " 降低到 " + ModBase.VersionCode); + States.System.LastVersion = ModBase.VersionCode; } #endregion diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.cs b/Plain Craft Launcher 2/Modules/Base/ModBase.cs deleted file mode 100644 index 1860d016b..000000000 --- a/Plain Craft Launcher 2/Modules/Base/ModBase.cs +++ /dev/null @@ -1,3759 +0,0 @@ -using System.Collections; -using System.Collections.Concurrent; -using System.ComponentModel; -using System.Diagnostics; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Threading; -using System.Xaml; -using System.Xml.Linq; -using Microsoft.VisualBasic; -using PCL.Core.App; -using PCL.Core.App.Localization; -using PCL.Core.IO; -using PCL.Core.Logging; -using PCL.Core.Utils; -using PCL.Core.Utils.Codecs; -using PCL.Core.Utils.Hash; -using PCL.Core.Utils.OS; -using Brush = System.Windows.Media.Brush; -using Color = System.Windows.Media.Color; -using ColorConverter = System.Windows.Media.ColorConverter; -using Size = System.Windows.Size; - -namespace PCL; - -public static class ModBase -{ - #region 声明 - - // 下列版本信息由更新器自动修改 - public static readonly string versionBaseName = Basics.VersionName; - public static readonly string versionStandardCode = Basics.Metadata.Version.StandardVersion; - public static readonly string upstreamVersion = Basics.Metadata.Version.UpstreamVersion; - public static readonly string commitHash = Basics.Metadata.Version.Commit; - public static readonly string commitHashShort = Basics.Metadata.Version.CommitDigest; - public static readonly int versionCode = Basics.VersionCode; - -#if DEBUG - public const string versionBranchName = "Debug"; - public const string versionBranchCode = "100"; -#elif DEBUGCI - public const string versionBranchName = "CI"; - public const string versionBranchCode = "50"; -#else - public const string versionBranchName = "Publish"; - public const string versionBranchCode = "0"; -#endif - /// - /// 主窗口句柄。 - /// - public static nint frmHandle; - - // 龙猫味石山小记: 用最不靠谱的实现写出能跑的代码 (AppDomain.CurrentDomain.SetupInformation.ApplicationBase 获取到的是当前工作目录而不是可执行文件所在目录) - /// - /// 程序可执行文件所在目录,以“\”结尾。 - /// - public static readonly string exePath = (Basics.ExecutableDirectory.EndsWith(@"\") - ? Basics.ExecutableDirectory - : Basics.ExecutableDirectory + @"\"); - - /// - /// 程序内嵌图片文件夹路径,以“/”结尾。 - /// - public static readonly string pathImage = "pack://application:,,,/Plain Craft Launcher 2;component/Images/"; - - /// - /// 当前程序的语言。 - /// - public static string currentLang = "zh_CN"; - - /// - /// 设置对象。 - /// - public static ModSetup setup = new(); - - /// - /// 程序的打开计时。 - /// - public static long applicationStartTick = TimeUtils.GetTimeTick(); - - /// - /// 程序打开时的时间。 - /// - public static DateTime applicationOpenTime = DateTime.Now; - - /// - /// 程序是否已结束。 - /// - public static bool isProgramEnded = false; - - /// - /// 程序的缓存文件夹路径,以 \ 结尾。 - /// - public static string pathTemp = Paths.Temp + @"\"; - - /// - /// AppData 中的 PCL 文件夹路径,以 \ 结尾。 - /// - public static string pathAppdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PCL") + @"\"; - - /// - /// AppData 中的 PCLCE 配置文件夹路径,以 \ 结尾。 - /// - public static string pathAppdataConfig = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - (versionBranchName == "Debug" ? @"\.pclcedebug\" : @"\.pclce\"); - - - #endregion - - #region 自定义类 - - /// - /// 支持小数与常见类型隐式转换的颜色。 - /// - public class MyColor - { - public double a = 255d; - public double b; - public double g; - public double r; - - // 构造函数 - public MyColor() - { - } - - public MyColor(Color col) - { - a = col.A; - r = col.R; - g = col.G; - b = col.B; - } - - public MyColor(string hexString) - { - var stringColor = (Color)ColorConverter.ConvertFromString(hexString); - a = stringColor.A; - r = stringColor.R; - g = stringColor.G; - b = stringColor.B; - } - - public MyColor(double newA, MyColor col) - { - a = newA; - r = col.r; - g = col.g; - b = col.b; - } - - public MyColor(double newR, double newG, double newB) - { - a = 255d; - r = newR; - g = newG; - b = newB; - } - - public MyColor(double newA, double newR, double newG, double newB) - { - a = newA; - r = newR; - g = newG; - b = newB; - } - - public MyColor(Brush brush) - { - var color = ((SolidColorBrush)brush).Color; - a = color.A; - r = color.R; - g = color.G; - b = color.B; - } - - public MyColor(SolidColorBrush brush) - { - var color = brush.Color; - a = color.A; - r = color.R; - g = color.G; - b = color.B; - } - - public MyColor(object obj) - { - if (obj is null) - { - a = 255d; - r = 255d; - g = 255d; - b = 255d; - } - else if (obj is SolidColorBrush) - { - // 避免反复获取 Color 对象造成性能下降 - var color = ((SolidColorBrush)obj).Color; - a = color.A; - r = color.R; - g = color.G; - b = color.B; - } - else - { - a = Convert.ToDouble(((dynamic)obj).A); - r = Convert.ToDouble(((dynamic)obj).R); - g = Convert.ToDouble(((dynamic)obj).G); - b = Convert.ToDouble(((dynamic)obj).B); - } - } - - // 类型转换 - public static implicit operator MyColor(string str) - { - return new MyColor(str); - } - - public static implicit operator MyColor(Color col) - { - return new MyColor(col); - } - - public static implicit operator Color(MyColor conv) - { - return Color.FromArgb(MathByte(conv.a), MathByte(conv.r), MathByte(conv.g), MathByte(conv.b)); - } - - public static implicit operator System.Drawing.Color(MyColor conv) - { - return System.Drawing.Color.FromArgb(MathByte(conv.a), MathByte(conv.r), MathByte(conv.g), - MathByte(conv.b)); - } - - public static implicit operator MyColor(SolidColorBrush bru) - { - return new MyColor(bru.Color); - } - - public static implicit operator SolidColorBrush(MyColor conv) - { - return new SolidColorBrush(Color.FromArgb(MathByte(conv.a), MathByte(conv.r), MathByte(conv.g), - MathByte(conv.b))); - } - - public static implicit operator MyColor(Brush bru) - { - return new MyColor(bru); - } - - public static implicit operator Brush(MyColor conv) - { - return new SolidColorBrush(Color.FromArgb(MathByte(conv.a), MathByte(conv.r), MathByte(conv.g), - MathByte(conv.b))); - } - - // 颜色运算 - public static MyColor operator +(MyColor a, MyColor b) - { - return new MyColor { a = a.a + b.a, b = a.b + b.b, g = a.g + b.g, r = a.r + b.r }; - } - - public static MyColor operator -(MyColor a, MyColor b) - { - return new MyColor { a = a.a - b.a, b = a.b - b.b, g = a.g - b.g, r = a.r - b.r }; - } - - public static MyColor operator *(MyColor a, double b) - { - return new MyColor { a = a.a * b, b = a.b * b, g = a.g * b, r = a.r * b }; - } - - public static MyColor operator /(MyColor a, double b) - { - return new MyColor { a = a.a / b, b = a.b / b, g = a.g / b, r = a.r / b }; - } - - public static bool operator ==(MyColor a, MyColor b) - { - if (a is null && b is null) - return true; - if (a is null || b is null) - return false; - return a.a == b.a && a.r == b.r && a.g == b.g && a.b == b.b; - } - - public static bool operator !=(MyColor a, MyColor b) - { - if (a is null && b is null) - return false; - if (a is null || b is null) - return true; - return !(a.a == b.a && a.r == b.r && a.g == b.g && a.b == b.b); - } - - // HSL - public double Hue(double v1, double v2, double vH) - { - if (vH < 0d) - vH += 1d; - if (vH > 1d) - vH -= 1d; - if (vH < 0.16667d) - return v1 + (v2 - v1) * 6d * vH; - if (vH < 0.5d) - return v2; - if (vH < 0.66667d) - return v1 + (v2 - v1) * (4d - vH * 6d); - return v1; - } - - public MyColor FromHSL(double sH, double sS, double sL) - { - if (sS == 0d) - { - r = sL * 2.55d; - g = r; - b = r; - } - else - { - var h = sH / 360d; - var s = sS / 100d; - var l = sL / 100d; - s = l < 0.5d ? s * l + l : s * (1.0d - l) + l; - l = 2d * l - s; - r = 255d * Hue(l, s, h + 1d / 3d); - g = 255d * Hue(l, s, h); - b = 255d * Hue(l, s, h - 1d / 3d); - } - - a = 255d; - return this; - } - - public MyColor FromHSL2(double sH, double sS, double sL) - { - if (sS == 0d) - { - r = sL * 2.55d; - g = r; - b = r; - } - else - { - // 初始化 - sH = (sH + 3600000d) % 360d; - var cent = new[] - { - +0.1d, -0.06d, -0.3d, -0.19d, -0.15d, -0.24d, -0.32d, -0.09d, +0.18d, +0.05d, -0.12d, -0.02d, +0.1d, - -0.06d - }; // 0, 30, 60 - // 90, 120, 150 - // 180, 210, 240 - // 270, 300, 330 - // 最后两位与前两位一致,加是变亮,减是变暗 - // 计算色调对应的亮度片区 - var center = sH / 30.0d; - var intCenter = (int)Math.Round(Math.Floor(center)); // 亮度片区编号 - center = 50d - - ((1d - center + intCenter) * cent[intCenter] + (center - intCenter) * cent[intCenter + 1]) * - sS; - // center = 50 + (cent(intCenter) + (center - intCenter) * (cent(intCenter + 1) - cent(intCenter))) * sS - sL = (sL < center ? sL / center : 1d + (sL - center) / (100d - center)) * 50d; - FromHSL(sH, sS, sL); - } - - a = 255d; - return this; - } - - public MyColor Alpha(double sA) - { - a = sA; - return this; - } - - public override string ToString() - { - return "(" + a + "," + r + "," + g + "," + b + ")"; - } - - public override bool Equals(object obj) - { - return obj is MyColor other && a == other.a && r == other.r && g == other.g && b == other.b; - } - } - - /// - /// 支持负数与浮点数的矩形。 - /// - public class MyRect - { - // 构造函数 - public MyRect() - { - } - - public MyRect(double left, double top, double width, double height) - { - Left = left; - Top = top; - Width = width; - Height = height; - } - - // 属性 - public double Width { get; set; } - public double Height { get; set; } - public double Left { get; set; } - public double Top { get; set; } - } - - /// - /// 模块加载状态枚举。 - /// - public enum LoadState - { - Waiting, - Loading, - Finished, - Failed, - Aborted - } - - /// - /// 执行返回值。 - /// - public enum ProcessReturnValues - { - /// - /// 执行成功,或进程被中断。 - /// - Aborted = -1, - - /// - /// 执行成功。 - /// - Success = 0, - - /// - /// 执行失败。 - /// - Fail = 1, - - /// - /// 执行时出现未经处理的异常。 - /// - Exception = 2, - - /// - /// 执行超时。 - /// - Timeout = 3, - - /// - /// 取消执行。可能是由于不满足执行的前置条件。 - /// - Cancel = 4, - - /// - /// 任务成功完成。 - /// - TaskDone = 5 - } - - /// - /// 可以使用 Equals 和等号的 List。 - /// - public class EqualableList : List - { - public override bool Equals(object obj) - { - if (obj as List is null) - // 类型不同 - return false; - - // 类型相同 - var objList = (List)obj; - if (objList.Count != Count) - return false; - for (int i = 0, loopTo = objList.Count - 1; i <= loopTo; i++) - if (!objList[i].Equals(this[i])) - return false; - return true; - } - - public static bool operator ==(EqualableList left, EqualableList right) - { - return EqualityComparer>.Default.Equals(left, right); - } - - public static bool operator !=(EqualableList left, EqualableList right) - { - return !(left == right); - } - } - - #endregion - - #region 数学 - - /// - /// 2~65 进制的转换。 - /// - public static string RadixConvert(string input, int fromRadix, int toRadix) - { - const string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+="; - // 零与负数的处理 - if (string.IsNullOrEmpty(input)) - return "0"; - var isNegative = input.StartsWithF("-"); - if (isNegative) - input = input.TrimStart('-'); - // 转换为十进制 - var realNum = 0L; - var scale = 1L; - foreach (var digit in input.Reverse().Select(l => digits.IndexOfF(l.ToString()))) - { - realNum += digit * scale; - scale *= fromRadix; - } - - // 转换为指定进制 - var result = ""; - while (realNum > 0L) - { - var newNum = (int)(realNum % toRadix); - realNum = (long)Math.Round((realNum - newNum) / (double)toRadix); - result = digits[newNum] + result; - } - - // 负数的结束处理与返回 - return (isNegative ? "-" : "") + result; - } - - /// - /// 计算二阶贝塞尔曲线。 - /// - public static double MathBezier(double x, double x1, double y1, double x2, double y2, double acc = 0.01d) - { - if (x <= 0d || double.IsNaN(x)) return 0d; - if (x >= 1d) return 1d; - double a, b; - a = x; - do - { - b = 3 * a * ((0.33333333 + x1 - x2) * a * a + (x2 - 2 * x1) * a + x1); - a += (x - b) * 0.5; - } while (!(Math.Abs(b - x) < acc)); // 精度 - - return 3 * a * ((0.33333333 + y1 - y2) * a * a + (y2 - 2 * y1) * a + y1); - } - - /// - /// 将一个数字限制为 0~255 的 Byte 值。 - /// - public static byte MathByte(double d) - { - if (d < 0d) - d = 0d; - if (d > 255d) - d = 255d; - return (byte)Math.Round(Math.Round(d)); - } - - /// - /// 提供 MyColor 类型支持的 Math.Round。 - /// - public static MyColor MathRound(MyColor col, int w = 0) - { - return new MyColor - { a = Math.Round(col.a, w), r = Math.Round(col.r, w), g = Math.Round(col.g, w), b = Math.Round(col.b, w) }; - } - - /// - /// 获取两数间的百分比。小数点精确到 6 位。 - /// - /// - public static double MathPercent(double valueA, double valueB, double percent) - { - return Math.Round(valueA * (1d - percent) + valueB * percent, 6); // 解决 Double 计算错误 - } - - /// - /// 获取两颜色间的百分比,根据 RGB 计算。小数点精确到 6 位。 - /// - public static MyColor MathPercent(MyColor valueA, MyColor valueB, double percent) - { - return MathRound(valueA * (1d - percent) + valueB * percent, 6); // 解决Double计算错误 - } - - /// - /// 将数值限定在某个范围内。 - /// - public static double MathClamp(double value, double min, double max) - { - return Math.Max(min, Math.Min(max, value)); - } - - /// - /// 符号函数。 - /// - public static int MathSgn(double value) - { - if (value == 0d) return 0; - - if (value > 0d) return 1; - - return -1; - } - - #endregion - - #region 文件 - - // ============================= - // ini - // ============================= - - private static readonly ConcurrentDictionary> iniCache = new(); - - /// - /// 清除某 ini 文件的运行时缓存。 - /// - /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 - public static void IniClearCache(string fileName) - { - if (!fileName.Contains(@":\")) - fileName = $@"{exePath}PCL\{fileName}.ini"; - if (iniCache.ContainsKey(fileName)) - iniCache.Remove(fileName, out _); - } - - /// - /// 获取 ini 文件缓存。如果没有,则新读取 ini 文件内容。 - /// 在文件不存在或读取失败时返回 Nothing。 - /// - /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 - private static ConcurrentDictionary IniGetContent(string fileName) - { - try - { - // 还原文件路径 - if (!fileName.Contains(@":\")) - fileName = $@"{exePath}PCL\{fileName}.ini"; - // 检索缓存 - if (iniCache.ContainsKey(fileName)) - return iniCache[fileName]; - // 读取文件 - if (!File.Exists(fileName)) - return null; - var ini = new ConcurrentDictionary(); - foreach (var line in ReadFile(fileName) - .Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries)) - { - var index = line.IndexOfF(":"); - if (index > 0) - ini[line.Substring(0, index)] = line.Substring(index + 1); // 可能会有重复键,见 #3616 - } - - iniCache[fileName] = ini; - return ini; - } - catch (Exception ex) - { - Log(ex, $"生成 ini 文件缓存失败({fileName})", LogLevel.Hint); - return null; - } - } - - /// - /// 读取 ini 文件。这可能会使用到缓存。 - /// - /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 - /// 键。 - /// 没有找到键时返回的默认值。 - public static string ReadIni(string fileName, string key, string defaultValue = "") - { - var content = IniGetContent(fileName); - if (content is null || !content.ContainsKey(key)) - return defaultValue; - return content[key]; - } - - /// - /// 判断 ini 文件中是否包含某个键。这可能会使用到缓存。 - /// - public static bool HasIniKey(string fileName, string key) - { - var content = IniGetContent(fileName); - return content is not null && content.ContainsKey(key); - } - - /// - /// 从 ini 文件中移除某个键。这会更新缓存。 - /// - public static void DeleteIniKey(string fileName, string key) - { - WriteIni(fileName, key, null); - } - - /// - /// 写入 ini 文件,这会更新缓存。 - /// 若 Value 为 Nothing,则删除该键。 - /// - /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 - /// 键。 - /// 值。 - /// - public static void WriteIni(string fileName, string key, string value) - { - try - { - // 预处理 - if (key.Contains(":")) - throw new Exception($"尝试写入 ini 文件 {fileName} 的键名中包含了冒号:{key}"); - key = key.Replace("\r", "").Replace("\n", ""); - value = value?.Replace("\r", "").Replace("\n", ""); - // 防止争用 - lock (writeIniLock) - { - // 获取目前文件 - var content = IniGetContent(fileName); - if (content is null) - content = new ConcurrentDictionary(); - // 更新值 - if (value is null) - { - if (!content.ContainsKey(key)) - return; // 无需处理 - content.Remove(key, out _); - } - else - { - if (content.ContainsKey(key) && (content[key] ?? "") == (value ?? "")) - return; // 无需处理 - content[key] = value; - } - - // 写入文件 - var fileContent = new StringBuilder(); - foreach (var pair in content) - { - fileContent.Append(pair.Key); - fileContent.Append(":"); - fileContent.Append(pair.Value); - fileContent.Append("\r\n"); - } - - if (!fileName.Contains(@":\")) - fileName = $@"{exePath}PCL\{fileName}.ini"; - WriteFile(fileName, fileContent.ToString()); - } - } - catch (Exception ex) - { - Log(ex, $"写入文件失败({fileName} → {key}:{value})", LogLevel.Hint); - } - } - - private static readonly object writeIniLock = new(); - - // 路径处理 - /// - /// 从文件路径或者 Url 获取不包含文件名的路径,或获取文件夹的父文件夹路径。 - /// 取决于原路径格式,路径以 / 或 \ 结尾。 - /// 不包含路径将会抛出异常。 - /// - public static string GetPathFromFullPath(string filePath) - { - string getPathFromFullPathRet = default; - if (!(filePath.Contains(@"\") || filePath.Contains("/"))) - throw new Exception("不包含路径:" + filePath); - if (filePath.EndsWithF(@"\") || filePath.EndsWithF("/")) - { - // 是文件夹路径 - var isRight = filePath.EndsWithF(@"\"); - filePath = filePath.Substring(0, filePath.Length - 1); - getPathFromFullPathRet = filePath.Substring(0, filePath.LastIndexOfAny(new[] { '\\', '/' })) + - (isRight ? @"\" : "/"); - } - else - { - // 是文件路径 - getPathFromFullPathRet = filePath.Substring(0, filePath.LastIndexOfAny(new[] { '\\', '/' }) + 1); - if (string.IsNullOrEmpty(getPathFromFullPathRet)) - throw new Exception("不包含路径:" + filePath); - } - - return getPathFromFullPathRet; - } - - /// - /// 从文件路径或者 Url 获取不包含路径的文件名。不包含文件名将会抛出异常。 - /// - public static string GetFileNameFromPath(string filePath) - { - filePath = filePath.Replace("/", @"\"); - if (filePath.EndsWithF(@"\")) - throw new Exception("不包含文件名:" + filePath); - if (filePath.Contains("?")) - filePath = filePath.Substring(0, filePath.IndexOfF("?")); // 去掉网络参数后的 ? - if (filePath.Contains(@"\")) - filePath = filePath.Substring(filePath.LastIndexOfF(@"\") + 1); - var length = filePath.Length; - if (length == 0) - throw new Exception("不包含文件名:" + filePath); - if (length > 250) - throw new PathTooLongException("文件名过长:" + filePath); - return filePath; - } - - /// - /// 从文件路径或者 Url 获取不包含路径与扩展名的文件名。不包含文件名将会抛出异常。 - /// - public static string GetFileNameWithoutExtentionFromPath(string filePath) - { - return Path.GetFileNameWithoutExtension(filePath); - } - - /// - /// 从文件夹路径获取文件夹名。 - /// - public static string GetFolderNameFromPath(string folderPath) - { - if (folderPath.EndsWithF(@":\") || folderPath.EndsWithF(@":\\")) - return folderPath.Substring(0, 1); - if (folderPath.EndsWithF(@"\") || folderPath.EndsWithF("/")) - folderPath = folderPath.Substring(0, folderPath.Length - 1); - return GetFileNameFromPath(folderPath); - } - - // 读取、写入、复制文件 - /// - /// 复制文件。会自动创建文件夹、会覆盖已有的文件。 - /// - public static void CopyFile(string fromPath, string toPath) - { - try - { - // 还原文件路径 - if (!fromPath.Contains(@":\")) - fromPath = exePath + fromPath; - if (!toPath.Contains(@":\")) - toPath = exePath + toPath; - // 如果复制同一个文件则跳过 - if ((fromPath ?? "") == (toPath ?? "")) - return; - // 确保目录存在 - Directory.CreateDirectory(GetPathFromFullPath(toPath)); - // 复制文件 - File.Copy(fromPath, toPath, true); - } - catch (Exception ex) - { - throw new Exception("复制文件出错:" + fromPath + " → " + toPath, ex); - } - } - - /// - /// 读取文件,如果失败则返回空数组。 - /// - public static byte[] ReadFileBytes(string filePath, Encoding encoding = null) - { - try - { - // 还原文件路径 - if (!filePath.Contains(@":\")) - filePath = exePath + filePath; - if (File.Exists(filePath)) - using (var readStream = - new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - using (var ms = new MemoryStream()) - { - readStream.CopyTo(ms); - return ms.ToArray(); - } - } - - Log("[System] 欲读取的文件不存在,已返回空内容:" + filePath); - return Array.Empty(); - } - catch (Exception ex) - { - Log(ex, "读取文件出错:" + filePath); - return Array.Empty(); - } - } - - /// - /// 读取文件,如果失败则返回空字符串。 - /// - /// 文件完整或相对路径。 - public static string ReadFile(string filePath, Encoding encoding = null) - { - string readFileRet = default; - var fileBytes = ReadFileBytes(filePath); - readFileRet = encoding is null ? DecodeBytes(fileBytes) : encoding.GetString(fileBytes); - return readFileRet; - } - - /// - /// 读取流中的所有文本。 - /// - public static string ReadFile(Stream stream, Encoding encoding = null) - { - try - { - var readedContent = new MemoryStream(); - stream.CopyTo(readedContent); - var bts = readedContent.ToArray(); - return (encoding ?? EncodingDetector.DetectEncoding(bts)).GetString(bts); - } - catch (Exception ex) - { - Log(ex, "读取流出错"); - return ""; - } - } - - /// - /// 写入文件。 - /// - /// 文件完整或相对路径。 - /// 文件内容。 - /// 是否将文件内容追加到当前文件,而不是覆盖它。 - public static void WriteFile(string filePath, string text, bool append = false, Encoding? encoding = null) - { - // 处理相对路径 - if (!filePath.Contains(@":\")) - filePath = exePath + filePath; - // 确保目录存在 - Directory.CreateDirectory(GetPathFromFullPath(filePath)); - // 写入文件 - if (append) - // 追加目前文件 - using (var writer = new StreamWriter(filePath, true, - encoding ?? EncodingDetector.DetectEncoding(ReadFileBytes(filePath)))) - { - writer.Write(text); - } - else - { - // 直接写入字节 - var bytes = encoding is null ? new UTF8Encoding(false).GetBytes(text) : encoding.GetBytes(text); - var tempPath = filePath + ".pcltmp." + Guid.NewGuid().ToString("N"); - File.WriteAllBytes(tempPath, bytes); - File.Move(tempPath, filePath, true); - } - } - - /// - /// 写入文件。 - /// 如果 CanThrow 设置为 False,返回是否写入成功。 - /// - /// 文件完整或相对路径。 - /// 文件内容。 - /// 是否将文件内容追加到当前文件,而不是覆盖它。 - public static void WriteFile(string filePath, byte[] content, bool append = false) - { - // 处理相对路径 - if (!filePath.Contains(@":\")) - filePath = exePath + filePath; - // 确保目录存在 - Directory.CreateDirectory(GetPathFromFullPath(filePath)); - // 写入文件 - File.WriteAllBytes(filePath, content); - } - - /// - /// 将流写入文件。 - /// - /// 文件完整或相对路径。 - public static bool WriteFile(string filePath, Stream stream) - { - try - { - // 还原文件路径 - if (!filePath.Contains(@":\")) - filePath = exePath + filePath; - // 确保目录存在 - Directory.CreateDirectory(GetPathFromFullPath(filePath)); - // 读取流 - using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read)) - { - fs.SetLength(0L); - stream.CopyTo(fs); - } - - return true; - } - catch (Exception ex) - { - Log(ex, "保存流出错"); - return false; - } - } - - /// - /// 解码 Bytes。 - /// - public static string DecodeBytes(byte[] bytes) - { - var length = bytes.Length; - if (length < 3) - return Encoding.UTF8.GetString(bytes); - // 根据 BOM 判断编码 - if (bytes[0] >= 0xEF) - { - // 有 BOM 类型 - if (bytes[0] == 0xEF && bytes[1] == 0xBB) return Encoding.UTF8.GetString(bytes, 3, length - 3); - - if (bytes[0] == 0xFE && bytes[1] == 0xFF) return Encoding.BigEndianUnicode.GetString(bytes, 3, length - 3); - - if (bytes[0] == 0xFF && bytes[1] == 0xFE) return Encoding.Unicode.GetString(bytes, 3, length - 3); - - return Encoding.GetEncoding("GB18030").GetString(bytes, 3, length - 3); - } - - // 无 BOM 文件:GB18030(ANSI)或 UTF8 - var uTF8 = Encoding.UTF8.GetString(bytes); - var errorChar = Encoding.UTF8.GetString(new[] { (byte)239, (byte)191, (byte)189 }).ToCharArray()[0]; - if (uTF8.Contains(errorChar)) return Encoding.GetEncoding("GB18030").GetString(bytes); - - return uTF8; - } - - public static object GetHexString(Memory bytes) - { - var sb = new StringBuilder(bytes.Length * 2); - foreach (var c in bytes.Span) - sb.Append(c.ToString("x2")); - - return sb.ToString(); - } - - // 文件校验 - /// - /// 获取文件 MD5,若失败则返回空字符串。 - /// - public static string GetFileMD5(string filePath) - { - var retry = false; - Re: ; - - try - { - // 获取 MD5 - using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - return (string)GetHexString(MD5Provider.Instance.ComputeHash(fs)); - } - } - catch (Exception ex) - { - if (retry || ex is FileNotFoundException) - { - Log(ex, "获取文件 MD5 失败:" + filePath); - return ""; - } - - retry = true; - Log(ex, "获取文件 MD5 可重试失败:" + filePath, LogLevel.Normal); - Thread.Sleep(RandomUtils.NextInt(200, 500)); - goto Re; - } - } - - /// - /// 获取文件 SHA512,若失败则返回空字符串。 - /// - public static string GetFileSHA512(string filePath) - { - var retry = false; - Re: ; - - try - { - // '检测该文件是否在下载中,若在下载则放弃检测 - // If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return "" - // 获取 SHA512 - using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - return (string)GetHexString(SHA512Provider.Instance.ComputeHash(fs)); - } - } - catch (Exception ex) - { - if (retry || ex is FileNotFoundException) - { - Log(ex, "获取文件 SHA512 失败:" + filePath); - return ""; - } - - retry = true; - Log(ex, "获取文件 SHA512 可重试失败:" + filePath, LogLevel.Normal); - Thread.Sleep(RandomUtils.NextInt(200, 500)); - goto Re; - } - } - - /// - /// 获取文件 SHA256,若失败则返回空字符串。 - /// - public static string GetFileSHA256(string filePath) - { - var retry = false; - Re: ; - - try - { - // '检测该文件是否在下载中,若在下载则放弃检测 - // If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return "" - // 获取 SHA256 - using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - return (string)GetHexString(SHA256Provider.Instance.ComputeHash(fs)); - } - } - catch (Exception ex) - { - if (retry || ex is FileNotFoundException) - { - Log(ex, "获取文件 SHA256 失败:" + filePath); - return ""; - } - - retry = true; - Log(ex, "获取文件 SHA256 可重试失败:" + filePath, LogLevel.Normal); - Thread.Sleep(RandomUtils.NextInt(200, 500)); - goto Re; - } - } - - /// - /// 获取文件 SHA1,若失败则返回空字符串。 - /// - public static string GetFileSHA1(string filePath) - { - var retry = false; - Re: ; - - try - { - // 获取 SHA1 - using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - return (string)GetHexString(SHA1Provider.Instance.ComputeHash(fs)); - } - } - catch (Exception ex) - { - if (retry || ex is FileNotFoundException) - { - Log(ex, "获取文件 SHA1 失败:" + filePath); - return ""; - } - - retry = true; - Log(ex, "获取文件 SHA1 可重试失败:" + filePath, LogLevel.Normal); - Thread.Sleep(RandomUtils.NextInt(200, 500)); - goto Re; - } - } - - /// - /// 获取流的 SHA1,若失败则返回空字符串。 - /// - public static string GetAuthSHA1(Stream inputStream) - { - try - { - return (string)GetHexString(SHA1Provider.Instance.ComputeHash(inputStream)); - } - catch (Exception ex) - { - Log(ex, "获取流 SHA1 失败"); - return ""; - } - } - - /// - /// 文件的校验规则。 - /// - public class FileChecker - { - /// - /// 文件的准确大小。 - /// 不检查则为 -1。 - /// - public long actualSize = -1; - - /// - /// 是否可以使用已经存在的文件。 - /// - public bool canUseExistsFile = true; - - /// - /// 文件的 MD5、SHA1 或 SHA256。会根据输入字符串的长度自动判断种类。 - /// 不检查则为 Nothing。 - /// - public string hash; - - /// - /// 是否要求为 JSON 文件。 - /// 即,开头结尾必须为 {} 或 []。 - /// - public bool isJson; - - /// - /// 文件的最小大小。 - /// 不检查则为 -1。 - /// - public long minSize = -1; - - public FileChecker(long minSize = -1, long actualSize = -1, string hash = null, bool canUseExistsFile = true, - bool isJson = false) - { - this.actualSize = actualSize; - this.minSize = minSize; - this.hash = hash; - this.canUseExistsFile = canUseExistsFile; - this.isJson = isJson; - } - - /// - /// 检查文件。若成功则返回 Nothing,失败则返回错误的描述文本,描述文本不以句号结尾。不会抛出错误。 - /// - public string Check(string localPath) - { - try - { - Log($"[Checker] 开始校验文件 {localPath}", LogLevel.Developer); - var info = new FileInfo(localPath); - if (!info.Exists) - return "文件不存在:" + localPath; - var fileSize = info.Length; - var errorMessage = new List(); - var allowIgnore = false; // 允许相信哈希正确但是大小不正确 - if (!string.IsNullOrEmpty(hash)) - { - if (hash.Length < 35) // MD5 - { - var computedHash = GetFileMD5(localPath); - if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) - errorMessage.Add("文件 MD5 应为 " + hash + ",实际为 " + computedHash); - } - else if (hash.Length == 64) // SHA256 - { - var computedHash = GetFileSHA256(localPath); - if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) - errorMessage.Add("文件 SHA256 应为 " + hash + ",实际为 " + computedHash); - } - else // SHA1 (40) - { - var computedHash = GetFileSHA1(localPath); - if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) - errorMessage.Add("文件 SHA1 应为 " + hash + ",实际为 " + computedHash); - } - - allowIgnore = errorMessage.Count == 0; - } - - if (actualSize >= 0L && actualSize != fileSize && !allowIgnore) // 不允许忽略大小不正确的情况 - errorMessage.Add($"文件大小应为 {actualSize} B,实际为 {fileSize} B" + - (fileSize < 2000L ? ",内容为" + ReadFile(localPath) : "")); - - if (minSize >= 0L && minSize > fileSize) - errorMessage.Add($"文件大小应大于 {minSize} B,实际为 {fileSize} B" + - (fileSize < 2000L ? ",内容为:" + ReadFile(localPath) : "")); - - if (isJson) - { - var content = ReadFile(localPath); - if (string.IsNullOrEmpty(content)) - throw new Exception("读取到的文件为空"); - try - { - GetJson(content); - } - catch (Exception ex) - { - throw new Exception(Lang.Text("Common.Error.InvalidJson"), ex); - } - } - - if (errorMessage.Count != 0) - { - errorMessage.Insert(0, $"实际校验地址:{localPath}"); - return errorMessage.Join(";"); - } - - return null; - } - catch (Exception ex) - { - Log(ex, "检查文件出错"); - return ex.ToString(); - } - } - } - - /// - /// 等待文件就绪可读,在指定超时时间内轮询检查文件是否存在且内容非空。 - /// - /// 文件路径。 - /// 超时时间(毫秒)。 - public static void WaitForFileReady(string filePath, int timeoutMs = 2000) - { - WaitForFileReady(filePath, timeoutMs, false); - } - - /// - /// 等待文件就绪可读,在指定超时时间内轮询检查文件是否存在且内容非空。 - /// - /// 文件路径。 - /// 超时时间(毫秒)。 - /// 是否要求文件为合法 JSON。 - public static void WaitForFileReady(string filePath, int timeoutMs, bool requireJson) - { - filePath = filePath.Contains(@":\") ? filePath : exePath + filePath; - var start = Environment.TickCount; - long lastSize = -1; - while (Environment.TickCount - start < timeoutMs) - { - if (File.Exists(filePath)) - { - try - { - var info = new FileInfo(filePath); - var size = info.Length; - if (size <= 0) - continue; - if (!requireJson) - { - if (size == lastSize) - return; - lastSize = size; - } - else - { - var content = ReadFile(filePath); - if (!string.IsNullOrEmpty(content) && content.Trim().StartsWith("{")) - return; - } - } - catch (IOException) - { - } - } - Thread.Sleep(50); - } - } - - /// - /// 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 Jar 以 zip 方式解压。 - /// 会尝试创建,但不会清空目标文件夹。 - /// - public static void ExtractFile(string compressFilePath, string destDirectory, Encoding encode = null, - Action progressIncrementHandler = null) - { - Directory.CreateDirectory(destDirectory); - destDirectory = Path.GetFullPath(destDirectory); - if (!destDirectory.EndsWith(Path.DirectorySeparatorChar.ToString())) - destDirectory += Path.DirectorySeparatorChar.ToString(); - if (compressFilePath.EndsWithF(".gz", true)) - // 以 gz 方式解压 - using (var compressedFile = new FileStream(compressFilePath, FileMode.Open, FileAccess.Read)) - { - using (var decompressStream = new GZipStream(compressedFile, CompressionMode.Decompress)) - { - using (var extractFileStream = - new FileStream( - Path.Combine(destDirectory, - GetFileNameFromPath(compressFilePath).ToLower().Replace(".tar", "") - .Replace(".gz", "")), FileMode.OpenOrCreate, FileAccess.Write)) - { - decompressStream.CopyTo(extractFileStream); - } - } - } - else - // 以 zip 方式解压 - using (var archive = ZipFile.Open(compressFilePath, ZipArchiveMode.Read, - encode ?? Encoding.GetEncoding("GB18030"))) - { - var totalCount = archive.Entries.Count; - foreach (var entry in archive.Entries) - { - if (progressIncrementHandler is not null) - progressIncrementHandler(1d / totalCount); - var destinationPath = Path.GetFullPath(Path.Combine(destDirectory, entry.FullName)); - if (!destinationPath.StartsWithF(destDirectory)) - throw new Exception( - $"解压文件 {entry.FullName} 错误:解压文件路径 {destinationPath} 不在目标目录 {destDirectory} 内"); - if (destinationPath.EndsWithF(@"\") || destinationPath.EndsWithF("/")) - { - } - else - { - Directory.CreateDirectory(GetPathFromFullPath(destinationPath)); - entry.ExtractToFile(destinationPath, true); - } - } - } - } - - /// - /// 删除文件夹,返回删除的文件个数。通过参数选择是否抛出异常。 - /// - public static int DeleteDirectory(string path, bool ignoreIssue = false) - { - if (!Directory.Exists(path)) - return 0; - var deletedCount = 0; - string[] files; - try - { - files = Directory.GetFiles(path); - } - catch (DirectoryNotFoundException ex) // #4549 - { - Log(ex, $"疑似为孤立符号链接,尝试直接删除({path})", LogLevel.Developer); - Directory.Delete(path); - return 0; - } - - foreach (var filePath in files) - { - var retriedFile = false; - RetryFile: ; - - try - { - File.Delete(filePath); - deletedCount += 1; - } - catch (Exception ex) - { - if (!retriedFile) - { - retriedFile = true; - Log(ex, $"删除文件失败,将在 0.3s 后重试({filePath})"); - Thread.Sleep(300); - goto RetryFile; - } - - if (ignoreIssue) - Log(ex, "删除单个文件可忽略地失败"); - else - throw; - } - } - - foreach (var str in Directory.GetDirectories(path)) - DeleteDirectory(str, ignoreIssue); - var retriedDir = false; - RetryDir: ; - - try - { - Directory.Delete(path, true); - } - catch (Exception ex) - { - if (!retriedDir && !RunInUi()) - { - retriedDir = true; - Log(ex, $"删除文件夹失败,将在 0.3s 后重试({path})"); - Thread.Sleep(300); - goto RetryDir; - } - - if (ignoreIssue) - Log(ex, "删除单个文件夹可忽略地失败"); - else - throw; - } - - return deletedCount; - } - - /// - /// 复制文件夹,失败会抛出异常。 - /// - public static void CopyDirectory(string fromPath, string toPath, Action progressIncrementHandler = null) - { - fromPath = fromPath.Replace("/", @"\"); - if (!fromPath.EndsWithF(@"\")) - fromPath += @"\"; - toPath = toPath.Replace("/", @"\"); - if (!toPath.EndsWithF(@"\")) - toPath += @"\"; - var allFiles = EnumerateFiles(fromPath).ToList(); - var fileCount = allFiles.Count; - foreach (var file in allFiles) - { - CopyFile(file.FullName, file.FullName.Replace(fromPath, toPath)); - if (progressIncrementHandler is not null) - progressIncrementHandler(1d / fileCount); - } - } - - /// - /// 遍历文件夹中的所有文件。 - /// - public static IEnumerable EnumerateFiles(string directory) - { - var info = new DirectoryInfo(ShortenPath(directory)); - if (!info.Exists) - return new List(); - return info.EnumerateFiles("*", SearchOption.AllDirectories); - } - - /// - /// 若路径长度大于指定值,则将长路径转换为短路径。 - /// - public static string ShortenPath(string longPath, int shortenThreshold = 247) - { - if (longPath.Length <= shortenThreshold) - return longPath; - var shortPath = new StringBuilder(260); - GetShortPathName(longPath, shortPath, 260); - return shortPath.ToString(); - } - - public static void MoveDirectory(string sourceDir, string targetDir) - { - if (!Directory.Exists(targetDir)) - Directory.CreateDirectory(targetDir); - foreach (var filePath in Directory.GetFiles(sourceDir)) - { - var fileName = GetFileNameFromPath(filePath); - File.Move(filePath, Path.Combine(targetDir, fileName)); - } - - foreach (var dirPath in Directory.GetDirectories(sourceDir)) - { - var dirName = GetFolderNameFromPath(dirPath); - MoveDirectory(dirPath, Path.Combine(targetDir, dirName)); - } - } - - [DllImport("kernel32", EntryPoint = "GetShortPathNameA")] - private static extern int GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer); - - public static void CreateSymbolicLink(string linkPath, string targetPath, int flags) - { - var cMDProcess = new Process(); - var linkDPath = ModLaunch.ExtractLinkD(); - { - var withBlock = cMDProcess.StartInfo; - withBlock.FileName = linkDPath; - withBlock.Arguments = $"\"{linkPath}\" \"{targetPath}\""; - withBlock.CreateNoWindow = true; - withBlock.UseShellExecute = false; - } - cMDProcess.Start(); - while (!cMDProcess.HasExited) - { - } - } - - #endregion - - #region 文本 - - public static char vbLQ = Convert.ToChar(8220); - public static char vbRQ = Convert.ToChar(8221); - - /// - /// 返回一个枚举对应的字符串。 - /// - /// 一个已经实例化的枚举类型。 - public static string GetStringFromEnum(Enum enumData) - { - return Enum.GetName(enumData.GetType(), enumData); - } - - /// - /// 将文件大小转化为适合的文本形式,如“1.28 M”。 - /// - /// 以字节为单位的大小表示。 - public static string GetString(long fileSize) - { - return ByteStream.GetReadableLength(fileSize, provider: Lang.Culture); - } - - /// - /// 获取 JSON 对象。 - /// - public static JsonNode GetJson(string data) - { - try - { - return JsonCompat.ParseNode(data); - } - catch (Exception ex) - { - var dataText = data ?? ""; - var length = dataText.Length; - throw new Exception("格式化 JSON 失败:" + (length > 2000 - ? dataText.Substring(0, 500) + $"...(全长 {length} 个字符)..." + dataText.Substring(length - 500) - : dataText), ex); - } - } - - /// - /// 将第一个字符转换为大写,其余字符转换为小写。 - /// - public static string Capitalize(this string word) - { - if (string.IsNullOrEmpty(word)) - return word; - return word.Substring(0, 1).ToUpperInvariant() + word.Substring(1).ToLowerInvariant(); - } - - /// - /// 将字符串统一至某个长度,过短则以 Code 将其右侧填充,过长则截取靠左的指定长度。 - /// - public static string StrFill(string str, string code, byte length) - { - if (str.Length > length) - return str.Substring(0, length); - return str.PadRight(length, code[0]).Substring(str.Length) + str; - } - - /// - /// 将一个小数显示为固定的小数点后位数形式,将向零取整。 - /// 如 12 保留 2 位则输出 12.00,而 95.678 保留 2 位则输出 95.67。 - /// - public static string StrFillNum(double num, int length) - { - return Lang.Number(num, $"F{length}"); - } - - /// - /// 移除字符串首尾的标点符号、回车,以及括号中、冒号后的补充说明内容。 - /// - public static object StrTrim(string str, bool removeQuote = true) - { - if (removeQuote) - str = str.Split("(")[0].Split(":")[0].Split("(")[0].Split(":")[0]; - return str.Trim('.', '。', '!', ' ', '!', '?', '?', '\r', - '\n'); - } - - /// - /// 连接字符串。 - /// - public static string Join(this IEnumerable list, string split) - { - var builder = new StringBuilder(); - var isFirst = true; - foreach (var element in list) - { - if (isFirst) - isFirst = false; - else - builder.Append(split); - if (element is not null) - builder.Append(element); - } - - return builder.ToString(); - } - - /// - /// 分割字符串。 - /// - public static string[] Split(this string fullStr, string splitStr) - { - if (splitStr.Length == 1) return fullStr.Split(splitStr[0]); - - return fullStr.Split(new[] { splitStr }, StringSplitOptions.None); - } - - /// - /// 获取字符串哈希值。 - /// - public static ulong GetHash(string str) - { - ulong getHashRet = default; - getHashRet = 5381UL; - for (int i = 0, loopTo = str.Length - 1; i <= loopTo; i++) - getHashRet = (getHashRet << 5) ^ getHashRet ^ str[i]; - return getHashRet ^ 0xA98F501BC684032FUL; - } - - /// - /// 获取字符串 MD5。 - /// - public static string GetStringMD5(string str) - { - return (string)GetHexString(MD5Provider.Instance.ComputeHash(str)); - } - - /// - /// 检查字符串中的字符是否均为 ASCII 字符。 - /// - public static bool IsASCII(this string input) - { - return input.All(c => c < 128); - } - - /// - /// 获取在子字符串第一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024。 - /// 如果未找到子字符串则不裁切。 - /// - public static string BeforeFirst(this string str, string text, bool ignoreCase = false) - { - var pos = string.IsNullOrEmpty(text) ? -1 : str.IndexOfF(text, ignoreCase); - if (pos >= 0) return str.Substring(0, pos); - - return str; - } - - /// - /// 获取在子字符串最后一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024/11。 - /// 如果未找到子字符串则不裁切。 - /// - public static string BeforeLast(this string str, string text, bool ignoreCase = false) - { - var pos = string.IsNullOrEmpty(text) ? -1 : str.LastIndexOfF(text, ignoreCase); - if (pos >= 0) return str.Substring(0, pos); - - return str; - } - - /// - /// 获取在子字符串第一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 11/08。 - /// 如果未找到子字符串则不裁切。 - /// - public static string AfterFirst(this string str, string text, bool ignoreCase = false) - { - var pos = string.IsNullOrEmpty(text) ? -1 : str.IndexOfF(text, ignoreCase); - if (pos >= 0) return str.Substring(pos + text.Length); - - return str; - } - - /// - /// 获取在子字符串最后一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 08。 - /// 如果未找到子字符串则不裁切。 - /// - public static string AfterLast(this string str, string text, bool ignoreCase = false) - { - var pos = string.IsNullOrEmpty(text) ? -1 : str.LastIndexOfF(text, ignoreCase); - if (pos >= 0) return str.Substring(pos + text.Length); - - return str; - } - - /// - /// 获取处于两个子字符串之间的部分,裁切尽可能多的内容。 - /// 等效于 AfterLast 后接 BeforeFirst。 - /// 如果未找到子字符串则不裁切。 - /// - public static string Between(this string str, string after, string before, bool ignoreCase = false) - { - var startPos = string.IsNullOrEmpty(after) ? -1 : str.LastIndexOfF(after, ignoreCase); - if (startPos >= 0) - startPos += after.Length; - else - startPos = 0; - var endPos = string.IsNullOrEmpty(before) ? -1 : str.IndexOfF(before, startPos, ignoreCase); - if (endPos >= 0) return str.Substring(startPos, endPos - startPos); - - if (startPos > 0) return str.Substring(startPos); - - return str; - } - - /// - /// 高速的 StartsWith。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool StartsWithF(this string str, string prefix, bool ignoreCase = false) - { - return str.StartsWith(prefix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 高速的 EndsWith。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool EndsWithF(this string str, string suffix, bool ignoreCase = false) - { - return str.EndsWith(suffix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 支持可变大小写判断的 Contains。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool ContainsF(this string str, string subStr, bool ignoreCase = false) - { - return str.IndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0; - } - - /// - /// 高速的 IndexOf。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfF(this string str, string subStr, bool ignoreCase = false) - { - return str.IndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 高速的 IndexOf。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfF(this string str, string subStr, int startIndex, bool ignoreCase = false) - { - return str.IndexOf(subStr, startIndex, - ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 高速的 LastIndexOf。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfF(this string str, string subStr, bool ignoreCase = false) - { - return str.LastIndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 高速的 LastIndexOf。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfF(this string str, string subStr, int startIndex, bool ignoreCase = false) - { - return str.LastIndexOf(subStr, startIndex, - ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 不会报错的 Val。 - /// 如果输入有误,返回 0。 - /// - public static double Val(object str) - { - try - { - return str is "&" ? 0d : Conversion.Val(str); - } - catch - { - return 0d; - } - } - - // 转义 - /// - /// 为字符串进行 XML 转义。 - /// - public static string EscapeXML(string str) - { - if (str.StartsWithF("{")) - str = "{}" + str; // #4187 - return str.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("'", "'") - .Replace("\"", """).Replace("\r\n", " "); - } - - /// - /// 为字符串进行 Like 关键字转义。 - /// - public static string EscapeLikePattern(string input) - { - var sb = new StringBuilder(); - foreach (var c in input) - switch (c) - { - case '[': - case ']': - case '*': - case '?': - case '#': - { - sb.Append('[').Append(c).Append(']'); - break; - } - - default: - { - sb.Append(c); - break; - } - } - - return sb.ToString(); - } - - // 正则 - /// - /// 搜索字符串中的所有正则匹配项。 - /// - public static List RegexSearch(this string str, string regex, RegexOptions options = RegexOptions.None) - { - List regexSearchRet = default; - try - { - regexSearchRet = new List(); - var regexSearchRes = new Regex(regex, options).Matches(str); - if (regexSearchRes is null) - return regexSearchRet; - foreach (Match item in regexSearchRes) - regexSearchRet.Add(item.Value); - } - catch (Exception ex) - { - Log(ex, "正则匹配全部项出错"); - return new List(); - } - - return regexSearchRet; - } - - /// - /// 搜索字符串中的所有正则匹配项。 - /// - /// 要搜索的字符串 - /// 正则表达式对象 - /// 所有匹配项的列表 - public static List RegexSearch(this string str, Regex regex) - { - try - { - var result = new List(); - foreach (Match item in regex.Matches(str)) - { - result.Add(item.Value); - } - return result; - } - catch (Exception ex) - { - Log(ex, "正则匹配全部项出错"); - return new List(); - } - } - - /// - /// 获取字符串中的第一个正则匹配项,若无匹配则返回 Nothing。 - /// - public static string RegexSeek(this string str, string regex, RegexOptions options = RegexOptions.None) - { - try - { - var result = Regex.Match(str, regex, options).Value; - return string.IsNullOrEmpty(result) ? null : result; - } - catch (Exception ex) - { - Log(ex, "正则匹配第一项出错"); - return null; - } - } - - /// - /// 获取字符串中的第一个正则匹配项,若无匹配则返回 Nothing。 - /// - public static string RegexSeek(this string str, Regex regex, RegexOptions options = RegexOptions.None) - { - try - { - var result = regex.Match(str, (int)options).Value; - return string.IsNullOrEmpty(result) ? null : result; - } - catch (Exception ex) - { - Log(ex, "正则匹配第一项出错"); - return null; - } - } - - /// - /// 检查字符串是否匹配某正则模式。 - /// - public static bool RegexCheck(this string str, string regex, RegexOptions options = RegexOptions.None) - { - try - { - return Regex.IsMatch(str, regex, options); - } - catch (Exception ex) - { - Log(ex, "正则检查出错"); - return false; - } - } - - /// - /// 进行正则替换,会抛出错误。 - /// - public static string RegexReplace(this string allContents, string searchRegex, string replaceTo, - RegexOptions options = RegexOptions.None) - { - return Regex.Replace(allContents, searchRegex, replaceTo, options); - } - - /// - /// 对每个正则匹配分别进行替换,会抛出错误。 - /// - public static string RegexReplaceEach(this string allContents, string searchRegex, MatchEvaluator replaceTo, - RegexOptions options = RegexOptions.None) - { - return Regex.Replace(allContents, searchRegex, replaceTo, options); - } - - #endregion - - #region 搜索 - - /// - /// 获取搜索文本的相似度。 - /// - /// 被搜索的长内容。 - /// 用户输入的搜索文本。 - private static double SearchSimilarity(string source, string query) - { - var qp = 0; - var lenSum = 0d; - source = source.ToLower().Replace(" ", ""); - query = query.ToLower().Replace(" ", ""); - var sourceLength = source.Length; - var queryLength = query.Length; // 用于计算最后因数的长度缓存 - while (qp < queryLength) - { - // 对 qp 作为开始位置计算 - var sp = 0; - var lenMax = 0; - var spMax = 0; - // 查找以 qp 为头的最大子串 - while (sp < source.Length) - { - // 对每个 sp 作为开始位置计算最大子串 - var len = 0; - while (qp + len < queryLength && sp + len < source.Length && source[sp + len] == query[qp + len]) - len += 1; - // 存储 len - if (len > lenMax) - { - lenMax = len; - spMax = sp; - } - - // 根据结果增加 sp - sp += Math.Max(1, len); - } - - if (lenMax > 0) - { - source = source.Substring(0, spMax) + - (source.Count() > spMax + lenMax - ? source.Substring(spMax + lenMax) - : string.Empty); // 将源中的对应字段替换空 - // 存储 lenSum - var incWeight = Math.Pow(1.4d, 3 + lenMax) - 3.6d; // 根据长度加成 - incWeight *= 1d + 0.3d * Math.Max(0, 3 - Math.Abs(qp - spMax)); // 根据位置加成 - lenSum += incWeight; - } - - // 根据结果增加 qp - qp += Math.Max(1, lenMax); - } - - // 计算结果:重复字段量 × 源长度影响比例 - return lenSum / queryLength * (3d / Math.Pow(sourceLength + 15, 0.5d)) * - (queryLength <= 2 ? 3 - queryLength : 1); - } - - /// - /// 获取多段文本加权后的相似度。 - /// - private static double SearchSimilarityWeighted(List source, string query) - { - var totalWeight = 0d; - var sum = 0d; - foreach (var pair in source) - { - if (pair.aliases.Any()) - sum += pair.aliases.Max(a => SearchSimilarity(a, query)) * pair.weight; - totalWeight += pair.weight; - } - - return sum / totalWeight; - } - - /// - /// 用于搜索的项目。 - /// - public class SearchEntry - { - /// - /// 是否完全匹配。 - /// - public bool absoluteRight; - - /// - /// 该项目对应的源数据。 - /// - public T item; - - /// - /// 该项目用于搜索的文本源。 - /// 在搜索时,会对每个文本源单独加权,但单个文本源内的多个别名只取最高的一个的相似度。 - /// - public List searchSource; - - /// - /// 相似度。 - /// - public double similarity; - } - - /// - /// 单个用于搜索的文本源。 - /// - public class SearchSource - { - public string[] aliases; - public double weight; - - public SearchSource(string[] aliases, double weight = 1) - { - this.aliases = aliases; - this.weight = weight; - } - - public SearchSource(string text, double weight = 1) - { - aliases = new[] { text }; - this.weight = weight; - } - } - - /// - /// 本地搜索返回的最大模糊结果数。 - /// - public const int MaxLocalSearchDepth = 25; - - /// - /// 进行多段文本加权搜索,获取相似度较高的数项结果。 - /// - /// 返回的最大模糊结果数。 - /// 返回结果要求的最低相似度。 - public static List> Search(List> entries, string query, int maxBlurCount = 5, - double minBlurSimilarity = 0.1d) - { - var resultList = new List>(); - - if (entries is null || !entries.Any()) return resultList; - - // Preprocess query into parts - var queryParts = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - if (queryParts.Length == 0) - { - resultList.AddRange(entries); - return resultList; - } - - // Precompute query parts in lowercase for case-insensitive comparison - var queryPartsLower = queryParts.Select(q => q.ToLower()).ToArray(); - - // Process each entry to compute similarity and absolute match status - foreach (var entry in entries) - { - entry.similarity = SearchSimilarityWeighted(entry.searchSource, query); - - // Preprocess search source keys: remove spaces and convert to lowercase - var processedSources = entry.searchSource.Select(s => - { - for (var i = 0; i < s.aliases.Length; i++) - s.aliases[i] = s.aliases[i].Replace(" ", "").ToLower(); - return s.aliases; - }).ToList(); - - // Check if all query parts are matched exactly by at least one source - var isAbsoluteRight = true; - foreach (var qp in queryPartsLower) - { - var found = false; - foreach (var ps in processedSources) - if (ps.Any(p => p.Contains(qp))) - { - found = true; - break; - } - - if (!found) - { - isAbsoluteRight = false; - break; - } - } - - entry.absoluteRight = isAbsoluteRight; - } - - // Sort by absolute match (descending), then by similarity (descending) - var sortedEntries = entries.OrderByDescending(e => e.absoluteRight).ThenByDescending(e => e.similarity) - .ToList(); - - // Build the final result list - var blurCount = 0; - foreach (var entry in sortedEntries) - if (entry.absoluteRight) - { - resultList.Add(entry); - } - else - { - if (entry.similarity < minBlurSimilarity || blurCount >= maxBlurCount) break; - resultList.Add(entry); - blurCount += 1; - } - - return resultList; - } - - #endregion - - #region 系统 - - public static bool IsUtf8CodePage() - { - return Encoding.Default.CodePage == 65001; - } - - /// - /// 线程安全的 List。 - /// 通过在 For Each 循环中使用一个浅表副本规避多线程操作或移除自身导致的异常。 - /// - public class SafeList : IEnumerable, IDisposable, ICollection - { - private readonly List _internalList; - private readonly ReaderWriterLockSlim _lock = new(); - - public SafeList() - { - _internalList = new List(); - } - - public SafeList(IEnumerable data) - { - _internalList = new List(data); - } - - public T this[int index] - { - get => _internalList[index]; - set => _internalList[index] = value; - } - - public void Add(T item) - { - _lock.EnterWriteLock(); - try - { - _internalList.Add(item); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public bool Remove(T item) - { - _lock.EnterWriteLock(); - try - { - return _internalList.Remove(item); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public void Clear() - { - _lock.EnterWriteLock(); - try - { - _internalList.Clear(); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public int Count - { - get - { - _lock.EnterReadLock(); - try - { - return _internalList.Count; - } - finally - { - _lock.ExitReadLock(); - } - } - } - - public bool IsReadOnly => ((ICollection)_internalList).IsReadOnly; - - public bool Contains(T item) - { - return ((ICollection)_internalList).Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - ((ICollection)_internalList).CopyTo(array, arrayIndex); - } - - public void Dispose() - { - _lock.Dispose(); - } - - public IEnumerator GetEnumerator() - { - return ToList().GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public List ToList() - { - _lock.EnterReadLock(); - try - { - return _internalList.ToList(); - } - finally - { - _lock.ExitReadLock(); - } - } - - public void RemoveAt(int index) - { - _lock.EnterWriteLock(); - try - { - _internalList.RemoveAt(index); - } - finally - { - _lock.ExitWriteLock(); - } - } - } - - /// - /// 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。 - /// - public static string pathPure = GetPureASCIIDir(); - - private static string GetPureASCIIDir() - { - if (exePath.IsASCII()) return exePath + @"PCL\"; - - if (pathAppdata.IsASCII()) return pathAppdata; - - if (pathTemp.IsASCII()) return pathTemp; - - return Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL"); - } - - /// - /// 指示接取到这个异常的函数进行重试。 - /// - public class RestartException : Exception - { - } - - /// - /// 指示用户手动取消了操作,或用户已知晓操作被取消的原因。 - /// - public class CancelledException : Exception - { - } - - /// - /// 判断对象是否为某个泛型类型的实例。 - /// - public static bool IsInstanceOfGenericType(this Type genericType, object obj) - { - if (obj is null) - return false; - var t = obj.GetType(); - while (t is not null) - { - if (t.IsGenericType && ReferenceEquals(t.GetGenericTypeDefinition(), genericType)) - return true; - t = t.BaseType; - } - - return false; - } - - private static int uuid = 1; - private static object uuidLock; - - /// - /// 获取一个全程序内不会重复的数字(伪 Uuid)。 - /// - public static int GetUuid() - { - if (uuidLock is null) - uuidLock = new object(); - lock (uuidLock) - { - uuid += 1; - return uuid; - } - } - - /// - /// 将元素与 List 的混合体拆分为元素组。 - /// - public static List GetFullList(IList data) - { - List getFullListRet = default; - getFullListRet = new List(); - for (int i = 0, loopTo = data.Count - 1; i <= loopTo; i++) - if (data[i] is ICollection) - getFullListRet.AddRange((IEnumerable)data[i]); - else - getFullListRet.Add((T)data[i]); - - return getFullListRet; - } - - /// - /// 数组去重。 - /// - public static List Distinct(this ICollection arr, ComparisonBoolean isEqual) - { - var resultArray = new List(); - for (int i = 0, loopTo = arr.Count - 1; i <= loopTo; i++) - { - for (int ii = i + 1, loopTo1 = arr.Count - 1; ii <= loopTo1; ii++) - if (isEqual(arr.ElementAtOrDefault(i), arr.ElementAtOrDefault(ii))) - goto NextElement; - resultArray.Add(arr.ElementAtOrDefault(i)); - NextElement: ; - } - - return resultArray; - } - - /// - /// 对集合的每个元素执行指定操作。 - /// - public static IEnumerable ForEach(this IEnumerable collection, Action action) - { - foreach (var item in collection) - action(item); - return collection; - } - - /// - /// 用于储存 RaiseByMouse 的 EventArgs。 - /// - public sealed class RouteEventArgs : EventArgs - { - public bool handled = false; - public bool raiseByMouse; - - public RouteEventArgs(bool raiseByMouse = false) - { - this.raiseByMouse = raiseByMouse; - } - } - - /// - /// 前台运行文件。 - /// - /// 文件名。可以为“notepad”等缩写。 - /// 运行参数。 - public static void ShellOnly(string fileName, string arguments = "") - { - try - { - fileName = ShortenPath(fileName); - using (var program = new Process()) - { - program.StartInfo.Arguments = arguments; - program.StartInfo.FileName = fileName; - program.StartInfo.UseShellExecute = true; - Log("[System] 执行外部命令:" + fileName + " " + arguments); - program.Start(); - } - } - catch (Exception ex) - { - Log( - ex, - "打开文件或程序失败:" + fileName, - LogLevel.Msgbox, - userSummary: Lang.Text("SystemDialog.File.OpenFailed.Message", fileName)); - } - } - - /// - /// 前台运行文件并返回返回值。 - /// - /// 文件名。可以为“notepad”等缩写。 - /// 运行参数。 - /// 等待该程序结束的最长时间(毫秒)。超时会返回 Result.Timeout。 - public static ProcessReturnValues ShellAndGetExitCode(string fileName, string arguments = "", int timeout = 1000000) - { - try - { - using (var program = new Process()) - { - program.StartInfo.Arguments = arguments; - program.StartInfo.FileName = fileName; - Log("[System] 执行外部命令并等待返回码:" + fileName + " " + arguments); - program.Start(); - if (program.WaitForExit(timeout)) return (ProcessReturnValues)program.ExitCode; - - return ProcessReturnValues.Timeout; - } - } - catch (Exception ex) - { - Log(ex, "执行命令失败:" + fileName, LogLevel.Msgbox); - return ProcessReturnValues.Fail; - } - } - - /// - /// 静默运行文件并返回输出流字符串。执行失败会抛出异常。 - /// - /// 文件名。可以为“notepad”等缩写。 - /// 运行参数。 - /// 等待该程序结束的最长时间(毫秒)。超时会抛出错误。 - public static string ShellAndGetOutput(string fileName, string arguments = "", int timeout = 1000000, - string workingDirectory = null) - { - var info = new ProcessStartInfo - { - FileName = fileName, - Arguments = arguments, - UseShellExecute = false, - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardError = true - }; - - // 设置工作目录(如果提供) - if (!string.IsNullOrEmpty(workingDirectory)) info.WorkingDirectory = workingDirectory.TrimEnd('\\'); - - Log("[System] 执行外部命令并等待返回结果:" + fileName + " " + arguments); - - using (var program = new Process { StartInfo = info }) - { - program.Start(); - - // 异步读取输出和错误流 - var outputTask = program.StandardOutput.ReadToEndAsync(); - var errorTask = program.StandardError.ReadToEndAsync(); - - // 等待进程退出或超时 - if (program.WaitForExit(timeout)) - { - // 确保异步读取完成 - Task.WaitAll(outputTask, errorTask); - } - else - { - // 超时后终止进程 - program.Kill(); - // 仍然尝试获取已输出的内容 - Task.WaitAll(outputTask, errorTask); - } - - // 合并结果并返回 - return outputTask.Result + errorTask.Result; - } - } - - /// - /// 在新的工作线程中执行代码。 - /// - public static Thread RunInNewThread(Action action, string name = null, - ThreadPriority priority = ThreadPriority.Normal) - { - var th = new Thread(() => - { - try - { - action(); - } - catch (ThreadInterruptedException ex) - { - Log(name + ":线程已中止"); - } - catch (Exception ex) - { - Log(ex, name + ":线程执行失败", LogLevel.Feedback); - } - }) { Name = name ?? "Runtime New Invoke " + GetUuid() + "#", Priority = priority }; - th.Start(); - return th; - } - - /// - /// 确保在 UI 线程中执行代码。 - /// 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。 - /// 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用! - /// - public static Output RunInUiWait(Func action) - { - if (RunInUi()) return action(); - - return System.Windows.Application.Current.Dispatcher.Invoke(action); - } - - /// - /// 确保在 UI 线程中执行代码。 - /// 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。 - /// 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用! - /// - public static void RunInUiWait(Action action) - { - if (System.Windows.Application.Current is null) - return; - if (RunInUi()) - action(); - else - System.Windows.Application.Current.Dispatcher.Invoke(action); - } - - /// - /// 确保在 UI 线程中执行代码,代码按触发顺序执行。 - /// 如果当前并非 UI 线程,也不阻断当前线程的执行。 - /// - public static void RunInUi(Action action, bool forceWaitUntilLoaded = false) - { - if (System.Windows.Application.Current is null) - return; - if (RunInUi()) - action(); - else - System.Windows.Application.Current.Dispatcher.InvokeAsync(action, - forceWaitUntilLoaded ? DispatcherPriority.Loaded : DispatcherPriority.Normal); - } - - /// - /// 确保在工作线程中执行代码。 - /// - public static void RunInThread(Action action) - { - if (RunInUi()) - RunInNewThread(action, "Runtime Invoke " + GetUuid() + "#"); - else - action(); - } - - /// - /// 使用优化的归并排序算法进行稳定排序。 - /// - /// 传入两个对象,若第一个对象应该排在前面,则返回 True。 - public static List Sort(this IList list, ComparisonBoolean sortRule) - { - // 创建原列表的副本以避免修改原始列表 - var tempList = new List(list); - if (tempList.Count <= 1) - return tempList; - - // 使用归并排序核心算法 - MergeSort_Sort(ref tempList, 0, tempList.Count - 1, sortRule); - return tempList; - } - - private static void MergeSort_Sort(ref List array, int left, int right, ComparisonBoolean comparator) - { - if (left >= right) - return; - - var mid = (left + right) / 2; - MergeSort_Sort(ref array, left, mid, comparator); - MergeSort_Sort(ref array, mid + 1, right, comparator); - MergeSort_Merge(ref array, left, mid, right, comparator); - } - - private static void MergeSort_Merge(ref List array, int left, int mid, int right, - ComparisonBoolean comparator) - { - var leftArray = new List(); - var rightArray = new List(); - - for (int i = left, loopTo = mid; i <= loopTo; i++) - leftArray.Add(array[i]); - - for (int j = mid + 1, loopTo1 = right; j <= loopTo1; j++) - rightArray.Add(array[j]); - - var leftPtr = 0; - var rightPtr = 0; - var current = left; - - while (leftPtr < leftArray.Count && rightPtr < rightArray.Count) - { - // 保持稳定性的关键比较逻辑:当相等时优先取左数组元素 - if (comparator(leftArray[leftPtr], rightArray[rightPtr])) - { - array[current] = leftArray[leftPtr]; - leftPtr += 1; - } - else - { - array[current] = rightArray[rightPtr]; - rightPtr += 1; - } - - current += 1; - } - - while (leftPtr < leftArray.Count) - { - array[current] = leftArray[leftPtr]; - leftPtr += 1; - current += 1; - } - - while (rightPtr < rightArray.Count) - { - array[current] = rightArray[rightPtr]; - rightPtr += 1; - current += 1; - } - } - - public delegate bool ComparisonBoolean(T left, T right); - - /// - /// 返回列表的浅表副本。 - /// - public static IList Clone(this IList list) - { - return new List(list); - } - - /// - /// 尝试从字典中获取某项,如果该项不存在,则返回默认值。 - /// - public static TValue GetOrDefault(this Dictionary dict, TKey key, - TValue defaultValue = default) - { - if (dict.ContainsKey(key)) return dict[key]; - - return defaultValue; - } - - /// - /// 将某项添加到以列表作为值的字典中。 - /// - public static void AddToList(this Dictionary> dict, TKey key, TValue value) - { - if (dict.ContainsKey(key)) - dict[key].Add(value); - else - dict.Add(key, new List { value }); - } - - /// - /// 获取程序启动参数。 - /// - /// 参数名。 - /// 默认值。 - public static object GetProgramArgument(string name, object defaultValue = null) - { - var allArguments = Interaction.Command().Split(" "); - for (int i = 0, loopTo = allArguments.Length - 1; i <= loopTo; i++) - if ((allArguments[i] ?? "") == ("-" + name ?? "")) - { - if (allArguments.Length == i + 1 || allArguments[i + 1].StartsWithF("-")) - return true; - return allArguments[i + 1]; - } - - return defaultValue; - } - - /// - /// 打开网页。 - /// - public static void OpenWebsite(string url) - { - try - { - if (!url.StartsWithF("http", true) && !url.StartsWithF("minecraft://", true)) - throw new Exception(url + " 不是一个有效的网址,它必须以 http 开头!"); - Log("[System] 正在打开网页:" + url); - var psi = new ProcessStartInfo(url) - { - UseShellExecute = true, - }; - Process.Start(psi); - } - catch (Exception ex) - { - Log(ex, "无法打开网页(" + url + ")"); - ClipboardSet(url, false); - var message = ExceptionDetails.Compose( - Lang.Text("SystemDialog.Browser.OpenFailed.Message", url), - ex); - ModMain.MyMsgBox( - message, - Lang.Text("SystemDialog.Browser.OpenFailed.Title")); - } - } - - /// - /// 打开 explorer。 - /// 若不以 \ 结尾,则将视作文件路径,打开并选中此文件。 - /// - public static void OpenExplorer(string location) - { - try - { - location = ShortenPath(location.Replace("/", @"\").Trim(' ', '"')); - Log("[System] 正在打开资源管理器:" + location); - if (location.EndsWithF(@"\")) - ShellOnly(location); - else - ShellOnly("explorer", $"/select,\"{location}\""); - } - catch (Exception ex) - { - Log( - ex, - "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", - LogLevel.Msgbox, - userSummary: Lang.Text("SystemDialog.Folder.OpenFailed.Message", location)); - } - } - - /// - /// 设置剪贴板。将在另一线程运行,且不会抛出异常。 - /// - public static void ClipboardSet(string text, bool showSuccessHint = true) - { - RunInThread(() => - { - var success = false; - - for (var attempt = 0; attempt <= 5; attempt++) - try - { - RunInUi(() => Clipboard.SetText(text)); - success = true; - break; - } - catch (Exception ex) when (attempt < 5) - { - Thread.Sleep(20); - } - catch (Exception finalEx) - { - Log( - finalEx, - "剪贴板被占用,文本复制失败", - LogLevel.Hint, - userSummary: Lang.Text("Common.Hint.CopyFailed")); - } - - if (success && showSuccessHint) - RunInUi(() => HintService.Hint(Lang.Text("Common.Hint.Copied"), HintType.Success)); - }); - } - - /// - /// 从剪切板粘贴文件或文件夹 - /// - /// 目标文件夹 - /// 是否粘贴文件 - /// 是否粘贴文件夹 - /// 总共粘贴的数量 - public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool copyDir = true) - { - Log("[System] 从剪贴板粘贴文件到:" + dest); - try - { - var files = Clipboard.GetFileDropList(); - if (files.Count.Equals(0)) - { - Log("[System] 剪贴板内无文件可粘贴"); - return 0; - } - - var copiedFiles = 0; - var copiedFolders = 0; - foreach (var i in files) - { - if (copyFile && File.Exists(i)) // 文件 - try - { - var thisDest = dest + GetFileNameFromPath(i); - if (File.Exists(thisDest)) - { - Log("[System] 已存在同名文件:" + thisDest); - } - else - { - File.Copy(i, thisDest); - copiedFiles += 1; - } - } - catch (Exception ex) - { - Log(ex, "[System] 复制文件时出错"); - continue; - } - - if (copyDir && Directory.Exists(i)) // 文件夹 - try - { - var thisDest = dest + GetFolderNameFromPath(i); - if (Directory.Exists(thisDest)) - { - Log("[System] 已存在同名文件夹:" + thisDest); - } - else - { - CopyDirectory(i, thisDest); - copiedFolders += 1; - } - } - catch (Exception ex) - { - Log(ex, "[System] 复制文件时出错"); - } - } - - HintService.Hint(Lang.Text("Common.Hint.FilesPasted", copiedFiles, copiedFolders)); - } - catch (Exception ex) - { - Log(ex, "[System] 从剪切板粘贴文件失败", LogLevel.Hint); - } - - return 0; - } - - /// - /// 获取程序打包资源的输入流。该资源必须声明为 Resource 类型,否则将会报错,Images - /// 和 Resources 目录已默认声明该类型。 - /// - public static Stream GetResourceStream(string path) - { - var resourceInfo = - System.Windows.Application.GetResourceStream(new Uri($"pack://application:,,,/{path}", UriKind.Absolute)); - return resourceInfo?.Stream; - } - - #endregion - - /// - /// 检查是否拥有某一文件夹的 I/O 权限。如果文件夹不存在,会返回 False。 - /// - public static bool CheckPermission(string path) - { - try - { - if (string.IsNullOrEmpty(path)) - return false; - if (!path.EndsWithF(@"\")) - path += @"\"; - if (path.EndsWithF(@":\System Volume Information\") || path.EndsWithF(@":\$RECYCLE.BIN\")) - return false; - if (!Directory.Exists(path)) - return false; - var fileName = "CheckPermission" + GetUuid(); - if (File.Exists(path + fileName)) - File.Delete(path + fileName); - File.Create(path + fileName).Dispose(); - File.Delete(path + fileName); - return true; - } - catch (Exception ex) - { - Log(ex, "没有对文件夹 " + path + " 的权限,请尝试以管理员权限运行 PCL"); - return false; - } - } - - /// - /// 检查是否拥有某一文件夹的 I/O 权限。如果出错,则抛出异常。 - /// - public static void CheckPermissionWithException(string path) - { - if (string.IsNullOrWhiteSpace(path)) - throw new ArgumentNullException("文件夹名不能为空!"); - if (!path.EndsWithF(@"\")) - path += @"\"; - if (!Directory.Exists(path)) - throw new DirectoryNotFoundException("文件夹不存在!"); - if (File.Exists(path + "CheckPermission")) - File.Delete(path + "CheckPermission"); - File.Create(path + "CheckPermission").Dispose(); - File.Delete(path + "CheckPermission"); - } - - #region UI - - public static void SetLaunchFont(string fontName = null) - { - try - { - LocalizationFontService.ApplyLaunchFont(fontName, LocalizationService.CurrentLanguage); - } - catch (Exception ex) - { - Log(ex, "设置字体失败", LogLevel.Hint); - } - } - - // 边距改变 - /// - /// 相对增减控件的左边距。 - /// - public static void DeltaLeft(FrameworkElement control, double newValue) - { - // 安全性检查 - DebugAssert(!double.IsNaN(newValue)); - DebugAssert(!double.IsInfinity(newValue)); - - if (control is Window) - // 窗口改变 - ((Window)control).Left += newValue; - else - // 根据 HorizontalAlignment 改变数值 - switch (control.HorizontalAlignment) - { - case HorizontalAlignment.Left: - case HorizontalAlignment.Stretch: - { - control.Margin = new Thickness(control.Margin.Left + newValue, control.Margin.Top, - control.Margin.Right, control.Margin.Bottom); - break; - } - case HorizontalAlignment.Right: - { - // control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, CType(control.Parent, Object).ActualWidth - control.ActualWidth - newValue, control.Margin.Bottom) - control.Margin = new Thickness(control.Margin.Left, control.Margin.Top, - control.Margin.Right - newValue, control.Margin.Bottom); - break; - } - - default: - { - DebugAssert(false); - break; - } - } - } - - /// - /// 设置控件的左边距。(仅针对置左控件) - /// - public static void SetLeft(FrameworkElement control, double newValue) - { - DebugAssert(control.HorizontalAlignment == HorizontalAlignment.Left); - control.Margin = new Thickness(newValue, control.Margin.Top, control.Margin.Right, control.Margin.Bottom); - } - - /// - /// 相对增减控件的上边距。 - /// - public static void DeltaTop(FrameworkElement control, double newValue) - { - // 安全性检查 - DebugAssert(!double.IsNaN(newValue)); - DebugAssert(!double.IsInfinity(newValue)); - - if (control is Window) - // 窗口改变 - ((Window)control).Top += newValue; - else - // 根据 VerticalAlignment 改变数值 - switch (control.VerticalAlignment) - { - case VerticalAlignment.Top: - { - control.Margin = new Thickness(control.Margin.Left, control.Margin.Top + newValue, - control.Margin.Right, control.Margin.Bottom); - break; - } - case VerticalAlignment.Bottom: - { - // control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, CType(control.Parent, Object).ActualWidth - control.ActualWidth - newValue, control.Margin.Bottom) - control.Margin = new Thickness(control.Margin.Left, control.Margin.Top, control.Margin.Right, - control.Margin.Bottom - newValue); - break; - } - - default: - { - DebugAssert(false); - break; - } - } - } - - /// - /// 设置控件的顶边距。(仅针对置上控件) - /// - public static void SetTop(FrameworkElement control, double newValue) - { - DebugAssert(control.VerticalAlignment == VerticalAlignment.Top); - control.Margin = new Thickness(control.Margin.Left, newValue, control.Margin.Right, control.Margin.Bottom); - } - - // DPI 转换 - public static readonly int dpi = (int)Math.Round(Graphics.FromHwnd(nint.Zero).DpiX); - - /// - /// 将经过 DPI 缩放的 WPF 尺寸转化为实际的像素尺寸。 - /// - public static double GetPixelSize(double wPFSize) - { - return wPFSize / 96d * dpi; - } - - /// - /// 将实际的像素尺寸转化为经过 DPI 缩放的 WPF 尺寸。 - /// - public static double GetWPFSize(double pixelSize) - { - return pixelSize * 96d / dpi; - } - - // UI 截图 - /// - /// 将某个控件的呈现转换为图片。 - /// - public static ImageBrush ControlBrush(FrameworkElement uI) - { - var width = uI.ActualWidth; - var height = uI.ActualHeight; - if (width < 1d || height < 1d) - return new ImageBrush(); - var bmp = new RenderTargetBitmap((int)Math.Round(GetPixelSize(width)), (int)Math.Round(GetPixelSize(height)), - dpi, dpi, PixelFormats.Pbgra32); - bmp.Render(uI); - return new ImageBrush(bmp); - } - - /// - /// 将某个控件的模拟呈现转换为图片。 - /// - public static ImageBrush ControlBrush(FrameworkElement uI, double width, double height, double left = 0d, - double top = 0d) - { - uI.Measure(new Size(width, height)); - uI.Arrange(new Rect(0d, 0d, width, height)); - var bmp = new RenderTargetBitmap((int)Math.Round(GetPixelSize(width)), (int)Math.Round(GetPixelSize(height)), - dpi, dpi, PixelFormats.Default); - bmp.Render(uI); - if (left != 0d || top != 0d) - uI.Arrange(new Rect(left, top, width, height)); - return new ImageBrush(bmp); - } - - /// - /// 将 UI 内容固定为图片并进行 Clear。 - /// - public static void ControlFreeze(Panel uI) - { - uI.Background = ControlBrush(uI); - uI.Children.Clear(); - } - - /// - /// 将 UI 内容固定为图片并进行 Clear。 - /// - public static void ControlFreeze(Border uI) - { - uI.Background = ControlBrush(uI); - uI.Child = null; - } - - /// - /// 将 XElement 转换为对应 UI 对象(不返回 XAML 清理结果)。 - /// - public static object GetObjectFromXML(XElement str) - { - return GetObjectFromXML(str.ToString()); - } - - /// - /// 将 XML 转换为对应 UI 对象。 - /// - public static object GetObjectFromXML(string str) - { - return GetObjectFromXML(str, out _); - } - - /// - /// 将 XML 转换为对应 UI 对象,并输出 XAML 清理结果。 - /// - public static object GetObjectFromXML(string str, out XamlEventSanitizer.SanitizeResult sanitizeResult) - { - str = str. // 兼容旧版自定义事件写法 - Replace("EventType=\"", "local:CustomEventService.EventType=\""). - Replace("EventData=\"", "local:CustomEventService.EventData=\""). - Replace("Property=\"EventType\"", "Property=\"local:CustomEventService.EventType\""). - Replace("Property=\"EventData\"", "Property=\"local:CustomEventService.EventData\""); - // 修复因上述替换导致重复前缀的情况:local:CustomEventService.local:CustomEventService.EventType - str = str.Replace("local:CustomEventService.local:CustomEventService.", "local:CustomEventService."); - - sanitizeResult = XamlEventSanitizer.Sanitize(str); - str = sanitizeResult.SanitizedXaml; - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(str))) - { - // 类型检查 - using (var reader = new XamlXmlReader(stream)) - { - while (reader.Read()) - { - foreach (var blackListType in new[] - { - typeof(WebBrowser), typeof(Frame), typeof(MediaElement), typeof(ObjectDataProvider), - typeof(XamlReader), typeof(Window), typeof(XmlDataProvider) - }) - { - if (reader.Type is not null && blackListType.IsAssignableFrom(reader.Type.UnderlyingType)) - throw new UnauthorizedAccessException($"不允许使用 {blackListType.Name} 类型。"); - if (reader.Value is not null && Equals(reader.Value, blackListType.Name)) - throw new UnauthorizedAccessException($"不允许使用 {blackListType.Name} 值。"); - } - - foreach (var blackListMember in new[] { "Code", "FactoryMethod", "Static" }) - if (reader.Member is not null && (reader.Member.Name ?? "") == (blackListMember ?? "")) - throw new UnauthorizedAccessException($"不允许使用 {blackListMember} 成员。"); - } - } - - // 实际的加载 - stream.Position = 0L; - using (var writer = new StreamWriter(stream)) - { - writer.Write(str); - writer.Flush(); - stream.Position = 0L; - return System.Windows.Markup.XamlReader.Load(stream); - } - } - } - - private static readonly int uiThreadId = Thread.CurrentThread.ManagedThreadId; - - /// - /// 当前线程是否为主线程。 - /// - public static bool RunInUi() - { - return Thread.CurrentThread.ManagedThreadId == uiThreadId; - } - - #endregion - - #region Debug - - public static bool modeDebug = false; - - // Log - public enum LogLevel - { - /// - /// 不提示,只记录日志。 - /// - Normal = 0, - - /// - /// 只提示开发者。 - /// - Developer = 1, - - /// - /// 只提示开发者与调试模式用户。 - /// - Debug = 2, - - /// - /// 弹出提示所有用户。 - /// - Hint = 3, - - /// - /// 弹窗,不要求反馈。 - /// - Msgbox = 4, - - /// - /// 弹窗,要求反馈。 - /// - Feedback = 5, - - /// - /// 弹出 Windows 原生弹窗,要求反馈。在无法保证 WPF 窗口能正常运行时使用此级别。 - /// 在第二次触发后会直接结束程序。 - /// - Critical = 6 - } - - private static bool isCriticalErrorTriggered; - - /// - /// 输出 Log。 - /// - /// 如果要求弹窗,指定弹窗的标题。 - public static void Log( - string text, - LogLevel level = LogLevel.Normal, - string? title = null, - string? userSummary = null) - { - // On Error Resume Next - // 放在最后会导致无法显示极端错误下的弹窗(如无法写入日志文件) - // 处理错误会导致再次调用 Log() 导致无限循环 - - // 输出日志 - if (new[] { LogLevel.Msgbox, LogLevel.Hint }.Contains(level)) - LogWrapper.Warn(text); - else if (LogLevel.Feedback == level) - LogWrapper.Error(text); - else if (LogLevel.Critical == level) - LogWrapper.Fatal(text); - else if (LogLevel.Debug == level) - LogWrapper.Debug(text); - else if (LogLevel.Developer == level) - LogWrapper.Trace(text); - else - LogWrapper.Info(text); - - if (isProgramEnded || level == LogLevel.Normal) - return; - - var userDetails = text.RegexReplace(@"\[[^\]]+?\] ", ""); - var userMessage = string.IsNullOrWhiteSpace(userSummary) - ? Lang.Text("SystemDialog.Error.UserVisible.Message", userDetails) - : userSummary; - var dialogTitle = _GetUserDialogTitle(title); - - switch (level) - { - case LogLevel.Developer: - break; - - case LogLevel.Debug: - if (modeDebug) - HintService.Hint("[调试模式] " + text, HintType.Info, false); - break; - - case LogLevel.Hint: - HintService.Hint(userMessage, HintType.Error, false); - break; - - case LogLevel.Msgbox: - ModMain.MyMsgBox(userMessage, dialogTitle, isWarn: true); - break; - - case LogLevel.Feedback: - _ShowFeedbackPrompt(userMessage, dialogTitle, false); - break; - - case LogLevel.Critical: - _ShowFeedbackPrompt(userMessage, dialogTitle, true); - break; - } - } - - /// - /// 输出错误信息。 - /// - /// 错误描述,仅用于日志和错误详情。 - /// 可选的本地化用户摘要;不会写入日志。 - public static void Log( - Exception ex, - string desc, - LogLevel level = LogLevel.Debug, - string? title = null, - string? userSummary = null) - { - // On Error Resume Next - if (ex is ThreadInterruptedException) - return; - - // 输出日志 - if (new[] { LogLevel.Msgbox, LogLevel.Hint }.Contains(level)) - LogWrapper.Warn(ex, desc); - else if (LogLevel.Feedback == level) - LogWrapper.Error(ex, desc); - else if (LogLevel.Critical == level) - LogWrapper.Fatal(ex, desc); - else if (LogLevel.Debug == level) - LogWrapper.Debug($"{desc}:{ex}"); - else if (LogLevel.Developer == level) - LogWrapper.Trace($"{desc}:{ex}"); - else - LogWrapper.Error(ex, desc); - - if (isProgramEnded) - return; - - var userMessage = _GetUserExceptionMessage(desc, ex, userSummary); - var dialogTitle = _GetUserDialogTitle(title); - - switch (level) - { - case LogLevel.Normal or LogLevel.Developer: - break; - - case LogLevel.Debug: - if (modeDebug) - HintService.Hint("[调试模式] " + desc + ":" + ex, HintType.Info, false); - break; - - case LogLevel.Hint: - HintService.Hint(userMessage, HintType.Error, false); - break; - - case LogLevel.Msgbox: - ModMain.MyMsgBox(userMessage, dialogTitle, isWarn: true); - break; - - case LogLevel.Feedback: - _ShowFeedbackPrompt(userMessage, dialogTitle, false); - break; - - case LogLevel.Critical: - _ShowFeedbackPrompt(userMessage, dialogTitle, true); - break; - } - } - - private static string _GetUserDialogTitle(string? title) - { - return string.IsNullOrWhiteSpace(title) - ? Lang.Text("SystemDialog.Error.Title") - : title; - } - - private static string _GetUserExceptionMessage( - string desc, - Exception ex, - string? userSummary) - { - if (!string.IsNullOrWhiteSpace(userSummary)) - return ExceptionDetails.Compose(userSummary, ex); - - return ex.GetType() == typeof(Win32Exception) - ? Lang.Text("SystemDialog.Error.OperationFailed.RuntimeMessage", desc, ex.ToString()) - : Lang.Text("SystemDialog.Error.OperationFailed.Message", desc, ex.ToString()); - } - - private static void _ShowFeedbackPrompt( - string userMessage, - string title, - bool isCritical) - { - if (isCritical && isCriticalErrorTriggered) - { - FormMain.EndProgramForce(ProcessReturnValues.Exception); - return; - } - - if (isCritical) - isCriticalErrorTriggered = true; - - if (CanFeedback(false)) - { - var message = Lang.Text("Setup.Feedback.ErrorPrompt.Submit.Message", userMessage); - var shouldSend = isCritical - ? Interaction.MsgBox( - message, - (MsgBoxStyle)((int)MsgBoxStyle.Critical + (int)MsgBoxStyle.YesNo), - title) == MsgBoxResult.Yes - : ModMain.MyMsgBox( - message, - title, - Lang.Text("Setup.Feedback.ErrorPrompt.Submit.Action"), - Lang.Text("Common.Action.Cancel"), - isWarn: true) == 1; - - if (shouldSend) - Feedback(false, true); - return; - } - - var updateMessage = Lang.Text("Setup.Feedback.ErrorPrompt.Update.Message", userMessage); - if (isCritical) - Interaction.MsgBox(updateMessage, MsgBoxStyle.Critical, title); - else - ModMain.MyMsgBox(updateMessage, title, isWarn: true); - } - - public static string Base64Decode(string text) - { - if (string.IsNullOrWhiteSpace(text)) - return ""; - var decodedBytes = Convert.FromBase64String(text); - return Encoding.UTF8.GetString(decodedBytes); - } - - public static string Base64Encode(string text) - { - var bytes = Encoding.UTF8.GetBytes(text); - return Convert.ToBase64String(bytes); - } - - public static string Base64Encode(byte[] bytes) - { - return Convert.ToBase64String(bytes); - } - - // 反馈 - public static void Feedback(bool showMsgbox = true, bool forceOpenLog = false) - { - // On Error Resume Next - FeedbackInfo(); - var currentDate = DateTime.Now.ToString("yyyy-M-dd", CultureInfo.InvariantCulture); - - if (forceOpenLog || (showMsgbox && - ModMain.MyMsgBox( - Lang.Text("Setup.Feedback.Reminder.Message", currentDate), - Lang.Text("Setup.Feedback.Reminder.Title"), - Lang.Text("Common.Action.OpenFolder"), - Lang.Text("Setup.Feedback.Reminder.NotNeeded")) == - 1)) OpenExplorer(exePath + @"PCL\Log\"); - OpenWebsite("https://github.com/PCL-Community/PCL2-CE/issues/"); - } - - public static bool CanFeedback(bool showHint) - { - var stat = UpdateManager.GetVersionStatus(); - if (stat == UpdateEnums.VersionStatus.Latest) return true; - - if (!showHint) return false; - - if (ModMain.MyMsgBox( - stat == UpdateEnums.VersionStatus.NotLatest - ? Lang.Text("Setup.Feedback.Unavailable.NotLatest.Message") - : Lang.Text("Setup.Feedback.Unavailable.CheckFailed.Message"), - Lang.Text("Setup.Feedback.Unavailable.Title"), - stat == UpdateEnums.VersionStatus.NotLatest - ? Lang.Text("Setup.Feedback.Unavailable.NotLatest.Action") - : Lang.Text("Setup.Feedback.Unavailable.CheckFailed.Action"), - Lang.Text("Common.Action.Cancel")) == 1) - ModMain.frmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupUpdate); - - return false; - } - - /// - /// 在日志中输出系统诊断信息。 - /// - public static void FeedbackInfo() - { - try - { - // Get system memory info - var phyRam = KernelInterop.GetPhysicalMemoryBytes(); - - // Calculate memory and DPI scale - var availableMb = phyRam.Available / 1024 / 1024; - var totalMb = phyRam.Total / 1024 / 1024; - var dpiScale = Math.Round(dpi / 96.0, 2); - - // Build diagnostic information string - var info = $""" - [System] Diagnostic Information: - OS: {RuntimeInformation.OSDescription} (32-bit: {SystemInfo.Is32BitSystem}) - Memory: {availableMb} MB / {totalMb} MB - DPI: {dpi} ({dpiScale * 100}%) - MC Folder: {ModFolder.mcFolderSelected ?? "Nothing"} - Executable Path: {exePath} - """; - - LogWrapper.Info(info); - } - catch (Exception ex) - { - // Basic fail-safe to replace "On Error Resume Next" - LogWrapper.Error(ex, "Failed to collect feedback information"); - } - } - - // 断言 - public static void DebugAssert(bool exp) - { - if (!exp) - throw new Exception("断言命中"); - } - - // 获取当前的堆栈信息 - public static string GetStackTrace() - { - var stack = new StackTrace(); - return stack.GetFrames().Skip(1).Select(f => f.GetMethod()) - .Select(f => f.Name + "(" + f.GetParameters().Select(p => p.ToString()).ToList().Join(", ") + ") - " + - f.Module).ToList().Join("\r\n") - .Replace("\r\n" + "\r\n", "\r\n"); - } - - #endregion -} - -#region WPF - -/// -/// 对数据绑定进行加法运算,使用参数决定加数。 -/// -public class AdditionConverter : IValueConverter -{ - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is null) - return 0; - double before; - if (!double.TryParse(value.ToString(), out before)) - return 0; - var scale = 1d; - if (parameter is not null) - double.TryParse(parameter.ToString(), out scale); - return before + scale; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is null) - return Binding.DoNothing; - double before; - if (!double.TryParse(value.ToString(), out before)) - return Binding.DoNothing; - var scale = 1d; - if (parameter is not null) - double.TryParse(parameter.ToString(), out scale); - if (scale == 0d) - return Binding.DoNothing; - return before - scale; - } -} - -/// -/// 对数据绑定进行乘法运算,使用参数决定乘数。 -/// -public class MultiplicationConverter : IValueConverter -{ - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is null) - return 0; - double before; - if (!double.TryParse(value.ToString(), out before)) - return 0; - var scale = 1d; - if (parameter is not null) - double.TryParse(parameter.ToString(), out scale); - return before * scale; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is null) - return Binding.DoNothing; - double before; - if (!double.TryParse(value.ToString(), out before)) - return Binding.DoNothing; - var scale = 1d; - if (parameter is not null) - double.TryParse(parameter.ToString(), out scale); - if (scale == 0d) - return Binding.DoNothing; - return before / scale; - } -} - -/// -/// 将取反的 Boolean 绑定到 Visibility。 -/// -public class InverseBooleanToVisibilityConverter : IValueConverter -{ - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is null) - return Visibility.Visible; - bool boolValue; - return bool.TryParse(value.ToString(), out boolValue) - ? boolValue ? Visibility.Collapsed : Visibility.Visible - : Visibility.Visible; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is null) - return false; - return value is Visibility - ? (Visibility)value != Visibility.Visible - : false; - } -} - -/// -/// 将 Boolean 取反。 -/// -public class InverseBooleanConverter : IValueConverter -{ - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is null) - return false; - bool boolValue; - return bool.TryParse(value.ToString(), out boolValue) ? !boolValue : false; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is null) return false; - - if (bool.TryParse(value.ToString(), out var result)) return !result; - - return false; - } -} - -#endregion diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs index f7de853e0..61d76364f 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs @@ -917,7 +917,7 @@ private static string[] MsLoginStep1New(ModLoader.LoaderTask ModBase.OpenWebsite("https://account.live.com/password/Change")) == 1) goto Retry; @@ -2857,7 +2857,7 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in gameArguments.Add("${library_directory}", ModBase.ShortenPath(ModFolder.mcFolderSelected + "libraries")); gameArguments.Add("${libraries_directory}", ModBase.ShortenPath(ModFolder.mcFolderSelected + "libraries")); gameArguments.Add("${launcher_name}", "PCLCE"); - gameArguments.Add("${launcher_version}", ModBase.versionCode.ToString()); + gameArguments.Add("${launcher_version}", ModBase.VersionCode.ToString()); gameArguments.Add("${version_name}", instance.Name); var argumentInfo = Config.Instance.TypeInfo[ModInstanceList.McMcInstanceSelected?.PathInstance]; gameArguments.Add("${version_type}", @@ -3539,7 +3539,7 @@ private static void McLaunchWait(ModLoader.LoaderTask loader) // 输出信息 McLaunchLog(""); McLaunchLog("~ 基础参数 ~"); - McLaunchLog("PCL 版本:" + ModBase.versionBaseName + " (" + ModBase.versionCode + ")"); + McLaunchLog("PCL 版本:" + ModBase.VersionBaseName + " (" + ModBase.VersionCode + ")"); McLaunchLog( $"游戏版本:{ModInstanceList.McMcInstanceSelected.Info.VanillaName}({ModInstanceList.McMcInstanceSelected.Info.vanilla},Drop {ModInstanceList.McMcInstanceSelected.Info.Drop}{(ModInstanceList.McMcInstanceSelected.Info.Reliable ? "" : ",无法完全确定")})"); McLaunchLog("资源版本:" + ModAssets.McAssetsGetIndexName(ModInstanceList.McMcInstanceSelected)); @@ -3686,9 +3686,9 @@ string replacer(string s) ; // 基础 - text = text.Replace("{pcl_version}", replacer(ModBase.versionBaseName)); - text = text.Replace("{pcl_version_code}", replacer(ModBase.versionCode.ToString())); - text = text.Replace("{pcl_version_branch}", replacer(ModBase.versionBranchName)); + text = text.Replace("{pcl_version}", replacer(ModBase.VersionBaseName)); + text = text.Replace("{pcl_version_code}", replacer(ModBase.VersionCode.ToString())); + text = text.Replace("{pcl_version_branch}", replacer(ModBase.VersionBranchName)); text = text.Replace("{identify}", replacer(Identify.LauncherId)); text = text.Replace("{path}", replacer(Basics.CurrentDirectory)); text = text.Replace("{path_with_name}", replacer(Basics.ExecutablePath)); diff --git a/Plain Craft Launcher 2/Modules/ModMain.cs b/Plain Craft Launcher 2/Modules/ModMain.cs index 5a6f43a6f..c929c5bdd 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.cs +++ b/Plain Craft Launcher 2/Modules/ModMain.cs @@ -908,10 +908,10 @@ public static string ArgumentReplace(string text, Func escapeHan }; // 基础 - text = text.Replace("{pcl_version}", replacer(ModBase.versionBaseName)); - text = text.Replace("{pcl_version_code}", replacer(ModBase.versionCode.ToString())); - text = text.Replace("{pcl_version_branch}", replacer(ModBase.versionBranchName)); - text = text.Replace("{pcl_branch}", replacer(ModBase.versionBranchName)); + text = text.Replace("{pcl_version}", replacer(ModBase.VersionBaseName)); + text = text.Replace("{pcl_version_code}", replacer(ModBase.VersionCode.ToString())); + text = text.Replace("{pcl_version_branch}", replacer(ModBase.VersionBranchName)); + text = text.Replace("{pcl_branch}", replacer(ModBase.VersionBranchName)); text = text.Replace("{identify}", replacer(Identify.LauncherId)); text = text.Replace("{path}", replacer(Basics.ExecutableDirectory)); text = text.Replace("{path_with_name}", replacer(Basics.ExecutableName)); diff --git a/Plain Craft Launcher 2/Modules/Network/Http/RequestSigning.cs b/Plain Craft Launcher 2/Modules/Network/Http/RequestSigning.cs index 29be9b762..171f41c03 100644 --- a/Plain Craft Launcher 2/Modules/Network/Http/RequestSigning.cs +++ b/Plain Craft Launcher 2/Modules/Network/Http/RequestSigning.cs @@ -31,8 +31,8 @@ internal static void SecretHeadersSign(string url, ref HttpRequestMessage client var userAgent = !string.IsNullOrEmpty(customUserAgent) ? customUserAgent : useBrowserUserAgent - ? $"PCL2/{ModBase.upstreamVersion}.{ModBase.versionBranchCode} PCLCE/{ModBase.versionStandardCode} Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0" - : $"PCL2/{ModBase.upstreamVersion}.{ModBase.versionBranchCode} PCLCE/{ModBase.versionStandardCode}"; + ? $"PCL2/{ModBase.UpstreamVersion}.{ModBase.VersionBranchCode} PCLCE/{ModBase.VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0" + : $"PCL2/{ModBase.UpstreamVersion}.{ModBase.VersionBranchCode} PCLCE/{ModBase.VersionStandardCode}"; client.Headers.Add("User-Agent", userAgent); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs b/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs index bb48ef708..cce26cda9 100644 --- a/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs +++ b/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs @@ -27,7 +27,7 @@ public static bool IsCurrentVersionBeta { get { - if (ModBase.versionBaseName.Contains("beta")) + if (ModBase.VersionBaseName.Contains("beta")) return true; return (int)Config.Update.UpdateChannel == 1; } @@ -40,11 +40,11 @@ public static UpdateEnums.VersionStatus GetVersionStatus() if (IsCurrentVersionBeta && (int)Config.Update.UpdateChannel != 1) { var isNewerThanStable = remoteServer.IsLatest(UpdateChannel.stable, - SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.versionBaseName), - ModBase.versionCode); + SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.VersionBaseName), + ModBase.VersionCode); var isBetaLatest = remoteServer.IsLatest(UpdateChannel.beta, - SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.versionBaseName), - ModBase.versionCode); + SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.VersionBaseName), + ModBase.VersionCode); return isNewerThanStable && isBetaLatest ? UpdateEnums.VersionStatus.Latest : UpdateEnums.VersionStatus.NotLatest; @@ -52,8 +52,8 @@ public static UpdateEnums.VersionStatus GetVersionStatus() return remoteServer.IsLatest( IsCurrentVersionBeta ? UpdateChannel.beta : UpdateChannel.stable, - SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.versionBaseName), - ModBase.versionCode) + SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.VersionBaseName), + ModBase.VersionCode) ? UpdateEnums.VersionStatus.Latest : UpdateEnums.VersionStatus.NotLatest; } @@ -83,15 +83,15 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = ); ModBase.WriteFile($"{ModBase.pathTemp}CEUpdateLog.md", version.Changelog); - ModBase.Log($"[Update] 远程最新版本: {version.VersionName}, 当前版本: {ModBase.versionBaseName}"); - if (!(SemVer.Parse(version.VersionName) > SemVer.Parse(ModBase.versionBaseName))) + ModBase.Log($"[Update] 远程最新版本: {version.VersionName}, 当前版本: {ModBase.VersionBaseName}"); + if (!(SemVer.Parse(version.VersionName) > SemVer.Parse(ModBase.VersionBaseName))) return; if (type == UpdateEnums.UpdateType.PromptOnly) { ModBase.RunInUi(() => { if (ModMain.MyMsgBox( - Lang.Text("Update.Available", ModBase.versionBaseName, version.VersionName), + Lang.Text("Update.Available", ModBase.VersionBaseName, version.VersionName), Lang.Text("Update.Title"), Lang.Text("Update.Action"), Lang.Text("Common.Action.Cancel") @@ -124,7 +124,7 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = ModBase.RunInUi(() => { ModMain.frmMain.BtnExtraUpdateRestart.ToolTip = - Lang.Text("Main.Extra.UpdateRestart.ToolTipWithVersion", ModBase.versionBaseName, version.VersionName); + Lang.Text("Main.Extra.UpdateRestart.ToolTipWithVersion", ModBase.VersionBaseName, version.VersionName); ModMain.frmMain.BtnExtraUpdateRestart.ShowRefresh(); ModMain.frmMain.BtnExtraUpdateRestart.Ribble(); }); diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs index 81284be8a..f42eefd32 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs @@ -33,9 +33,9 @@ private void PageOtherAbout_Loaded(object sender, RoutedEventArgs e) return; isLoaded = true; - ItemAboutPcl.Info = ItemAboutPcl.Info.Replace("%VERSION%", ModBase.versionBaseName) - .Replace("%VERSIONCODE%", ModBase.versionCode.ToString()).Replace("%BRANCH%", ModBase.versionBranchName) - .Replace("%COMMIT_HASH%", ModBase.commitHashShort); + ItemAboutPcl.Info = ItemAboutPcl.Info.Replace("%VERSION%", ModBase.VersionBaseName) + .Replace("%VERSIONCODE%", ModBase.VersionCode.ToString()).Replace("%BRANCH%", ModBase.VersionBranchName) + .Replace("%COMMIT_HASH%", ModBase.CommitHashShort); if (!Lang.IsChineseMainland) { diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs index ac34f4198..6aa432467 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs @@ -26,7 +26,7 @@ private void Init() ComboSystemUpdateChannel.SelectedIndex = (int)Config.Update.UpdateChannel; ComboSystemUpdateMode.SelectedIndex = (int)Config.Update.UpdateMode; - TextCurrentVersion.Text = "PCL CE " + VersionNameFormat(ModBase.versionBaseName); + TextCurrentVersion.Text = "PCL CE " + VersionNameFormat(ModBase.VersionBaseName); ModAnimation.AniControlEnabled -= 1; CheckUpdate(); } @@ -40,8 +40,8 @@ private async Task IsLatestAsync() if (await UpdateManager.remoteServer.IsLatestAsync( UpdateManager.IsCurrentVersionBeta ? UpdateChannel.beta : UpdateChannel.stable, SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, - SemVer.Parse(ModBase.versionBaseName), - ModBase.versionCode)) + SemVer.Parse(ModBase.VersionBaseName), + ModBase.VersionCode)) { ModBase.Log("[Update] 已是最新版本"); return UpdateStatus.Latest; @@ -270,7 +270,7 @@ private void BtnGetMirrorCDK_Click(object sender, MouseButtonEventArgs e) private void BtnChangelog_Click(object sender, MouseButtonEventArgs e) { - ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases/v" + ModBase.versionBaseName); + ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases/v" + ModBase.VersionBaseName); } public string VersionNameFormat(string str) diff --git a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs index f35f55fef..4b52df1ac 100644 --- a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs @@ -273,7 +273,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) var cardXAML = $@" + Tag=""{loader.Progress + (double)loader.State}"" Title=""{ModBase.EscapeXml(loader.name)}"" Margin=""0,0,0,15""> @@ -314,7 +314,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) } } - cardXAML += $""; + cardXAML += $""; row += 1; } diff --git a/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs b/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs index 211feee14..116ccbe29 100644 --- a/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs @@ -454,7 +454,7 @@ private void GetAnnouncement() // 版本过滤 var minVer = notice["minVer"].ToObject(); var maxVer = notice["maxVer"].ToObject(); - if (ModBase.versionCode < minVer || ModBase.versionCode > maxVer) continue; + if (ModBase.VersionCode < minVer || ModBase.VersionCode > maxVer) continue; // 类型映射 var type = LinkAnnounceType.Notice; diff --git a/Plain Craft Launcher 2/UI/Converters/AdditionConverter.cs b/Plain Craft Launcher 2/UI/Converters/AdditionConverter.cs new file mode 100644 index 000000000..d605ccb8d --- /dev/null +++ b/Plain Craft Launcher 2/UI/Converters/AdditionConverter.cs @@ -0,0 +1,35 @@ +using System.Globalization; +using System.Windows.Data; +using static System.Double; + +namespace PCL; + +/// +/// 对数据绑定进行加法运算,使用参数决定加数。 +/// +public class AdditionConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null) + return 0; + if (!TryParse(value.ToString(), out var before)) + return 0; + var scale = 1d; + if (parameter is not null) + TryParse(parameter.ToString(), out scale); + return before + scale; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null || !TryParse(value.ToString(), out var before)) + return Binding.DoNothing; + var scale = 1d; + if (parameter is not null) + TryParse(parameter.ToString(), out scale); + if (scale == 0d) + return Binding.DoNothing; + return before - scale; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/UI/Converters/InverseBooleanConverter.cs b/Plain Craft Launcher 2/UI/Converters/InverseBooleanConverter.cs new file mode 100644 index 000000000..677666f3a --- /dev/null +++ b/Plain Craft Launcher 2/UI/Converters/InverseBooleanConverter.cs @@ -0,0 +1,26 @@ +using System.Globalization; +using System.Windows.Data; + +namespace PCL; + +/// +/// 将 Boolean 取反。 +/// +public class InverseBooleanConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null) + return false; + return bool.TryParse(value.ToString(), out var boolValue) && !boolValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null) return false; + + if (bool.TryParse(value.ToString(), out var result)) return !result; + + return false; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/UI/Converters/InverseBooleanToVisibilityConverter.cs b/Plain Craft Launcher 2/UI/Converters/InverseBooleanToVisibilityConverter.cs new file mode 100644 index 000000000..ac6696d84 --- /dev/null +++ b/Plain Craft Launcher 2/UI/Converters/InverseBooleanToVisibilityConverter.cs @@ -0,0 +1,27 @@ +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace PCL; + +/// +/// 将取反的 Boolean 绑定到 Visibility。 +/// +public class InverseBooleanToVisibilityConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null) + return Visibility.Visible; + return bool.TryParse(value.ToString(), out var boolValue) + ? boolValue ? Visibility.Collapsed : Visibility.Visible + : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null) + return false; + return value is Visibility visibility && visibility != Visibility.Visible; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/UI/Converters/MultiplicationConverter.cs b/Plain Craft Launcher 2/UI/Converters/MultiplicationConverter.cs new file mode 100644 index 000000000..6e0dbcefd --- /dev/null +++ b/Plain Craft Launcher 2/UI/Converters/MultiplicationConverter.cs @@ -0,0 +1,35 @@ +using System.Globalization; +using System.Windows.Data; +using static System.Double; + +namespace PCL; + +/// +/// 对数据绑定进行乘法运算,使用参数决定乘数。 +/// +public class MultiplicationConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null) + return 0; + if (!TryParse(value.ToString(), out var before)) + return 0; + var scale = 1d; + if (parameter is not null) + TryParse(parameter.ToString(), out scale); + return before * scale; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is null || !TryParse(value.ToString(), out var before)) + return Binding.DoNothing; + var scale = 1d; + if (parameter is not null) + TryParse(parameter.ToString(), out scale); + if (scale == 0d) + return Binding.DoNothing; + return before / scale; + } +} \ No newline at end of file From 8565db7eed5e99309eb8c4696704680779869882 Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Tue, 30 Jun 2026 21:37:33 +0800 Subject: [PATCH 02/16] =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E5=B7=B2=E6=9C=89?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Compatibility/ModBase.LegacyFiles.cs | 527 ++---------------- .../Compatibility/ModBase.LegacySearch.cs | 148 +---- .../Compatibility/ModBase.LegacySystem.cs | 37 +- 3 files changed, 94 insertions(+), 618 deletions(-) diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs index dedc53b4a..d72990468 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs @@ -1,12 +1,11 @@ using System.Diagnostics; using System.IO; -using System.IO.Compression; using System.Runtime.InteropServices; using System.Text; -using PCL.Core.App.Localization; -using PCL.Core.Utils; using PCL.Core.Utils.Codecs; using PCL.Core.Utils.Hash; +using CoreDirectories = PCL.Core.IO.Directories; +using CoreFiles = PCL.Core.IO.Files; namespace PCL; @@ -14,6 +13,13 @@ public static partial class ModBase { #region LegacyFiles + private static string ResolveLegacyFilePath(string filePath) + { + if (string.IsNullOrEmpty(filePath)) + return filePath; + return filePath.Contains(@":\") ? filePath : exePath + filePath; + } + // 路径处理 /// /// 从文件路径或者 Url 获取不包含文件名的路径,或获取文件夹的父文件夹路径。 @@ -92,25 +98,9 @@ public static string GetFolderNameFromPath(string folderPath) /// public static void CopyFile(string fromPath, string toPath) { - try - { - // 还原文件路径 - if (!fromPath.Contains(@":\")) - fromPath = exePath + fromPath; - if (!toPath.Contains(@":\")) - toPath = exePath + toPath; - // 如果复制同一个文件则跳过 - if ((fromPath ?? "") == (toPath ?? "")) - return; - // 确保目录存在 - Directory.CreateDirectory(GetPathFromFullPath(toPath)); - // 复制文件 - File.Copy(fromPath, toPath, true); - } - catch (Exception ex) - { - throw new Exception("复制文件出错:" + fromPath + " → " + toPath, ex); - } + CoreFiles.CopyFileAsync(ResolveLegacyFilePath(fromPath), ResolveLegacyFilePath(toPath)) + .GetAwaiter() + .GetResult(); } /// @@ -118,31 +108,9 @@ public static void CopyFile(string fromPath, string toPath) /// public static byte[] ReadFileBytes(string filePath, Encoding encoding = null) { - try - { - // 还原文件路径 - if (!filePath.Contains(@":\")) - filePath = exePath + filePath; - if (File.Exists(filePath)) - { - using var readStream = new FileStream( - filePath, - FileMode.Open, - FileAccess.Read, - FileShare.Read); - using var ms = new MemoryStream(); - readStream.CopyTo(ms); - return ms.ToArray(); - } - - Log("[System] 欲读取的文件不存在,已返回空内容:" + filePath); - return []; - } - catch (Exception ex) - { - Log(ex, "读取文件出错:" + filePath); - return []; - } + return CoreFiles.ReadAllBytesOrEmptyAsync(ResolveLegacyFilePath(filePath)) + .GetAwaiter() + .GetResult(); } /// @@ -151,9 +119,9 @@ public static byte[] ReadFileBytes(string filePath, Encoding encoding = null) /// 文件完整或相对路径。 public static string ReadFile(string filePath, Encoding encoding = null) { - var fileBytes = ReadFileBytes(filePath); - var readFileRet = encoding is null ? DecodeBytes(fileBytes) : encoding.GetString(fileBytes); - return readFileRet; + return CoreFiles.ReadAllTextOrEmptyAsync(ResolveLegacyFilePath(filePath), encoding) + .GetAwaiter() + .GetResult(); } /// @@ -161,18 +129,9 @@ public static string ReadFile(string filePath, Encoding encoding = null) /// public static string ReadFile(Stream stream, Encoding encoding = null) { - try - { - var readedContent = new MemoryStream(); - stream.CopyTo(readedContent); - var bts = readedContent.ToArray(); - return (encoding ?? EncodingDetector.DetectEncoding(bts)).GetString(bts); - } - catch (Exception ex) - { - Log(ex, "读取流出错"); - return ""; - } + return CoreFiles.ReadAllTextOrEmptyAsync(stream, encoding) + .GetAwaiter() + .GetResult(); } /// @@ -187,31 +146,9 @@ public static void WriteFile( bool append = false, Encoding? encoding = null) { - // 处理相对路径 - if (!filePath.Contains(@":\")) - filePath = exePath + filePath; - // 确保目录存在 - Directory.CreateDirectory(GetPathFromFullPath(filePath)); - // 写入文件 - if (append) - // 追加目前文件 - { - using var writer = new StreamWriter( - filePath, - true, - encoding ?? EncodingDetector.DetectEncoding(ReadFileBytes(filePath))); - writer.Write(text); - } - else - { - // 直接写入字节 - var bytes = encoding is null - ? new UTF8Encoding(false).GetBytes(text) - : encoding.GetBytes(text); - var tempPath = filePath + ".pcltmp." + Guid.NewGuid().ToString("N"); - File.WriteAllBytes(tempPath, bytes); - File.Move(tempPath, filePath, true); - } + CoreFiles.WriteFileAsync(ResolveLegacyFilePath(filePath), text, append, encoding) + .GetAwaiter() + .GetResult(); } /// @@ -223,13 +160,9 @@ public static void WriteFile( /// 是否将文件内容追加到当前文件,而不是覆盖它。 public static void WriteFile(string filePath, byte[] content, bool append = false) { - // 处理相对路径 - if (!filePath.Contains(@":\")) - filePath = exePath + filePath; - // 确保目录存在 - Directory.CreateDirectory(GetPathFromFullPath(filePath)); - // 写入文件 - File.WriteAllBytes(filePath, content); + CoreFiles.WriteFileAsync(ResolveLegacyFilePath(filePath), content, append) + .GetAwaiter() + .GetResult(); } /// @@ -238,25 +171,9 @@ public static void WriteFile(string filePath, byte[] content, bool append = fals /// 文件完整或相对路径。 public static bool WriteFile(string filePath, Stream stream) { - try - { - // 还原文件路径 - if (!filePath.Contains(@":\")) - filePath = exePath + filePath; - // 确保目录存在 - Directory.CreateDirectory(GetPathFromFullPath(filePath)); - // 读取流 - using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read); - fs.SetLength(0L); - stream.CopyTo(fs); - - return true; - } - catch (Exception ex) - { - Log(ex, "保存流出错"); - return false; - } + return CoreFiles.WriteFileAsync(ResolveLegacyFilePath(filePath), stream) + .GetAwaiter() + .GetResult(); } /// @@ -264,40 +181,12 @@ public static bool WriteFile(string filePath, Stream stream) /// public static string DecodeBytes(byte[] bytes) { - var length = bytes.Length; - if (length < 3) - return Encoding.UTF8.GetString(bytes); - // 根据 BOM 判断编码 - if (bytes[0] >= 0xEF) - { - // 有 BOM 类型 - if (bytes[0] == 0xEF && bytes[1] == 0xBB) - return Encoding.UTF8.GetString(bytes, 3, length - 3); - - if (bytes[0] == 0xFE && bytes[1] == 0xFF) - return Encoding.BigEndianUnicode.GetString(bytes, 3, length - 3); - - if (bytes[0] == 0xFF && bytes[1] == 0xFE) - return Encoding.Unicode.GetString(bytes, 3, length - 3); - - return Encoding.GetEncoding("GB18030").GetString(bytes, 3, length - 3); - } - - // 无 BOM 文件:GB18030(ANSI)或 UTF8 - var uTF8 = Encoding.UTF8.GetString(bytes); - var errorChar = Encoding.UTF8.GetString("\ufffd"u8.ToArray()).ToCharArray()[0]; - return uTF8.Contains(errorChar) - ? Encoding.GetEncoding("GB18030").GetString(bytes) - : uTF8; + return EncodingUtils.DecodeBytes(bytes); } public static object GetHexString(Memory bytes) { - var sb = new StringBuilder(bytes.Length * 2); - foreach (var c in bytes.Span) - sb.Append(c.ToString("x2")); - - return sb.ToString(); + return Convert.ToHexString(bytes.Span).ToLowerInvariant(); } // 文件校验 @@ -306,28 +195,7 @@ public static object GetHexString(Memory bytes) /// public static string GetFileMD5(string filePath) { - var retry = false; - Re: ; - - try - { - // 获取 MD5 - using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return (string)GetHexString(MD5Provider.Instance.ComputeHash(fs)); - } - catch (Exception ex) - { - if (retry || ex is FileNotFoundException) - { - Log(ex, "获取文件 MD5 失败:" + filePath); - return ""; - } - - retry = true; - Log(ex, "获取文件 MD5 可重试失败:" + filePath, LogLevel.Normal); - Thread.Sleep(RandomUtils.NextInt(200, 500)); - goto Re; - } + return CoreFiles.GetFileMD5Async(filePath).GetAwaiter().GetResult(); } /// @@ -335,30 +203,7 @@ public static string GetFileMD5(string filePath) /// public static string GetFileSHA512(string filePath) { - var retry = false; - Re: ; - - try - { - // '检测该文件是否在下载中,若在下载则放弃检测 - // If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return "" - // 获取 SHA512 - using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return (string)GetHexString(SHA512Provider.Instance.ComputeHash(fs)); - } - catch (Exception ex) - { - if (retry || ex is FileNotFoundException) - { - Log(ex, "获取文件 SHA512 失败:" + filePath); - return ""; - } - - retry = true; - Log(ex, "获取文件 SHA512 可重试失败:" + filePath, LogLevel.Normal); - Thread.Sleep(RandomUtils.NextInt(200, 500)); - goto Re; - } + return CoreFiles.GetFileSHA512Async(filePath).GetAwaiter().GetResult(); } /// @@ -366,30 +211,7 @@ public static string GetFileSHA512(string filePath) /// public static string GetFileSHA256(string filePath) { - var retry = false; - Re: ; - - try - { - // '检测该文件是否在下载中,若在下载则放弃检测 - // If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return "" - // 获取 SHA256 - using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return (string)GetHexString(SHA256Provider.Instance.ComputeHash(fs)); - } - catch (Exception ex) - { - if (retry || ex is FileNotFoundException) - { - Log(ex, "获取文件 SHA256 失败:" + filePath); - return ""; - } - - retry = true; - Log(ex, "获取文件 SHA256 可重试失败:" + filePath, LogLevel.Normal); - Thread.Sleep(RandomUtils.NextInt(200, 500)); - goto Re; - } + return CoreFiles.GetFileSHA256Async(filePath).GetAwaiter().GetResult(); } /// @@ -397,28 +219,7 @@ public static string GetFileSHA256(string filePath) /// public static string GetFileSHA1(string filePath) { - var retry = false; - Re: ; - - try - { - // 获取 SHA1 - using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return (string)GetHexString(SHA1Provider.Instance.ComputeHash(fs)); - } - catch (Exception ex) - { - if (retry || ex is FileNotFoundException) - { - Log(ex, "获取文件 SHA1 失败:" + filePath); - return ""; - } - - retry = true; - Log(ex, "获取文件 SHA1 可重试失败:" + filePath, LogLevel.Normal); - Thread.Sleep(RandomUtils.NextInt(200, 500)); - goto Re; - } + return CoreFiles.GetFileSHA1Async(filePath).GetAwaiter().GetResult(); } /// @@ -490,81 +291,9 @@ public FileChecker( /// public string Check(string localPath) { - try - { - Log($"[Checker] 开始校验文件 {localPath}", LogLevel.Developer); - var info = new FileInfo(localPath); - if (!info.Exists) - return "文件不存在:" + localPath; - var fileSize = info.Length; - var errorMessage = new List(); - var allowIgnore = false; // 允许相信哈希正确但是大小不正确 - if (!string.IsNullOrEmpty(hash)) - { - switch (hash.Length) - { - // MD5 - case < 35: - { - var computedHash = GetFileMD5(localPath); - if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) - errorMessage.Add("文件 MD5 应为 " + hash + ",实际为 " + computedHash); - break; - } - // SHA256 - case 64: - { - var computedHash = GetFileSHA256(localPath); - if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) - errorMessage.Add("文件 SHA256 应为 " + hash + ",实际为 " + computedHash); - break; - } - // SHA1 (40) - default: - { - var computedHash = GetFileSHA1(localPath); - if ((hash.ToLowerInvariant() ?? "") != (computedHash ?? "")) - errorMessage.Add("文件 SHA1 应为 " + hash + ",实际为 " + computedHash); - break; - } - } - - allowIgnore = errorMessage.Count == 0; - } - - if (actualSize >= 0L && actualSize != fileSize && !allowIgnore) // 不允许忽略大小不正确的情况 - errorMessage.Add($"文件大小应为 {actualSize} B,实际为 {fileSize} B" + - (fileSize < 2000L ? ",内容为" + ReadFile(localPath) : "")); - - if (minSize >= 0L && minSize > fileSize) - errorMessage.Add($"文件大小应大于 {minSize} B,实际为 {fileSize} B" + - (fileSize < 2000L ? ",内容为:" + ReadFile(localPath) : "")); - - if (isJson) - { - var content = ReadFile(localPath); - if (string.IsNullOrEmpty(content)) - throw new Exception("读取到的文件为空"); - try - { - GetJson(content); - } - catch (Exception ex) - { - throw new Exception(Lang.Text("Common.Error.InvalidJson"), ex); - } - } - - if (errorMessage.Count == 0) return null; - - errorMessage.Insert(0, $"实际校验地址:{localPath}"); - return errorMessage.Join(";"); - } - catch (Exception ex) - { - Log(ex, "检查文件出错"); - return ex.ToString(); - } + return CoreFiles.CheckAsync(localPath, minSize, actualSize, hash, isJson) + .GetAwaiter() + .GetResult(); } } @@ -586,7 +315,7 @@ public static void WaitForFileReady(string filePath, int timeoutMs = 2000) /// 是否要求文件为合法 JSON。 public static void WaitForFileReady(string filePath, int timeoutMs, bool requireJson) { - filePath = filePath.Contains(@":\") ? filePath : exePath + filePath; + filePath = ResolveLegacyFilePath(filePath); var start = Environment.TickCount; long lastSize = -1; while (Environment.TickCount - start < timeoutMs) @@ -626,43 +355,9 @@ public static void WaitForFileReady(string filePath, int timeoutMs, bool require public static void ExtractFile(string compressFilePath, string destDirectory, Encoding encode = null, Action progressIncrementHandler = null) { - Directory.CreateDirectory(destDirectory); - destDirectory = Path.GetFullPath(destDirectory); - if (!destDirectory.EndsWith(Path.DirectorySeparatorChar.ToString())) - destDirectory += Path.DirectorySeparatorChar.ToString(); - if (compressFilePath.EndsWithF(".gz", true)) - // 以 gz 方式解压 - { - using var compressedFile = new FileStream(compressFilePath, FileMode.Open, FileAccess.Read); - using var decompressStream = new GZipStream(compressedFile, CompressionMode.Decompress); - using var extractFileStream = new FileStream( - Path.Combine( - destDirectory, - GetFileNameFromPath(compressFilePath) - .ToLower() - .Replace(".tar", "") - .Replace(".gz", "")), - FileMode.OpenOrCreate, FileAccess.Write); - decompressStream.CopyTo(extractFileStream); - } - else - // 以 zip 方式解压 - { - using var archive = ZipFile.Open(compressFilePath, ZipArchiveMode.Read, - encode ?? Encoding.GetEncoding("GB18030")); - var totalCount = archive.Entries.Count; - foreach (var entry in archive.Entries) - { - progressIncrementHandler?.Invoke(1d / totalCount); - var destinationPath = Path.GetFullPath(Path.Combine(destDirectory, entry.FullName)); - if (!destinationPath.StartsWithF(destDirectory)) - throw new Exception( - $"解压文件 {entry.FullName} 错误:解压文件路径 {destinationPath} 不在目标目录 {destDirectory} 内"); - if (destinationPath.EndsWithF(@"\") || destinationPath.EndsWithF("/")) continue; - Directory.CreateDirectory(GetPathFromFullPath(destinationPath)); - entry.ExtractToFile(destinationPath, true); - } - } + CoreFiles.ExtractFileAsync(compressFilePath, destDirectory, progressIncrementHandler) + .GetAwaiter() + .GetResult(); } /// @@ -670,74 +365,9 @@ public static void ExtractFile(string compressFilePath, string destDirectory, En /// public static int DeleteDirectory(string path, bool ignoreIssue = false) { - if (!Directory.Exists(path)) - return 0; - var deletedCount = 0; - string[] files; - try - { - files = Directory.GetFiles(path); - } - catch (DirectoryNotFoundException ex) // #4549 - { - Log(ex, $"疑似为孤立符号链接,尝试直接删除({path})", LogLevel.Developer); - Directory.Delete(path); - return 0; - } - - foreach (var filePath in files) - { - var retriedFile = false; - RetryFile: ; - - try - { - File.Delete(filePath); - deletedCount += 1; - } - catch (Exception ex) - { - if (!retriedFile) - { - retriedFile = true; - Log(ex, $"删除文件失败,将在 0.3s 后重试({filePath})"); - Thread.Sleep(300); - goto RetryFile; - } - - if (ignoreIssue) - Log(ex, "删除单个文件可忽略地失败"); - else - throw; - } - } - - foreach (var str in Directory.GetDirectories(path)) - DeleteDirectory(str, ignoreIssue); - var retriedDir = false; - RetryDir: ; - - try - { - Directory.Delete(path, true); - } - catch (Exception ex) - { - if (!retriedDir && !RunInUi()) - { - retriedDir = true; - Log(ex, $"删除文件夹失败,将在 0.3s 后重试({path})"); - Thread.Sleep(300); - goto RetryDir; - } - - if (ignoreIssue) - Log(ex, "删除单个文件夹可忽略地失败"); - else - throw; - } - - return deletedCount; + return CoreDirectories.DeleteDirectoryAsync(path, ignoreIssue) + .GetAwaiter() + .GetResult(); } /// @@ -745,20 +375,9 @@ public static int DeleteDirectory(string path, bool ignoreIssue = false) /// public static void CopyDirectory(string fromPath, string toPath, Action progressIncrementHandler = null) { - fromPath = fromPath.Replace("/", @"\"); - if (!fromPath.EndsWithF(@"\")) - fromPath += @"\"; - toPath = toPath.Replace("/", @"\"); - if (!toPath.EndsWithF(@"\")) - toPath += @"\"; - var allFiles = EnumerateFiles(fromPath).ToList(); - var fileCount = allFiles.Count; - foreach (var file in allFiles) - { - CopyFile(file.FullName, file.FullName.Replace(fromPath, toPath)); - if (progressIncrementHandler is not null) - progressIncrementHandler(1d / fileCount); - } + CoreDirectories.CopyDirectoryAsync(fromPath, toPath, progressIncrementHandler) + .GetAwaiter() + .GetResult(); } /// @@ -766,10 +385,16 @@ public static void CopyDirectory(string fromPath, string toPath, Action /// public static IEnumerable EnumerateFiles(string directory) { - var info = new DirectoryInfo(ShortenPath(directory)); - if (!info.Exists) - return new List(); - return info.EnumerateFiles("*", SearchOption.AllDirectories); + try + { + return CoreDirectories.EnumerateFilesAsync(ShortenPath(directory)) + .GetAwaiter() + .GetResult(); + } + catch (DirectoryNotFoundException) + { + return []; + } } /// @@ -827,28 +452,7 @@ public static void CreateSymbolicLink(string linkPath, string targetPath, int fl /// public static bool CheckPermission(string path) { - try - { - if (string.IsNullOrEmpty(path)) - return false; - if (!path.EndsWithF(@"\")) - path += @"\"; - if (path.EndsWithF(@":\System Volume Information\") || path.EndsWithF(@":\$RECYCLE.BIN\")) - return false; - if (!Directory.Exists(path)) - return false; - var fileName = "CheckPermission" + GetUuid(); - if (File.Exists(path + fileName)) - File.Delete(path + fileName); - File.Create(path + fileName).Dispose(); - File.Delete(path + fileName); - return true; - } - catch (Exception ex) - { - Log(ex, "没有对文件夹 " + path + " 的权限,请尝试以管理员权限运行 PCL"); - return false; - } + return CoreDirectories.CheckPermissionAsync(path).GetAwaiter().GetResult(); } /// @@ -856,16 +460,7 @@ public static bool CheckPermission(string path) /// public static void CheckPermissionWithException(string path) { - if (string.IsNullOrWhiteSpace(path)) - throw new ArgumentNullException("文件夹名不能为空!"); - if (!path.EndsWithF(@"\")) - path += @"\"; - if (!Directory.Exists(path)) - throw new DirectoryNotFoundException("文件夹不存在!"); - if (File.Exists(path + "CheckPermission")) - File.Delete(path + "CheckPermission"); - File.Create(path + "CheckPermission").Dispose(); - File.Delete(path + "CheckPermission"); + CoreDirectories.CheckPermissionWithExceptionAsync(path).GetAwaiter().GetResult(); } #endregion diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs index 8d5932937..bf4f33c46 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs @@ -1,81 +1,26 @@ -namespace PCL; +using CoreSimilaritySearch = PCL.Core.Utils.SimilaritySearch; + +namespace PCL; public static partial class ModBase { #region 搜索 - /// - /// 获取搜索文本的相似度。 - /// - /// 被搜索的长内容。 - /// 用户输入的搜索文本。 - private static double SearchSimilarity(string source, string query) + private static List> ToCoreSearchSources(IEnumerable sources) { - var qp = 0; - var lenSum = 0d; - source = source.ToLower().Replace(" ", ""); - query = query.ToLower().Replace(" ", ""); - var sourceLength = source.Length; - var queryLength = query.Length; // 用于计算最后因数的长度缓存 - while (qp < queryLength) - { - // 对 qp 作为开始位置计算 - var sp = 0; - var lenMax = 0; - var spMax = 0; - // 查找以 qp 为头的最大子串 - while (sp < source.Length) - { - // 对每个 sp 作为开始位置计算最大子串 - var len = 0; - while (qp + len < queryLength && sp + len < source.Length && source[sp + len] == query[qp + len]) - len += 1; - // 存储 len - if (len > lenMax) - { - lenMax = len; - spMax = sp; - } - - // 根据结果增加 sp - sp += Math.Max(1, len); - } - - if (lenMax > 0) - { - source = string.Concat(source.AsSpan(0, spMax), source.Length > spMax + lenMax - ? source[(spMax + lenMax)..] - : string.Empty); // 将源中的对应字段替换空 - // 存储 lenSum - var incWeight = Math.Pow(1.4d, 3 + lenMax) - 3.6d; // 根据长度加成 - incWeight *= 1d + 0.3d * Math.Max(0, 3 - Math.Abs(qp - spMax)); // 根据位置加成 - lenSum += incWeight; - } - - // 根据结果增加 qp - qp += Math.Max(1, lenMax); - } - - // 计算结果:重复字段量 × 源长度影响比例 - return lenSum / queryLength * (3d / Math.Pow(sourceLength + 15, 0.5d)) * - (queryLength <= 2 ? 3 - queryLength : 1); - } + var result = new List>(); + if (sources is null) + return result; - /// - /// 获取多段文本加权后的相似度。 - /// - private static double SearchSimilarityWeighted(List source, string query) - { - var totalWeight = 0d; - var sum = 0d; - foreach (var pair in source) + foreach (var source in sources) { - if (pair.aliases.Length != 0) - sum += pair.aliases.Max(a => SearchSimilarity(a, query)) * pair.weight; - totalWeight += pair.weight; + if (source.aliases is null) + continue; + foreach (var alias in source.aliases) + result.Add(new KeyValuePair(alias, source.weight)); } - return sum / totalWeight; + return result; } /// @@ -139,66 +84,25 @@ public SearchSource(string text, double weight = 1) public static List> Search(List> entries, string query, int maxBlurCount = 5, double minBlurSimilarity = 0.1d) { - var resultList = new List>(); - - if (entries is null || entries.Count == 0) return resultList; - - // Preprocess query into parts - var queryParts = query.Split([' '], StringSplitOptions.RemoveEmptyEntries); - if (queryParts.Length == 0) - { - resultList.AddRange(entries); - return resultList; - } + if (entries is null || entries.Count == 0) + return []; - // Precompute query parts in lowercase for case-insensitive comparison - var queryPartsLower = queryParts.Select(q => q.ToLower()).ToArray(); + var coreEntries = entries + .Select((entry, index) => new Core.Utils.SearchEntry<(SearchEntry Legacy, int Index)>( + (entry, index), + ToCoreSearchSources(entry.searchSource))) + .ToList(); - // Process each entry to compute similarity and absolute match status - foreach (var entry in entries) + var coreResults = CoreSimilaritySearch.Search(coreEntries, query, maxBlurCount, minBlurSimilarity); + foreach (var coreEntry in coreResults) { - entry.similarity = SearchSimilarityWeighted(entry.searchSource, query); - - // Preprocess search source keys: remove spaces and convert to lowercase - var processedSources = entry.searchSource.Select(s => - { - for (var i = 0; i < s.aliases.Length; i++) - s.aliases[i] = s.aliases[i].Replace(" ", "").ToLower(); - return s.aliases; - }).ToList(); - - // Check if all query parts are matched exactly by at least one source - var isAbsoluteRight = queryPartsLower - .Select(qp => processedSources - .Any(ps => ps - .Any(p => p - .Contains(qp)))) - .All(found => found); - - entry.absoluteRight = isAbsoluteRight; + coreEntry.Item.Legacy.absoluteRight = coreEntry.AbsoluteRight; + coreEntry.Item.Legacy.similarity = coreEntry.Similarity; } - // Sort by absolute match (descending), then by similarity (descending) - var sortedEntries = entries - .OrderByDescending(e => e.absoluteRight) - .ThenByDescending(e => e.similarity) + return coreResults + .Select(result => result.Item.Legacy) .ToList(); - - // Build the final result list - var blurCount = 0; - foreach (var entry in sortedEntries) - if (entry.absoluteRight) - { - resultList.Add(entry); - } - else - { - if (entry.similarity < minBlurSimilarity || blurCount >= maxBlurCount) break; - resultList.Add(entry); - blurCount += 1; - } - - return resultList; } #endregion diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs index 67ecca863..c26027e96 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs @@ -1,12 +1,14 @@ using System.Collections; using System.Diagnostics; using System.IO; -using System.Text; using System.Windows; using System.Windows.Threading; using Microsoft.VisualBasic; +using PCL.Core.App; using PCL.Core.App.Localization; using PCL.Core.Logging; +using PCL.Core.Utils.Codecs; +using PCL.Core.Utils.Exts; using PCL.Core.Utils.OS; namespace PCL; @@ -17,7 +19,7 @@ public static partial class ModBase public static bool IsUtf8CodePage() { - return Encoding.Default.CodePage == 65001; + return EncodingUtils.IsDefaultEncodingUtf8(); } /// @@ -382,23 +384,7 @@ public static Thread RunInNewThread( string name = null, ThreadPriority priority = ThreadPriority.Normal) { - var th = new Thread(() => - { - try - { - action(); - } - catch (ThreadInterruptedException ex) - { - Log(name + ":线程已中止"); - } - catch (Exception ex) - { - Log(ex, name + ":线程执行失败", LogLevel.Feedback); - } - }) { Name = name ?? "Runtime New Invoke " + GetUuid() + "#", Priority = priority }; - th.Start(); - return th; + return Basics.RunInNewThread(action, name ?? "Runtime New Invoke " + GetUuid() + "#", priority); } /// @@ -460,14 +446,7 @@ public static void RunInThread(Action action) /// 传入两个对象,若第一个对象应该排在前面,则返回 True。 public static List Sort(this IList list, ComparisonBoolean sortRule) { - // 创建原列表的副本以避免修改原始列表 - var tempList = new List(list); - if (tempList.Count <= 1) - return tempList; - - // 使用归并排序核心算法 - MergeSort_Sort(ref tempList, 0, tempList.Count - 1, sortRule); - return tempList; + return SortUtils.Sort(list, sortRule); } private static void MergeSort_Sort( @@ -756,9 +735,7 @@ public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool /// public static Stream GetResourceStream(string path) { - var resourceInfo = - System.Windows.Application.GetResourceStream(new Uri($"pack://application:,,,/{path}", UriKind.Absolute)); - return resourceInfo?.Stream; + return Basics.GetResourceStream(path); } #endregion From 916702111cd7a862c79a97a9218e767ddfc6ce7a Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Tue, 30 Jun 2026 22:26:57 +0800 Subject: [PATCH 03/16] =?UTF-8?q?=E4=B8=93=E5=B1=9E=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Compatibility/ModBase.Declarations.cs | 81 ++-- .../Compatibility/ModBase.LegacyFiles.cs | 261 ++---------- .../Compatibility/ModBase.LegacyIni.cs | 114 +----- .../Compatibility/ModBase.LegacyLog.cs | 280 +------------ .../Compatibility/ModBase.LegacySearch.cs | 9 +- .../Compatibility/ModBase.LegacySystem.cs | 383 ++---------------- .../Compatibility/ModBase.LegacyUi.cs | 170 +------- .../Controls/MyPageRight.cs | 22 +- Plain Craft Launcher 2/FormMain.xaml.cs | 2 +- .../Infrastructure/CustomXamlLoader.cs | 76 ++++ .../Infrastructure/LauncherArguments.cs | 23 ++ .../Infrastructure/LauncherEnvironment.cs | 43 ++ .../Infrastructure/LauncherExitCode.cs | 15 + .../Infrastructure/LauncherFeedbackService.cs | 130 ++++++ .../Infrastructure/LauncherFontService.cs | 21 + .../Infrastructure/LauncherLog.cs | 210 ++++++++++ .../Infrastructure/LauncherPaths.cs | 92 +++++ .../Infrastructure/LauncherProcess.cs | 236 +++++++++++ .../Infrastructure/LauncherRuntime.cs | 39 ++ .../Infrastructure/LegacyFileFacade.cs | 289 +++++++++++++ .../Infrastructure/LegacyIniStore.cs | 124 ++++++ .../Infrastructure/UiThread.cs | 54 +++ .../Modules/Base/ModAnimation.cs | 4 +- .../Modules/Base/ModLoader.cs | 10 +- .../Modules/Base/ModSetup.cs | 2 +- .../Modules/Minecraft/ModLaunch.cs | 22 +- .../Modules/Minecraft/ModLocalComp.cs | 4 +- .../Pages/PageDownload/ModDownloadLib.cs | 12 +- .../PageInstance/PageInstanceSaves.xaml.cs | 4 +- .../Pages/PageLaunch/PageLaunchRight.xaml.cs | 8 +- .../Pages/PageSetup/PageSetupUI.xaml.cs | 2 +- .../Pages/PageSpeedLeft.xaml.cs | 2 +- Plain Craft Launcher 2/UI/LayoutExtensions.cs | 95 +++++ Plain Craft Launcher 2/UI/Visual/DpiUtils.cs | 21 + .../UI/Visual/VisualCapture.cs | 68 ++++ 35 files changed, 1740 insertions(+), 1188 deletions(-) create mode 100644 Plain Craft Launcher 2/Infrastructure/CustomXamlLoader.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherArguments.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherEnvironment.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherLog.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/UiThread.cs create mode 100644 Plain Craft Launcher 2/UI/LayoutExtensions.cs create mode 100644 Plain Craft Launcher 2/UI/Visual/DpiUtils.cs create mode 100644 Plain Craft Launcher 2/UI/Visual/VisualCapture.cs diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs b/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs index b27b65dde..bc83f5f76 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs @@ -1,7 +1,4 @@ -using System.IO; -using System.Windows.Media; -using PCL.Core.App; -using PCL.Core.Utils; +using System.Windows.Media; using Brush = System.Windows.Media.Brush; using Color = System.Windows.Media.Color; using ColorConverter = System.Windows.Media.ColorConverter; @@ -13,12 +10,12 @@ public static partial class ModBase #region 声明 // 下列版本信息由更新器自动修改 - public static readonly string VersionBaseName = Basics.VersionName; - public static readonly string VersionStandardCode = Basics.Metadata.Version.StandardVersion; - public static readonly string UpstreamVersion = Basics.Metadata.Version.UpstreamVersion; - public static readonly string CommitHash = Basics.Metadata.Version.Commit; - public static readonly string CommitHashShort = Basics.Metadata.Version.CommitDigest; - public static readonly int VersionCode = Basics.VersionCode; + public static readonly string VersionBaseName = LauncherEnvironment.VersionBaseName; + public static readonly string VersionStandardCode = LauncherEnvironment.VersionStandardCode; + public static readonly string UpstreamVersion = LauncherEnvironment.UpstreamVersion; + public static readonly string CommitHash = LauncherEnvironment.CommitHash; + public static readonly string CommitHashShort = LauncherEnvironment.CommitHashShort; + public static readonly int VersionCode = LauncherEnvironment.VersionCode; #if DEBUG public const string VersionBranchName = "Debug"; @@ -30,65 +27,97 @@ public static partial class ModBase public const string VersionBranchName = "Publish"; public const string VersionBranchCode = "0"; #endif + /// /// 主窗口句柄。 /// - public static nint frmHandle; + public static nint frmHandle + { + get => LauncherEnvironment.MainWindowHandle; + set => LauncherEnvironment.MainWindowHandle = value; + } - // 龙猫味石山小记: 用最不靠谱的实现写出能跑的代码 (AppDomain.CurrentDomain.SetupInformation.ApplicationBase 获取到的是当前工作目录而不是可执行文件所在目录) /// /// 程序可执行文件所在目录,以“\”结尾。 /// - public static readonly string exePath = Basics.ExecutableDirectory.EndsWith(@"\") - ? Basics.ExecutableDirectory - : Basics.ExecutableDirectory + @"\"; + public static string exePath => LauncherPaths.ExecutableDirectoryWithSlash; /// /// 程序内嵌图片文件夹路径,以“/”结尾。 /// - public static readonly string pathImage = "pack://application:,,,/Plain Craft Launcher 2;component/Images/"; + public static string pathImage => LauncherPaths.ImageBaseUri; /// /// 当前程序的语言。 /// - public static string currentLang = "zh_CN"; + public static string currentLang + { + get => LauncherEnvironment.CurrentLanguage; + set => LauncherEnvironment.CurrentLanguage = value; + } /// /// 设置对象。 /// - public static ModSetup setup = new(); + public static ModSetup setup + { + get => LauncherEnvironment.Setup; + set => LauncherEnvironment.Setup = value; + } /// /// 程序的打开计时。 /// - public static long applicationStartTick = TimeUtils.GetTimeTick(); + public static long applicationStartTick + { + get => LauncherRuntime.ApplicationStartTick; + set => LauncherRuntime.ApplicationStartTick = value; + } /// /// 程序打开时的时间。 /// - public static DateTime applicationOpenTime = DateTime.Now; + public static DateTime applicationOpenTime + { + get => LauncherRuntime.ApplicationOpenTime; + set => LauncherRuntime.ApplicationOpenTime = value; + } /// /// 程序是否已结束。 /// - public static bool isProgramEnded = false; + public static bool isProgramEnded + { + get => LauncherRuntime.IsProgramEnded; + set => LauncherRuntime.IsProgramEnded = value; + } /// /// 程序的缓存文件夹路径,以 \ 结尾。 /// - public static string pathTemp = Paths.Temp + @"\"; + public static string pathTemp + { + get => LauncherPaths.TempWithSlash; + set => LauncherPaths.TempWithSlash = value; + } /// /// AppData 中的 PCL 文件夹路径,以 \ 结尾。 /// - public static string pathAppdata = - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PCL") + @"\"; + public static string pathAppdata + { + get => LauncherPaths.LegacyAppDataWithSlash; + set => LauncherPaths.LegacyAppDataWithSlash = value; + } /// /// AppData 中的 PCLCE 配置文件夹路径,以 \ 结尾。 /// - public static string pathAppdataConfig = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + - (VersionBranchName == "Debug" ? @"\.pclcedebug\" : @"\.pclce\"); + public static string pathAppdataConfig + { + get => LauncherPaths.SharedConfigWithSlash; + set => LauncherPaths.SharedConfigWithSlash = value; + } #endregion diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs index d72990468..00584f3ad 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs @@ -1,11 +1,5 @@ -using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices; using System.Text; -using PCL.Core.Utils.Codecs; -using PCL.Core.Utils.Hash; -using CoreDirectories = PCL.Core.IO.Directories; -using CoreFiles = PCL.Core.IO.Files; namespace PCL; @@ -13,13 +7,6 @@ public static partial class ModBase { #region LegacyFiles - private static string ResolveLegacyFilePath(string filePath) - { - if (string.IsNullOrEmpty(filePath)) - return filePath; - return filePath.Contains(@":\") ? filePath : exePath + filePath; - } - // 路径处理 /// /// 从文件路径或者 Url 获取不包含文件名的路径,或获取文件夹的父文件夹路径。 @@ -28,26 +15,7 @@ private static string ResolveLegacyFilePath(string filePath) /// public static string GetPathFromFullPath(string filePath) { - string getPathFromFullPathRet = default; - if (!(filePath.Contains(@"\") || filePath.Contains("/"))) - throw new Exception("不包含路径:" + filePath); - if (filePath.EndsWithF(@"\") || filePath.EndsWithF("/")) - { - // 是文件夹路径 - var isRight = filePath.EndsWithF(@"\"); - filePath = filePath[..^1]; - getPathFromFullPathRet = filePath[..filePath.LastIndexOfAny( - ['\\', '/'])] + (isRight ? @"\" : "/"); - } - else - { - // 是文件路径 - getPathFromFullPathRet = filePath[..(filePath.LastIndexOfAny(['\\', '/']) + 1)]; - if (string.IsNullOrEmpty(getPathFromFullPathRet)) - throw new Exception("不包含路径:" + filePath); - } - - return getPathFromFullPathRet; + return LegacyFileFacade.GetPathFromFullPath(filePath); } /// @@ -55,21 +23,7 @@ public static string GetPathFromFullPath(string filePath) /// public static string GetFileNameFromPath(string filePath) { - filePath = filePath.Replace("/", @"\"); - if (filePath.EndsWithF(@"\")) - throw new Exception("不包含文件名:" + filePath); - if (filePath.Contains('?')) - filePath = filePath[..filePath.IndexOfF("?")]; // 去掉网络参数后的 ? - if (filePath.Contains('\\')) - filePath = filePath[(filePath.LastIndexOfF(@"\") + 1)..]; - - var length = filePath.Length; - return length switch - { - 0 => throw new Exception("不包含文件名:" + filePath), - > 250 => throw new PathTooLongException("文件名过长:" + filePath), - _ => filePath - }; + return LegacyFileFacade.GetFileNameFromPath(filePath); } /// @@ -77,7 +31,7 @@ public static string GetFileNameFromPath(string filePath) /// public static string GetFileNameWithoutExtentionFromPath(string filePath) { - return Path.GetFileNameWithoutExtension(filePath); + return LegacyFileFacade.GetFileNameWithoutExtensionFromPath(filePath); } /// @@ -85,11 +39,7 @@ public static string GetFileNameWithoutExtentionFromPath(string filePath) /// public static string GetFolderNameFromPath(string folderPath) { - if (folderPath.EndsWithF(@":\") || folderPath.EndsWithF(@":\\")) - return folderPath[..1]; - if (folderPath.EndsWithF(@"\") || folderPath.EndsWithF("/")) - folderPath = folderPath[..^1]; - return GetFileNameFromPath(folderPath); + return LegacyFileFacade.GetFolderNameFromPath(folderPath); } // 读取、写入、复制文件 @@ -98,9 +48,7 @@ public static string GetFolderNameFromPath(string folderPath) /// public static void CopyFile(string fromPath, string toPath) { - CoreFiles.CopyFileAsync(ResolveLegacyFilePath(fromPath), ResolveLegacyFilePath(toPath)) - .GetAwaiter() - .GetResult(); + LegacyFileFacade.CopyFile(fromPath, toPath); } /// @@ -108,20 +56,15 @@ public static void CopyFile(string fromPath, string toPath) /// public static byte[] ReadFileBytes(string filePath, Encoding encoding = null) { - return CoreFiles.ReadAllBytesOrEmptyAsync(ResolveLegacyFilePath(filePath)) - .GetAwaiter() - .GetResult(); + return LegacyFileFacade.ReadBytes(filePath, encoding); } /// /// 读取文件,如果失败则返回空字符串。 /// - /// 文件完整或相对路径。 public static string ReadFile(string filePath, Encoding encoding = null) { - return CoreFiles.ReadAllTextOrEmptyAsync(ResolveLegacyFilePath(filePath), encoding) - .GetAwaiter() - .GetResult(); + return LegacyFileFacade.ReadText(filePath, encoding); } /// @@ -129,51 +72,32 @@ public static string ReadFile(string filePath, Encoding encoding = null) /// public static string ReadFile(Stream stream, Encoding encoding = null) { - return CoreFiles.ReadAllTextOrEmptyAsync(stream, encoding) - .GetAwaiter() - .GetResult(); + return LegacyFileFacade.ReadText(stream, encoding); } /// /// 写入文件。 /// - /// 文件完整或相对路径。 - /// 文件内容。 - /// 是否将文件内容追加到当前文件,而不是覆盖它。 - public static void WriteFile( - string filePath, - string text, - bool append = false, - Encoding? encoding = null) + public static void WriteFile(string filePath, string text, bool append = false, Encoding? encoding = null) { - CoreFiles.WriteFileAsync(ResolveLegacyFilePath(filePath), text, append, encoding) - .GetAwaiter() - .GetResult(); + LegacyFileFacade.WriteText(filePath, text, append, encoding); } /// /// 写入文件。 /// 如果 CanThrow 设置为 False,返回是否写入成功。 /// - /// 文件完整或相对路径。 - /// 文件内容。 - /// 是否将文件内容追加到当前文件,而不是覆盖它。 public static void WriteFile(string filePath, byte[] content, bool append = false) { - CoreFiles.WriteFileAsync(ResolveLegacyFilePath(filePath), content, append) - .GetAwaiter() - .GetResult(); + LegacyFileFacade.WriteBytes(filePath, content, append); } /// /// 将流写入文件。 /// - /// 文件完整或相对路径。 public static bool WriteFile(string filePath, Stream stream) { - return CoreFiles.WriteFileAsync(ResolveLegacyFilePath(filePath), stream) - .GetAwaiter() - .GetResult(); + return LegacyFileFacade.WriteStream(filePath, stream); } /// @@ -181,12 +105,12 @@ public static bool WriteFile(string filePath, Stream stream) /// public static string DecodeBytes(byte[] bytes) { - return EncodingUtils.DecodeBytes(bytes); + return LegacyFileFacade.DecodeBytes(bytes); } public static object GetHexString(Memory bytes) { - return Convert.ToHexString(bytes.Span).ToLowerInvariant(); + return LegacyFileFacade.GetHexString(bytes); } // 文件校验 @@ -195,7 +119,7 @@ public static object GetHexString(Memory bytes) /// public static string GetFileMD5(string filePath) { - return CoreFiles.GetFileMD5Async(filePath).GetAwaiter().GetResult(); + return LegacyFileFacade.GetFileMd5(filePath); } /// @@ -203,7 +127,7 @@ public static string GetFileMD5(string filePath) /// public static string GetFileSHA512(string filePath) { - return CoreFiles.GetFileSHA512Async(filePath).GetAwaiter().GetResult(); + return LegacyFileFacade.GetFileSha512(filePath); } /// @@ -211,7 +135,7 @@ public static string GetFileSHA512(string filePath) /// public static string GetFileSHA256(string filePath) { - return CoreFiles.GetFileSHA256Async(filePath).GetAwaiter().GetResult(); + return LegacyFileFacade.GetFileSha256(filePath); } /// @@ -219,7 +143,7 @@ public static string GetFileSHA256(string filePath) /// public static string GetFileSHA1(string filePath) { - return CoreFiles.GetFileSHA1Async(filePath).GetAwaiter().GetResult(); + return LegacyFileFacade.GetFileSha1(filePath); } /// @@ -227,15 +151,7 @@ public static string GetFileSHA1(string filePath) /// public static string GetAuthSHA1(Stream inputStream) { - try - { - return (string)GetHexString(SHA1Provider.Instance.ComputeHash(inputStream)); - } - catch (Exception ex) - { - Log(ex, "获取流 SHA1 失败"); - return ""; - } + return LegacyFileFacade.GetStreamSha1(inputStream); } /// @@ -243,41 +159,14 @@ public static string GetAuthSHA1(Stream inputStream) /// public class FileChecker { - /// - /// 文件的准确大小。 - /// 不检查则为 -1。 - /// public long actualSize = -1; - - /// - /// 是否可以使用已经存在的文件。 - /// public bool canUseExistsFile = true; - - /// - /// 文件的 MD5、SHA1 或 SHA256。会根据输入字符串的长度自动判断种类。 - /// 不检查则为 Nothing。 - /// public string hash; - - /// - /// 是否要求为 JSON 文件。 - /// 即,开头结尾必须为 {} 或 []。 - /// public bool isJson; - - /// - /// 文件的最小大小。 - /// 不检查则为 -1。 - /// public long minSize = -1; - public FileChecker( - long minSize = -1, - long actualSize = -1, - string hash = null, - bool canUseExistsFile = true, - bool isJson = false) + public FileChecker(long minSize = -1, long actualSize = -1, string hash = null, + bool canUseExistsFile = true, bool isJson = false) { this.actualSize = actualSize; this.minSize = minSize; @@ -291,61 +180,24 @@ public FileChecker( /// public string Check(string localPath) { - return CoreFiles.CheckAsync(localPath, minSize, actualSize, hash, isJson) - .GetAwaiter() - .GetResult(); + return LegacyFileFacade.CheckFile(localPath, minSize, actualSize, hash, isJson); } } /// /// 等待文件就绪可读,在指定超时时间内轮询检查文件是否存在且内容非空。 /// - /// 文件路径。 - /// 超时时间(毫秒)。 public static void WaitForFileReady(string filePath, int timeoutMs = 2000) { - WaitForFileReady(filePath, timeoutMs, false); + LegacyFileFacade.WaitForFileReady(filePath, timeoutMs); } /// /// 等待文件就绪可读,在指定超时时间内轮询检查文件是否存在且内容非空。 /// - /// 文件路径。 - /// 超时时间(毫秒)。 - /// 是否要求文件为合法 JSON。 public static void WaitForFileReady(string filePath, int timeoutMs, bool requireJson) { - filePath = ResolveLegacyFilePath(filePath); - var start = Environment.TickCount; - long lastSize = -1; - while (Environment.TickCount - start < timeoutMs) - { - if (File.Exists(filePath)) - try - { - var info = new FileInfo(filePath); - var size = info.Length; - if (size <= 0) - continue; - if (!requireJson) - { - if (size == lastSize) - return; - lastSize = size; - } - else - { - var content = ReadFile(filePath); - if (!string.IsNullOrEmpty(content) && content.Trim().StartsWith("{")) - return; - } - } - catch (IOException) - { - } - - Thread.Sleep(50); - } + LegacyFileFacade.WaitForFileReady(filePath, timeoutMs, requireJson); } /// @@ -355,9 +207,7 @@ public static void WaitForFileReady(string filePath, int timeoutMs, bool require public static void ExtractFile(string compressFilePath, string destDirectory, Encoding encode = null, Action progressIncrementHandler = null) { - CoreFiles.ExtractFileAsync(compressFilePath, destDirectory, progressIncrementHandler) - .GetAwaiter() - .GetResult(); + LegacyFileFacade.ExtractFile(compressFilePath, destDirectory, encode, progressIncrementHandler); } /// @@ -365,9 +215,7 @@ public static void ExtractFile(string compressFilePath, string destDirectory, En /// public static int DeleteDirectory(string path, bool ignoreIssue = false) { - return CoreDirectories.DeleteDirectoryAsync(path, ignoreIssue) - .GetAwaiter() - .GetResult(); + return LegacyFileFacade.DeleteDirectory(path, ignoreIssue); } /// @@ -375,9 +223,7 @@ public static int DeleteDirectory(string path, bool ignoreIssue = false) /// public static void CopyDirectory(string fromPath, string toPath, Action progressIncrementHandler = null) { - CoreDirectories.CopyDirectoryAsync(fromPath, toPath, progressIncrementHandler) - .GetAwaiter() - .GetResult(); + LegacyFileFacade.CopyDirectory(fromPath, toPath, progressIncrementHandler); } /// @@ -385,16 +231,7 @@ public static void CopyDirectory(string fromPath, string toPath, Action /// public static IEnumerable EnumerateFiles(string directory) { - try - { - return CoreDirectories.EnumerateFilesAsync(ShortenPath(directory)) - .GetAwaiter() - .GetResult(); - } - catch (DirectoryNotFoundException) - { - return []; - } + return LegacyFileFacade.EnumerateFiles(directory); } /// @@ -402,57 +239,25 @@ public static IEnumerable EnumerateFiles(string directory) /// public static string ShortenPath(string longPath, int shortenThreshold = 247) { - if (longPath.Length <= shortenThreshold) - return longPath; - var shortPath = new StringBuilder(260); - GetShortPathName(longPath, shortPath, 260); - return shortPath.ToString(); + return LegacyFileFacade.ShortenPath(longPath, shortenThreshold); } public static void MoveDirectory(string sourceDir, string targetDir) { - if (!Directory.Exists(targetDir)) - Directory.CreateDirectory(targetDir); - foreach (var filePath in Directory.GetFiles(sourceDir)) - { - var fileName = GetFileNameFromPath(filePath); - File.Move(filePath, Path.Combine(targetDir, fileName)); - } - - foreach (var dirPath in Directory.GetDirectories(sourceDir)) - { - var dirName = GetFolderNameFromPath(dirPath); - MoveDirectory(dirPath, Path.Combine(targetDir, dirName)); - } + LegacyFileFacade.MoveDirectory(sourceDir, targetDir); } - [DllImport("kernel32", EntryPoint = "GetShortPathNameA")] - private static extern int GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer); - public static void CreateSymbolicLink(string linkPath, string targetPath, int flags) { - var cMDProcess = new Process(); - var linkDPath = ModLaunch.ExtractLinkD(); - { - var withBlock = cMDProcess.StartInfo; - withBlock.FileName = linkDPath; - withBlock.Arguments = $"\"{linkPath}\" \"{targetPath}\""; - withBlock.CreateNoWindow = true; - withBlock.UseShellExecute = false; - } - cMDProcess.Start(); - while (!cMDProcess.HasExited) - { - } + LegacyFileFacade.CreateSymbolicLink(linkPath, targetPath, flags); } - /// /// 检查是否拥有某一文件夹的 I/O 权限。如果文件夹不存在,会返回 False。 /// public static bool CheckPermission(string path) { - return CoreDirectories.CheckPermissionAsync(path).GetAwaiter().GetResult(); + return LegacyFileFacade.CheckPermission(path); } /// @@ -460,7 +265,7 @@ public static bool CheckPermission(string path) /// public static void CheckPermissionWithException(string path) { - CoreDirectories.CheckPermissionWithExceptionAsync(path).GetAwaiter().GetResult(); + LegacyFileFacade.CheckPermissionWithException(path); } #endregion diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs index 795431896..1ed135bb4 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs @@ -1,65 +1,16 @@ -using System.Collections.Concurrent; -using System.IO; -using System.Text; - namespace PCL; public static partial class ModBase { #region LegacyIni - // ============================= - // ini - // ============================= - - private static readonly ConcurrentDictionary> iniCache = new(); - /// /// 清除某 ini 文件的运行时缓存。 /// /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 public static void IniClearCache(string fileName) { - if (!fileName.Contains(@":\")) - fileName = $@"{exePath}PCL\{fileName}.ini"; - iniCache.Remove(fileName, out _); - } - - /// - /// 获取 ini 文件缓存。如果没有,则新读取 ini 文件内容。 - /// 在文件不存在或读取失败时返回 Nothing。 - /// - /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 - private static ConcurrentDictionary IniGetContent(string fileName) - { - try - { - // 还原文件路径 - if (!fileName.Contains(@":\")) - fileName = $@"{exePath}PCL\{fileName}.ini"; - // 检索缓存 - if (iniCache.TryGetValue(fileName, out var value)) - return value; - // 读取文件 - if (!File.Exists(fileName)) - return null; - var ini = new ConcurrentDictionary(); - foreach (var line in ReadFile(fileName) - .Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries)) - { - var index = line.IndexOfF(":"); - if (index > 0) - ini[line[..index]] = line[(index + 1)..]; // 可能会有重复键,见 #3616 - } - - iniCache[fileName] = ini; - return ini; - } - catch (Exception ex) - { - Log(ex, $"生成 ini 文件缓存失败({fileName})", LogLevel.Hint); - return null; - } + LegacyIniStore.Shared.ClearCache(fileName); } /// @@ -70,10 +21,7 @@ private static ConcurrentDictionary IniGetContent(string fileNam /// 没有找到键时返回的默认值。 public static string ReadIni(string fileName, string key, string defaultValue = "") { - var content = IniGetContent(fileName); - if (content is null || !content.TryGetValue(key, out var value)) - return defaultValue; - return value; + return LegacyIniStore.Shared.Read(fileName, key, defaultValue); } /// @@ -81,8 +29,7 @@ public static string ReadIni(string fileName, string key, string defaultValue = /// public static bool HasIniKey(string fileName, string key) { - var content = IniGetContent(fileName); - return content is not null && content.ContainsKey(key); + return LegacyIniStore.Shared.ContainsKey(fileName, key); } /// @@ -90,68 +37,17 @@ public static bool HasIniKey(string fileName, string key) /// public static void DeleteIniKey(string fileName, string key) { - WriteIni(fileName, key, null); + LegacyIniStore.Shared.Delete(fileName, key); } /// /// 写入 ini 文件,这会更新缓存。 /// 若 Value 为 Nothing,则删除该键。 /// - /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 - /// 键。 - /// 值。 - /// public static void WriteIni(string fileName, string key, string value) { - try - { - // 预处理 - if (key.Contains(':')) - throw new Exception($"尝试写入 ini 文件 {fileName} 的键名中包含了冒号:{key}"); - key = key.Replace("\r", "").Replace("\n", ""); - value = value?.Replace("\r", "").Replace("\n", ""); - // 防止争用 - lock (writeIniLock) - { - // 获取目前文件 - var content = IniGetContent(fileName) - ?? new ConcurrentDictionary(); - // 更新值 - if (value is null) - { - if (!content.ContainsKey(key)) - return; // 无需处理 - content.Remove(key, out _); - } - else - { - if (content.TryGetValue(key, out var value1) && (value1 ?? "") == (value ?? "")) - return; // 无需处理 - content[key] = value; - } - - // 写入文件 - var fileContent = new StringBuilder(); - foreach (var pair in content) - { - fileContent.Append(pair.Key); - fileContent.Append(':'); - fileContent.Append(pair.Value); - fileContent.Append("\r\n"); - } - - if (!fileName.Contains(@":\")) - fileName = $@"{exePath}PCL\{fileName}.ini"; - WriteFile(fileName, fileContent.ToString()); - } - } - catch (Exception ex) - { - Log(ex, $"写入文件失败({fileName} → {key}:{value})", LogLevel.Hint); - } + LegacyIniStore.Shared.Write(fileName, key, value); } - private static readonly object writeIniLock = new(); - #endregion } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs index 7b5918c7a..98a985459 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs @@ -1,12 +1,4 @@ -using System.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.InteropServices; using System.Text; -using Microsoft.VisualBasic; -using PCL.Core.App.Localization; -using PCL.Core.Logging; -using PCL.Core.Utils.OS; namespace PCL; @@ -14,7 +6,11 @@ public static partial class ModBase { #region Debug - public static bool modeDebug = false; + public static bool ModeDebug + { + get => LauncherRuntime.ModeDebug; + set => LauncherRuntime.ModeDebug = value; + } // Log public enum LogLevel @@ -56,80 +52,14 @@ public enum LogLevel Critical = 6 } - private static bool isCriticalErrorTriggered; - /// /// 输出 Log。 /// /// 如果要求弹窗,指定弹窗的标题。 - public static void Log( - string text, - LogLevel level = LogLevel.Normal, - string? title = null, + public static void Log(string text, LogLevel level = LogLevel.Normal, string? title = null, string? userSummary = null) { - // On Error Resume Next - // 放在最后会导致无法显示极端错误下的弹窗(如无法写入日志文件) - // 处理错误会导致再次调用 Log() 导致无限循环 - - // 输出日志 - if (new[] { LogLevel.Msgbox, LogLevel.Hint }.Contains(level)) - LogWrapper.Warn(text); - else - switch (level) - { - case LogLevel.Feedback: - LogWrapper.Error(text); - break; - case LogLevel.Critical: - LogWrapper.Fatal(text); - break; - case LogLevel.Debug: - LogWrapper.Debug(text); - break; - case LogLevel.Developer: - LogWrapper.Trace(text); - break; - default: - LogWrapper.Info(text); - break; - } - - if (isProgramEnded || level == LogLevel.Normal) - return; - - var userDetails = text.RegexReplace(@"\[[^\]]+?\] ", ""); - var userMessage = string.IsNullOrWhiteSpace(userSummary) - ? Lang.Text("SystemDialog.Error.UserVisible.Message", userDetails) - : userSummary; - var dialogTitle = _GetUserDialogTitle(title); - - switch (level) - { - case LogLevel.Developer: - break; - - case LogLevel.Debug: - if (modeDebug) - HintService.Hint("[调试模式] " + text, HintType.Info, false); - break; - - case LogLevel.Hint: - HintService.Hint(userMessage, HintType.Error, false); - break; - - case LogLevel.Msgbox: - ModMain.MyMsgBox(userMessage, dialogTitle, isWarn: true); - break; - - case LogLevel.Feedback: - _ShowFeedbackPrompt(userMessage, dialogTitle, false); - break; - - case LogLevel.Critical: - _ShowFeedbackPrompt(userMessage, dialogTitle, true); - break; - } + LauncherLog.Log(text, level, title, userSummary); } /// @@ -137,134 +67,10 @@ public static void Log( /// /// 错误描述,仅用于日志和错误详情。 /// 可选的本地化用户摘要;不会写入日志。 - public static void Log( - Exception ex, - string desc, - LogLevel level = LogLevel.Debug, - string? title = null, + public static void Log(Exception ex, string desc, LogLevel level = LogLevel.Debug, string? title = null, string? userSummary = null) { - // On Error Resume Next - if (ex is ThreadInterruptedException) - return; - - // 输出日志 - if (new[] { LogLevel.Msgbox, LogLevel.Hint }.Contains(level)) - LogWrapper.Warn(ex, desc); - else - switch (level) - { - case LogLevel.Feedback: - LogWrapper.Error(ex, desc); - break; - case LogLevel.Critical: - LogWrapper.Fatal(ex, desc); - break; - case LogLevel.Debug: - LogWrapper.Debug($"{desc}:{ex}"); - break; - case LogLevel.Developer: - LogWrapper.Trace($"{desc}:{ex}"); - break; - default: - LogWrapper.Error(ex, desc); - break; - } - - if (isProgramEnded) - return; - - var userMessage = _GetUserExceptionMessage(desc, ex, userSummary); - var dialogTitle = _GetUserDialogTitle(title); - - switch (level) - { - case LogLevel.Normal or LogLevel.Developer: - break; - - case LogLevel.Debug: - if (modeDebug) - HintService.Hint("[调试模式] " + desc + ":" + ex, HintType.Info, false); - break; - - case LogLevel.Hint: - HintService.Hint(userMessage, HintType.Error, false); - break; - - case LogLevel.Msgbox: - ModMain.MyMsgBox(userMessage, dialogTitle, isWarn: true); - break; - - case LogLevel.Feedback: - _ShowFeedbackPrompt(userMessage, dialogTitle, false); - break; - - case LogLevel.Critical: - _ShowFeedbackPrompt(userMessage, dialogTitle, true); - break; - } - } - - private static string _GetUserDialogTitle(string? title) - { - return string.IsNullOrWhiteSpace(title) - ? Lang.Text("SystemDialog.Error.Title") - : title; - } - - private static string _GetUserExceptionMessage( - string desc, - Exception ex, - string? userSummary) - { - if (!string.IsNullOrWhiteSpace(userSummary)) - return ExceptionDetails.Compose(userSummary, ex); - - return ex.GetType() == typeof(Win32Exception) - ? Lang.Text("SystemDialog.Error.OperationFailed.RuntimeMessage", desc, ex.ToString()) - : Lang.Text("SystemDialog.Error.OperationFailed.Message", desc, ex.ToString()); - } - - private static void _ShowFeedbackPrompt( - string userMessage, - string title, - bool isCritical) - { - switch (isCritical) - { - case true when isCriticalErrorTriggered: - FormMain.EndProgramForce(ProcessReturnValues.Exception); - return; - case true: - isCriticalErrorTriggered = true; - break; - } - - if (CanFeedback(false)) - { - var message = Lang.Text("Setup.Feedback.ErrorPrompt.Submit.Message", userMessage); - var shouldSend = isCritical - ? Interaction.MsgBox( - message, - (MsgBoxStyle)((int)MsgBoxStyle.Critical + (int)MsgBoxStyle.YesNo), - title) == MsgBoxResult.Yes - : ModMain.MyMsgBox( - message, - title, - Lang.Text("Setup.Feedback.ErrorPrompt.Submit.Action"), - Lang.Text("Common.Action.Cancel"), - isWarn: true) == 1; - - if (shouldSend) - Feedback(false, true); - return; - } - - var updateMessage = Lang.Text("Setup.Feedback.ErrorPrompt.Update.Message", userMessage); - if (isCritical) - Interaction.MsgBox(updateMessage, MsgBoxStyle.Critical, title); - else - ModMain.MyMsgBox(updateMessage, title, isWarn: true); + LauncherLog.Log(ex, desc, level, title, userSummary); } public static string Base64Decode(string text) @@ -289,39 +95,12 @@ public static string Base64Encode(byte[] bytes) // 反馈 public static void Feedback(bool showMsgbox = true, bool forceOpenLog = false) { - // On Error Resume Next - FeedbackInfo(); - var currentDate = DateTime.Now.ToString("yyyy-M-dd", CultureInfo.InvariantCulture); - - if (forceOpenLog || (showMsgbox && - ModMain.MyMsgBox( - Lang.Text("Setup.Feedback.Reminder.Message", currentDate), - Lang.Text("Setup.Feedback.Reminder.Title"), - Lang.Text("Common.Action.OpenFolder"), - Lang.Text("Setup.Feedback.Reminder.NotNeeded")) == - 1)) OpenExplorer(exePath + @"PCL\Log\"); - OpenWebsite("https://github.com/PCL-Community/PCL2-CE/issues/"); + LauncherFeedbackService.Feedback(showMsgbox, forceOpenLog); } public static bool CanFeedback(bool showHint) { - var stat = UpdateManager.GetVersionStatus(); - if (stat == UpdateEnums.VersionStatus.Latest) return true; - - if (!showHint) return false; - - if (ModMain.MyMsgBox( - stat == UpdateEnums.VersionStatus.NotLatest - ? Lang.Text("Setup.Feedback.Unavailable.NotLatest.Message") - : Lang.Text("Setup.Feedback.Unavailable.CheckFailed.Message"), - Lang.Text("Setup.Feedback.Unavailable.Title"), - stat == UpdateEnums.VersionStatus.NotLatest - ? Lang.Text("Setup.Feedback.Unavailable.NotLatest.Action") - : Lang.Text("Setup.Feedback.Unavailable.CheckFailed.Action"), - Lang.Text("Common.Action.Cancel")) == 1) - ModMain.frmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupUpdate); - - return false; + return LauncherFeedbackService.CanFeedback(showHint); } /// @@ -329,50 +108,19 @@ public static bool CanFeedback(bool showHint) /// public static void FeedbackInfo() { - try - { - // Get system memory info - var phyRam = KernelInterop.GetPhysicalMemoryBytes(); - - // Calculate memory and DPI scale - var availableMb = phyRam.Available / 1024 / 1024; - var totalMb = phyRam.Total / 1024 / 1024; - var dpiScale = Math.Round(dpi / 96.0, 2); - - // Build diagnostic information string - var info = $""" - [System] Diagnostic Information: - OS: {RuntimeInformation.OSDescription} (32-bit: {SystemInfo.Is32BitSystem}) - Memory: {availableMb} MB / {totalMb} MB - DPI: {dpi} ({dpiScale * 100}%) - MC Folder: {ModFolder.mcFolderSelected ?? "Nothing"} - Executable Path: {exePath} - """; - - LogWrapper.Info(info); - } - catch (Exception ex) - { - // Basic fail-safe to replace "On Error Resume Next" - LogWrapper.Error(ex, "Failed to collect feedback information"); - } + LauncherFeedbackService.FeedbackInfo(); } // 断言 public static void DebugAssert(bool exp) { - if (!exp) - throw new Exception("断言命中"); + LauncherLog.DebugAssert(exp); } // 获取当前的堆栈信息 public static string GetStackTrace() { - var stack = new StackTrace(); - return stack.GetFrames().Skip(1).Select(f => f.GetMethod()) - .Select(f => f.Name + "(" + f.GetParameters().Select(p => p.ToString()).ToList().Join(", ") + ") - " + - f.Module).ToList().Join("\r\n") - .Replace("\r\n" + "\r\n", "\r\n"); + return LauncherLog.GetStackTrace(); } #endregion diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs index bf4f33c46..3797ff3cd 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs @@ -16,8 +16,8 @@ private static List> ToCoreSearchSources(IEnumerabl { if (source.aliases is null) continue; - foreach (var alias in source.aliases) - result.Add(new KeyValuePair(alias, source.weight)); + result.AddRange( + source.aliases.Select(alias => new KeyValuePair(alias, source.weight))); } return result; @@ -81,7 +81,10 @@ public SearchSource(string text, double weight = 1) /// /// 返回的最大模糊结果数。 /// 返回结果要求的最低相似度。 - public static List> Search(List> entries, string query, int maxBlurCount = 5, + public static List> Search( + List> entries, + string query, + int maxBlurCount = 5, double minBlurSimilarity = 0.1d) { if (entries is null || entries.Count == 0) diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs index c26027e96..1e7c783b7 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs @@ -1,15 +1,8 @@ -using System.Collections; -using System.Diagnostics; +using System.Collections; using System.IO; -using System.Windows; -using System.Windows.Threading; -using Microsoft.VisualBasic; using PCL.Core.App; -using PCL.Core.App.Localization; -using PCL.Core.Logging; using PCL.Core.Utils.Codecs; using PCL.Core.Utils.Exts; -using PCL.Core.Utils.OS; namespace PCL; @@ -159,17 +152,10 @@ public void RemoveAt(int index) /// /// 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。 /// - public static string pathPure = GetPureASCIIDir(); - - private static string GetPureASCIIDir() + public static string pathPure { - if (exePath.IsASCII()) return exePath + @"PCL\"; - - if (pathAppdata.IsASCII()) return pathAppdata; - - if (pathTemp.IsASCII()) return pathTemp; - - return Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL"); + get => LauncherPaths.PureAsciiDirectory; + set => LauncherPaths.PureAsciiDirectory = value; } /// @@ -204,20 +190,12 @@ public static bool IsInstanceOfGenericType(this Type genericType, object obj) return false; } - private static int uuid = 1; - private static object uuidLock; - /// /// 获取一个全程序内不会重复的数字(伪 Uuid)。 /// public static int GetUuid() { - uuidLock ??= new object(); - lock (uuidLock) - { - uuid += 1; - return uuid; - } + return LauncherRuntime.GetUuid(); } /// @@ -225,15 +203,14 @@ public static int GetUuid() /// public static List GetFullList(IList data) { - List getFullListRet = default; - getFullListRet = []; + var result = new List(); for (int i = 0, loopTo = data.Count - 1; i <= loopTo; i++) if (data[i] is ICollection) - getFullListRet.AddRange((IEnumerable)data[i]); + result.AddRange((IEnumerable)data[i]); else - getFullListRet.Add((T)data[i]); + result.Add((T)data[i]); - return getFullListRet; + return result; } /// @@ -276,112 +253,32 @@ public sealed class RouteEventArgs(bool raiseByMouse = false) : EventArgs /// /// 前台运行文件。 /// - /// 文件名。可以为“notepad”等缩写。 - /// 运行参数。 public static void ShellOnly(string fileName, string arguments = "") { - try - { - fileName = ShortenPath(fileName); - using var program = new Process(); - program.StartInfo.Arguments = arguments; - program.StartInfo.FileName = fileName; - program.StartInfo.UseShellExecute = true; - Log("[System] 执行外部命令:" + fileName + " " + arguments); - program.Start(); - } - catch (Exception ex) - { - Log( - ex, - "打开文件或程序失败:" + fileName, - LogLevel.Msgbox, - userSummary: Lang.Text("SystemDialog.File.OpenFailed.Message", fileName)); - } + LauncherProcess.ShellOnly(fileName, arguments); } /// /// 前台运行文件并返回返回值。 /// - /// 文件名。可以为“notepad”等缩写。 - /// 运行参数。 - /// 等待该程序结束的最长时间(毫秒)。超时会返回 Result.Timeout。 public static ProcessReturnValues ShellAndGetExitCode(string fileName, string arguments = "", int timeout = 1000000) { - try - { - using var program = new Process(); - program.StartInfo.Arguments = arguments; - program.StartInfo.FileName = fileName; - Log("[System] 执行外部命令并等待返回码:" + fileName + " " + arguments); - program.Start(); - if (program.WaitForExit(timeout)) return (ProcessReturnValues)program.ExitCode; - - return ProcessReturnValues.Timeout; - } - catch (Exception ex) - { - Log(ex, "执行命令失败:" + fileName, LogLevel.Msgbox); - return ProcessReturnValues.Fail; - } + return LauncherProcess.ShellAndGetExitCode(fileName, arguments, timeout); } /// /// 静默运行文件并返回输出流字符串。执行失败会抛出异常。 /// - /// 文件名。可以为“notepad”等缩写。 - /// 运行参数。 - /// 等待该程序结束的最长时间(毫秒)。超时会抛出错误。 public static string ShellAndGetOutput(string fileName, string arguments = "", int timeout = 1000000, string workingDirectory = null) { - var info = new ProcessStartInfo - { - FileName = fileName, - Arguments = arguments, - UseShellExecute = false, - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardError = true - }; - - // 设置工作目录(如果提供) - if (!string.IsNullOrEmpty(workingDirectory)) info.WorkingDirectory = workingDirectory.TrimEnd('\\'); - - Log("[System] 执行外部命令并等待返回结果:" + fileName + " " + arguments); - - using var program = new Process(); - program.StartInfo = info; - program.Start(); - - // 异步读取输出和错误流 - var outputTask = program.StandardOutput.ReadToEndAsync(); - var errorTask = program.StandardError.ReadToEndAsync(); - - // 等待进程退出或超时 - if (program.WaitForExit(timeout)) - { - // 确保异步读取完成 - Task.WaitAll(outputTask, errorTask); - } - else - { - // 超时后终止进程 - program.Kill(); - // 仍然尝试获取已输出的内容 - Task.WaitAll(outputTask, errorTask); - } - - // 合并结果并返回 - return outputTask.Result + errorTask.Result; + return LauncherProcess.ShellAndGetOutput(fileName, arguments, timeout, workingDirectory); } /// /// 在新的工作线程中执行代码。 /// - public static Thread RunInNewThread( - Action action, - string name = null, + public static Thread RunInNewThread(Action action, string name = null, ThreadPriority priority = ThreadPriority.Normal) { return Basics.RunInNewThread(action, name ?? "Runtime New Invoke " + GetUuid() + "#", priority); @@ -390,28 +287,19 @@ public static Thread RunInNewThread( /// /// 确保在 UI 线程中执行代码。 /// 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。 - /// 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用! /// public static Output RunInUiWait(Func action) { - return RunInUi() - ? action() - : System.Windows.Application.Current.Dispatcher.Invoke(action); + return UiThread.Invoke(action); } /// /// 确保在 UI 线程中执行代码。 /// 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。 - /// 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用! /// public static void RunInUiWait(Action action) { - if (System.Windows.Application.Current is null) - return; - if (RunInUi()) - action(); - else - System.Windows.Application.Current.Dispatcher.Invoke(action); + UiThread.Invoke(action); } /// @@ -420,13 +308,7 @@ public static void RunInUiWait(Action action) /// public static void RunInUi(Action action, bool forceWaitUntilLoaded = false) { - if (System.Windows.Application.Current is null) - return; - if (RunInUi()) - action(); - else - System.Windows.Application.Current.Dispatcher.InvokeAsync(action, - forceWaitUntilLoaded ? DispatcherPriority.Loaded : DispatcherPriority.Normal); + UiThread.Post(action, forceWaitUntilLoaded); } /// @@ -434,86 +316,15 @@ public static void RunInUi(Action action, bool forceWaitUntilLoaded = false) /// public static void RunInThread(Action action) { - if (RunInUi()) - RunInNewThread(action, "Runtime Invoke " + GetUuid() + "#"); - else - action(); + UiThread.RunInThread(action); } /// /// 使用优化的归并排序算法进行稳定排序。 /// - /// 传入两个对象,若第一个对象应该排在前面,则返回 True。 public static List Sort(this IList list, ComparisonBoolean sortRule) { - return SortUtils.Sort(list, sortRule); - } - - private static void MergeSort_Sort( - ref List array, - int left, - int right, - ComparisonBoolean comparator) - { - if (left >= right) - return; - - var mid = (left + right) / 2; - MergeSort_Sort(ref array, left, mid, comparator); - MergeSort_Sort(ref array, mid + 1, right, comparator); - MergeSort_Merge(ref array, left, mid, right, comparator); - } - - private static void MergeSort_Merge( - ref List array, - int left, - int mid, - int right, - ComparisonBoolean comparator) - { - var leftArray = new List(); - var rightArray = new List(); - - for (var i = left; i <= mid; i++) - leftArray.Add(array[i]); - - for (var j = mid + 1; j <= right; j++) - rightArray.Add(array[j]); - - var leftPtr = 0; - var rightPtr = 0; - var current = left; - - while (leftPtr < leftArray.Count && rightPtr < rightArray.Count) - { - // 保持稳定性的关键比较逻辑:当相等时优先取左数组元素 - if (comparator(leftArray[leftPtr], rightArray[rightPtr])) - { - array[current] = leftArray[leftPtr]; - leftPtr += 1; - } - else - { - array[current] = rightArray[rightPtr]; - rightPtr += 1; - } - - current += 1; - } - - while (leftPtr < leftArray.Count) - { - array[current] = leftArray[leftPtr]; - leftPtr += 1; - current += 1; - } - - while (rightPtr < rightArray.Count) - { - array[current] = rightArray[rightPtr]; - rightPtr += 1; - current += 1; - } + return SortUtils.Sort(list, (left, right) => sortRule(left, right)); } public delegate bool ComparisonBoolean(T left, T right); @@ -529,7 +340,9 @@ public static IList Clone(this IList list) /// /// 尝试从字典中获取某项,如果该项不存在,则返回默认值。 /// - public static TValue GetOrDefault(this Dictionary dict, TKey key, + public static TValue GetOrDefault( + this Dictionary dict, + TKey key, TValue defaultValue = default) { return dict.GetValueOrDefault(key, defaultValue); @@ -552,20 +365,9 @@ public static void AddToList( /// /// 获取程序启动参数。 /// - /// 参数名。 - /// 默认值。 - public static object GetProgramArgument(string name, object defaultValue = null) + public static object GetProgramArgument(string name, object? defaultValue = null) { - var allArguments = Interaction.Command().Split(" "); - for (int i = 0, loopTo = allArguments.Length - 1; i <= loopTo; i++) - if ((allArguments[i] ?? "") == ("-" + name ?? "")) - { - if (allArguments.Length == i + 1 || allArguments[i + 1].StartsWithF("-")) - return true; - return allArguments[i + 1]; - } - - return defaultValue; + return LauncherArguments.Get(name, defaultValue); } /// @@ -573,28 +375,7 @@ public static object GetProgramArgument(string name, object defaultValue = null) /// public static void OpenWebsite(string url) { - try - { - if (!url.StartsWithF("http", true) && !url.StartsWithF("minecraft://", true)) - throw new Exception(url + " 不是一个有效的网址,它必须以 http 开头!"); - Log("[System] 正在打开网页:" + url); - var psi = new ProcessStartInfo(url) - { - UseShellExecute = true - }; - Process.Start(psi); - } - catch (Exception ex) - { - Log(ex, "无法打开网页(" + url + ")"); - ClipboardSet(url, false); - var message = ExceptionDetails.Compose( - Lang.Text("SystemDialog.Browser.OpenFailed.Message", url), - ex); - ModMain.MyMsgBox( - message, - Lang.Text("SystemDialog.Browser.OpenFailed.Title")); - } + LauncherProcess.OpenWebsite(url); } /// @@ -603,23 +384,7 @@ public static void OpenWebsite(string url) /// public static void OpenExplorer(string location) { - try - { - location = ShortenPath(location.Replace("/", @"\").Trim(' ', '"')); - Log("[System] 正在打开资源管理器:" + location); - if (location.EndsWithF(@"\")) - ShellOnly(location); - else - ShellOnly("explorer", $"/select,\"{location}\""); - } - catch (Exception ex) - { - Log( - ex, - "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", - LogLevel.Msgbox, - userSummary: Lang.Text("SystemDialog.Folder.OpenFailed.Message", location)); - } + LauncherProcess.OpenExplorer(location); } /// @@ -627,111 +392,19 @@ public static void OpenExplorer(string location) /// public static void ClipboardSet(string text, bool showSuccessHint = true) { - RunInThread(() => - { - var success = false; - - for (var attempt = 0; attempt <= 5; attempt++) - try - { - RunInUi(() => Clipboard.SetText(text)); - success = true; - break; - } - catch (Exception ex) when (attempt < 5) - { - Thread.Sleep(20); - } - catch (Exception finalEx) - { - Log( - finalEx, - "剪贴板被占用,文本复制失败", - LogLevel.Hint, - userSummary: Lang.Text("Common.Hint.CopyFailed")); - } - - if (success && showSuccessHint) - RunInUi(() => HintService.Hint(Lang.Text("Common.Hint.Copied"), HintType.Success)); - }); + LauncherProcess.ClipboardSet(text, showSuccessHint); } /// /// 从剪切板粘贴文件或文件夹 /// - /// 目标文件夹 - /// 是否粘贴文件 - /// 是否粘贴文件夹 - /// 总共粘贴的数量 public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool copyDir = true) { - Log("[System] 从剪贴板粘贴文件到:" + dest); - try - { - var files = Clipboard.GetFileDropList(); - if (files.Count.Equals(0)) - { - Log("[System] 剪贴板内无文件可粘贴"); - return 0; - } - - var copiedFiles = 0; - var copiedFolders = 0; - foreach (var i in files) - { - if (copyFile && File.Exists(i)) // 文件 - try - { - var thisDest = dest + GetFileNameFromPath(i); - if (File.Exists(thisDest)) - { - Log("[System] 已存在同名文件:" + thisDest); - } - else - { - File.Copy(i, thisDest); - copiedFiles += 1; - } - } - catch (Exception ex) - { - Log(ex, "[System] 复制文件时出错"); - continue; - } - - if (copyDir && Directory.Exists(i)) // 文件夹 - try - { - var thisDest = dest + GetFolderNameFromPath(i); - if (Directory.Exists(thisDest)) - { - Log("[System] 已存在同名文件夹:" + thisDest); - } - else - { - CopyDirectory(i, thisDest); - copiedFolders += 1; - } - } - catch (Exception ex) - { - Log(ex, "[System] 复制文件时出错"); - } - } - - HintService.Hint(Lang.Text("Common.Hint.FilesPasted", copiedFiles, copiedFolders)); - } - catch (Exception ex) - { - Log(ex, "[System] 从剪切板粘贴文件失败", LogLevel.Hint); - } - - return 0; + return LauncherProcess.PasteFileFromClipboard(dest, copyFile, copyDir); } /// - /// 获取程序打包资源的输入流。该资源必须声明为 Resource 类型,否则将会报错,Images - /// 和 Resources 目录已默认声明该类型。 + /// 获取程序打包资源的输入流。 /// public static Stream GetResourceStream(string path) { diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs index 6391a7ea6..ddd9584ae 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs @@ -1,15 +1,7 @@ -using System.Drawing; -using System.IO; -using System.Text; using System.Windows; using System.Windows.Controls; -using System.Windows.Data; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Xaml; using System.Xml.Linq; -using PCL.Core.App.Localization; -using Size = System.Windows.Size; namespace PCL; @@ -19,14 +11,7 @@ public static partial class ModBase public static void SetLaunchFont(string fontName = null) { - try - { - LocalizationFontService.ApplyLaunchFont(fontName, LocalizationService.CurrentLanguage); - } - catch (Exception ex) - { - Log(ex, "设置字体失败", LogLevel.Hint); - } + LauncherFontService.SetLaunchFont(fontName); } // 边距改变 @@ -35,38 +20,7 @@ public static void SetLaunchFont(string fontName = null) /// public static void DeltaLeft(FrameworkElement control, double newValue) { - // 安全性检查 - DebugAssert(!double.IsNaN(newValue)); - DebugAssert(!double.IsInfinity(newValue)); - - if (control is Window window) - // 窗口改变 - window.Left += newValue; - else - // 根据 HorizontalAlignment 改变数值 - switch (control.HorizontalAlignment) - { - case HorizontalAlignment.Left: - case HorizontalAlignment.Stretch: - { - control.Margin = new Thickness(control.Margin.Left + newValue, control.Margin.Top, - control.Margin.Right, control.Margin.Bottom); - break; - } - case HorizontalAlignment.Right: - { - // control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, CType(control.Parent, Object).ActualWidth - control.ActualWidth - newValue, control.Margin.Bottom) - control.Margin = new Thickness(control.Margin.Left, control.Margin.Top, - control.Margin.Right - newValue, control.Margin.Bottom); - break; - } - - default: - { - DebugAssert(false); - break; - } - } + LayoutExtensions.DeltaLeft(control, newValue); } /// @@ -74,8 +28,7 @@ public static void DeltaLeft(FrameworkElement control, double newValue) /// public static void SetLeft(FrameworkElement control, double newValue) { - DebugAssert(control.HorizontalAlignment == HorizontalAlignment.Left); - control.Margin = new Thickness(newValue, control.Margin.Top, control.Margin.Right, control.Margin.Bottom); + LayoutExtensions.SetLeft(control, newValue); } /// @@ -83,37 +36,7 @@ public static void SetLeft(FrameworkElement control, double newValue) /// public static void DeltaTop(FrameworkElement control, double newValue) { - // 安全性检查 - DebugAssert(!double.IsNaN(newValue)); - DebugAssert(!double.IsInfinity(newValue)); - - if (control is Window window) - // 窗口改变 - window.Top += newValue; - else - // 根据 VerticalAlignment 改变数值 - switch (control.VerticalAlignment) - { - case VerticalAlignment.Top: - { - control.Margin = new Thickness(control.Margin.Left, control.Margin.Top + newValue, - control.Margin.Right, control.Margin.Bottom); - break; - } - case VerticalAlignment.Bottom: - { - // control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, CType(control.Parent, Object).ActualWidth - control.ActualWidth - newValue, control.Margin.Bottom) - control.Margin = new Thickness(control.Margin.Left, control.Margin.Top, control.Margin.Right, - control.Margin.Bottom - newValue); - break; - } - - default: - { - DebugAssert(false); - break; - } - } + LayoutExtensions.DeltaTop(control, newValue); } /// @@ -121,19 +44,18 @@ public static void DeltaTop(FrameworkElement control, double newValue) /// public static void SetTop(FrameworkElement control, double newValue) { - DebugAssert(control.VerticalAlignment == VerticalAlignment.Top); - control.Margin = new Thickness(control.Margin.Left, newValue, control.Margin.Right, control.Margin.Bottom); + LayoutExtensions.SetTop(control, newValue); } // DPI 转换 - public static readonly int dpi = (int)Math.Round(Graphics.FromHwnd(nint.Zero).DpiX); + public static int dpi => DpiUtils.Dpi; /// /// 将经过 DPI 缩放的 WPF 尺寸转化为实际的像素尺寸。 /// public static double GetPixelSize(double wPFSize) { - return wPFSize / 96d * dpi; + return DpiUtils.GetPixelSize(wPFSize); } /// @@ -141,7 +63,7 @@ public static double GetPixelSize(double wPFSize) /// public static double GetWPFSize(double pixelSize) { - return pixelSize * 96d / dpi; + return DpiUtils.GetWpfSize(pixelSize); } // UI 截图 @@ -150,14 +72,7 @@ public static double GetWPFSize(double pixelSize) /// public static ImageBrush ControlBrush(FrameworkElement uI) { - var width = uI.ActualWidth; - var height = uI.ActualHeight; - if (width < 1d || height < 1d) - return new ImageBrush(); - var bmp = new RenderTargetBitmap((int)Math.Round(GetPixelSize(width)), (int)Math.Round(GetPixelSize(height)), - dpi, dpi, PixelFormats.Pbgra32); - bmp.Render(uI); - return new ImageBrush(bmp); + return VisualCapture.ControlBrush(uI); } /// @@ -166,14 +81,7 @@ public static ImageBrush ControlBrush(FrameworkElement uI) public static ImageBrush ControlBrush(FrameworkElement uI, double width, double height, double left = 0d, double top = 0d) { - uI.Measure(new Size(width, height)); - uI.Arrange(new Rect(0d, 0d, width, height)); - var bmp = new RenderTargetBitmap((int)Math.Round(GetPixelSize(width)), (int)Math.Round(GetPixelSize(height)), - dpi, dpi, PixelFormats.Default); - bmp.Render(uI); - if (left != 0d || top != 0d) - uI.Arrange(new Rect(left, top, width, height)); - return new ImageBrush(bmp); + return VisualCapture.ControlBrush(uI, width, height, left, top); } /// @@ -181,8 +89,7 @@ public static ImageBrush ControlBrush(FrameworkElement uI, double width, double /// public static void ControlFreeze(Panel uI) { - uI.Background = ControlBrush(uI); - uI.Children.Clear(); + VisualCapture.ControlFreeze(uI); } /// @@ -190,8 +97,7 @@ public static void ControlFreeze(Panel uI) /// public static void ControlFreeze(Border uI) { - uI.Background = ControlBrush(uI); - uI.Child = null; + VisualCapture.ControlFreeze(uI); } /// @@ -199,7 +105,7 @@ public static void ControlFreeze(Border uI) /// public static object GetObjectFromXML(XElement str) { - return GetObjectFromXML(str.ToString()); + return CustomXamlLoader.Load(str); } /// @@ -207,7 +113,7 @@ public static object GetObjectFromXML(XElement str) /// public static object GetObjectFromXML(string str) { - return GetObjectFromXML(str, out _); + return CustomXamlLoader.Load(str); } /// @@ -215,59 +121,15 @@ public static object GetObjectFromXML(string str) /// public static object GetObjectFromXML(string str, out XamlEventSanitizer.SanitizeResult sanitizeResult) { - str = str. // 兼容旧版自定义事件写法 - Replace("EventType=\"", "local:CustomEventService.EventType=\"") - .Replace("EventData=\"", "local:CustomEventService.EventData=\"") - .Replace("Property=\"EventType\"", "Property=\"local:CustomEventService.EventType\"") - .Replace("Property=\"EventData\"", "Property=\"local:CustomEventService.EventData\""); - // 修复因上述替换导致重复前缀的情况:local:CustomEventService.local:CustomEventService.EventType - str = str.Replace("local:CustomEventService.local:CustomEventService.", "local:CustomEventService."); - - sanitizeResult = XamlEventSanitizer.Sanitize(str); - str = sanitizeResult.SanitizedXaml; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(str)); - // 类型检查 - using (var reader = new XamlXmlReader(stream)) - { - while (reader.Read()) - { - foreach (var blackListType in new[] - { - typeof(WebBrowser), typeof(Frame), typeof(MediaElement), typeof(ObjectDataProvider), - typeof(XamlReader), typeof(Window), typeof(XmlDataProvider) - }) - { - if (reader.Type is not null && blackListType.IsAssignableFrom(reader.Type.UnderlyingType)) - throw new UnauthorizedAccessException($"不允许使用 {blackListType.Name} 类型。"); - if (reader.Value is not null && Equals(reader.Value, blackListType.Name)) - throw new UnauthorizedAccessException($"不允许使用 {blackListType.Name} 值。"); - } - - foreach (var blackListMember in new[] { "Code", "FactoryMethod", "Static" }) - if (reader.Member is not null && (reader.Member.Name ?? "") == (blackListMember ?? "")) - throw new UnauthorizedAccessException($"不允许使用 {blackListMember} 成员。"); - } - } - - // 实际的加载 - stream.Position = 0L; - using (var writer = new StreamWriter(stream)) - { - writer.Write(str); - writer.Flush(); - stream.Position = 0L; - return System.Windows.Markup.XamlReader.Load(stream); - } + return CustomXamlLoader.Load(str, out sanitizeResult); } - private static readonly int uiThreadId = Environment.CurrentManagedThreadId; - /// /// 当前线程是否为主线程。 /// public static bool RunInUi() { - return Environment.CurrentManagedThreadId == uiThreadId; + return UiThread.CheckAccess(); } #endregion diff --git a/Plain Craft Launcher 2/Controls/MyPageRight.cs b/Plain Craft Launcher 2/Controls/MyPageRight.cs index 635cac4c9..4807f28bf 100644 --- a/Plain Craft Launcher 2/Controls/MyPageRight.cs +++ b/Plain Craft Launcher 2/Controls/MyPageRight.cs @@ -55,7 +55,7 @@ public PageStates PageState if (field == value) return; field = value; - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 页面状态切换为 " + ModBase.GetStringFromEnum(value)); } } = PageStates.Empty; @@ -161,7 +161,7 @@ public void PageLoaderRestart(object input = null, bool isForceRestart = true) / /// public void PageOnEnter() { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageOnEnter"); PageEnter?.Invoke(); switch (PageState) @@ -234,7 +234,7 @@ public void PageOnEnter() /// public void PageOnExit() { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageOnExit"); PageExit?.Invoke(); switch (PageState) @@ -288,7 +288,7 @@ public void PageOnForceExit() { if (PageState == PageStates.Empty) return; - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageOnForceExit"); PageState = PageStates.Empty; ModAnimation.AniStop("PageRight PageChange " + pageUuid); @@ -312,7 +312,7 @@ public void PageOnForceExit() /// public void PageOnContentExit() { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageOnContentExit"); if (pageLoader is not null && pageLoader.State == ModBase.LoadState.Loading) throw new Exception("在调用 PageOnContentExit 时,加载器不能为 Loading 状态"); @@ -355,7 +355,7 @@ public void PageOnContentExit() /// private void PageOnEnterAnimationFinished() { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageOnEnterAnimationFinished"); switch (PageState) { @@ -386,7 +386,7 @@ private void PageOnEnterAnimationFinished() /// private void PageOnExitAnimationFinished() { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageOnExitAnimationFinished"); switch (PageState) { @@ -421,7 +421,7 @@ private void PageOnExitAnimationFinished() /// private void PageOnLoaderWaitFinished() { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageOnLoaderWaitFinished"); switch (PageState) { @@ -450,7 +450,7 @@ private void PageOnLoaderWaitFinished() /// private void PageOnLoaderStayFinished() { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageOnLoaderStayFinished"); switch (PageState) { @@ -489,7 +489,7 @@ private void PageLoaderState(object sender, ModBase.LoadState newState, ModBase. { if (oldState == ModBase.LoadState.Failed || oldState == ModBase.LoadState.Loading) return; - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageLoaderState (Start/Refresh)"); // (重新)开始运行 // 需要从部分状态切换到 ReloadExit @@ -517,7 +517,7 @@ private void PageLoaderState(object sender, ModBase.LoadState newState, ModBase. { if (oldState != ModBase.LoadState.Failed && oldState != ModBase.LoadState.Loading) return; - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[UI] 已触发 PageLoaderState (Stop/Abort)"); // 运行结束 // 需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit diff --git a/Plain Craft Launcher 2/FormMain.xaml.cs b/Plain Craft Launcher 2/FormMain.xaml.cs index fd1f3d04f..81d510987 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.cs +++ b/Plain Craft Launcher 2/FormMain.xaml.cs @@ -138,7 +138,7 @@ public FormMain() pageRight = ModMain.frmLaunchRight; ModMain.frmLaunchRight.PageState = MyPageRight.PageStates.ContentStay; // 调试模式提醒 - if (ModBase.modeDebug) + if (ModBase.ModeDebug) HintService.Hint(Lang.Text("Main.DebugMode.Hint")); // 尽早执行的加载池 ModFolder.mcFolderListLoader diff --git a/Plain Craft Launcher 2/Infrastructure/CustomXamlLoader.cs b/Plain Craft Launcher 2/Infrastructure/CustomXamlLoader.cs new file mode 100644 index 000000000..7736060a7 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/CustomXamlLoader.cs @@ -0,0 +1,76 @@ +using System.IO; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Xaml; +using System.Xml.Linq; +using XamlReader = System.Windows.Markup.XamlReader; + +namespace PCL; + +/// +/// 自定义 XAML 安全加载器。 +/// +public static class CustomXamlLoader +{ + public static object Load(XElement element) + { + return Load(element.ToString()); + } + + public static object Load(string xaml) + { + return Load(xaml, out _); + } + + public static object Load(string xaml, out XamlEventSanitizer.SanitizeResult sanitizeResult) + { + xaml = NormalizeLegacyCustomEventSyntax(xaml); + + sanitizeResult = XamlEventSanitizer.Sanitize(xaml); + xaml = sanitizeResult.SanitizedXaml; + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml)); + ValidateXaml(stream); + + stream.Position = 0L; + using var writer = new StreamWriter(stream); + writer.Write(xaml); + writer.Flush(); + stream.Position = 0L; + return XamlReader.Load(stream); + } + + private static string NormalizeLegacyCustomEventSyntax(string xaml) + { + xaml = xaml + .Replace("EventType=\"", "local:CustomEventService.EventType=\"") + .Replace("EventData=\"", "local:CustomEventService.EventData=\"") + .Replace("Property=\"EventType\"", "Property=\"local:CustomEventService.EventType\"") + .Replace("Property=\"EventData\"", "Property=\"local:CustomEventService.EventData\""); + return xaml.Replace("local:CustomEventService.local:CustomEventService.", "local:CustomEventService."); + } + + private static void ValidateXaml(Stream stream) + { + using var reader = new XamlXmlReader(stream); + while (reader.Read()) + { + foreach (var blackListType in new[] + { + typeof(WebBrowser), typeof(Frame), typeof(MediaElement), typeof(ObjectDataProvider), + typeof(System.Xaml.XamlReader), typeof(Window), typeof(XmlDataProvider) + }) + { + if (reader.Type is not null && blackListType.IsAssignableFrom(reader.Type.UnderlyingType)) + throw new UnauthorizedAccessException($"不允许使用 {blackListType.Name} 类型。"); + if (reader.Value is not null && Equals(reader.Value, blackListType.Name)) + throw new UnauthorizedAccessException($"不允许使用 {blackListType.Name} 值。"); + } + + foreach (var blackListMember in new[] { "Code", "FactoryMethod", "Static" }) + if (reader.Member is not null && (reader.Member.Name ?? "") == (blackListMember ?? "")) + throw new UnauthorizedAccessException($"不允许使用 {blackListMember} 成员。"); + } + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherArguments.cs b/Plain Craft Launcher 2/Infrastructure/LauncherArguments.cs new file mode 100644 index 000000000..6c2c84d26 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherArguments.cs @@ -0,0 +1,23 @@ +using Microsoft.VisualBasic; + +namespace PCL; + +/// +/// PCL2 历史命令行参数解析兼容层。 +/// +public static class LauncherArguments +{ + public static object? Get(string name, object? defaultValue = null) + { + var allArguments = Interaction.Command().Split(" "); + for (int i = 0, loopTo = allArguments.Length - 1; i <= loopTo; i++) + if ((allArguments[i] ?? "") == ("-" + name ?? "")) + { + if (allArguments.Length == i + 1 || allArguments[i + 1].StartsWithF("-")) + return true; + return allArguments[i + 1]; + } + + return defaultValue; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherEnvironment.cs b/Plain Craft Launcher 2/Infrastructure/LauncherEnvironment.cs new file mode 100644 index 000000000..ef31898b9 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherEnvironment.cs @@ -0,0 +1,43 @@ +using PCL.Core.App; + +namespace PCL; + +/// +/// PCL2 侧启动器环境信息与历史全局字段的宿主。 +/// +public static class LauncherEnvironment +{ + // 下列版本信息由更新器自动修改。 + public static readonly string VersionBaseName = Basics.VersionName; + public static readonly string VersionStandardCode = Basics.Metadata.Version.StandardVersion; + public static readonly string UpstreamVersion = Basics.Metadata.Version.UpstreamVersion; + public static readonly string CommitHash = Basics.Metadata.Version.Commit; + public static readonly string CommitHashShort = Basics.Metadata.Version.CommitDigest; + public static readonly int VersionCode = Basics.VersionCode; + +#if DEBUG + public const string VersionBranchName = "Debug"; + public const string VersionBranchCode = "100"; +#elif DEBUGCI + public const string VersionBranchName = "CI"; + public const string VersionBranchCode = "50"; +#else + public const string VersionBranchName = "Publish"; + public const string VersionBranchCode = "0"; +#endif + + /// + /// 主窗口句柄。 + /// + public static nint MainWindowHandle { get; set; } + + /// + /// 当前程序的语言。 + /// + public static string CurrentLanguage { get; set; } = "zh_CN"; + + /// + /// 设置对象。 + /// + public static ModSetup Setup { get; set; } = new(); +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs b/Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs new file mode 100644 index 000000000..47a04d6c7 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs @@ -0,0 +1,15 @@ +namespace PCL; + +/// +/// PCL2 进程退出码。ModBase.ProcessReturnValues 保留为旧 API 兼容层。 +/// +public enum LauncherExitCode +{ + Aborted = -1, + Success = 0, + Fail = 1, + Exception = 2, + Timeout = 3, + Cancel = 4, + TaskDone = 5 +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs b/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs new file mode 100644 index 000000000..49aed767b --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs @@ -0,0 +1,130 @@ +using System.Globalization; +using System.Runtime.InteropServices; +using Microsoft.VisualBasic; +using PCL.Core.App.Localization; +using PCL.Core.Logging; +using PCL.Core.Utils.OS; + +namespace PCL; + +/// +/// PCL2 反馈入口与诊断信息收集。 +/// +public static class LauncherFeedbackService +{ + public static void Feedback(bool showMsgbox = true, bool forceOpenLog = false) + { + FeedbackInfo(); + + var currentDate = DateTime.Now.ToString("yyyy-M-dd", CultureInfo.InvariantCulture); + var shouldOpenLogFolder = forceOpenLog || + (showMsgbox && + ModMain.MyMsgBox( + Lang.Text("Setup.Feedback.Reminder.Message", currentDate), + Lang.Text("Setup.Feedback.Reminder.Title"), + Lang.Text("Common.Action.OpenFolder"), + Lang.Text("Setup.Feedback.Reminder.NotNeeded")) == 1); + + if (shouldOpenLogFolder) + LauncherProcess.OpenExplorer( + LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Log\"); + + LauncherProcess.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/issues/"); + } + + public static bool CanFeedback(bool showHint) + { + var stat = UpdateManager.GetVersionStatus(); + + if (stat == UpdateEnums.VersionStatus.Latest) + return true; + + if (!showHint) + return false; + + var message = stat == UpdateEnums.VersionStatus.NotLatest + ? Lang.Text("Setup.Feedback.Unavailable.NotLatest.Message") + : Lang.Text("Setup.Feedback.Unavailable.CheckFailed.Message"); + + var action = stat == UpdateEnums.VersionStatus.NotLatest + ? Lang.Text("Setup.Feedback.Unavailable.NotLatest.Action") + : Lang.Text("Setup.Feedback.Unavailable.CheckFailed.Action"); + + if (ModMain.MyMsgBox( + message, + Lang.Text("Setup.Feedback.Unavailable.Title"), + action, + Lang.Text("Common.Action.Cancel")) == 1) + ModMain.frmMain.PageChange( + FormMain.PageType.Setup, + FormMain.PageSubType.SetupUpdate); + + return false; + } + + /// + /// 在日志中输出系统诊断信息。 + /// + public static void FeedbackInfo() + { + try + { + var phyRam = KernelInterop.GetPhysicalMemoryBytes(); + var availableMb = phyRam.Available / 1024 / 1024; + var totalMb = phyRam.Total / 1024 / 1024; + var dpiScale = Math.Round(DpiUtils.Dpi / 96.0, 2); + + var info = $""" + [System] Diagnostic Information: + OS: {RuntimeInformation.OSDescription} (32-bit: {SystemInfo.Is32BitSystem}) + Memory: {availableMb} MB / {totalMb} MB + DPI: {DpiUtils.Dpi} ({dpiScale * 100}%) + MC Folder: {ModFolder.mcFolderSelected ?? "Nothing"} + Executable Path: {LauncherPaths.ExecutableDirectoryWithSlash} + """; + + LogWrapper.Info(info); + } + catch (Exception ex) + { + LogWrapper.Error(ex, "Failed to collect feedback information"); + } + } + + public static void ShowFeedbackPrompt(string userMessage, string title, bool isCritical) + { + if (isCritical && LauncherLog.MarkCriticalErrorTriggered()) + { + FormMain.EndProgramForce(ModBase.ProcessReturnValues.Exception); + return; + } + + if (CanFeedback(false)) + { + var message = Lang.Text("Setup.Feedback.ErrorPrompt.Submit.Message", userMessage); + var shouldSend = isCritical + ? Interaction.MsgBox( + message, + (MsgBoxStyle)((int)MsgBoxStyle.Critical + (int)MsgBoxStyle.YesNo), + title) == MsgBoxResult.Yes + : ModMain.MyMsgBox( + message, + title, + Lang.Text("Setup.Feedback.ErrorPrompt.Submit.Action"), + Lang.Text("Common.Action.Cancel"), + isWarn: true) == 1; + + if (shouldSend) + Feedback(false, true); + + return; + } + + var updateMessage = Lang.Text("Setup.Feedback.ErrorPrompt.Update.Message", userMessage); + + if (isCritical) + Interaction.MsgBox(updateMessage, MsgBoxStyle.Critical, title); + else + ModMain.MyMsgBox(updateMessage, title, isWarn: true); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs b/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs new file mode 100644 index 000000000..3883922e8 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs @@ -0,0 +1,21 @@ +using PCL.Core.App.Localization; + +namespace PCL; + +/// +/// PCL2 启动器字体应用入口。 +/// +public static class LauncherFontService +{ + public static void SetLaunchFont(string? fontName = null) + { + try + { + LocalizationFontService.ApplyLaunchFont(fontName, LocalizationService.CurrentLanguage); + } + catch (Exception ex) + { + LauncherLog.Log(ex, "设置字体失败", ModBase.LogLevel.Hint); + } + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs b/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs new file mode 100644 index 000000000..dc19090ff --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs @@ -0,0 +1,210 @@ +using System.ComponentModel; +using System.Diagnostics; +using PCL.Core.App.Localization; +using PCL.Core.Logging; + +namespace PCL; + +/// +/// 日志与用户错误提示门面。 +/// +public static class LauncherLog +{ + private static bool _isCriticalErrorTriggered; + + public static void Log( + string text, + ModBase.LogLevel level = ModBase.LogLevel.Normal, + string? title = null, + string? userSummary = null) + { + WriteTextLog(text, level); + + if (LauncherRuntime.IsProgramEnded|| level is ModBase.LogLevel.Normal or ModBase.LogLevel.Developer) + return; + + if (level == ModBase.LogLevel.Debug) + { + ShowDebugHint(text); + return; + } + + var userDetails = text.RegexReplace(@"\[[^\]]+?\] ", ""); + var userMessage = string.IsNullOrWhiteSpace(userSummary) + ? Lang.Text("SystemDialog.Error.UserVisible.Message", userDetails) + : userSummary; + + ShowUserNotification(level, userMessage, GetUserDialogTitle(title)); + } + + public static void Log( + Exception ex, + string desc, + ModBase.LogLevel level = ModBase.LogLevel.Debug, + string? title = null, + string? userSummary = null) + { + if (ex is ThreadInterruptedException) + return; + + WriteExceptionLog(ex, desc, level); + + if (LauncherRuntime.IsProgramEnded || level is ModBase.LogLevel.Normal or ModBase.LogLevel.Developer) + return; + + if (level == ModBase.LogLevel.Debug) + { + ShowDebugHint($"{desc}:{ex}"); + return; + } + + var userMessage = GetUserExceptionMessage(desc, ex, userSummary); + ShowUserNotification(level, userMessage, GetUserDialogTitle(title)); + } + + public static bool MarkCriticalErrorTriggered() + { + if (_isCriticalErrorTriggered) + return true; + + _isCriticalErrorTriggered = true; + return false; + } + + public static void DebugAssert(bool exp) + { + if (!exp) + throw new Exception("断言命中"); + } + + public static string GetStackTrace() + { + var stack = new StackTrace(); + + return string.Join( + "\r\n", + stack.GetFrames() + .Skip(1) + .Select(frame => frame.GetMethod()) + .Where(method => method is not null) + .Select(method => + $"{method!.Name}({string.Join(", ", method.GetParameters().Select(p => p.ToString()))}) - {method.Module}")) + .Replace("\r\n\r\n", "\r\n"); + } + + private static void WriteTextLog(string text, ModBase.LogLevel level) + { + switch (level) + { + case ModBase.LogLevel.Msgbox or ModBase.LogLevel.Hint: + LogWrapper.Warn(text); + break; + + case ModBase.LogLevel.Feedback: + LogWrapper.Error(text); + break; + + case ModBase.LogLevel.Critical: + LogWrapper.Fatal(text); + break; + + case ModBase.LogLevel.Debug: + LogWrapper.Debug(text); + break; + + case ModBase.LogLevel.Developer: + LogWrapper.Trace(text); + break; + + case ModBase.LogLevel.Normal: + default: + LogWrapper.Info(text); + break; + } + } + + private static void WriteExceptionLog(Exception ex, string desc, ModBase.LogLevel level) + { + switch (level) + { + case ModBase.LogLevel.Msgbox or ModBase.LogLevel.Hint: + LogWrapper.Warn(ex, desc); + break; + + case ModBase.LogLevel.Feedback: + LogWrapper.Error(ex, desc); + break; + + case ModBase.LogLevel.Critical: + LogWrapper.Fatal(ex, desc); + break; + + case ModBase.LogLevel.Debug: + LogWrapper.Debug($"{desc}:{ex}"); + break; + + case ModBase.LogLevel.Developer: + LogWrapper.Trace($"{desc}:{ex}"); + break; + + case ModBase.LogLevel.Normal: + default: + LogWrapper.Error(ex, desc); + break; + } + } + + private static void ShowDebugHint(string message) + { + if (LauncherRuntime.ModeDebug) + HintService.Hint("[调试模式] " + message, HintType.Info, false); + } + + private static void ShowUserNotification( + ModBase.LogLevel level, + string userMessage, + string dialogTitle) + { + switch (level) + { + case ModBase.LogLevel.Hint: + HintService.Hint(userMessage, HintType.Error, false); + break; + + case ModBase.LogLevel.Msgbox: + ModMain.MyMsgBox(userMessage, dialogTitle, isWarn: true); + break; + + case ModBase.LogLevel.Feedback: + LauncherFeedbackService.ShowFeedbackPrompt(userMessage, dialogTitle, false); + break; + + case ModBase.LogLevel.Critical: + LauncherFeedbackService.ShowFeedbackPrompt(userMessage, dialogTitle, true); + break; + + case ModBase.LogLevel.Normal + or ModBase.LogLevel.Developer + or ModBase.LogLevel.Debug: + default: + return; + } + } + + private static string GetUserDialogTitle(string? title) + { + return string.IsNullOrWhiteSpace(title) + ? Lang.Text("SystemDialog.Error.Title") + : title; + } + + private static string GetUserExceptionMessage(string desc, Exception ex, string? userSummary) + { + if (!string.IsNullOrWhiteSpace(userSummary)) + return ExceptionDetails.Compose(userSummary, ex); + + return ex.GetType() == typeof(Win32Exception) + ? Lang.Text("SystemDialog.Error.OperationFailed.RuntimeMessage", desc, ex.ToString()) + : Lang.Text("SystemDialog.Error.OperationFailed.Message", desc, ex.ToString()); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs b/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs new file mode 100644 index 000000000..c2c8ea753 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs @@ -0,0 +1,92 @@ +using System.IO; +using PCL.Core.App; +using PCL.Core.Utils.OS; + +namespace PCL; + +/// +/// PCL2 历史路径与兼容路径解析。 +/// +public static class LauncherPaths +{ + private const string DirectorySeparator = @"\"; + + /// + /// 程序可执行文件所在目录,以“\”结尾。 + /// + public static string ExecutableDirectoryWithSlash { get; } = + EnsureTrailingSlash(Basics.ExecutableDirectory); + + /// + /// 程序内嵌图片文件夹路径,以“/”结尾。 + /// + public static string ImageBaseUri { get; } = + "pack://application:,,,/Plain Craft Launcher 2;component/Images/"; + + /// + /// 程序的缓存文件夹路径,以“\”结尾。 + /// + public static string TempWithSlash { get; set; } = EnsureTrailingSlash(Paths.Temp); + + /// + /// AppData 中的 PCL 文件夹路径,以“\”结尾。 + /// + public static string LegacyAppDataWithSlash { get; set; } = + EnsureTrailingSlash(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PCL")); + + /// + /// AppData 中的 PCLCE 配置文件夹路径,以“\”结尾。 + /// + public static string SharedConfigWithSlash { get; set; } = + EnsureTrailingSlash(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + + (LauncherEnvironment.VersionBranchName == "Debug" ? @"\.pclcedebug" : @"\.pclce")); + + /// + /// 可用于临时存放文件的,不含任何特殊字符的文件夹路径。 + /// + public static string PureAsciiDirectory { get; set; } = ResolvePureAsciiDirectory(); + + public static string ResolveLegacyFilePath(string filePath) + { + if (string.IsNullOrEmpty(filePath)) + return filePath; + return IsWindowsAbsolutePath(filePath) + ? filePath + : ExecutableDirectoryWithSlash + filePath; + } + + public static string ResolveLegacyIniPath(string fileName) + { + return IsWindowsAbsolutePath(fileName) + ? fileName + : $@"{ExecutableDirectoryWithSlash}PCL\{fileName}.ini"; + } + + public static string EnsureTrailingSlash(string path) + { + if (string.IsNullOrEmpty(path)) + return DirectorySeparator; + return path.EndsWith('\\') || path.EndsWith('/') + ? path + : path + DirectorySeparator; + } + + public static bool IsWindowsAbsolutePath(string path) + { + return !string.IsNullOrEmpty(path) && path.Contains(@":\", StringComparison.Ordinal); + } + + private static string ResolvePureAsciiDirectory() + { + if (IsAscii(ExecutableDirectoryWithSlash)) return ExecutableDirectoryWithSlash + @"PCL\"; + if (IsAscii(LegacyAppDataWithSlash)) return LegacyAppDataWithSlash; + if (IsAscii(TempWithSlash)) return TempWithSlash; + + return Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL"); + } + + private static bool IsAscii(string input) + { + return input.All(c => c < 128); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs new file mode 100644 index 000000000..720c51667 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs @@ -0,0 +1,236 @@ +using System.Diagnostics; +using System.IO; +using System.Windows; +using PCL.Core.App.Localization; +using PCL.Core.Logging; + +namespace PCL; + +/// +/// 进程、网页、资源管理器与剪贴板操作。 +/// +public static class LauncherProcess +{ + public static void ShellOnly(string fileName, string arguments = "") + { + try + { + fileName = LegacyFileFacade.ShortenPath(fileName); + using var program = new Process(); + program.StartInfo.Arguments = arguments; + program.StartInfo.FileName = fileName; + program.StartInfo.UseShellExecute = true; + LauncherLog.Log($"[System] 执行外部命令:{fileName} {arguments}"); + program.Start(); + } + catch (Exception ex) + { + LauncherLog.Log( + ex, + "打开文件或程序失败:" + fileName, + ModBase.LogLevel.Msgbox, + userSummary: Lang.Text("SystemDialog.File.OpenFailed.Message", fileName)); + } + } + + public static ModBase.ProcessReturnValues ShellAndGetExitCode( + string fileName, + string arguments = "", + int timeout = 1000000) + { + try + { + using var program = new Process(); + program.StartInfo.Arguments = arguments; + program.StartInfo.FileName = fileName; + LauncherLog.Log($"[System] 执行外部命令并等待返回码:{fileName} {arguments}"); + program.Start(); + if (program.WaitForExit(timeout)) return (ModBase.ProcessReturnValues)program.ExitCode; + + return ModBase.ProcessReturnValues.Timeout; + } + catch (Exception ex) + { + LauncherLog.Log(ex, $"执行命令失败:{fileName}", ModBase.LogLevel.Msgbox); + return ModBase.ProcessReturnValues.Fail; + } + } + + public static string ShellAndGetOutput( + string fileName, + string arguments = "", + int timeout = 1000000, + string? workingDirectory = null) + { + var info = new ProcessStartInfo + { + FileName = fileName, + Arguments = arguments, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true + }; + + if (!string.IsNullOrEmpty(workingDirectory)) info.WorkingDirectory = workingDirectory.TrimEnd('\\'); + + LauncherLog.Log($"[System] 执行外部命令并等待返回结果:{fileName} {arguments}"); + + using var program = new Process(); + program.StartInfo = info; + program.Start(); + + var outputTask = program.StandardOutput.ReadToEndAsync(); + var errorTask = program.StandardError.ReadToEndAsync(); + + if (!program.WaitForExit(timeout)) program.Kill(); + Task.WaitAll(outputTask, errorTask); + + return outputTask.Result + errorTask.Result; + } + + public static void OpenWebsite(string url) + { + try + { + if (!url.StartsWithF("http", true) + && !url.StartsWithF("minecraft://", true)) + throw new Exception($"{url} 不是一个有效的网址,它必须以 http 开头!"); + LauncherLog.Log($"[System] 正在打开网页:{url}"); + var psi = new ProcessStartInfo(url) + { + UseShellExecute = true + }; + Process.Start(psi); + } + catch (Exception ex) + { + LauncherLog.Log(ex, $"无法打开网页({url})"); + ClipboardSet(url, false); + var message = ExceptionDetails.Compose( + Lang.Text("SystemDialog.Browser.OpenFailed.Message", url), + ex); + ModMain.MyMsgBox( + message, + Lang.Text("SystemDialog.Browser.OpenFailed.Title")); + } + } + + public static void OpenExplorer(string location) + { + try + { + location = LegacyFileFacade.ShortenPath(location.Replace("/", @"\").Trim(' ', '"')); + LauncherLog.Log($"[System] 正在打开资源管理器:{location}"); + if (location.EndsWithF(@"\")) + ShellOnly(location); + else + ShellOnly("explorer", $"/select,\"{location}\""); + } + catch (Exception ex) + { + LauncherLog.Log( + ex, + "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", + ModBase.LogLevel.Msgbox, + userSummary: Lang.Text("SystemDialog.Folder.OpenFailed.Message", location)); + } + } + + public static void ClipboardSet(string text, bool showSuccessHint = true) + { + UiThread.RunInThread(() => + { + var success = false; + + for (var attempt = 0; attempt <= 5; attempt++) + try + { + UiThread.Post(() => Clipboard.SetText(text)); + success = true; + break; + } + catch (Exception) when (attempt < 5) + { + Thread.Sleep(20); + } + catch (Exception finalEx) + { + LauncherLog.Log( + finalEx, + "剪贴板被占用,文本复制失败", + ModBase.LogLevel.Hint, + userSummary: Lang.Text("Common.Hint.CopyFailed")); + } + + if (success && showSuccessHint) + UiThread.Post(() => HintService.Hint(Lang.Text("Common.Hint.Copied"), HintType.Success)); + }); + } + + public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool copyDir = true) + { + LauncherLog.Log($"[System] 从剪贴板粘贴文件到:{dest}"); + try + { + var files = Clipboard.GetFileDropList(); + if (files.Count.Equals(0)) + { + LauncherLog.Log("[System] 剪贴板内无文件可粘贴"); + return 0; + } + + var copiedFiles = 0; + var copiedFolders = 0; + foreach (var i in files) + { + if (copyFile && File.Exists(i)) + try + { + var thisDest = dest + LegacyFileFacade.GetFileNameFromPath(i); + if (File.Exists(thisDest)) + { + LauncherLog.Log($"[System] 已存在同名文件:{thisDest}"); + } + else + { + File.Copy(i, thisDest); + copiedFiles += 1; + } + } + catch (Exception ex) + { + LauncherLog.Log(ex, "[System] 复制文件时出错"); + continue; + } + + if (copyDir && Directory.Exists(i)) + try + { + var thisDest = dest + LegacyFileFacade.GetFolderNameFromPath(i); + if (Directory.Exists(thisDest)) + { + LauncherLog.Log($"[System] 已存在同名文件夹:{thisDest}"); + } + else + { + LegacyFileFacade.CopyDirectory(i, thisDest); + copiedFolders += 1; + } + } + catch (Exception ex) + { + LauncherLog.Log(ex, "[System] 复制文件时出错"); + } + } + + HintService.Hint(Lang.Text("Common.Hint.FilesPasted", copiedFiles, copiedFolders)); + } + catch (Exception ex) + { + LauncherLog.Log(ex, "[System] 从剪切板粘贴文件失败", ModBase.LogLevel.Hint); + } + + return 0; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs b/Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs new file mode 100644 index 000000000..d63a6ee6b --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs @@ -0,0 +1,39 @@ +using PCL.Core.Utils; + +namespace PCL; + +/// +/// 运行期状态,承接历史 ModBase 全局运行态字段。 +/// +public static class LauncherRuntime +{ + private static int _uuid = 1; + + /// + /// 程序的打开计时。 + /// + public static long ApplicationStartTick { get; set; } = TimeUtils.GetTimeTick(); + + /// + /// 程序打开时的时间。 + /// + public static DateTime ApplicationOpenTime { get; set; } = DateTime.Now; + + /// + /// 程序是否已结束。 + /// + public static bool IsProgramEnded { get; set; } + + /// + /// 是否开启调试模式提示。 + /// + public static bool ModeDebug { get; set; } + + /// + /// 获取一个全程序内不会重复的数字(伪 Uuid)。 + /// + public static int GetUuid() + { + return Interlocked.Increment(ref _uuid); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs new file mode 100644 index 000000000..b4377b90e --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs @@ -0,0 +1,289 @@ +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using PCL.Core.Utils.Codecs; +using PCL.Core.Utils.Hash; +using CoreDirectories = PCL.Core.IO.Directories; +using CoreFiles = PCL.Core.IO.Files; + +namespace PCL; + +/// +/// 历史文件 API 的同步兼容层。 +/// +public static class LegacyFileFacade +{ + public static string ResolvePath(string filePath) + { + return LauncherPaths.ResolveLegacyFilePath(filePath); + } + + public static string GetPathFromFullPath(string filePath) + { + string getPathFromFullPathRet; + if (!(filePath.Contains('\\') || filePath.Contains('/'))) + throw new Exception("不包含路径:" + filePath); + if (filePath.EndsWithF(@"\") || filePath.EndsWithF("/")) + { + var isRight = filePath.EndsWithF(@"\"); + filePath = filePath[..^1]; + getPathFromFullPathRet = filePath[..filePath.LastIndexOfAny(['\\', '/'])] + (isRight ? @"\" : "/"); + } + else + { + getPathFromFullPathRet = filePath[..(filePath.LastIndexOfAny(['\\', '/']) + 1)]; + if (string.IsNullOrEmpty(getPathFromFullPathRet)) + throw new Exception("不包含路径:" + filePath); + } + + return getPathFromFullPathRet; + } + + public static string GetFileNameFromPath(string filePath) + { + filePath = filePath.Replace("/", @"\"); + if (filePath.EndsWithF(@"\")) + throw new Exception("不包含文件名:" + filePath); + if (filePath.Contains('?')) + filePath = filePath[..filePath.IndexOfF("?")]; + if (filePath.Contains('\\')) + filePath = filePath[(filePath.LastIndexOfF(@"\") + 1)..]; + + var length = filePath.Length; + return length switch + { + 0 => throw new Exception("不包含文件名:" + filePath), + > 250 => throw new PathTooLongException("文件名过长:" + filePath), + _ => filePath + }; + } + + public static string GetFileNameWithoutExtensionFromPath(string filePath) + { + return Path.GetFileNameWithoutExtension(filePath); + } + + public static string GetFolderNameFromPath(string folderPath) + { + if (folderPath.EndsWithF(@":\") || folderPath.EndsWithF(@":\\")) + return folderPath[..1]; + if (folderPath.EndsWithF(@"\") || folderPath.EndsWithF("/")) + folderPath = folderPath[..^1]; + return GetFileNameFromPath(folderPath); + } + + public static void CopyFile(string fromPath, string toPath) + { + CoreFiles.CopyFileAsync(ResolvePath(fromPath), ResolvePath(toPath)).GetAwaiter().GetResult(); + } + + public static byte[] ReadBytes(string filePath, Encoding? encoding = null) + { + return CoreFiles.ReadAllBytesOrEmptyAsync(ResolvePath(filePath)).GetAwaiter().GetResult(); + } + + public static string ReadText(string filePath, Encoding? encoding = null) + { + return CoreFiles.ReadAllTextOrEmptyAsync(ResolvePath(filePath), encoding).GetAwaiter().GetResult(); + } + + public static string ReadText(Stream stream, Encoding? encoding = null) + { + return CoreFiles.ReadAllTextOrEmptyAsync(stream, encoding).GetAwaiter().GetResult(); + } + + public static void WriteText(string filePath, string text, bool append = false, Encoding? encoding = null) + { + CoreFiles.WriteFileAsync(ResolvePath(filePath), text, append, encoding).GetAwaiter().GetResult(); + } + + public static void WriteBytes(string filePath, byte[] content, bool append = false) + { + CoreFiles.WriteFileAsync(ResolvePath(filePath), content, append).GetAwaiter().GetResult(); + } + + public static bool WriteStream(string filePath, Stream stream) + { + return CoreFiles.WriteFileAsync(ResolvePath(filePath), stream).GetAwaiter().GetResult(); + } + + public static string DecodeBytes(byte[] bytes) + { + return EncodingUtils.DecodeBytes(bytes); + } + + public static object GetHexString(Memory bytes) + { + return Convert.ToHexString(bytes.Span).ToLowerInvariant(); + } + + public static string GetFileMd5(string filePath) + { + return CoreFiles.GetFileMD5Async(filePath).GetAwaiter().GetResult(); + } + + public static string GetFileSha512(string filePath) + { + return CoreFiles.GetFileSHA512Async(filePath).GetAwaiter().GetResult(); + } + + public static string GetFileSha256(string filePath) + { + return CoreFiles.GetFileSHA256Async(filePath).GetAwaiter().GetResult(); + } + + public static string GetFileSha1(string filePath) + { + return CoreFiles.GetFileSHA1Async(filePath).GetAwaiter().GetResult(); + } + + public static string GetStreamSha1(Stream inputStream) + { + try + { + return (string)GetHexString(SHA1Provider.Instance.ComputeHash(inputStream)); + } + catch (Exception ex) + { + LauncherLog.Log(ex, "获取流 SHA1 失败"); + return ""; + } + } + + public static string CheckFile( + string localPath, + long minSize, + long actualSize, + string hash, + bool isJson) + { + return CoreFiles.CheckAsync(localPath, minSize, actualSize, hash, isJson).GetAwaiter().GetResult(); + } + + public static void WaitForFileReady( + string filePath, + int timeoutMs = 2000, + bool requireJson = false) + { + filePath = ResolvePath(filePath); + var start = Environment.TickCount; + long lastSize = -1; + while (Environment.TickCount - start < timeoutMs) + { + if (File.Exists(filePath)) + try + { + var info = new FileInfo(filePath); + var size = info.Length; + if (size <= 0) + continue; + if (!requireJson) + { + if (size == lastSize) + return; + lastSize = size; + } + else + { + var content = ReadText(filePath); + if (!string.IsNullOrEmpty(content) && content.Trim().StartsWith("{")) + return; + } + } + catch (IOException) + { + } + + Thread.Sleep(50); + } + } + + public static void ExtractFile( + string compressFilePath, + string destDirectory, + Encoding? encode = null, + Action? progressIncrementHandler = null) + { + CoreFiles.ExtractFileAsync(compressFilePath, destDirectory, progressIncrementHandler).GetAwaiter().GetResult(); + } + + public static int DeleteDirectory(string path, bool ignoreIssue = false) + { + return CoreDirectories.DeleteDirectoryAsync(path, ignoreIssue).GetAwaiter().GetResult(); + } + + public static void CopyDirectory( + string fromPath, + string toPath, + Action? progressIncrementHandler = null) + { + CoreDirectories.CopyDirectoryAsync(fromPath, toPath, progressIncrementHandler).GetAwaiter().GetResult(); + } + + public static IEnumerable EnumerateFiles(string directory) + { + try + { + return CoreDirectories.EnumerateFilesAsync(ShortenPath(directory)).GetAwaiter().GetResult(); + } + catch (DirectoryNotFoundException) + { + return []; + } + } + + public static string ShortenPath(string longPath, int shortenThreshold = 247) + { + if (longPath.Length <= shortenThreshold) + return longPath; + var shortPath = new StringBuilder(260); + GetShortPathName(longPath, shortPath, 260); + return shortPath.ToString(); + } + + public static void MoveDirectory(string sourceDir, string targetDir) + { + if (!Directory.Exists(targetDir)) + Directory.CreateDirectory(targetDir); + foreach (var filePath in Directory.GetFiles(sourceDir)) + { + var fileName = GetFileNameFromPath(filePath); + File.Move(filePath, Path.Combine(targetDir, fileName)); + } + + foreach (var dirPath in Directory.GetDirectories(sourceDir)) + { + var dirName = GetFolderNameFromPath(dirPath); + MoveDirectory(dirPath, Path.Combine(targetDir, dirName)); + } + } + + public static void CreateSymbolicLink(string linkPath, string targetPath, int flags) + { + var cmdProcess = new Process(); + var linkDPath = ModLaunch.ExtractLinkD(); + var startInfo = cmdProcess.StartInfo; + startInfo.FileName = linkDPath; + startInfo.Arguments = $"\"{linkPath}\" \"{targetPath}\""; + startInfo.CreateNoWindow = true; + startInfo.UseShellExecute = false; + cmdProcess.Start(); + while (!cmdProcess.HasExited) + { + } + } + + public static bool CheckPermission(string path) + { + return CoreDirectories.CheckPermissionAsync(path).GetAwaiter().GetResult(); + } + + public static void CheckPermissionWithException(string path) + { + CoreDirectories.CheckPermissionWithExceptionAsync(path).GetAwaiter().GetResult(); + } + + [DllImport("kernel32", EntryPoint = "GetShortPathNameA", CharSet = CharSet.Unicode)] + private static extern int GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer); +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs b/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs new file mode 100644 index 000000000..345ada84f --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs @@ -0,0 +1,124 @@ +using System.Collections.Concurrent; +using System.IO; +using System.Text; + +namespace PCL; + +public interface ILegacyKeyValueStore +{ + string Read(string fileName, string key, string defaultValue = ""); + bool ContainsKey(string fileName, string key); + void Write(string fileName, string key, string? value); + void ClearCache(string fileName); +} + +/// +/// PCL2 历史 “key:value” ini 文件格式的读写与缓存。 +/// +public sealed class LegacyIniStore : ILegacyKeyValueStore +{ + private readonly ConcurrentDictionary> _cache = new(); + private readonly object _writeLock = new(); + + private LegacyIniStore() + { + } + + public static LegacyIniStore Shared { get; } = new(); + + public void ClearCache(string fileName) + { + _cache.Remove(LauncherPaths.ResolveLegacyIniPath(fileName), out _); + } + + public string Read(string fileName, string key, string defaultValue = "") + { + var content = GetContent(fileName); + if (content is null || !content.TryGetValue(key, out var value)) + return defaultValue; + return value; + } + + public bool ContainsKey(string fileName, string key) + { + var content = GetContent(fileName); + return content is not null && content.ContainsKey(key); + } + + public void Write(string fileName, string key, string? value) + { + try + { + if (key.Contains(':')) + throw new Exception($"尝试写入 ini 文件 {fileName} 的键名中包含了冒号:{key}"); + key = key.Replace("\r", "").Replace("\n", ""); + value = value?.Replace("\r", "").Replace("\n", ""); + + lock (_writeLock) + { + var content = GetContent(fileName) ?? new ConcurrentDictionary(); + if (value is null) + { + if (!content.ContainsKey(key)) + return; + content.Remove(key, out _); + } + else + { + if (content.TryGetValue(key, out var oldValue) && (oldValue ?? "") == (value ?? "")) + return; + content[key] = value; + } + + var fileContent = new StringBuilder(); + foreach (var pair in content) + { + fileContent.Append(pair.Key); + fileContent.Append(':'); + fileContent.Append(pair.Value); + fileContent.Append("\r\n"); + } + + LegacyFileFacade.WriteText(LauncherPaths.ResolveLegacyIniPath(fileName), fileContent.ToString()); + } + } + catch (Exception ex) + { + LauncherLog.Log(ex, $"写入文件失败({fileName} → {key}:{value})", ModBase.LogLevel.Hint); + } + } + + public void Delete(string fileName, string key) + { + Write(fileName, key, null); + } + + private ConcurrentDictionary? GetContent(string fileName) + { + try + { + var resolvedPath = LauncherPaths.ResolveLegacyIniPath(fileName); + if (_cache.TryGetValue(resolvedPath, out var cached)) + return cached; + if (!File.Exists(resolvedPath)) + return null; + + var ini = new ConcurrentDictionary(); + foreach (var line in LegacyFileFacade.ReadText(resolvedPath) + .Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries)) + { + var index = line.IndexOfF(":"); + if (index > 0) + ini[line[..index]] = line[(index + 1)..]; + } + + _cache[resolvedPath] = ini; + return ini; + } + catch (Exception ex) + { + LauncherLog.Log(ex, $"生成 ini 文件缓存失败({fileName})", ModBase.LogLevel.Hint); + return null; + } + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/UiThread.cs b/Plain Craft Launcher 2/Infrastructure/UiThread.cs new file mode 100644 index 000000000..d500dc575 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/UiThread.cs @@ -0,0 +1,54 @@ +using System.Windows.Threading; +using PCL.Core.App; + +namespace PCL; + +/// +/// PCL2 UI 线程调度兼容层。 +/// +public static class UiThread +{ + private static readonly int InitialThreadId = Environment.CurrentManagedThreadId; + + public static bool CheckAccess() + { + return System.Windows.Application.Current?.Dispatcher?.CheckAccess() ?? + Environment.CurrentManagedThreadId == InitialThreadId; + } + + public static T Invoke(Func action) + { + return CheckAccess() + ? action() + : System.Windows.Application.Current.Dispatcher.Invoke(action); + } + + public static void Invoke(Action action) + { + if (System.Windows.Application.Current is null) + return; + if (CheckAccess()) + action(); + else + System.Windows.Application.Current.Dispatcher.Invoke(action); + } + + public static void Post(Action action, bool forceWaitUntilLoaded = false) + { + if (System.Windows.Application.Current is null) + return; + if (CheckAccess()) + action(); + else + System.Windows.Application.Current.Dispatcher.InvokeAsync(action, + forceWaitUntilLoaded ? DispatcherPriority.Loaded : DispatcherPriority.Normal); + } + + public static void RunInThread(Action action) + { + if (CheckAccess()) + Basics.RunInNewThread(action, $"Runtime Invoke {LauncherRuntime.GetUuid()}#"); + else + action(); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs index 73cb52a8d..fb65ba210 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs @@ -54,7 +54,7 @@ public static void AniStart() aniLastTick = TimeUtils.GetTimeTick(); // 记录 FPS - if (ModBase.modeDebug) + if (ModBase.ModeDebug) { if (ModBase.MathClamp(aniLastTick - aniFPSTimer, 0d, 100000d) >= 500d) { @@ -76,7 +76,7 @@ public static void AniStart() // #Else // If ModeDebug Then FrmMain.Title = "FPS " & AniFPS & ", 动画 " & AniCount & ", 下载中 " & NetManage.FileRemain // #End If - if (RandomUtils.NextInt(0, 64 * (ModBase.modeDebug ? 5 : 30)) == 0 && + if (RandomUtils.NextInt(0, 64 * (ModBase.ModeDebug ? 5 : 30)) == 0 && ((aniFPS < 62 && aniFPS > 0) || aniCount > 4 || ModNet.NetManager.FileRemain != 0)) ModBase.Log("[Report] FPS " + aniFPS + ", 动画 " + aniCount + ", 下载中 " + ModNet.NetManager.FileRemain + "(" + diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.cs b/Plain Craft Launcher 2/Modules/Base/ModLoader.cs index 01e15528e..16ec2d13f 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModLoader.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.cs @@ -632,7 +632,7 @@ public override void Start(object input = null, bool isForceRestart = false) try { isForceRestarting = isForceRestart; - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log( $"[Loader] 加载线程 {name} ({Task.CurrentId}) 已{(isForceRestarting ? "强制" : "")}启动"); loadDelegate(this); @@ -644,7 +644,7 @@ public override void Start(object input = null, bool isForceRestart = false) return; } - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log($"[Loader] 加载线程 {name} ({Task.CurrentId}) 已完成"); RaisePreviewFinish(); State = ModBase.LoadState.Finished; @@ -652,14 +652,14 @@ public override void Start(object input = null, bool isForceRestart = false) } catch (ModBase.CancelledException ex) { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log(ex, $"加载线程 {name} ({Task.CurrentId}) 已触发取消中断,已完成 {Math.Round(Progress * 100d)}%"); if (!IsAborted) State = ModBase.LoadState.Aborted; } catch (ThreadInterruptedException ex) { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log(ex, $"加载线程 {name} ({Task.CurrentId}) 已触发线程中断,已完成 {Math.Round(Progress * 100d)}%"); if (!IsAborted) State = ModBase.LoadState.Aborted; @@ -692,7 +692,7 @@ public override void Abort() private void TriggerThreadAbort() { if (lastRunningTask is null) return; - if (ModBase.modeDebug) ModBase.Log($"[Loader] 加载线程 {name} ({lastRunningTask.Id}) 已中断"); + if (ModBase.ModeDebug) ModBase.Log($"[Loader] 加载线程 {name} ({lastRunningTask.Id}) 已中断"); if (!lastRunningTask.IsCompleted) cancelToken?.Cancel(); lastRunningTask = null; cancelToken = null; diff --git a/Plain Craft Launcher 2/Modules/Base/ModSetup.cs b/Plain Craft Launcher 2/Modules/Base/ModSetup.cs index 0591d203f..0527b5a05 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModSetup.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModSetup.cs @@ -594,7 +594,7 @@ public static void UiLogoLeft(bool value) // 调试选项 public static void SystemDebugMode(bool value) { - ModBase.modeDebug = value; + ModBase.ModeDebug = value; } public static void SystemDebugAnim(int value) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs index 61d76364f..e0aedbbb9 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs @@ -1820,7 +1820,7 @@ private static void McLaunchJava(ModLoader.LoaderTask task) ModInstanceList.McMcInstanceSelected.Info.vanilla >= new Version(20, 0, 5))) { // 1.20.5+ (24w14a+):至少 Java 21 - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] MC 1.20.5+ (24w14a+) 要求至少 Java 21"); minVer = new Version(21, 0, 0, 0); } @@ -1830,7 +1830,7 @@ private static void McLaunchJava(ModLoader.LoaderTask task) ModInstanceList.McMcInstanceSelected.Info.vanilla.Major >= 18)) { // 1.18 pre2+:至少 Java 17 - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] MC 1.18 pre2+ 要求至少 Java 17"); minVer = new Version(17, 0, 0, 0); } @@ -1840,14 +1840,14 @@ private static void McLaunchJava(ModLoader.LoaderTask task) ModInstanceList.McMcInstanceSelected.Info.vanilla.Major >= 17)) { // 1.17+ (21w19a+):至少 Java 16 - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] MC 1.17+ (21w19a+) 要求至少 Java 16"); minVer = new Version(16, 0, 0, 0); } else if (ModInstanceList.McMcInstanceSelected.releaseTime.Year >= 2017) // Minecraft 1.12 与 1.11 的分界线正好是 2017 年,太棒了 { // 1.12+:至少 Java 8 - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] MC 1.12+ 要求至少 Java 8"); minVer = new Version(1, 8, 0, 0); } @@ -1855,7 +1855,7 @@ private static void McLaunchJava(ModLoader.LoaderTask task) ModInstanceList.McMcInstanceSelected.releaseTime.Year >= 2001) // 避免某些版本写个 1960 年 { // 1.5.2-:最高 Java 8 - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] MC 1.5.2- 要求最高 Java 12"); maxVer = new Version(1, 8, 999, 999); } @@ -1948,12 +1948,12 @@ private static void McLaunchJava(ModLoader.LoaderTask task) throw new FormatException("无法解析 Cleanroom 版本号:" + ModInstanceList.McMcInstanceSelected.Info.Cleanroom); if (cleanroomVersion < new Version(0, 5, 0, 0)) { - if (ModBase.modeDebug) ModBase.Log("[Launch] [Debug] Cleanroom 版本低于 0.5,要求至少 Java 21"); + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] Cleanroom 版本低于 0.5,要求至少 Java 21"); minVer = new Version(21, 0, 0, 0) > minVer ? new Version(21, 0, 0, 0) : minVer; } else { - if (ModBase.modeDebug) ModBase.Log("[Launch] [Debug] Cleanroom 版本高于 0.5,要求至少 Java 25"); + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] Cleanroom 版本高于 0.5,要求至少 Java 25"); minVer = new Version(25, 0, 0, 0) > minVer ? new Version(25, 0, 0, 0) : minVer; } } @@ -1974,7 +1974,7 @@ private static void McLaunchJava(ModLoader.LoaderTask task) if (ModInstanceList.McMcInstanceSelected.Info.HasLiteLoader && ModInstanceList.McMcInstanceSelected.Info.Valid) { // 最高 Java 8 - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] LiteLoader 要求最高 Java 8"); maxVer = new Version(8, 999, 999, 999) < maxVer ? new Version(8, 999, 999, 999) : maxVer; } @@ -1982,7 +1982,7 @@ private static void McLaunchJava(ModLoader.LoaderTask task) // LabyMod 检测 if (ModInstanceList.McMcInstanceSelected.Info.HasLabyMod) { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] LabyMod 要求至少 Java 21"); minVer = new Version(21, 0, 0, 0) > minVer ? new Version(21, 0, 0, 0) : minVer; maxVer = new Version(999, 999, 999, 999); @@ -1992,7 +1992,7 @@ private static void McLaunchJava(ModLoader.LoaderTask task) if (ModInstanceList.McMcInstanceSelected.JsonObject["javaVersion"] is not null) { var majorVersion = ModBase.Val(ModInstanceList.McMcInstanceSelected.JsonObject["javaVersion"]["majorVersion"]); - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] JSON 中参数要求至少 Java " + majorVersion); if (majorVersion <= 8d) minVer = new Version(1, (int)Math.Round(majorVersion), 0, 0) > minVer @@ -3029,7 +3029,7 @@ private static void McLaunchNatives(ModLoader.LoaderTask lo var updateFile = new CompFile((JsonObject)modrinthUpdate[Entry.ModrinthHash], CompType.Mod); if (!updateFile.Available) continue; - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log($"[Mod] 本地文件 {Entry.compFile.FileName} 在 Modrinth 上的最新版为 {updateFile.FileName}"); if (Entry.compFile.ReleaseDate >= updateFile.ReleaseDate || Entry.compFile.Hash == updateFile.Hash) continue; @@ -2223,7 +2223,7 @@ private static void CompUpdateDetailLoad(LoaderTask lo } ModBase.WriteFile(Path.Combine(ModBase.pathTemp, "Cache", "LocalComp.json"), - cache.ToJsonString(ModBase.modeDebug ? new JsonSerializerOptions(JsonCompat.SerializerOptions) { WriteIndented = true } : null)); + cache.ToJsonString(ModBase.ModeDebug ? new JsonSerializerOptions(JsonCompat.SerializerOptions) { WriteIndented = true } : null)); // 刷新 UI ModBase.RunInUi(() => diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs index 787386317..beb8d3b41 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs @@ -792,7 +792,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta else { lastResult = e.Data; - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Installer] " + lastResult); totalLength += 1; task.Progress += 0.9d / 7000d; @@ -829,7 +829,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta else { lastResult = e.Data; - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[Installer] " + lastResult); totalLength += 1; task.Progress += 0.9d / 7000d; @@ -1876,7 +1876,7 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask(); - if (ModBase.modeDebug) + if (ModBase.ModeDebug) ModBase.Log("[World] 共发现 " + saveFolders.Count + " 个存档文件夹", ModBase.LogLevel.Debug); PanList.Children.Clear(); CheckQuickPlay(); - if (ModBase.modeDebug) + if (ModBase.ModeDebug) { if ((bool)quickPlayFeature) ModBase.Log("[World] 该实例支持存档快捷启动", ModBase.LogLevel.Debug); diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs index 7ebed2f08..78ecfc571 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs @@ -33,7 +33,7 @@ private void Init() { PanBack.ScrollToHome(); PanScroll = PanBack; // 不知道为啥不能在 XAML 设置 - PanLog.Visibility = ModBase.modeDebug ? Visibility.Visible : Visibility.Collapsed; + PanLog.Visibility = ModBase.ModeDebug ? Visibility.Visible : Visibility.Collapsed; // 社区版提示 PanHint.Visibility = States.Hint.CEMessage ? Visibility.Visible @@ -82,7 +82,7 @@ private void Refresh() ModBase.Log( ex, "加载 PCL 主页自定义信息失败", - ModBase.modeDebug + ModBase.ModeDebug ? ModBase.LogLevel.Msgbox : ModBase.LogLevel.Hint, userSummary: Lang.Text("Launch.Error.OperationFailed")); @@ -385,7 +385,7 @@ private void OnlineLoaderSub(ModLoader.LoaderTask task) ModBase.Log( ex, Lang.Text("Launch.Homepage.Error.Download", address), - ModBase.modeDebug + ModBase.ModeDebug ? ModBase.LogLevel.Msgbox : ModBase.LogLevel.Hint, userSummary: Lang.Text("Launch.Homepage.Error.Download", address)); @@ -468,7 +468,7 @@ private void LoadContent(string content) } catch (Exception ex) { - if (ModBase.modeDebug) + if (ModBase.ModeDebug) { ModBase.Log(ex, $"加载失败的主页内容:\r\n{content}"); if (ModMain.MyMsgBox( diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs index 614b0a5e2..81e60bb2a 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs @@ -389,7 +389,7 @@ 你可以尝试使用视频转码工具打开视频文件并设定目标格式 { ModMain.frmMain.VideoBack.MediaFailed += videoHandler; ModBase.Log(ex, "[UI] 加载背景图片失败" + address); - if (ModBase.modeDebug) + if (ModBase.ModeDebug) HintService.Hint(Lang.Text("Setup.Ui.Background.ImageLoadFailed", address)); ModMain.frmMain.ImgBack.Visibility = Visibility.Visible; ModMain.frmMain.VideoBack.Source = new Uri(address, UriKind.Absolute); diff --git a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs index 4b52df1ac..82f031ed0 100644 --- a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs @@ -40,7 +40,7 @@ private void Page_Loaded(object sender, RoutedEventArgs e) timer.Start(); // 非调试模式隐藏线程数 - if (!ModBase.modeDebug) + if (!ModBase.ModeDebug) { RowDefinitions[12].Height = new GridLength(0d); RowDefinitions[13].Height = new GridLength(0d); diff --git a/Plain Craft Launcher 2/UI/LayoutExtensions.cs b/Plain Craft Launcher 2/UI/LayoutExtensions.cs new file mode 100644 index 000000000..ec2f318b9 --- /dev/null +++ b/Plain Craft Launcher 2/UI/LayoutExtensions.cs @@ -0,0 +1,95 @@ +using System.Windows; + +namespace PCL; + +/// +/// 历史布局辅助方法。 +/// +public static class LayoutExtensions +{ + public static void DeltaLeft(FrameworkElement control, double newValue) + { + LauncherLog.DebugAssert(!double.IsNaN(newValue)); + LauncherLog.DebugAssert(!double.IsInfinity(newValue)); + + if (control is Window window) + window.Left += newValue; + else + switch (control.HorizontalAlignment) + { + case HorizontalAlignment.Left or HorizontalAlignment.Stretch: + control.Margin = new Thickness( + control.Margin.Left + newValue, + control.Margin.Top, + control.Margin.Right, + control.Margin.Bottom); + break; + + case HorizontalAlignment.Right: + control.Margin = new Thickness( + control.Margin.Left, + control.Margin.Top, + control.Margin.Right - newValue, + control.Margin.Bottom); + break; + + case HorizontalAlignment.Center: + default: + LauncherLog.DebugAssert(false); + break; + } + } + + public static void SetLeft(FrameworkElement control, double newValue) + { + LauncherLog.DebugAssert(control.HorizontalAlignment == HorizontalAlignment.Left); + control.Margin = new Thickness( + newValue, + control.Margin.Top, + control.Margin.Right, + control.Margin.Bottom); + } + + public static void DeltaTop(FrameworkElement control, double newValue) + { + LauncherLog.DebugAssert(!double.IsNaN(newValue)); + LauncherLog.DebugAssert(!double.IsInfinity(newValue)); + + if (control is Window window) + window.Top += newValue; + else + switch (control.VerticalAlignment) + { + case VerticalAlignment.Top: + control.Margin = new Thickness( + control.Margin.Left, + control.Margin.Top + newValue, + control.Margin.Right, + control.Margin.Bottom); + break; + + case VerticalAlignment.Bottom: + control.Margin = new Thickness( + control.Margin.Left, + control.Margin.Top, + control.Margin.Right, + control.Margin.Bottom - newValue); + break; + + case VerticalAlignment.Center or VerticalAlignment.Stretch: + default: + LauncherLog.DebugAssert(false); + break; + } + } + + public static void SetTop(FrameworkElement control, double newValue) + { + LauncherLog.DebugAssert(control.VerticalAlignment == VerticalAlignment.Top); + control.Margin = new Thickness( + control.Margin.Left, + newValue, + control.Margin.Right, + control.Margin.Bottom); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/UI/Visual/DpiUtils.cs b/Plain Craft Launcher 2/UI/Visual/DpiUtils.cs new file mode 100644 index 000000000..582b15863 --- /dev/null +++ b/Plain Craft Launcher 2/UI/Visual/DpiUtils.cs @@ -0,0 +1,21 @@ +using System.Drawing; + +namespace PCL; + +/// +/// WPF 与像素尺寸换算。 +/// +public static class DpiUtils +{ + public static readonly int Dpi = (int)Math.Round(Graphics.FromHwnd(nint.Zero).DpiX); + + public static double GetPixelSize(double wpfSize) + { + return wpfSize / 96d * Dpi; + } + + public static double GetWpfSize(double pixelSize) + { + return pixelSize * 96d / Dpi; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/UI/Visual/VisualCapture.cs b/Plain Craft Launcher 2/UI/Visual/VisualCapture.cs new file mode 100644 index 000000000..80d124fea --- /dev/null +++ b/Plain Craft Launcher 2/UI/Visual/VisualCapture.cs @@ -0,0 +1,68 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Size = System.Windows.Size; + +namespace PCL; + +/// +/// 视觉捕获与冻结工具。 +/// +public static class VisualCapture +{ + public static ImageBrush ControlBrush(FrameworkElement ui) + { + var width = ui.ActualWidth; + var height = ui.ActualHeight; + + if (width < 1d || height < 1d) + return new ImageBrush(); + + var bmp = new RenderTargetBitmap( + (int)Math.Round(DpiUtils.GetPixelSize(width)), + (int)Math.Round(DpiUtils.GetPixelSize(height)), + DpiUtils.Dpi, + DpiUtils.Dpi, + PixelFormats.Pbgra32); + bmp.Render(ui); + + return new ImageBrush(bmp); + } + + public static ImageBrush ControlBrush( + FrameworkElement ui, + double width, + double height, + double left = 0d, + double top = 0d) + { + ui.Measure(new Size(width, height)); + ui.Arrange(new Rect(0d, 0d, width, height)); + + var bmp = new RenderTargetBitmap( + (int)Math.Round(DpiUtils.GetPixelSize(width)), + (int)Math.Round(DpiUtils.GetPixelSize(height)), + DpiUtils.Dpi, + DpiUtils.Dpi, + PixelFormats.Default); + bmp.Render(ui); + + if (left != 0d || top != 0d) + ui.Arrange(new Rect(left, top, width, height)); + + return new ImageBrush(bmp); + } + + public static void ControlFreeze(Panel ui) + { + ui.Background = ControlBrush(ui); + ui.Children.Clear(); + } + + public static void ControlFreeze(Border ui) + { + ui.Background = ControlBrush(ui); + ui.Child = null; + } +} \ No newline at end of file From 81b8661afce287b900aa2a8dc6df4b9a61a4b32b Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Tue, 30 Jun 2026 23:09:24 +0800 Subject: [PATCH 04/16] Core --- PCL.Core.Test/Utils/Base64UtilsTest.cs | 16 +++ PCL.Core.Test/Utils/NumberUtilsTest.cs | 25 ++++ PCL.Core.Test/Utils/PathUtilsTest.cs | 25 ++++ PCL.Core.Test/Utils/ProcessRunnerTest.cs | 28 +++++ PCL.Core.Test/Utils/RadixUtilsTest.cs | 23 ++++ PCL.Core.Test/Utils/RegexExtensionsTest.cs | 25 ++++ PCL.Core.Test/Utils/TextUtilsTest.cs | 31 +++++ PCL.Core/IO/Directories.cs | 30 +++++ PCL.Core/IO/PathUtils.cs | 116 ++++++++++++++++++ PCL.Core/Utils/Base64Utils.cs | 56 +++++++++ PCL.Core/Utils/BinaryEncoding.cs | 20 +++ PCL.Core/Utils/CollectionUtils.cs | 59 +++++++++ PCL.Core/Utils/Exts/DictionaryExtensions.cs | 23 ++++ PCL.Core/Utils/Exts/RegexExtensions.cs | 76 ++++++++++++ PCL.Core/Utils/Exts/StringSliceExtensions.cs | 95 ++++++++++++++ PCL.Core/Utils/InterpolationUtils.cs | 42 +++++++ PCL.Core/Utils/NumberUtils.cs | 51 ++++++++ PCL.Core/Utils/OS/ProcessRunner.cs | 106 ++++++++++++++++ PCL.Core/Utils/RadixUtils.cs | 62 ++++++++++ PCL.Core/Utils/ReflectionUtils.cs | 22 ++++ PCL.Core/Utils/TextUtils.cs | 87 +++++++++++++ .../Compatibility/ModBase.Declarations.cs | 64 ++-------- .../Compatibility/ModBase.LegacyLog.cs | 12 +- .../Compatibility/ModBase.LegacySystem.cs | 41 +------ .../Compatibility/ModBase.LegacyText.cs | 92 +++----------- .../Infrastructure/LauncherProcess.cs | 45 +++---- .../Infrastructure/LegacyFileFacade.cs | 70 ++--------- 27 files changed, 1076 insertions(+), 266 deletions(-) create mode 100644 PCL.Core.Test/Utils/Base64UtilsTest.cs create mode 100644 PCL.Core.Test/Utils/NumberUtilsTest.cs create mode 100644 PCL.Core.Test/Utils/PathUtilsTest.cs create mode 100644 PCL.Core.Test/Utils/ProcessRunnerTest.cs create mode 100644 PCL.Core.Test/Utils/RadixUtilsTest.cs create mode 100644 PCL.Core.Test/Utils/RegexExtensionsTest.cs create mode 100644 PCL.Core.Test/Utils/TextUtilsTest.cs create mode 100644 PCL.Core/IO/PathUtils.cs create mode 100644 PCL.Core/Utils/Base64Utils.cs create mode 100644 PCL.Core/Utils/BinaryEncoding.cs create mode 100644 PCL.Core/Utils/CollectionUtils.cs create mode 100644 PCL.Core/Utils/Exts/DictionaryExtensions.cs create mode 100644 PCL.Core/Utils/Exts/RegexExtensions.cs create mode 100644 PCL.Core/Utils/Exts/StringSliceExtensions.cs create mode 100644 PCL.Core/Utils/InterpolationUtils.cs create mode 100644 PCL.Core/Utils/NumberUtils.cs create mode 100644 PCL.Core/Utils/OS/ProcessRunner.cs create mode 100644 PCL.Core/Utils/RadixUtils.cs create mode 100644 PCL.Core/Utils/ReflectionUtils.cs create mode 100644 PCL.Core/Utils/TextUtils.cs diff --git a/PCL.Core.Test/Utils/Base64UtilsTest.cs b/PCL.Core.Test/Utils/Base64UtilsTest.cs new file mode 100644 index 000000000..64c57f340 --- /dev/null +++ b/PCL.Core.Test/Utils/Base64UtilsTest.cs @@ -0,0 +1,16 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.Utils; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class Base64UtilsTest +{ + [TestMethod] + public void EncodesAndDecodesUtf8Text() + { + const string text = "Plain Craft Launcher 测试"; + var encoded = Base64Utils.EncodeString(text); + Assert.AreEqual(text, Base64Utils.DecodeToString(encoded)); + } +} \ No newline at end of file diff --git a/PCL.Core.Test/Utils/NumberUtilsTest.cs b/PCL.Core.Test/Utils/NumberUtilsTest.cs new file mode 100644 index 000000000..680f43f81 --- /dev/null +++ b/PCL.Core.Test/Utils/NumberUtilsTest.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.Utils; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class NumberUtilsTest +{ + [TestMethod] + [DataRow(-1d, 0)] + [DataRow(0d, 0)] + [DataRow(12.4d, 12)] + [DataRow(12.6d, 13)] + [DataRow(300d, 255)] + public void ClampToByte(double value, int expected) + { + Assert.AreEqual((byte)expected, NumberUtils.ClampToByte(value)); + } + + [TestMethod] + public void LerpRoundsToSixDigits() + { + Assert.AreEqual(0.333333d, NumberUtils.Lerp(0d, 1d, 1d / 3d)); + } +} \ No newline at end of file diff --git a/PCL.Core.Test/Utils/PathUtilsTest.cs b/PCL.Core.Test/Utils/PathUtilsTest.cs new file mode 100644 index 000000000..3d68ef092 --- /dev/null +++ b/PCL.Core.Test/Utils/PathUtilsTest.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.IO; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class PathUtilsTest +{ + [TestMethod] + [DataRow("https://example.com/files/core.jar?download=1", "core.jar")] + [DataRow(@"C:\\Games\\Minecraft\\core.jar", "core.jar")] + [DataRow("/tmp/a/b/core.jar", "core.jar")] + public void GetsFileNameFromUrlOrPath(string path, string expected) + { + Assert.AreEqual(expected, PathUtils.GetFileNameFromUrlOrPath(path)); + } + + [TestMethod] + [DataRow(@"C:\\Games\\Minecraft\\", "Minecraft")] + [DataRow(@"D:\\", "D")] + public void GetsDirectoryLeaf(string path, string expected) + { + Assert.AreEqual(expected, PathUtils.GetDirectoryNameLeaf(path)); + } +} \ No newline at end of file diff --git a/PCL.Core.Test/Utils/ProcessRunnerTest.cs b/PCL.Core.Test/Utils/ProcessRunnerTest.cs new file mode 100644 index 000000000..17421dea6 --- /dev/null +++ b/PCL.Core.Test/Utils/ProcessRunnerTest.cs @@ -0,0 +1,28 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.Utils.OS; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class ProcessRunnerTest +{ + public TestContext TestContext { get; set; } + + [TestMethod] + [OSCondition(OperatingSystems.Windows)] + public void CapturesProcessOutput() + { + var result = ProcessRunner + .CaptureAsync( + "cmd.exe", + "/c echo hello", + 5000, + cancellationToken: TestContext.CancellationToken) + .GetAwaiter() + .GetResult(); + + Assert.IsFalse(result.TimedOut); + Assert.AreEqual(0, result.ExitCode); + Assert.Contains("hello", result.CombinedOutput); + } +} \ No newline at end of file diff --git a/PCL.Core.Test/Utils/RadixUtilsTest.cs b/PCL.Core.Test/Utils/RadixUtilsTest.cs new file mode 100644 index 000000000..45d0260c4 --- /dev/null +++ b/PCL.Core.Test/Utils/RadixUtilsTest.cs @@ -0,0 +1,23 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.Utils; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class RadixUtilsTest +{ + [TestMethod] + public void ConvertsLargeNumbersWithBigInteger() + { + const string input = "999999999999999999999999999999"; + var encoded = RadixUtils.Convert(input, 10, 65); + var decoded = RadixUtils.Convert(encoded, 65, 10); + Assert.AreEqual(input, decoded); + } + + [TestMethod] + public void ConvertsNegativeNumbers() + { + Assert.AreEqual("-11111111", RadixUtils.Convert("-255", 10, 2)); + } +} \ No newline at end of file diff --git a/PCL.Core.Test/Utils/RegexExtensionsTest.cs b/PCL.Core.Test/Utils/RegexExtensionsTest.cs new file mode 100644 index 000000000..74cbbc2cd --- /dev/null +++ b/PCL.Core.Test/Utils/RegexExtensionsTest.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.Utils.Exts; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class RegexExtensionsTest +{ + private static readonly string[] Expected = ["12", "34"]; + + [TestMethod] + public void FindsAndChecksMatches() + { + CollectionAssert.AreEqual(Expected, "a12b34".RegexSearch(@"\\d+")); + Assert.AreEqual("12", "a12b34".RegexSeek(@"\\d+")); + Assert.IsTrue("a12".RegexCheck(@"\\d+")); + } + + [TestMethod] + public void ReplacesEachMatch() + { + var replaced = "a12b34".RegexReplaceEach(@"\\d+", match => $"[{match.Value}]"); + Assert.AreEqual("a[12]b[34]", replaced); + } +} \ No newline at end of file diff --git a/PCL.Core.Test/Utils/TextUtilsTest.cs b/PCL.Core.Test/Utils/TextUtilsTest.cs new file mode 100644 index 000000000..edb789ef3 --- /dev/null +++ b/PCL.Core.Test/Utils/TextUtilsTest.cs @@ -0,0 +1,31 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.Utils; +using PCL.Core.Utils.Exts; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class TextUtilsTest +{ + [TestMethod] + public void LeftPadOrTrimKeepsLegacyBehavior() + { + Assert.AreEqual("00abc", TextUtils.LeftPadOrTrim("abc", "0", 5)); + Assert.AreEqual("abc", TextUtils.LeftPadOrTrim("abcdef", "0", 3)); + } + + [TestMethod] + public void EscapesLikePattern() + { + Assert.AreEqual("a[*][?][#][[]b[]]", TextUtils.EscapeLikePattern("a*?#[b]")); + } + + [TestMethod] + public void StringSliceExtensionsKeepUnmatchedText() + { + Assert.AreEqual("2026", "2026/06/30".BeforeFirst("/")); + Assert.AreEqual("06/30", "2026/06/30".AfterFirst("/")); + Assert.AreEqual("30", "2026/06/30".Between("/", "/")); + Assert.AreEqual("2026/06/30", "2026/06/30".BeforeFirst("#")); + } +} \ No newline at end of file diff --git a/PCL.Core/IO/Directories.cs b/PCL.Core/IO/Directories.cs index b6a421930..7f1afa882 100644 --- a/PCL.Core/IO/Directories.cs +++ b/PCL.Core/IO/Directories.cs @@ -284,6 +284,36 @@ public static async Task> EnumerateFilesAsync(string? dire } } + /// + /// 异步移动目录中的全部文件和子目录到目标目录。目标目录不存在时会自动创建。 + /// + public static async Task MoveDirectoryAsync( + string sourceDir, + string targetDir, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(sourceDir)) throw new ArgumentNullException(nameof(sourceDir)); + if (string.IsNullOrWhiteSpace(targetDir)) throw new ArgumentNullException(nameof(targetDir)); + if (!Directory.Exists(sourceDir)) throw new DirectoryNotFoundException($"源目录不存在:{sourceDir}"); + + Directory.CreateDirectory(targetDir); + + foreach (var filePath in Directory.EnumerateFiles(sourceDir)) + { + cancellationToken.ThrowIfCancellationRequested(); + var targetPath = Path.Combine(targetDir, Path.GetFileName(filePath)); + Directory.CreateDirectory(Path.GetDirectoryName(targetPath)!); + await Task.Run(() => File.Move(filePath, targetPath, true), cancellationToken).ConfigureAwait(false); + } + + foreach (var childDir in Directory.EnumerateDirectories(sourceDir)) + { + cancellationToken.ThrowIfCancellationRequested(); + var childTarget = Path.Combine(targetDir, Path.GetFileName(childDir)); + await MoveDirectoryAsync(childDir, childTarget, cancellationToken).ConfigureAwait(false); + } + } + // 辅助方法:异步打开 FileStream private static async Task FileStreamOpenAsync(string path, FileMode mode, FileAccess access, FileShare share, CancellationToken cancellationToken) { var fs = new FileStream(path, mode, access, share, bufferSize: 4096, useAsync: true); diff --git a/PCL.Core/IO/PathUtils.cs b/PCL.Core/IO/PathUtils.cs new file mode 100644 index 000000000..cae8212ee --- /dev/null +++ b/PCL.Core/IO/PathUtils.cs @@ -0,0 +1,116 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace PCL.Core.IO; + +/// +/// 路径和 URL 文件名处理工具。 +/// +public static class PathUtils +{ + private static readonly char[] _DirectorySeparators = ['\\', '/']; + + /// + /// 从文件路径或 URL 获取不包含文件名的目录部分。返回值保留原分隔符风格并以分隔符结尾。 + /// + public static string GetDirectoryPart(string path) + { + ArgumentException.ThrowIfNullOrEmpty(path); + if (!path.Contains('\\') && !path.Contains('/')) + throw new ArgumentException($"不包含路径:{path}", nameof(path)); + + if (_EndsWithDirectorySeparator(path)) + { + var separator = path[^1]; + path = path[..^1]; + var parentIndex = path.LastIndexOfAny(_DirectorySeparators); + if (parentIndex < 0) + throw new ArgumentException($"不包含路径:{path}", nameof(path)); + return path[..(parentIndex + 1)].TrimEnd('\\', '/') + separator; + } + + var index = path.LastIndexOfAny(_DirectorySeparators); + if (index < 0) + throw new ArgumentException($"不包含路径:{path}", nameof(path)); + + var result = path[..(index + 1)]; + return string.IsNullOrEmpty(result) + ? throw new ArgumentException($"不包含路径:{path}", nameof(path)) + : result; + } + + /// + /// 从本地路径或 URL 中提取文件名,URL 查询字符串与片段会被忽略。 + /// + public static string GetFileNameFromUrlOrPath(string path) + { + ArgumentException.ThrowIfNullOrEmpty(path); + path = path.Trim(' ', '"'); + + if (Uri.TryCreate(path, UriKind.Absolute, out var uri) && !string.IsNullOrEmpty(uri.LocalPath)) + { + path = Uri.UnescapeDataString(uri.LocalPath); + } + else + { + var queryIndex = path.IndexOfAny(['?', '#']); + if (queryIndex >= 0) path = path[..queryIndex]; + } + + if (_EndsWithDirectorySeparator(path)) + throw new ArgumentException($"不包含文件名:{path}", nameof(path)); + + var separatorIndex = path.LastIndexOfAny(_DirectorySeparators); + var fileName = separatorIndex >= 0 ? path[(separatorIndex + 1)..] : path; + + return fileName.Length switch + { + 0 => throw new ArgumentException($"不包含文件名:{path}", nameof(path)), + > 250 => throw new PathTooLongException($"文件名过长:{fileName}"), + _ => fileName + }; + } + + public static string GetFileNameWithoutExtensionFromUrlOrPath(string path) + { + return Path.GetFileNameWithoutExtension(GetFileNameFromUrlOrPath(path)); + } + + /// + /// 从目录路径中提取目录名。根驱动器返回驱动器字母。 + /// + public static string GetDirectoryNameLeaf(string path) + { + ArgumentException.ThrowIfNullOrEmpty(path); + path = path.Trim(' ', '"'); + + if (path.EndsWith(@":\", StringComparison.Ordinal) || path.EndsWith(@":\\", StringComparison.Ordinal)) + return path[..1]; + + path = path.TrimEnd('\\', '/'); + return GetFileNameFromUrlOrPath(path); + } + + /// + /// 当路径过长时尝试转换为 Windows 8.3 短路径;失败或非 Windows 系统时返回原路径。 + /// + public static string ShortenPath(string path, int shortenThreshold = 247) + { + ArgumentNullException.ThrowIfNull(path); + if (path.Length <= shortenThreshold || !OperatingSystem.IsWindows()) return path; + + var buffer = new StringBuilder(260); + var length = GetShortPathName(path, buffer, buffer.Capacity); + return length > 0 ? buffer.ToString() : path; + } + + private static bool _EndsWithDirectorySeparator(string path) + { + return path.EndsWith('\\') || path.EndsWith('/'); + } + + [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer); +} \ No newline at end of file diff --git a/PCL.Core/Utils/Base64Utils.cs b/PCL.Core/Utils/Base64Utils.cs new file mode 100644 index 000000000..c75330d40 --- /dev/null +++ b/PCL.Core/Utils/Base64Utils.cs @@ -0,0 +1,56 @@ +using System; +using System.Text; + +namespace PCL.Core.Utils; + +/// +/// Base64 编解码工具。 +/// +public static class Base64Utils +{ + public static string EncodeString(string text, Encoding? encoding = null) + { + encoding ??= Encoding.UTF8; + return Convert.ToBase64String(encoding.GetBytes(text)); + } + + public static string DecodeToString(string? text, Encoding? encoding = null) + { + if (string.IsNullOrWhiteSpace(text)) return string.Empty; + encoding ??= Encoding.UTF8; + return encoding.GetString(DecodeToBytes(text)); + } + + public static string EncodeBytes(byte[] bytes) + { + ArgumentNullException.ThrowIfNull(bytes); + return Convert.ToBase64String(bytes); + } + + public static byte[] DecodeToBytes(string text) + { + ArgumentNullException.ThrowIfNull(text); + return Convert.FromBase64String(_AddPadding(text.Trim())); + } + + public static string EncodeUrlSafe(byte[] bytes, bool trimPadding = true) + { + var encoded = Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_'); + return trimPadding ? encoded.TrimEnd('=') : encoded; + } + + public static byte[] DecodeUrlSafeToBytes(string text) + { + ArgumentNullException.ThrowIfNull(text); + text = text.Replace('-', '+').Replace('_', '/'); + return Convert.FromBase64String(_AddPadding(text)); + } + + private static string _AddPadding(string text) + { + var remainder = text.Length % 4; + return remainder == 0 + ? text + : text.PadRight(text.Length + 4 - remainder, '='); + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/BinaryEncoding.cs b/PCL.Core/Utils/BinaryEncoding.cs new file mode 100644 index 000000000..d73a673e9 --- /dev/null +++ b/PCL.Core/Utils/BinaryEncoding.cs @@ -0,0 +1,20 @@ +using System; + +namespace PCL.Core.Utils; + +/// +/// 二进制数据文本编码工具。 +/// +public static class BinaryEncoding +{ + public static string ToHexLower(ReadOnlySpan bytes) + { + return Convert.ToHexString(bytes).ToLowerInvariant(); + } + + public static string ToHexLower(byte[] bytes) + { + ArgumentNullException.ThrowIfNull(bytes); + return ToHexLower(bytes.AsSpan()); + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/CollectionUtils.cs b/PCL.Core/Utils/CollectionUtils.cs new file mode 100644 index 000000000..9e1b5768a --- /dev/null +++ b/PCL.Core/Utils/CollectionUtils.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace PCL.Core.Utils; + +/// +/// 集合辅助工具。 +/// +public static class CollectionUtils +{ + public static List FlattenMixedList(IList data) + { + ArgumentNullException.ThrowIfNull(data); + var result = new List(); + foreach (var item in data) + switch (item) + { + case IEnumerable typedCollection: + result.AddRange(typedCollection); + break; + case T typedItem: + result.Add(typedItem); + break; + default: + { + if (item is not string && item is IEnumerable enumerable) + result.AddRange(enumerable.Cast()); + else + result.Add((T)item!); + break; + } + } + + return result; + } + + public static List DistinctByComparison( + ICollection values, + Func isEqual, + bool keepLast = false) + { + ArgumentNullException.ThrowIfNull(values); + ArgumentNullException.ThrowIfNull(isEqual); + + var result = new List(); + var source = values.ToList(); + for (var i = 0; i < source.Count; i++) + { + var hasDuplicateLater = keepLast && source.Skip(i + 1).Any(other => isEqual(source[i], other)); + if (hasDuplicateLater) continue; + if (!keepLast && result.Any(existing => isEqual(existing, source[i]))) continue; + result.Add(source[i]); + } + + return result; + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/Exts/DictionaryExtensions.cs b/PCL.Core/Utils/Exts/DictionaryExtensions.cs new file mode 100644 index 000000000..f21865599 --- /dev/null +++ b/PCL.Core/Utils/Exts/DictionaryExtensions.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace PCL.Core.Utils.Exts; + +public static class DictionaryExtensions +{ + public static TValue GetOrDefault( + this Dictionary dictionary, + TKey key, + TValue defaultValue = default!) + { + return dictionary.GetValueOrDefault(key, defaultValue); + } + + public static void AddToList( + this Dictionary> dictionary, + TKey key, + TValue value) + { + if (dictionary.TryGetValue(key, out var list)) list.Add(value); + else dictionary.Add(key, [value]); + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/Exts/RegexExtensions.cs b/PCL.Core/Utils/Exts/RegexExtensions.cs new file mode 100644 index 000000000..077b85f50 --- /dev/null +++ b/PCL.Core/Utils/Exts/RegexExtensions.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace PCL.Core.Utils.Exts; + +/// +/// 正则表达式扩展。 +/// +public static class RegexExtensions +{ + extension(string value) + { + public string RegexReplace( + string pattern, + string replacement, + RegexOptions options = RegexOptions.None) + { + ArgumentNullException.ThrowIfNull(value); + return Regex.Replace(value, pattern, replacement, options); + } + + public string RegexReplaceEach( + string pattern, + MatchEvaluator evaluator, + RegexOptions options = RegexOptions.None) + { + ArgumentNullException.ThrowIfNull(value); + ArgumentNullException.ThrowIfNull(evaluator); + return Regex.Replace(value, pattern, evaluator, options); + } + } + + extension(string? value) + { + public List RegexSearch( + string pattern, + RegexOptions options = RegexOptions.None) + { + return value is null + ? [] + : Regex.Matches(value, pattern, options) + .Select(match => match.Value) + .ToList(); + } + + public string? RegexSeek( + string pattern, + RegexOptions options = RegexOptions.None) + { + if (value is null) return null; + var result = Regex.Match(value, pattern, options).Value; + return string.IsNullOrEmpty(result) + ? null + : result; + } + + public string? RegexSeek(Regex regex) + { + ArgumentNullException.ThrowIfNull(regex); + if (value is null) return null; + var result = regex.Match(value).Value; + return string.IsNullOrEmpty(result) + ? null + : result; + } + + public bool RegexCheck( + string pattern, + RegexOptions options = RegexOptions.None) + { + return value is not null && Regex.IsMatch(value, pattern, options); + } + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/Exts/StringSliceExtensions.cs b/PCL.Core/Utils/Exts/StringSliceExtensions.cs new file mode 100644 index 000000000..2a608749a --- /dev/null +++ b/PCL.Core/Utils/Exts/StringSliceExtensions.cs @@ -0,0 +1,95 @@ +using System; + +namespace PCL.Core.Utils.Exts; + +/// +/// 字符串切片扩展。 +/// +public static class StringSliceExtensions +{ + extension(string value) + { + public string BeforeFirst(string marker, bool ignoreCase = false) + { + ArgumentNullException.ThrowIfNull(value); + var index = string.IsNullOrEmpty(marker) + ? -1 + : value.IndexOf( + marker, + ignoreCase + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal); + return index >= 0 + ? value[..index] + : value; + } + + public string BeforeLast(string marker, bool ignoreCase = false) + { + ArgumentNullException.ThrowIfNull(value); + var index = string.IsNullOrEmpty(marker) + ? -1 + : value.LastIndexOf( + marker, + ignoreCase + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal); + return index >= 0 + ? value[..index] + : value; + } + + public string AfterFirst(string marker, bool ignoreCase = false) + { + ArgumentNullException.ThrowIfNull(value); + var index = string.IsNullOrEmpty(marker) + ? -1 + : value.IndexOf( + marker, + ignoreCase + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal); + return index >= 0 + ? value[(index + marker.Length)..] + : value; + } + + public string AfterLast(string marker, bool ignoreCase = false) + { + ArgumentNullException.ThrowIfNull(value); + var index = string.IsNullOrEmpty(marker) + ? -1 + : value.LastIndexOf( + marker, + ignoreCase + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal); + return index >= 0 + ? value[(index + marker.Length)..] + : value; + } + + public string Between(string after, string before, bool ignoreCase = false) + { + ArgumentNullException.ThrowIfNull(value); + + var comparison = ignoreCase + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + var start = string.IsNullOrEmpty(after) + ? -1 + : value.LastIndexOf(after, comparison); + start = start >= 0 + ? start + after.Length + : 0; + + var end = string.IsNullOrEmpty(before) + ? -1 + : value.IndexOf(before, start, comparison); + if (end >= 0) return value[start..end]; + return start > 0 + ? value[start..] + : value; + } + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/InterpolationUtils.cs b/PCL.Core/Utils/InterpolationUtils.cs new file mode 100644 index 000000000..16a9dc272 --- /dev/null +++ b/PCL.Core/Utils/InterpolationUtils.cs @@ -0,0 +1,42 @@ +using System; + +namespace PCL.Core.Utils; + +/// +/// 插值和缓动曲线工具。 +/// +public static class InterpolationUtils +{ + /// + /// 根据三次贝塞尔控制点求指定 x 位置对应的 y 值。起点为 (0,0),终点为 (1,1)。 + /// + public static double CubicBezierY( + double x, + double x1, double y1, + double x2, double y2, + double epsilon = 0.000_001d) + { + if (double.IsNaN(x) || x <= 0d) return 0d; + if (x >= 1d) return 1d; + + var low = 0d; + var high = 1d; + var t = x; + for (var i = 0; i < 32; i++) + { + t = (low + high) / 2d; + var currentX = _CubicBezier(t, x1, x2); + if (Math.Abs(currentX - x) <= epsilon) break; + if (currentX < x) low = t; + else high = t; + } + + return _CubicBezier(t, y1, y2); + } + + private static double _CubicBezier(double t, double p1, double p2) + { + var u = 1d - t; + return 3d * u * u * t * p1 + 3d * u * t * t * p2 + t * t * t; + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/NumberUtils.cs b/PCL.Core/Utils/NumberUtils.cs new file mode 100644 index 000000000..4c7f8e23d --- /dev/null +++ b/PCL.Core/Utils/NumberUtils.cs @@ -0,0 +1,51 @@ +using System; + +namespace PCL.Core.Utils; + +/// +/// 通用数值处理工具。 +/// +public static class NumberUtils +{ + /// + /// 将浮点数舍入并限制到 可表示的 0~255 范围。 + /// + public static byte ClampToByte(double value) + { + if (double.IsNaN(value)) return 0; + value = Math.Clamp(value, 0d, 255d); + return (byte)Math.Round(value); + } + + /// + /// 返回数值符号:正数为 1,负数为 -1,0 或 NaN 为 0。 + /// + public static int Sign(double value) + { + if (value is 0d or double.NaN) return 0; + return value > 0d ? 1 : -1; + } + + /// + /// 在两个数值之间做线性插值。 + /// + public static double Lerp( + double start, + double end, + double progress, + int digits = 6) + { + var value = start * (1d - progress) + end * progress; + return digits >= 0 ? Math.Round(value, digits) : value; + } + + /// + /// 将数值限制在指定闭区间。 + /// + public static double Clamp(double value, double min, double max) + { + return min > max + ? min + : Math.Clamp(value, min, max); + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/OS/ProcessRunner.cs b/PCL.Core/Utils/OS/ProcessRunner.cs new file mode 100644 index 000000000..98d0a6246 --- /dev/null +++ b/PCL.Core/Utils/OS/ProcessRunner.cs @@ -0,0 +1,106 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace PCL.Core.Utils.OS; + +/// +/// 外部进程执行工具。 +/// +public static class ProcessRunner +{ + public static async Task CaptureAsync( + string fileName, + string arguments = "", + int timeoutMs = 1_000_000, + string? workingDirectory = null, + CancellationToken cancellationToken = default) + { + var startInfo = new ProcessStartInfo + { + FileName = fileName, + Arguments = arguments, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true + }; + + if (!string.IsNullOrWhiteSpace(workingDirectory)) + startInfo.WorkingDirectory = workingDirectory.TrimEnd('\\', '/'); + + using var process = new Process(); + process.StartInfo = startInfo; + process.EnableRaisingEvents = true; + process.Start(); + + var outputTask = process.StandardOutput.ReadToEndAsync(cancellationToken); + var errorTask = process.StandardError.ReadToEndAsync(cancellationToken); + var timedOut = false; + + using var timeoutCts = timeoutMs >= 0 + ? CancellationTokenSource.CreateLinkedTokenSource(cancellationToken) + : null; + timeoutCts?.CancelAfter(timeoutMs); + + try + { + await process.WaitForExitAsync(timeoutCts?.Token ?? cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) + { + timedOut = true; + _TryKill(process); + } + + string output, error; + try + { + output = await outputTask.ConfigureAwait(false); + error = await errorTask.ConfigureAwait(false); + } + catch (OperationCanceledException) + { + output = string.Empty; + error = string.Empty; + } + + int? exitCode = null; + if (!timedOut && process.HasExited) exitCode = process.ExitCode; + return new ProcessRunResult(exitCode, timedOut, output, error); + } + + public static async Task RunAsync( + string fileName, + string arguments = "", + int timeoutMs = 1_000_000, + string? workingDirectory = null, + CancellationToken cancellationToken = default) + { + var result = await CaptureAsync(fileName, arguments, timeoutMs, workingDirectory, cancellationToken) + .ConfigureAwait(false); + return result.ExitCode; + } + + private static void _TryKill(Process process) + { + try + { + if (!process.HasExited) process.Kill(true); + } + catch + { + // ignored: the process may have exited between HasExited and Kill. + } + } +} + +public sealed record ProcessRunResult( + int? ExitCode, + bool TimedOut, + string StandardOutput, + string StandardError) +{ + public string CombinedOutput => StandardOutput + StandardError; +} \ No newline at end of file diff --git a/PCL.Core/Utils/RadixUtils.cs b/PCL.Core/Utils/RadixUtils.cs new file mode 100644 index 000000000..a609388e6 --- /dev/null +++ b/PCL.Core/Utils/RadixUtils.cs @@ -0,0 +1,62 @@ +using System; +using System.Numerics; +using System.Text; + +namespace PCL.Core.Utils; + +/// +/// 提供 2~65 进制文本转换能力。 +/// +public static class RadixUtils +{ + private const string DefaultDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+="; + + /// + /// 将文本从一个进制转换到另一个进制。默认字符集兼容 PCL 历史 2~65 进制定义。 + /// + public static string Convert( + string? input, + int sourceRadix, + int targetRadix, + string? digits = null) + { + digits ??= DefaultDigits; + _ValidateRadix(sourceRadix, digits, nameof(sourceRadix)); + _ValidateRadix(targetRadix, digits, nameof(targetRadix)); + + if (string.IsNullOrEmpty(input)) return "0"; + + input = input.Trim(); + if (input.Length == 0) return "0"; + + var negative = input[0] == '-'; + if (negative) input = input[1..]; + if (input.Length == 0) return "0"; + + var value = BigInteger.Zero; + foreach (var ch in input) + { + var digit = digits.IndexOf(ch, StringComparison.Ordinal); + if (digit < 0 || digit >= sourceRadix) + throw new ArgumentOutOfRangeException(nameof(input), $"字符 '{ch}' 不在 {sourceRadix} 进制范围内。"); + value = value * sourceRadix + digit; + } + + if (value.IsZero) return "0"; + + var builder = new StringBuilder(); + while (value > BigInteger.Zero) + { + value = BigInteger.DivRem(value, targetRadix, out var remainder); + builder.Insert(0, digits[(int)remainder]); + } + + return negative ? "-" + builder : builder.ToString(); + } + + private static void _ValidateRadix(int radix, string digits, string paramName) + { + if (radix < 2 || radix > digits.Length) + throw new ArgumentOutOfRangeException(paramName, radix, $"进制必须位于 2 到 {digits.Length} 之间。"); + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/ReflectionUtils.cs b/PCL.Core/Utils/ReflectionUtils.cs new file mode 100644 index 000000000..a86d20919 --- /dev/null +++ b/PCL.Core/Utils/ReflectionUtils.cs @@ -0,0 +1,22 @@ +using System; + +namespace PCL.Core.Utils; + +/// +/// 反射辅助工具。 +/// +public static class ReflectionUtils +{ + public static bool IsInstanceOfGenericType(Type genericTypeDefinition, object? instance) + { + ArgumentNullException.ThrowIfNull(genericTypeDefinition); + if (instance is null) return false; + if (!genericTypeDefinition.IsGenericTypeDefinition) return false; + + for (var type = instance.GetType(); type is not null; type = type.BaseType) + if (type.IsGenericType && type.GetGenericTypeDefinition() == genericTypeDefinition) + return true; + + return false; + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/TextUtils.cs b/PCL.Core/Utils/TextUtils.cs new file mode 100644 index 000000000..cf008f527 --- /dev/null +++ b/PCL.Core/Utils/TextUtils.cs @@ -0,0 +1,87 @@ +using System; +using System.Text; + +namespace PCL.Core.Utils; + +/// +/// 通用文本处理工具。 +/// +public static class TextUtils +{ + /// + /// 将首字符转为大写,其余字符转为小写。空文本保持原样。 + /// + public static string CapitalizeInvariant(string? word) + { + if (string.IsNullOrEmpty(word)) return string.Empty; + return word[..1].ToUpperInvariant() + word[1..].ToLowerInvariant(); + } + + /// + /// 将文本统一到指定长度:过长时截取左侧指定长度,过短时在左侧填充指定字符。 + /// + public static string LeftPadOrTrim(string value, string padding, int length) + { + ArgumentNullException.ThrowIfNull(value); + ArgumentOutOfRangeException.ThrowIfNegative(length); + if (value.Length > length) return value[..length]; + if (value.Length == length) return value; + + var padChar = string.IsNullOrEmpty(padding) ? ' ' : padding[0]; + return value.PadLeft(length, padChar); + } + + /// + /// 移除展示名称首尾常见标点,并可移除括号或冒号后的补充说明。 + /// + public static string TrimDisplayName(string value, bool removeQuote = true) + { + ArgumentNullException.ThrowIfNull(value); + if (removeQuote) + { + value = _CutBefore(value, "("); + value = _CutBefore(value, ":"); + value = _CutBefore(value, "("); + value = _CutBefore(value, ":"); + } + + return value.Trim('.', '。', '!', ' ', '!', '?', '?', '\r', '\n'); + } + + /// + /// 对 XML 特殊字符进行转义。 + /// + public static string EscapeXml(string value) + { + if (string.IsNullOrEmpty(value)) return string.Empty; + return value + .Replace("&", "&") + .Replace("<", "<") + .Replace(">", ">") + .Replace("'", "'") + .Replace("\"", """) + .Replace("\r\n", " "); + } + + /// + /// 为 Access/VB Like 风格通配字符添加方括号转义。 + /// + public static string EscapeLikePattern(string input) + { + ArgumentNullException.ThrowIfNull(input); + var builder = new StringBuilder(input.Length); + foreach (var c in input) + if (c is '[' or ']' or '*' or '?' or '#') + builder.Append('[').Append(c).Append(']'); + else + builder.Append(c); + + return builder.ToString(); + } + + private static string _CutBefore(string value, string marker) + { + var index = value.IndexOf(marker, StringComparison.Ordinal); + return index >= 0 ? value[..index] : value; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs b/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs index bc83f5f76..c06e9d575 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs @@ -1,4 +1,5 @@ using System.Windows.Media; +using PCL.Core.Utils; using Brush = System.Windows.Media.Brush; using Color = System.Windows.Media.Color; using ColorConverter = System.Windows.Media.ColorConverter; @@ -534,33 +535,7 @@ public override bool Equals(object obj) /// public static string RadixConvert(string input, int fromRadix, int toRadix) { - const string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+="; - // 零与负数的处理 - if (string.IsNullOrEmpty(input)) - return "0"; - var isNegative = input.StartsWithF("-"); - if (isNegative) - input = input.TrimStart('-'); - // 转换为十进制 - var realNum = 0L; - var scale = 1L; - foreach (var digit in input.Reverse().Select(l => digits.IndexOfF(l.ToString()))) - { - realNum += digit * scale; - scale *= fromRadix; - } - - // 转换为指定进制 - var result = ""; - while (realNum > 0L) - { - var newNum = (int)(realNum % toRadix); - realNum = (long)Math.Round((realNum - newNum) / (double)toRadix); - result = digits[newNum] + result; - } - - // 负数的结束处理与返回 - return (isNegative ? "-" : "") + result; + return RadixUtils.Convert(input, fromRadix, toRadix); } /// @@ -574,23 +549,7 @@ public static double MathBezier( double y2, double acc = 0.01d) { - switch (x) - { - case <= 0d or double.NaN: - return 0d; - case >= 1d: - return 1d; - } - - double b; - var a = x; - do - { - b = 3 * a * ((0.33333333 + x1 - x2) * a * a + (x2 - 2 * x1) * a + x1); - a += (x - b) * 0.5; - } while (!(Math.Abs(b - x) < acc)); // 精度 - - return 3 * a * ((0.33333333 + y1 - y2) * a * a + (y2 - 2 * y1) * a + y1); + return InterpolationUtils.CubicBezierY(x, x1, y1, x2, y2, acc); } /// @@ -598,11 +557,7 @@ public static double MathBezier( /// public static byte MathByte(double d) { - if (d < 0d) - d = 0d; - if (d > 255d) - d = 255d; - return (byte)Math.Round(Math.Round(d)); + return NumberUtils.ClampToByte(d); } /// @@ -625,7 +580,7 @@ public static MyColor MathRound(MyColor col, int w = 0) /// public static double MathPercent(double valueA, double valueB, double percent) { - return Math.Round(valueA * (1d - percent) + valueB * percent, 6); // 解决 Double 计算错误 + return NumberUtils.Lerp(valueA, valueB, percent); } /// @@ -641,7 +596,7 @@ public static MyColor MathPercent(MyColor valueA, MyColor valueB, double percent /// public static double MathClamp(double value, double min, double max) { - return Math.Max(min, Math.Min(max, value)); + return NumberUtils.Clamp(value, min, max); } /// @@ -649,12 +604,7 @@ public static double MathClamp(double value, double min, double max) /// public static int MathSgn(double value) { - return value switch - { - 0d => 0, - > 0d => 1, - _ => -1 - }; + return NumberUtils.Sign(value); } #endregion diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs index 98a985459..eda3d7c3c 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs @@ -1,4 +1,4 @@ -using System.Text; +using PCL.Core.Utils; namespace PCL; @@ -75,21 +75,17 @@ public static void Log(Exception ex, string desc, LogLevel level = LogLevel.Debu public static string Base64Decode(string text) { - if (string.IsNullOrWhiteSpace(text)) - return ""; - var decodedBytes = Convert.FromBase64String(text); - return Encoding.UTF8.GetString(decodedBytes); + return Base64Utils.DecodeToString(text); } public static string Base64Encode(string text) { - var bytes = Encoding.UTF8.GetBytes(text); - return Convert.ToBase64String(bytes); + return Base64Utils.EncodeString(text); } public static string Base64Encode(byte[] bytes) { - return Convert.ToBase64String(bytes); + return Base64Utils.EncodeBytes(bytes); } // 反馈 diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs index 1e7c783b7..9d15e15aa 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs @@ -1,6 +1,7 @@ using System.Collections; using System.IO; using PCL.Core.App; +using PCL.Core.Utils; using PCL.Core.Utils.Codecs; using PCL.Core.Utils.Exts; @@ -177,17 +178,7 @@ public class CancelledException : Exception /// public static bool IsInstanceOfGenericType(this Type genericType, object obj) { - if (obj is null) - return false; - var t = obj.GetType(); - while (t is not null) - { - if (t.IsGenericType && ReferenceEquals(t.GetGenericTypeDefinition(), genericType)) - return true; - t = t.BaseType; - } - - return false; + return ReflectionUtils.IsInstanceOfGenericType(genericType, obj); } /// @@ -203,14 +194,7 @@ public static int GetUuid() /// public static List GetFullList(IList data) { - var result = new List(); - for (int i = 0, loopTo = data.Count - 1; i <= loopTo; i++) - if (data[i] is ICollection) - result.AddRange((IEnumerable)data[i]); - else - result.Add((T)data[i]); - - return result; + return CollectionUtils.FlattenMixedList(data); } /// @@ -218,17 +202,7 @@ public static List GetFullList(IList data) /// public static List Distinct(this ICollection arr, ComparisonBoolean isEqual) { - var resultArray = new List(); - for (int i = 0, loopTo = arr.Count - 1; i <= loopTo; i++) - { - for (int ii = i + 1, loopTo1 = arr.Count - 1; ii <= loopTo1; ii++) - if (isEqual(arr.ElementAtOrDefault(i), arr.ElementAtOrDefault(ii))) - goto NextElement; - resultArray.Add(arr.ElementAtOrDefault(i)); - NextElement: ; - } - - return resultArray; + return CollectionUtils.DistinctByComparison(arr, (left, right) => isEqual(left, right), true); } /// @@ -345,7 +319,7 @@ public static TValue GetOrDefault( TKey key, TValue defaultValue = default) { - return dict.GetValueOrDefault(key, defaultValue); + return DictionaryExtensions.GetOrDefault(dict, key, defaultValue); } /// @@ -356,10 +330,7 @@ public static void AddToList( TKey key, TValue value) { - if (dict.TryGetValue(key, out var value1)) - value1.Add(value); - else - dict.Add(key, [value]); + DictionaryExtensions.AddToList(dict, key, value); } /// diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs index 52b2b412b..bd7d80e1e 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs @@ -6,6 +6,7 @@ using PCL.Core.App.Localization; using PCL.Core.IO; using PCL.Core.Utils; +using PCL.Core.Utils.Exts; using PCL.Core.Utils.Hash; namespace PCL; @@ -59,9 +60,7 @@ public static JsonNode GetJson(string data) /// public static string Capitalize(this string word) { - if (string.IsNullOrEmpty(word)) - return word; - return word[..1].ToUpperInvariant() + word[1..].ToLowerInvariant(); + return TextUtils.CapitalizeInvariant(word); } /// @@ -69,9 +68,7 @@ public static string Capitalize(this string word) /// public static string StrFill(string str, string code, byte length) { - return str.Length > length - ? str[..length] - : string.Concat(str.PadRight(length, code[0]).AsSpan(str.Length), str); + return TextUtils.LeftPadOrTrim(str, code, length); } /// @@ -88,10 +85,7 @@ public static string StrFillNum(double num, int length) /// public static object StrTrim(string str, bool removeQuote = true) { - if (removeQuote) - str = str.Split("(")[0].Split(":")[0].Split("(")[0].Split(":")[0]; - return str.Trim('.', '。', '!', ' ', '!', '?', '?', '\r', - '\n'); + return TextUtils.TrimDisplayName(str, removeQuote); } /// @@ -157,12 +151,7 @@ public static bool IsASCII(this string input) /// public static string BeforeFirst(this string str, string text, bool ignoreCase = false) { - var pos = string.IsNullOrEmpty(text) - ? -1 - : str.IndexOfF(text, ignoreCase); - return pos >= 0 - ? str[..pos] - : str; + return StringSliceExtensions.BeforeFirst(str, text, ignoreCase); } /// @@ -171,8 +160,7 @@ public static string BeforeFirst(this string str, string text, bool ignoreCase = /// public static string BeforeLast(this string str, string text, bool ignoreCase = false) { - var pos = string.IsNullOrEmpty(text) ? -1 : str.LastIndexOfF(text, ignoreCase); - return pos >= 0 ? str[..pos] : str; + return StringSliceExtensions.BeforeLast(str, text, ignoreCase); } /// @@ -181,8 +169,7 @@ public static string BeforeLast(this string str, string text, bool ignoreCase = /// public static string AfterFirst(this string str, string text, bool ignoreCase = false) { - var pos = string.IsNullOrEmpty(text) ? -1 : str.IndexOfF(text, ignoreCase); - return pos >= 0 ? str[(pos + text.Length)..] : str; + return StringSliceExtensions.AfterFirst(str, text, ignoreCase); } /// @@ -191,8 +178,7 @@ public static string AfterFirst(this string str, string text, bool ignoreCase = /// public static string AfterLast(this string str, string text, bool ignoreCase = false) { - var pos = string.IsNullOrEmpty(text) ? -1 : str.LastIndexOfF(text, ignoreCase); - return pos >= 0 ? str[(pos + text.Length)..] : str; + return StringSliceExtensions.AfterLast(str, text, ignoreCase); } /// @@ -202,15 +188,7 @@ public static string AfterLast(this string str, string text, bool ignoreCase = f /// public static string Between(this string str, string after, string before, bool ignoreCase = false) { - var startPos = string.IsNullOrEmpty(after) ? -1 : str.LastIndexOfF(after, ignoreCase); - if (startPos >= 0) - startPos += after.Length; - else - startPos = 0; - var endPos = string.IsNullOrEmpty(before) ? -1 : str.IndexOfF(before, startPos, ignoreCase); - if (endPos >= 0) return str.Substring(startPos, endPos - startPos); - - return startPos > 0 ? str[startPos..] : str; + return StringSliceExtensions.Between(str, after, before, ignoreCase); } /// @@ -302,8 +280,7 @@ public static string EscapeXml(string str) { if (str.StartsWithF("{")) str = "{}" + str; // #4187 - return str.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("'", "'") - .Replace("\"", """).Replace("\r\n", " "); + return TextUtils.EscapeXml(str); } /// @@ -311,28 +288,7 @@ public static string EscapeXml(string str) /// public static string EscapeLikePattern(string input) { - var sb = new StringBuilder(); - foreach (var c in input) - switch (c) - { - case '[': - case ']': - case '*': - case '?': - case '#': - { - sb.Append('[').Append(c).Append(']'); - break; - } - - default: - { - sb.Append(c); - break; - } - } - - return sb.ToString(); + return TextUtils.EscapeLikePattern(input); } // 正则 @@ -341,23 +297,15 @@ public static string EscapeLikePattern(string input) /// public static List RegexSearch(this string str, string regex, RegexOptions options = RegexOptions.None) { - List regexSearchRet; try { - regexSearchRet = []; - var regexSearchRes = new Regex(regex, options).Matches(str); - if (regexSearchRes is null) - return regexSearchRet; - foreach (Match item in regexSearchRes) - regexSearchRet.Add(item.Value); + return RegexExtensions.RegexSearch(str, regex, options); } catch (Exception ex) { Log(ex, "正则匹配全部项出错"); return []; } - - return regexSearchRet; } /// @@ -370,9 +318,7 @@ public static List RegexSearch(this string str, Regex regex) { try { - var result = new List(); - foreach (Match item in regex.Matches(str)) result.Add(item.Value); - return result; + return regex.Matches(str).Select(item => item.Value).ToList(); } catch (Exception ex) { @@ -388,8 +334,7 @@ public static string RegexSeek(this string str, string regex, RegexOptions optio { try { - var result = Regex.Match(str, regex, options).Value; - return string.IsNullOrEmpty(result) ? null : result; + return RegexExtensions.RegexSeek(str, regex, options); } catch (Exception ex) { @@ -405,8 +350,7 @@ public static string RegexSeek(this string str, Regex regex, RegexOptions option { try { - var result = regex.Match(str, (int)options).Value; - return string.IsNullOrEmpty(result) ? null : result; + return RegexExtensions.RegexSeek(str, regex); } catch (Exception ex) { @@ -422,7 +366,7 @@ public static bool RegexCheck(this string str, string regex, RegexOptions option { try { - return Regex.IsMatch(str, regex, options); + return RegexExtensions.RegexCheck(str, regex, options); } catch (Exception ex) { @@ -437,7 +381,7 @@ public static bool RegexCheck(this string str, string regex, RegexOptions option public static string RegexReplace(this string allContents, string searchRegex, string replaceTo, RegexOptions options = RegexOptions.None) { - return Regex.Replace(allContents, searchRegex, replaceTo, options); + return RegexExtensions.RegexReplace(allContents, searchRegex, replaceTo, options); } /// @@ -446,7 +390,7 @@ public static string RegexReplace(this string allContents, string searchRegex, s public static string RegexReplaceEach(this string allContents, string searchRegex, MatchEvaluator replaceTo, RegexOptions options = RegexOptions.None) { - return Regex.Replace(allContents, searchRegex, replaceTo, options); + return RegexExtensions.RegexReplaceEach(allContents, searchRegex, replaceTo, options); } #endregion diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs index 720c51667..ccea566b8 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs @@ -3,6 +3,7 @@ using System.Windows; using PCL.Core.App.Localization; using PCL.Core.Logging; +using PCL.Core.Utils.OS; namespace PCL; @@ -40,14 +41,15 @@ public static ModBase.ProcessReturnValues ShellAndGetExitCode( { try { - using var program = new Process(); - program.StartInfo.Arguments = arguments; - program.StartInfo.FileName = fileName; LauncherLog.Log($"[System] 执行外部命令并等待返回码:{fileName} {arguments}"); - program.Start(); - if (program.WaitForExit(timeout)) return (ModBase.ProcessReturnValues)program.ExitCode; - - return ModBase.ProcessReturnValues.Timeout; + var result = ProcessRunner + .CaptureAsync(fileName, arguments, timeout) + .GetAwaiter() + .GetResult(); + if (result.TimedOut) return ModBase.ProcessReturnValues.Timeout; + return result.ExitCode.HasValue + ? (ModBase.ProcessReturnValues)result.ExitCode.Value + : ModBase.ProcessReturnValues.Fail; } catch (Exception ex) { @@ -62,31 +64,12 @@ public static string ShellAndGetOutput( int timeout = 1000000, string? workingDirectory = null) { - var info = new ProcessStartInfo - { - FileName = fileName, - Arguments = arguments, - UseShellExecute = false, - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardError = true - }; - - if (!string.IsNullOrEmpty(workingDirectory)) info.WorkingDirectory = workingDirectory.TrimEnd('\\'); - LauncherLog.Log($"[System] 执行外部命令并等待返回结果:{fileName} {arguments}"); - - using var program = new Process(); - program.StartInfo = info; - program.Start(); - - var outputTask = program.StandardOutput.ReadToEndAsync(); - var errorTask = program.StandardError.ReadToEndAsync(); - - if (!program.WaitForExit(timeout)) program.Kill(); - Task.WaitAll(outputTask, errorTask); - - return outputTask.Result + errorTask.Result; + var result = ProcessRunner + .CaptureAsync(fileName, arguments, timeout, workingDirectory) + .GetAwaiter() + .GetResult(); + return result.CombinedOutput; } public static void OpenWebsite(string url) diff --git a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs index b4377b90e..72c4d9ddf 100644 --- a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs +++ b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs @@ -1,7 +1,8 @@ using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices; using System.Text; +using PCL.Core.IO; +using PCL.Core.Utils; using PCL.Core.Utils.Codecs; using PCL.Core.Utils.Hash; using CoreDirectories = PCL.Core.IO.Directories; @@ -21,56 +22,22 @@ public static string ResolvePath(string filePath) public static string GetPathFromFullPath(string filePath) { - string getPathFromFullPathRet; - if (!(filePath.Contains('\\') || filePath.Contains('/'))) - throw new Exception("不包含路径:" + filePath); - if (filePath.EndsWithF(@"\") || filePath.EndsWithF("/")) - { - var isRight = filePath.EndsWithF(@"\"); - filePath = filePath[..^1]; - getPathFromFullPathRet = filePath[..filePath.LastIndexOfAny(['\\', '/'])] + (isRight ? @"\" : "/"); - } - else - { - getPathFromFullPathRet = filePath[..(filePath.LastIndexOfAny(['\\', '/']) + 1)]; - if (string.IsNullOrEmpty(getPathFromFullPathRet)) - throw new Exception("不包含路径:" + filePath); - } - - return getPathFromFullPathRet; + return PathUtils.GetDirectoryPart(filePath); } public static string GetFileNameFromPath(string filePath) { - filePath = filePath.Replace("/", @"\"); - if (filePath.EndsWithF(@"\")) - throw new Exception("不包含文件名:" + filePath); - if (filePath.Contains('?')) - filePath = filePath[..filePath.IndexOfF("?")]; - if (filePath.Contains('\\')) - filePath = filePath[(filePath.LastIndexOfF(@"\") + 1)..]; - - var length = filePath.Length; - return length switch - { - 0 => throw new Exception("不包含文件名:" + filePath), - > 250 => throw new PathTooLongException("文件名过长:" + filePath), - _ => filePath - }; + return PathUtils.GetFileNameFromUrlOrPath(filePath); } public static string GetFileNameWithoutExtensionFromPath(string filePath) { - return Path.GetFileNameWithoutExtension(filePath); + return PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(filePath); } public static string GetFolderNameFromPath(string folderPath) { - if (folderPath.EndsWithF(@":\") || folderPath.EndsWithF(@":\\")) - return folderPath[..1]; - if (folderPath.EndsWithF(@"\") || folderPath.EndsWithF("/")) - folderPath = folderPath[..^1]; - return GetFileNameFromPath(folderPath); + return PathUtils.GetDirectoryNameLeaf(folderPath); } public static void CopyFile(string fromPath, string toPath) @@ -115,7 +82,7 @@ public static string DecodeBytes(byte[] bytes) public static object GetHexString(Memory bytes) { - return Convert.ToHexString(bytes.Span).ToLowerInvariant(); + return BinaryEncoding.ToHexLower(bytes.Span); } public static string GetFileMd5(string filePath) @@ -235,28 +202,12 @@ public static IEnumerable EnumerateFiles(string directory) public static string ShortenPath(string longPath, int shortenThreshold = 247) { - if (longPath.Length <= shortenThreshold) - return longPath; - var shortPath = new StringBuilder(260); - GetShortPathName(longPath, shortPath, 260); - return shortPath.ToString(); + return PathUtils.ShortenPath(longPath, shortenThreshold); } public static void MoveDirectory(string sourceDir, string targetDir) { - if (!Directory.Exists(targetDir)) - Directory.CreateDirectory(targetDir); - foreach (var filePath in Directory.GetFiles(sourceDir)) - { - var fileName = GetFileNameFromPath(filePath); - File.Move(filePath, Path.Combine(targetDir, fileName)); - } - - foreach (var dirPath in Directory.GetDirectories(sourceDir)) - { - var dirName = GetFolderNameFromPath(dirPath); - MoveDirectory(dirPath, Path.Combine(targetDir, dirName)); - } + CoreDirectories.MoveDirectoryAsync(sourceDir, targetDir).GetAwaiter().GetResult(); } public static void CreateSymbolicLink(string linkPath, string targetPath, int flags) @@ -283,7 +234,4 @@ public static void CheckPermissionWithException(string path) { CoreDirectories.CheckPermissionWithExceptionAsync(path).GetAwaiter().GetResult(); } - - [DllImport("kernel32", EntryPoint = "GetShortPathNameA", CharSet = CharSet.Unicode)] - private static extern int GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer); } \ No newline at end of file From 9fcbe7f2d27c5696133893747406328a6c8cf2d6 Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 1 Jul 2026 01:09:12 +0800 Subject: [PATCH 05/16] =?UTF-8?q?=E8=B0=83=E7=94=A8=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plain Craft Launcher 2/Application.xaml.cs | 45 +- .../GlobalCompatibilityAliases.cs | 7 + .../Compatibility/LauncherLegacyTypes.cs | 22 + .../Compatibility/ModBase.LegacyLog.cs | 6 +- .../Compatibility/ModBase.LegacySystem.cs | 4 +- .../Controls/AnimatedBackgroundGrid.cs | 6 +- Plain Craft Launcher 2/Controls/IMyRadio.cs | 6 +- .../Controls/MinecraftServer.xaml.cs | 4 +- .../Controls/MyButton.xaml.cs | 8 +- Plain Craft Launcher 2/Controls/MyCard.cs | 16 +- .../Controls/MyCheckBox.xaml.cs | 12 +- .../Controls/MyCollapseBar.cs | 4 +- Plain Craft Launcher 2/Controls/MyComboBox.cs | 12 +- .../Controls/MyComboBoxItem.cs | 6 +- .../Controls/MyExtraButton.xaml.cs | 18 +- .../Controls/MyExtraTextButton.xaml.cs | 10 +- .../Controls/MyHint.xaml.cs | 22 +- .../Controls/MyIconButton.xaml.cs | 56 +- .../Controls/MyIconTextButton.xaml.cs | 14 +- Plain Craft Launcher 2/Controls/MyImage.cs | 21 +- .../Controls/MyListItem.xaml.cs | 23 +- .../Controls/MyLoading.xaml.cs | 12 +- Plain Craft Launcher 2/Controls/MyMenuItem.cs | 4 +- .../Controls/MyMsg/MyMsgInput.xaml.cs | 28 +- .../Controls/MyMsg/MyMsgMarkdown.xaml.cs | 28 +- .../Controls/MyMsg/MyMsgSelect.xaml.cs | 28 +- .../Controls/MyMsg/MyMsgText.xaml.cs | 28 +- Plain Craft Launcher 2/Controls/MyPageLeft.cs | 6 +- .../Controls/MyPageRight.cs | 126 ++-- .../Controls/MyRadioBox.xaml.cs | 25 +- .../Controls/MyRadioButton.xaml.cs | 57 +- .../Controls/MyScrollBar.cs | 6 +- .../Controls/MyScrollViewer.cs | 4 +- .../Controls/MySlider.xaml.cs | 23 +- Plain Craft Launcher 2/Controls/MyTextBox.cs | 19 +- .../Controls/MyTextButton.cs | 6 +- .../Controls/MyToast.xaml.cs | 6 +- .../Controls/SvgIconControlHelper.cs | 4 +- Plain Craft Launcher 2/FormMain.xaml.cs | 261 ++++---- .../Infrastructure/LauncherExitCode.cs | 4 +- .../Infrastructure/LauncherFeedbackService.cs | 4 +- .../Infrastructure/LauncherFontService.cs | 4 +- .../Infrastructure/LauncherLog.cs | 58 +- .../Infrastructure/LauncherLogLevel.cs | 43 ++ .../Infrastructure/LauncherMath.cs | 35 + .../Infrastructure/LauncherProcess.cs | 24 +- .../Infrastructure/LauncherSearch.cs | 84 +++ .../Infrastructure/LauncherText.cs | 94 +++ .../Infrastructure/LegacyFileFacade.cs | 18 +- .../Infrastructure/LegacyIniStore.cs | 6 +- .../Modules/Base/ModAnimation.cs | 124 ++-- .../Modules/Base/ModLoader.cs | 243 ++++--- .../Modules/Base/ModSetup.cs | 32 +- .../Modules/Base/MyBitmap.cs | 8 +- .../Modules/Event/CustomEvent.cs | 42 +- .../Export/CrashReportExporter.cs | 4 +- .../Presentation/CrashDialogPresenter.cs | 6 +- .../Modules/Minecraft/McInstance.cs | 109 ++-- .../Modules/Minecraft/McInstanceInfo.cs | 30 +- .../Modules/Minecraft/McVersionComparer.cs | 7 +- .../Modules/Minecraft/ModAssets.cs | 27 +- .../Modules/Minecraft/ModComp.cs | 126 ++-- .../Modules/Minecraft/ModCompDependency.cs | 10 +- .../Modules/Minecraft/ModDownload.cs | 84 +-- .../Modules/Minecraft/ModFolder.cs | 45 +- .../Modules/Minecraft/ModInstanceList.cs | 120 ++-- .../Modules/Minecraft/ModJava.cs | 64 +- .../Modules/Minecraft/ModLaunch.cs | 421 ++++++------ .../Modules/Minecraft/ModLibrary.cs | 84 +-- .../Modules/Minecraft/ModLocalComp.cs | 200 +++--- .../Modules/Minecraft/ModModpack.cs | 266 ++++---- .../Modules/Minecraft/ModProfile.cs | 92 +-- .../Modules/Minecraft/ModSkin.cs | 30 +- .../Modules/Minecraft/ModStyle.cs | 8 +- .../Modules/Minecraft/ModWatcher.cs | 58 +- Plain Craft Launcher 2/Modules/ModLink.cs | 42 +- Plain Craft Launcher 2/Modules/ModMain.cs | 120 ++-- Plain Craft Launcher 2/Modules/ModMusic.cs | 58 +- .../Modules/ModVideoBack.cs | 28 +- .../Modules/ModWebServer.cs | 24 +- .../Network/Downloader/FileDownloader.cs | 13 +- .../Modules/Network/Facade/ModNet.cs | 20 +- .../Modules/Network/Http/RequestSigning.cs | 6 +- .../Modules/Network/Http/Requester.cs | 7 +- .../Modules/Network/Loaders/LoaderDownload.cs | 61 +- .../Network/Loaders/LoaderDownloadUnc.cs | 20 +- .../Modules/Network/Management/NetManager.cs | 8 +- .../Modules/Network/Models/DownloadFile.cs | 12 +- .../Modules/UI/HintService.cs | 12 +- .../Modules/UI/Theme/ThemeManager.cs | 22 +- .../Modules/Updates/AnnouncementService.cs | 6 +- .../Modules/Updates/UpdateManager.cs | 72 +-- .../Modules/Updates/UpdatesMinioModel.cs | 24 +- .../Updates/UpdatesMirrorChyanModel.cs | 4 +- .../Modules/Updates/UpdatesWrapperModel.cs | 28 +- .../PageDownload/Comp/MyCompItem.xaml.cs | 10 +- .../Pages/PageDownload/Comp/PageComp.xaml.cs | 28 +- .../Comp/PageDownloadCompDetail.xaml.cs | 94 +-- .../Pages/PageDownload/ModDownloadLib.cs | 608 +++++++++--------- .../PageDownloadCleanroom.xaml.cs | 6 +- .../PageDownload/PageDownloadClient.xaml.cs | 4 +- .../PageDownloadCompFavorites.xaml.cs | 72 +-- .../PageDownload/PageDownloadFabric.xaml.cs | 6 +- .../PageDownload/PageDownloadForge.xaml.cs | 6 +- .../PageDownload/PageDownloadInstall.xaml.cs | 130 ++-- .../PageDownload/PageDownloadLabyMod.xaml.cs | 6 +- .../PageDownload/PageDownloadLeft.xaml.cs | 10 +- .../PageDownloadLegacyFabric.xaml.cs | 6 +- .../PageDownloadLiteLoader.xaml.cs | 6 +- .../PageDownload/PageDownloadNeoForge.xaml.cs | 4 +- .../PageDownload/PageDownloadOptiFine.xaml.cs | 6 +- .../PageDownload/PageDownloadQuilt.xaml.cs | 6 +- .../Pages/PageInstance/MyLocalModItem.xaml.cs | 36 +- .../PageInstanceCompResource.xaml.cs | 218 +++---- .../PageInstance/PageInstanceExport.xaml.cs | 108 ++-- .../PageInstance/PageInstanceInstall.xaml.cs | 134 ++-- .../PageInstance/PageInstanceLeft.xaml.cs | 10 +- .../PageInstance/PageInstanceOverall.xaml.cs | 110 ++-- .../PageInstance/PageInstanceSaves.xaml.cs | 70 +- .../PageInstanceSavesDatapack.xaml.cs | 172 ++--- .../PageInstanceSavesInfo.xaml.cs | 32 +- .../PageInstanceSavesLeft.xaml.cs | 12 +- .../PageInstanceScreenshot.xaml.cs | 24 +- .../PageInstance/PageInstanceServer.xaml.cs | 44 +- .../PageInstance/PageInstanceSetup.xaml.cs | 26 +- .../Pages/PageInstance/ServerCard.xaml.cs | 8 +- .../Pages/PageLaunch/MyMsgLogin.xaml.cs | 40 +- .../Pages/PageLaunch/MySkin.xaml.cs | 98 +-- .../Pages/PageLaunch/PageLaunchLeft.xaml.cs | 192 +++--- .../Pages/PageLaunch/PageLaunchRight.xaml.cs | 92 +-- .../Pages/PageLaunch/PageLoginAuth.xaml.cs | 22 +- .../Pages/PageLaunch/PageLoginMs.xaml.cs | 24 +- .../Pages/PageLaunch/PageLoginOffline.xaml.cs | 8 +- .../Pages/PageLaunch/PageLoginProfile.xaml.cs | 28 +- .../PageLaunch/PageLoginProfileSkin.xaml.cs | 20 +- .../Pages/PageLogLeft.xaml.cs | 16 +- .../Pages/PageLogRight.xaml.cs | 24 +- .../Pages/PageSelectLeft.xaml.cs | 76 +-- .../Pages/PageSelectRight.xaml.cs | 22 +- .../Pages/PageSetup/PageSetupAbout.xaml.cs | 10 +- .../Pages/PageSetup/PageSetupFeedback.xaml.cs | 6 +- .../Pages/PageSetup/PageSetupGameLink.xaml.cs | 18 +- .../PageSetup/PageSetupGameManage.xaml.cs | 8 +- .../Pages/PageSetup/PageSetupJava.xaml.cs | 8 +- .../Pages/PageSetup/PageSetupLaunch.xaml.cs | 18 +- .../PageSetupLauncherLanguage.xaml.cs | 6 +- .../PageSetup/PageSetupLauncherMisc.xaml.cs | 12 +- .../Pages/PageSetup/PageSetupLeft.xaml.cs | 20 +- .../Pages/PageSetup/PageSetupLog.xaml.cs | 4 +- .../Pages/PageSetup/PageSetupUI.xaml.cs | 124 ++-- .../Pages/PageSetup/PageSetupUpdate.xaml.cs | 38 +- .../Pages/PageSpeedLeft.xaml.cs | 96 +-- .../Pages/PageTools/PageToolsGameLink.xaml.cs | 100 +-- .../Pages/PageTools/PageToolsLeft.xaml.cs | 10 +- .../Pages/PageTools/PageToolsTest.xaml.cs | 86 +-- 155 files changed, 3883 insertions(+), 3549 deletions(-) create mode 100644 Plain Craft Launcher 2/Compatibility/GlobalCompatibilityAliases.cs create mode 100644 Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherLogLevel.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherMath.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherSearch.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherText.cs diff --git a/Plain Craft Launcher 2/Application.xaml.cs b/Plain Craft Launcher 2/Application.xaml.cs index 2cc16f4e0..79fe77480 100644 --- a/Plain Craft Launcher 2/Application.xaml.cs +++ b/Plain Craft Launcher 2/Application.xaml.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -49,19 +49,19 @@ private static void _ApplicationStartup() try { ModMain.SetGPUPreference(args[1].Trim('"')); - Environment.Exit((int)ModBase.ProcessReturnValues.TaskDone); + Environment.Exit((int)LauncherExitCode.TaskDone); } catch (Exception) { - Environment.Exit((int)ModBase.ProcessReturnValues.Fail); + Environment.Exit((int)LauncherExitCode.Fail); } // 初始化文件结构 - Directory.CreateDirectory(ModBase.exePath + @"PCL\Pictures"); - Directory.CreateDirectory(ModBase.exePath + @"PCL\Musics"); - Directory.CreateDirectory(Path.Combine(ModBase.pathTemp, "Cache")); - Directory.CreateDirectory(Path.Combine(ModBase.pathTemp, "Download")); - Directory.CreateDirectory(ModBase.pathAppdata); + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures"); + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics"); + Directory.CreateDirectory(Path.Combine(LauncherPaths.TempWithSlash, "Cache")); + Directory.CreateDirectory(Path.Combine(LauncherPaths.TempWithSlash, "Download")); + Directory.CreateDirectory(LauncherPaths.LegacyAppDataWithSlash); // 设置 ToolTipService 默认值 ToolTipService.InitialShowDelayProperty.OverrideMetadata(typeof(DependencyObject), @@ -95,21 +95,22 @@ private static void _ApplicationStartup() _ = Config.Preference.Font; var updateBranchCfg = Config.Update.UpdateChannelConfig; if (updateBranchCfg.IsDefault()) - updateBranchCfg.SetValue(ModBase.VersionBaseName.Contains("beta") + updateBranchCfg.SetValue(LauncherEnvironment.VersionBaseName.Contains("beta") ? Core.App.UpdateChannel.Beta : Core.App.UpdateChannel.Release); // 删除旧日志 for (var i = 1; i <= 5; i++) { - var oldLogFile = $@"{ModBase.exePath}PCL\Log-CE{i}.log"; + var oldLogFile = $@"{LauncherPaths.ExecutableDirectoryWithSlash}PCL\Log-CE{i}.log"; if (File.Exists(oldLogFile)) File.Delete(oldLogFile); } // 计时 - ModBase.Log("[Start] 第一阶段加载用时:" + (TimeUtils.GetTimeTick() - ModBase.applicationStartTick) + " ms"); - ModBase.applicationStartTick = TimeUtils.GetTimeTick(); + LauncherLog.Log("[Start] 第一阶段加载用时:" + (TimeUtils.GetTimeTick() - LauncherRuntime.ApplicationStartTick) + + " ms"); + LauncherRuntime.ApplicationStartTick = TimeUtils.GetTimeTick(); ModAnimation.AniControlEnabled += 1; } catch (Exception ex) @@ -124,7 +125,7 @@ private static void _ApplicationStartup() Lang.Text("SystemDialog.Startup.InitializationTitle"), MessageBoxButton.OK, MessageBoxImage.Error); - FormMain.EndProgramForce(ModBase.ProcessReturnValues.Exception); + FormMain.EndProgramForce(LauncherExitCode.Exception); } } @@ -137,10 +138,12 @@ private static void _ShowEnvironmentWarning() problemList.Add(Lang.Text("Application.EnvironmentWarning.WindowsVersion")); if (SystemInfo.Is32BitSystem) problemList.Add(Lang.Text("Application.EnvironmentWarning.System32Bit")); - if (ModBase.exePath.Contains(Path.GetTempPath()) || ModBase.exePath.Contains(@"AppData\Local\Temp\")) + if (LauncherPaths.ExecutableDirectoryWithSlash.Contains(Path.GetTempPath()) || + LauncherPaths.ExecutableDirectoryWithSlash.Contains(@"AppData\Local\Temp\")) problemList.Add(Lang.Text("Application.EnvironmentWarning.TempFolder")); - if (ModBase.exePath.ContainsF("wechat_files", true) || ModBase.exePath.ContainsF("WeChat Files", true) || - ModBase.exePath.ContainsF("Tencent Files", true)) + if (LauncherPaths.ExecutableDirectoryWithSlash.ContainsF("wechat_files", true) || + LauncherPaths.ExecutableDirectoryWithSlash.ContainsF("WeChat Files", true) || + LauncherPaths.ExecutableDirectoryWithSlash.ContainsF("Tencent Files", true)) problemList.Add(Lang.Text("Application.EnvironmentWarning.SocialSoftwareFolder")); if (problemList.Count == 0) return; @@ -165,9 +168,9 @@ private void Application_DispatcherUnhandledException(object sender, DispatcherU try { e.Handled = true; - if (ModBase.isProgramEnded) return; + if (LauncherRuntime.IsProgramEnded) return; - ModBase.FeedbackInfo(); + LauncherFeedbackService.FeedbackInfo(); var detail = e.Exception.ToString(); @@ -176,7 +179,7 @@ private void Application_DispatcherUnhandledException(object sender, DispatcherU detail.Contains("MS.Internal.AppModel.ITaskbarList.HrInit") || detail.Contains("未能加载文件或程序集")) { - ModBase.OpenWebsite("https://get.dot.net/8"); + LauncherProcess.OpenWebsite("https://get.dot.net/8"); LogWrapper.Error( e.Exception, Lang.Text("SystemDialog.Startup.DotNetRuntimeOutdated.Message")); @@ -217,12 +220,12 @@ public class BindingErrorTraceListener : TraceListener { public override void Write(string message) { - ModBase.Log($"警告,检测到 Binding 失败:{message}"); + LauncherLog.Log($"警告,检测到 Binding 失败:{message}"); } public override void WriteLine(string message) { - ModBase.Log($"警告,检测到 Binding 失败:{message}"); + LauncherLog.Log($"警告,检测到 Binding 失败:{message}"); } } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/GlobalCompatibilityAliases.cs b/Plain Craft Launcher 2/Compatibility/GlobalCompatibilityAliases.cs new file mode 100644 index 000000000..ac9c660eb --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/GlobalCompatibilityAliases.cs @@ -0,0 +1,7 @@ +global using LoadState = PCL.ModBase.LoadState; +global using MyColor = PCL.ModBase.MyColor; +global using MyRect = PCL.ModBase.MyRect; +global using RouteEventArgs = PCL.ModBase.RouteEventArgs; +global using CancelledException = PCL.ModBase.CancelledException; +global using RestartException = PCL.ModBase.RestartException; +global using FileChecker = PCL.ModBase.FileChecker; \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs b/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs new file mode 100644 index 000000000..04988d0dd --- /dev/null +++ b/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs @@ -0,0 +1,22 @@ +namespace PCL; + +/// +/// 顶层兼容集合类型,用于逐步移除调用点中的 ModBase 前缀。 +/// +public class SafeList : ModBase.SafeList +{ + public SafeList() + { + } + + public SafeList(IEnumerable data) : base(data) + { + } +} + +/// +/// 顶层兼容集合类型,用于逐步移除调用点中的 ModBase 前缀。 +/// +public class EqualableList : ModBase.EqualableList +{ +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs index eda3d7c3c..65ec693bb 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs @@ -1,4 +1,4 @@ -using PCL.Core.Utils; +using PCL.Core.Utils; namespace PCL; @@ -59,7 +59,7 @@ public enum LogLevel public static void Log(string text, LogLevel level = LogLevel.Normal, string? title = null, string? userSummary = null) { - LauncherLog.Log(text, level, title, userSummary); + LauncherLog.Log(text, (LauncherLogLevel)level, title, userSummary); } /// @@ -70,7 +70,7 @@ public static void Log(string text, LogLevel level = LogLevel.Normal, string? ti public static void Log(Exception ex, string desc, LogLevel level = LogLevel.Debug, string? title = null, string? userSummary = null) { - LauncherLog.Log(ex, desc, level, title, userSummary); + LauncherLog.Log(ex, desc, (LauncherLogLevel)level, title, userSummary); } public static string Base64Decode(string text) diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs index 9d15e15aa..0d7cf7365 100644 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs +++ b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.IO; using PCL.Core.App; using PCL.Core.Utils; @@ -237,7 +237,7 @@ public static void ShellOnly(string fileName, string arguments = "") /// public static ProcessReturnValues ShellAndGetExitCode(string fileName, string arguments = "", int timeout = 1000000) { - return LauncherProcess.ShellAndGetExitCode(fileName, arguments, timeout); + return (ProcessReturnValues)LauncherProcess.ShellAndGetExitCode(fileName, arguments, timeout); } /// diff --git a/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs b/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs index 47daf6ffb..a0a9f2bd0 100644 --- a/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs +++ b/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -12,7 +12,7 @@ public class AnimatedBackgroundGrid : Grid private readonly DependencyProperty _animatableBrushProperty; - public readonly int uuid = ModBase.GetUuid(); + public readonly int uuid = LauncherRuntime.GetUuid(); public AnimatedBackgroundGrid(DependencyProperty brushDp) { @@ -61,7 +61,7 @@ private static void _BackgroundBrushChanged(DependencyObject d, DependencyProper new[] { ModAnimation.AaColor(grid.AnimatableElement, grid._animatableBrushProperty, - new ModBase.MyColor(brush) - grid.AnimatableBrush, 300) + new MyColor(brush) - grid.AnimatableBrush, 300) }, "MyCard Theme " + grid.uuid); await Task.Delay(300); grid.AnimatableBrush = brush; diff --git a/Plain Craft Launcher 2/Controls/IMyRadio.cs b/Plain Craft Launcher 2/Controls/IMyRadio.cs index 063906dfe..863816396 100644 --- a/Plain Craft Launcher 2/Controls/IMyRadio.cs +++ b/Plain Craft Launcher 2/Controls/IMyRadio.cs @@ -1,10 +1,10 @@ -namespace PCL; +namespace PCL; public interface IMyRadio { - delegate void ChangedEventHandler(object sender, ModBase.RouteEventArgs e); + delegate void ChangedEventHandler(object sender, RouteEventArgs e); - delegate void CheckEventHandler(object sender, ModBase.RouteEventArgs e); + delegate void CheckEventHandler(object sender, RouteEventArgs e); event CheckEventHandler Check; event ChangedEventHandler Changed; diff --git a/Plain Craft Launcher 2/Controls/MinecraftServer.xaml.cs b/Plain Craft Launcher 2/Controls/MinecraftServer.xaml.cs index d9482e791..9e4d7818f 100644 --- a/Plain Craft Launcher 2/Controls/MinecraftServer.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MinecraftServer.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Media; @@ -68,7 +68,7 @@ public async Task UpdateServerInfoAsync(string address) } catch (Exception ex) { - ModBase.Log(ex, "[MinecraftServer] 信息查询失败"); + LauncherLog.Log(ex, "[MinecraftServer] 信息查询失败"); LabServerDesc.Text = Lang.Text("Tools.ServerQuery.Error.UnableToConnect", ex.Message); LabServerDesc.Foreground = Brushes.Red; ImageLoaderHelper.SetFallbackImage(ImgServerLogo, fallbackImageUri); diff --git a/Plain Craft Launcher 2/Controls/MyButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyButton.xaml.cs index 366272be7..3fcce2f52 100644 --- a/Plain Craft Launcher 2/Controls/MyButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyButton.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Markup; @@ -41,7 +41,7 @@ public enum ColorState // 自定义属性 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyButton() { @@ -145,7 +145,7 @@ private void RefreshColor(object obj = null, object e = null) } catch (Exception ex) { - ModBase.Log(ex, "刷新按钮颜色出错"); + LauncherLog.Log(ex, "刷新按钮颜色出错"); } } @@ -155,7 +155,7 @@ private void Button_MouseUp(object sender, MouseButtonEventArgs e) { if (!isMouseDown) return; - ModBase.Log("[Control] 按下按钮:" + Text); + LauncherLog.Log("[Control] 按下按钮:" + Text); Click?.Invoke(sender, e); ModMain.RaiseCustomEvent(this); } diff --git a/Plain Craft Launcher 2/Controls/MyCard.cs b/Plain Craft Launcher 2/Controls/MyCard.cs index d3de81a5c..392fa7a3c 100644 --- a/Plain Craft Launcher 2/Controls/MyCard.cs +++ b/Plain Craft Launcher 2/Controls/MyCard.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; @@ -30,7 +30,7 @@ public MyCard() : base(BlurBorder.BackgroundProperty) { MainChrome = new MyDropShadow { - Margin = new Thickness(-3, -3, -3, -3 - ModBase.GetWPFSize(1d)), ShadowRadius = 3d, + Margin = new Thickness(-3, -3, -3, -3 - DpiUtils.GetWpfSize(1d)), ShadowRadius = 3d, Opacity = dropShadowIdleOpacity, CornerRadius = new CornerRadius(5d) }; MainChrome.SetResourceReference(MyDropShadow.ColorProperty, "ColorObject1"); @@ -159,7 +159,7 @@ private void Init() Height = SwapedHeight; ModAnimation.AniStop("MyCard Height " + uuid); isHeightAnimating = false; - ModBase.RunInUi(() => UseAnimation = rawUseAnimation, true); + UiThread.Post(() => UseAnimation = rawUseAnimation, true); } } @@ -181,7 +181,7 @@ public static void StackInstall(ref StackPanel stack, Action install } catch (Exception ex) { - ModBase.Log(ex, "[MyCard] InstallMethod 调用失败"); + LauncherLog.Log(ex, "[MyCard] InstallMethod 调用失败"); } stack.Children.Add(new FrameworkElement { Height = 18d }); // 下边距,同时适应折叠 @@ -396,11 +396,11 @@ public bool IsSwaped private bool isCustomMouseDown = false; //用于触发自定义事件的 MouseDown public event PreviewSwapEventHandler? PreviewSwap; - public delegate void PreviewSwapEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void PreviewSwapEventHandler(object sender, RouteEventArgs e); public event SwapEventHandler? Swap; - public delegate void SwapEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void SwapEventHandler(object sender, RouteEventArgs e); public const int SwapedHeight = 40; @@ -428,7 +428,7 @@ private void MyCard_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) if (!IsSwapped && (SwapControl is null || pos > (IsSwapped ? SwapedHeight : SwapedHeight - 6) || (pos == 0 && !IsMouseDirectlyOver))) return; // 检测点击位置;或已经不在可视树上的误判 - var e2 = new ModBase.RouteEventArgs(true); + var e2 = new RouteEventArgs(true); PreviewSwap?.Invoke(this, e2); if (e2.handled) { @@ -437,7 +437,7 @@ private void MyCard_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) } IsSwapped = !IsSwapped; - ModBase.Log("[Control] " + (IsSwapped ? "折叠卡片" : "展开卡片") + (Title is null ? "" : ":" + Title)); + LauncherLog.Log("[Control] " + (IsSwapped ? "折叠卡片" : "展开卡片") + (Title is null ? "" : ":" + Title)); Swap?.Invoke(this, e2); } diff --git a/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.cs b/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.cs index 1fc7f4aca..55d87301b 100644 --- a/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Markup; @@ -11,7 +11,7 @@ public partial class MyCheckBox { public delegate void ChangeEventHandler(object sender, bool user); - public delegate void PreviewChangeEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void PreviewChangeEventHandler(object sender, RouteEventArgs e); private const int animationTimeOfCheck = 150; // 勾选状态变更动画长度 @@ -50,7 +50,7 @@ public partial class MyCheckBox // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyCheckBox() { @@ -108,7 +108,7 @@ public void SetChecked(bool? value, bool user) // Preview 事件 if (value.HasValue && value.Value && user) { - var e = new ModBase.RouteEventArgs(user); + var e = new RouteEventArgs(user); PreviewChange?.Invoke(this, e); if (e.handled) { @@ -133,7 +133,7 @@ public void SetChecked(bool? value, bool user) } catch (Exception ex) { - ModBase.Log(ex, "设置 Checked 失败"); + LauncherLog.Log(ex, "设置 Checked 失败"); } } @@ -224,7 +224,7 @@ private void Checkbox_MouseUp() { if (!mouseDowned) return; - ModBase.Log("[Control] 按下复选框(" + !Checked + "):" + Text); + LauncherLog.Log("[Control] 按下复选框(" + !Checked + "):" + Text); mouseDowned = false; if (IsThreeState) { diff --git a/Plain Craft Launcher 2/Controls/MyCollapseBar.cs b/Plain Craft Launcher 2/Controls/MyCollapseBar.cs index 440bee225..7b1e77a8d 100644 --- a/Plain Craft Launcher 2/Controls/MyCollapseBar.cs +++ b/Plain Craft Launcher 2/Controls/MyCollapseBar.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; @@ -18,7 +18,7 @@ public class MyCollapseBar : StackPanel private const double HeaderHeight = 30d; - private readonly int _uuid = ModBase.GetUuid(); + private readonly int _uuid = LauncherRuntime.GetUuid(); private readonly TextBlock _titleBlock; private readonly Path _triangle; private readonly StackPanel _contentPanel; diff --git a/Plain Craft Launcher 2/Controls/MyComboBox.cs b/Plain Craft Launcher 2/Controls/MyComboBox.cs index 0f37cd2a8..dbf318b8e 100644 --- a/Plain Craft Launcher 2/Controls/MyComboBox.cs +++ b/Plain Craft Launcher 2/Controls/MyComboBox.cs @@ -2,8 +2,8 @@ using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; - using PCL.Core.App.Localization; + namespace PCL; public class MyComboBox : ComboBox @@ -29,7 +29,7 @@ public class MyComboBox : ComboBox private MyTextBox textBox; // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyComboBox() { @@ -108,10 +108,10 @@ public override void OnApplyTemplate() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "初始化可编辑文本框失败(" + (Name ?? "") + ")", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Application.Control.Error.OperationFailed")); } } @@ -196,10 +196,10 @@ private void MyComboBox_DropDownOpened(object sender, EventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "设置下拉框属性失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Application.Control.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Controls/MyComboBoxItem.cs b/Plain Craft Launcher 2/Controls/MyComboBoxItem.cs index e42524a15..b86a44d34 100644 --- a/Plain Craft Launcher 2/Controls/MyComboBoxItem.cs +++ b/Plain Craft Launcher 2/Controls/MyComboBoxItem.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -15,7 +15,7 @@ public class MyComboBoxItem : ComboBoxItem // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyComboBoxItem() { @@ -95,6 +95,6 @@ public static implicit operator string(MyComboBoxItem value) private void MyComboBoxItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { - ModBase.Log("[Control] 选择下拉列表项:" + ToString()); + LauncherLog.Log($"[Control] 选择下拉列表项:{ToString()}"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.cs index 98e3fd7b2..abdd718e5 100644 --- a/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; @@ -24,7 +24,7 @@ public partial class MyExtraButton public ShowCheckDelegate showCheck = null; // 自定义属性 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyExtraButton() { @@ -105,7 +105,7 @@ public bool Show if (field == value) return; field = value; - ModBase.RunInUi(() => + UiThread.Post(() => { if (value) { @@ -184,8 +184,7 @@ private void Button_LeftMouseUp(object sender, MouseButtonEventArgs e) { if (isLeftMouseHeld) { - ModBase.Log("[Control] 按下附加按钮" + - (ToolTip is null or "" ? "" : ":" + ToolTip)); + LauncherLog.Log($"[Control] 按下附加按钮{(ToolTip is null or "" ? "" : ":" + ToolTip)}"); Click?.Invoke(sender, e); e.Handled = true; Button_LeftMouseUp(); @@ -196,8 +195,7 @@ private void Button_RightMouseUp(object sender, MouseButtonEventArgs e) { if (isRightMouseHeld) { - ModBase.Log("[Control] 右键按下附加按钮" + - (ToolTip is null or "" ? "" : ":" + ToolTip)); + LauncherLog.Log($"[Control] 右键按下附加按钮{(ToolTip is null or "" ? "" : ":" + ToolTip)}"); RightClick?.Invoke(sender, e); e.Handled = true; Button_RightMouseUp(); @@ -287,7 +285,7 @@ public void RefreshColor() } catch (Exception ex) { - ModBase.Log(ex, "刷新图标按钮颜色出错"); + LauncherLog.Log(ex, "刷新图标按钮颜色出错"); } } @@ -296,7 +294,7 @@ public void RefreshColor() /// public void Ribble() { - ModBase.RunInUi(() => + UiThread.Post(() => { var shape = new Border { @@ -312,7 +310,7 @@ public void Ribble() ease: new ModAnimation.AniEaseInoutFluent(ModAnimation.AniEasePower.Strong, 0.3d)), ModAnimation.AaOpacity(shape, -shape.Opacity, 1000), ModAnimation.AaCode(() => PanScale.Children.Remove(shape), after: true) - }, "ExtraButton Ribble " + ModBase.GetUuid()); + }, $"ExtraButton Ribble {LauncherRuntime.GetUuid()}"); }); } diff --git a/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.cs index bb40ba768..599b69f95 100644 --- a/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Markup; @@ -26,7 +26,7 @@ public partial class MyExtraTextButton private bool isLeftMouseHeld; // 自定义属性 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyExtraTextButton() { @@ -142,7 +142,7 @@ public bool Show if (field == value) return; field = value; - ModBase.RunInUi(() => + UiThread.Post(() => { if (value) { @@ -203,7 +203,7 @@ private void RefreshScaleAfterRelease() private void Button_LeftMouseUp(object sender, MouseButtonEventArgs e) { if (!isLeftMouseHeld) return; - ModBase.Log("[Control] 按下附加图标按钮:" + Text); + LauncherLog.Log($"[Control] 按下附加图标按钮:{Text}"); Click?.Invoke(sender, e); e.Handled = true; ModMain.RaiseCustomEvent(this); @@ -277,7 +277,7 @@ public void RefreshColor() } catch (Exception ex) { - ModBase.Log(ex, "刷新附加图标按钮颜色出错"); + LauncherLog.Log(ex, "刷新附加图标按钮颜色出错"); } } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/MyHint.xaml.cs b/Plain Craft Launcher 2/Controls/MyHint.xaml.cs index 72142ff78..a4e150246 100644 --- a/Plain Craft Launcher 2/Controls/MyHint.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyHint.xaml.cs @@ -1,11 +1,11 @@ -using System.Windows; +using System.Windows; +using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Markup; using PCL.Core.App; using PCL.Core.App.Configuration; using PCL.Core.UI.Theme; -using System.Windows.Controls; namespace PCL; @@ -38,7 +38,7 @@ public enum Themes // 触发点击事件 private bool isMouseDown; - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyHint() { @@ -59,7 +59,11 @@ public bool HasBorder set { if (value) - BorderThickness = new Thickness(3d, ModBase.GetWPFSize(1d), ModBase.GetWPFSize(1d), ModBase.GetWPFSize(1d)); + BorderThickness = new Thickness( + 3d, + DpiUtils.GetWpfSize(1d), + DpiUtils.GetWpfSize(1d), + DpiUtils.GetWpfSize(1d)); else BorderThickness = new Thickness(3d, 0d, 0d, 0d); } @@ -123,10 +127,10 @@ private void UpdateUI() } var s = ThemeService.CurrentTone; - Background = new ModBase.MyColor().FromHSL2(hue, 90, s.L7 * 100); - BorderBrush = new ModBase.MyColor().FromHSL2(hue, 90, s.L2 * 100); - LabText.Foreground = new ModBase.MyColor().FromHSL2(hue, 90, s.L2 * 100); - BtnClose.Foreground = new ModBase.MyColor().FromHSL2(hue, 90, s.L2 * 100); + Background = new MyColor().FromHSL2(hue, 90, s.L7 * 100); + BorderBrush = new MyColor().FromHSL2(hue, 90, s.L2 * 100); + LabText.Foreground = new MyColor().FromHSL2(hue, 90, s.L2 * 100); + BtnClose.Foreground = new MyColor().FromHSL2(hue, 90, s.L2 * 100); // 根据提示气泡对齐方向刷新边框 // 此处依赖 HasBorder 的副作用进行范围检查 @@ -152,7 +156,7 @@ private void MyHint_MouseUp(object sender, MouseButtonEventArgs e) if (!isMouseDown) return; isMouseDown = false; - ModBase.Log("[Control] 按下提示条" + (string.IsNullOrEmpty(Name) ? "" : ":" + Name)); + LauncherLog.Log("[Control] 按下提示条" + (string.IsNullOrEmpty(Name) ? "" : ":" + Name)); e.Handled = true; ModMain.RaiseCustomEvent(this); } diff --git a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs index 58bf10406..8e2d68985 100644 --- a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; @@ -28,7 +28,7 @@ public enum Themes // 自定义属性 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); protected override Size MeasureOverride(Size constraint) { @@ -117,20 +117,20 @@ public SolidColorBrush Foreground // 自定义事件 public event ClickEventHandler? Click; - private static ModBase.MyColor GetTransparentBackground() + private static MyColor GetTransparentBackground() { - return new ModBase.MyColor(0d, 255d, 255d, 255d); + return new MyColor(0d, 255d, 255d, 255d); } - private ModBase.MyColor? GetBaseFillColor() + private MyColor? GetBaseFillColor() { return Theme switch { - Themes.Red => new ModBase.MyColor(160d, 255d, 76d, 76d), + Themes.Red => new MyColor(160d, 255d, 76d, 76d), Themes.Black => ThemeManager.IsDarkMode - ? new ModBase.MyColor(160d, 255d, 255d, 255d) - : new ModBase.MyColor(160d, 0d, 0d, 0d), - Themes.Custom => new ModBase.MyColor(160d, Foreground), + ? new MyColor(160d, 255d, 255d, 255d) + : new MyColor(160d, 0d, 0d, 0d), + Themes.Custom => new MyColor(160d, Foreground), _ => null }; } @@ -149,7 +149,7 @@ private void AnimateActiveSvgIconBrush(string resourceKey, int duration) SvgIconControlHelper.AnimateSvgIconBrushTo(ShapeSvgIcon, resourceKey, duration, ColorAnimationKey); } - private void AnimateActiveSvgIconBrush(ModBase.MyColor color, int duration) + private void AnimateActiveSvgIconBrush(MyColor color, int duration) { if (IsUsingSvgIcon) SvgIconControlHelper.AnimateSvgIconBrushTo(ShapeSvgIcon, color, duration, ColorAnimationKey); @@ -188,7 +188,7 @@ private void SetActiveIconBrush(Brush brush) animations.Add(ModAnimation.AaColor( PanBack, BackgroundProperty, - new ModBase.MyColor(50d, 255d, 255d, 255d) - PanBack.Background, + new MyColor(50d, 255d, 255d, 255d) - PanBack.Background, animationColorIn)); break; } @@ -196,21 +196,21 @@ private void SetActiveIconBrush(Brush brush) { if (IsUsingSvgIcon) AnimateActiveSvgIconBrush( - new ModBase.MyColor(255d, 76d, 76d), + new MyColor(255d, 76d, 76d), animationColorIn); else animations.Add(ModAnimation.AaColor( Path, Shape.FillProperty, - new ModBase.MyColor(255d, 76d, 76d) - Path.Fill, + new MyColor(255d, 76d, 76d) - Path.Fill, animationColorIn)); break; } case Themes.Black: { var blackHoverColor = ThemeManager.IsDarkMode - ? new ModBase.MyColor(230d, 255d, 255d, 255d) - : new ModBase.MyColor(230d, 0d, 0d, 0d); + ? new MyColor(230d, 255d, 255d, 255d) + : new MyColor(230d, 0d, 0d, 0d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(blackHoverColor, animationColorIn); else @@ -223,7 +223,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.Custom: { - var customHoverColor = new ModBase.MyColor(255d, Foreground); + var customHoverColor = new MyColor(255d, Foreground); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(customHoverColor, animationColorIn); else @@ -260,7 +260,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.White: { - var whiteNormalColor = new ModBase.MyColor(234d, 242d, 254d); + var whiteNormalColor = new MyColor(234d, 242d, 254d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(whiteNormalColor, animationColorOut); else @@ -279,7 +279,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.Red: { - var redNormalColor = new ModBase.MyColor(160d, 255d, 76d, 76d); + var redNormalColor = new MyColor(160d, 255d, 76d, 76d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(redNormalColor, animationColorOut); else @@ -295,8 +295,8 @@ private void SetActiveIconBrush(Brush brush) case Themes.Black: { var blackNormalColor = ThemeManager.IsDarkMode - ? new ModBase.MyColor(160d, 255d, 255d, 255d) - : new ModBase.MyColor(160d, 0d, 0d, 0d); + ? new MyColor(160d, 255d, 255d, 255d) + : new MyColor(160d, 0d, 0d, 0d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(blackNormalColor, animationColorOut); else @@ -311,7 +311,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.Custom: { - var customNormalColor = new ModBase.MyColor(160d, Foreground); + var customNormalColor = new MyColor(160d, Foreground); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(customNormalColor, animationColorOut); else @@ -337,18 +337,18 @@ private void ApplyNonAnimatedTheme() SetActiveIconResource("ColorBrush4"); break; case Themes.White: - SetActiveIconBrush(new ModBase.MyColor(234d, 242d, 254d)); + SetActiveIconBrush(new MyColor(234d, 242d, 254d)); break; case Themes.Red: - SetActiveIconBrush(new ModBase.MyColor(160d, 255d, 76d, 76d)); + SetActiveIconBrush(new MyColor(160d, 255d, 76d, 76d)); break; case Themes.Black: SetActiveIconBrush(ThemeManager.IsDarkMode - ? new ModBase.MyColor(160d, 255d, 255d, 255d) - : new ModBase.MyColor(160d, 0d, 0d, 0d)); + ? new MyColor(160d, 255d, 255d, 255d) + : new MyColor(160d, 0d, 0d, 0d)); break; case Themes.Custom: - SetActiveIconBrush(new ModBase.MyColor(160d, Foreground)); + SetActiveIconBrush(new MyColor(160d, Foreground)); break; } @@ -359,7 +359,7 @@ private void Button_MouseUp(object sender, MouseButtonEventArgs e) { if (!isMouseDown) return; - ModBase.Log("[Control] 按下图标按钮" + (string.IsNullOrEmpty(Name) ? "" : ":" + Name)); + LauncherLog.Log("[Control] 按下图标按钮" + (string.IsNullOrEmpty(Name) ? "" : ":" + Name)); Click?.Invoke(sender, e); e.Handled = true; Button_MouseUp(); @@ -425,7 +425,7 @@ public void RefreshAnim() } catch (Exception ex) { - ModBase.Log(ex, "刷新图标按钮动画状态出错"); + LauncherLog.Log(ex, "刷新图标按钮动画状态出错"); } } } diff --git a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs index 6258c2309..f63fd202c 100644 --- a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Markup; @@ -14,7 +14,7 @@ public partial class MyIconTextButton public delegate void CheckEventHandler(object sender, bool raiseByMouse); - public delegate void ClickEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void ClickEventHandler(object sender, RouteEventArgs e); public enum ColorState { @@ -41,7 +41,7 @@ public enum ColorState // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyIconTextButton() { @@ -199,7 +199,7 @@ private void StartBackgroundAnimation(string resourceKey, int duration) ModAnimation.AniStart(ModAnimation.AaColor(this, BackgroundProperty, resourceKey, duration), ColorAnimationKey); } - private void StartBackgroundAnimation(ModBase.MyColor delta, int duration) + private void StartBackgroundAnimation(MyColor delta, int duration) { ModAnimation.AniStart(ModAnimation.AaColor(this, BackgroundProperty, delta, duration), ColorAnimationKey); } @@ -208,9 +208,9 @@ private void MyIconTextButton_MouseUp() { if (!isMouseDown) return; - ModBase.Log("[Control] 按下带图标按钮:" + Text); + LauncherLog.Log($"[Control] 按下带图标按钮:{Text}"); isMouseDown = false; - Click?.Invoke(this, new ModBase.RouteEventArgs(true)); + Click?.Invoke(this, new RouteEventArgs(true)); ModMain.RaiseCustomEvent(this); RefreshColor(); } @@ -267,7 +267,7 @@ private void RefreshColor(object? obj = null, object? e = null) } catch (Exception ex) { - ModBase.Log(ex, "刷新带图标按钮颜色出错"); + LauncherLog.Log(ex, "刷新带图标按钮颜色出错"); } } } diff --git a/Plain Craft Launcher 2/Controls/MyImage.cs b/Plain Craft Launcher 2/Controls/MyImage.cs index d439dc106..dc2b5f24f 100644 --- a/Plain Craft Launcher 2/Controls/MyImage.cs +++ b/Plain Craft Launcher 2/Controls/MyImage.cs @@ -1,12 +1,10 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.IO; -using System.Net; -using System.Net.Http; using System.Windows; using System.Windows.Controls; using System.Windows.Media; -using PCL.Core.Utils; using PCL.Core.IO.Net.Http; +using PCL.Core.Utils; namespace PCL; @@ -40,10 +38,10 @@ public string ActualSource } catch (Exception ex) { - ModBase.Log(ex, $"加载图片失败({value})"); + LauncherLog.Log(ex, $"加载图片失败({value})"); try { - if (value.StartsWithF(ModBase.pathTemp) && File.Exists(value)) File.Delete(value); + if (value.StartsWithF(LauncherPaths.TempWithSlash) && File.Exists(value)) File.Delete(value); } catch { @@ -103,7 +101,10 @@ private void Load() // 属性读取顺序修正:在完成 XAML 属性读取后 catch (Exception ex) { // 更换备用地址 - ModBase.Log(ex, $"Online image get fail(source = {url}, fallback = {FallbackSource})", ModBase.LogLevel.Developer); + LauncherLog.Log( + ex, + $"Online image get fail(source = {url}, fallback = {FallbackSource})", + LauncherLogLevel.Developer); tempPath = GetTempPath(url); tempFile = new FileInfo(tempPath); if (enableCache && tempFile.Exists) @@ -128,7 +129,7 @@ public static Task DownloadImageAsync(string url) public static string GetTempPath(string url) { - return Path.Combine(ModBase.pathTemp, "Cache", "Images", $"{ModBase.GetStringMD5(url)}.png"); + return Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{LauncherText.GetStringMD5(url)}.png"); } private static readonly ConcurrentDictionary> _downloadTasks = new(); @@ -140,7 +141,7 @@ private static async Task DownloadImageInternalAsync(string url) try { - Directory.CreateDirectory(ModBase.GetPathFromFullPath(tempPath)); // 重新实现下载,以避免携带 Header(#5072) + Directory.CreateDirectory(LegacyFileFacade.GetPathFromFullPath(tempPath)); // 重新实现下载,以避免携带 Header(#5072) using (var fs = new FileStream(tempDownloadingPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { using (var response = await HttpRequest.Create(url) @@ -164,7 +165,7 @@ private static async Task DownloadImageInternalAsync(string url) if (File.Exists(tempPath)) File.Delete(tempPath); if (File.Exists(tempDownloadingPath)) File.Delete(tempDownloadingPath); - ModBase.Log(ex, $"Try to get online image fail (url = {url}, dest = {tempPath})"); + LauncherLog.Log(ex, $"Try to get online image fail (url = {url}, dest = {tempPath})"); return string.Empty; } } diff --git a/Plain Craft Launcher 2/Controls/MyListItem.xaml.cs b/Plain Craft Launcher 2/Controls/MyListItem.xaml.cs index dce07b624..6c75e3315 100644 --- a/Plain Craft Launcher 2/Controls/MyListItem.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyListItem.xaml.cs @@ -1,5 +1,4 @@ -using System.Collections; -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; @@ -196,7 +195,7 @@ public Border RectBack CornerRadius = new CornerRadius(IsScaleAnimationEnabled || Height > 40d ? 6 : 0), RenderTransform = IsScaleAnimationEnabled ? new ScaleTransform(0.8d, 0.8d) : null, RenderTransformOrigin = new Point(0.5d, 0.5d), - BorderThickness = new Thickness(ModBase.GetWPFSize(1d)), + BorderThickness = new Thickness(DpiUtils.GetWpfSize(1d)), SnapsToDevicePixels = true, IsHitTestVisible = false, Opacity = 0d @@ -323,7 +322,7 @@ public TextBlock LabInfo #region 自定义属性 // Uuid - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); /// /// 是否启用缩放动画。 @@ -597,8 +596,8 @@ private void UpdateLogo(string logo) HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch }; - if (logo.Contains(ModBase.pathTemp + @"Cache\Skin\Head") || - logo.Contains(ModBase.pathTemp + @"Cache\Cape")) + if (logo.Contains(LauncherPaths.TempWithSlash + @"Cache\Skin\Head") || + logo.Contains(LauncherPaths.TempWithSlash + @"Cache\Cape")) RenderOptions.SetBitmapScalingMode(pathLogo, BitmapScalingMode.NearestNeighbor); else RenderOptions.SetBitmapScalingMode(pathLogo, BitmapScalingMode.Linear); @@ -773,7 +772,7 @@ public void SetChecked(bool value, bool user, bool anime) { // 自定义属性基础 - var ChangedEventArgs = new ModBase.RouteEventArgs(user); + var ChangedEventArgs = new RouteEventArgs(user); var rawValue = _Checked; if (Type == CheckType.RadioBox) { @@ -808,7 +807,7 @@ public void SetChecked(bool value, bool user, bool anime) if (value) { - var checkEventArgs = new ModBase.RouteEventArgs(user); + var checkEventArgs = new RouteEventArgs(user); Check?.Invoke(this, checkEventArgs); if (checkEventArgs.handled) return; @@ -967,7 +966,7 @@ public void SetChecked(bool value, bool user, bool anime) } catch (Exception ex) { - ModBase.Log(ex, "设置 Checked 失败"); + LauncherLog.Log(ex, "设置 Checked 失败"); } } @@ -1069,19 +1068,19 @@ private void Button_MouseUp(object sender, MouseButtonEventArgs e) { case CheckType.Clickable: { - ModBase.Log("[Control] 按下单击列表项:" + Title); + LauncherLog.Log($"[Control] 按下单击列表项:{Title}"); break; } case CheckType.RadioBox: { - ModBase.Log("[Control] 按下单选列表项:" + Title); + LauncherLog.Log($"[Control] 按下单选列表项:{Title}"); if (!Checked) SetChecked(true, true, true); break; } case CheckType.CheckBox: { - ModBase.Log("[Control] 按下复选列表项(" + !Checked + "):" + Title); + LauncherLog.Log($"[Control] 按下复选列表项({!Checked}):{Title}"); SetChecked(!Checked, true, true); break; } diff --git a/Plain Craft Launcher 2/Controls/MyLoading.xaml.cs b/Plain Craft Launcher 2/Controls/MyLoading.xaml.cs index c5ac4562f..64fb75c82 100644 --- a/Plain Craft Launcher 2/Controls/MyLoading.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyLoading.xaml.cs @@ -1,9 +1,9 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Input; using System.Windows.Media; -using static PCL.MyLoading; using PCL.Core.App.Localization; +using static PCL.MyLoading; namespace PCL; @@ -15,7 +15,7 @@ public partial class MyLoading public delegate void StateChangedEventHandler(object sender, MyLoadingState newState, MyLoadingState oldState); - private readonly int uuid = ModBase.GetUuid(); + private readonly int uuid = LauncherRuntime.GetUuid(); public bool AutoRun { get; set; } = true; @@ -96,7 +96,7 @@ public string TextError private void RefreshText() { - ModBase.RunInUi(() => + UiThread.Post(() => { if (InnerState == MyLoadingState.Error) { @@ -110,7 +110,7 @@ private void RefreshText() else { while (ex.InnerException is not null) ex = ex.InnerException; - LabText.Text = ModBase.StrTrim(ex.Message).ToString(); + LabText.Text = LauncherText.StrTrim(ex.Message).ToString(); if (new[] { "远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝", "操作已超时", "操作超时", "服务器超时", "连接超时" @@ -292,7 +292,7 @@ private void AniLoop() isLooping = false; AniLoop(); }, after: true) - }, "MyLoader Loop " + uuid + "/" + ModBase.GetUuid()); + }, "MyLoader Loop " + uuid + "/" + LauncherRuntime.GetUuid()); } /// diff --git a/Plain Craft Launcher 2/Controls/MyMenuItem.cs b/Plain Craft Launcher 2/Controls/MyMenuItem.cs index 28325bb79..959641c11 100644 --- a/Plain Craft Launcher 2/Controls/MyMenuItem.cs +++ b/Plain Craft Launcher 2/Controls/MyMenuItem.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; @@ -26,7 +26,7 @@ public class MyMenuItem : MenuItem // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyMenuItem() { diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs index e14d31548..155927f28 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs @@ -2,15 +2,15 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; +using PCL.Core.App.Localization; using PCL.Core.UI.Controls; -using PCL.Core.App.Localization; namespace PCL; public partial class MyMsgInput { private readonly ModMain.MyMsgBoxConverter myConverter; - private readonly int uuid = ModBase.GetUuid(); + private readonly int uuid = LauncherRuntime.GetUuid(); public MyMsgInput(ModMain.MyMsgBoxConverter converter) { @@ -28,15 +28,15 @@ public MyMsgInput(ModMain.MyMsgBoxConverter converter) TextArea.ValidateRules = converter.ValidateRules; ConfigurePrimaryButton(converter.Button1, converter.IsWarn); ConfigureSecondaryButton(converter.Button2); - ShapeLine.StrokeThickness = ModBase.GetWPFSize(1d); + ShapeLine.StrokeThickness = DpiUtils.GetWpfSize(1d); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "输入弹窗初始化失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } @@ -45,7 +45,7 @@ public MyMsgInput(ModMain.MyMsgBoxConverter converter) private void AppendUniqueNameSuffix(FrameworkElement element) { - element.Name += ModBase.GetUuid(); + element.Name += LauncherRuntime.GetUuid(); } private void ConfigurePrimaryButton(string text, bool isWarn) @@ -78,8 +78,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new ModBase.MyColor(140d, 80d, 0d, 0d) - : new ModBase.MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -92,15 +92,15 @@ private void Load(object sender, EventArgs e) new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)) }, "MyMsgBox " + uuid); // 记录日志 - ModBase.Log("[Control] 输入弹窗:" + LabTitle.Text); + LauncherLog.Log("[Control] 输入弹窗:" + LabTitle.Text); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "输入弹窗加载失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } } @@ -118,7 +118,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new ModBase.MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), @@ -164,10 +164,10 @@ private void Drag(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "拖拽移动失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs index d4d9df080..bd1032e51 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs @@ -2,15 +2,15 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; +using PCL.Core.App.Localization; using PCL.Core.UI.Controls; -using PCL.Core.App.Localization; namespace PCL; public partial class MyMsgMarkdown { private readonly ModMain.MyMsgBoxConverter myConverter; - private readonly int uuid = ModBase.GetUuid(); + private readonly int uuid = LauncherRuntime.GetUuid(); public MyMsgMarkdown(ModMain.MyMsgBoxConverter converter) { @@ -27,15 +27,15 @@ public MyMsgMarkdown(ModMain.MyMsgBoxConverter converter) ConfigurePrimaryButton(converter.Button1, converter.IsWarn); ConfigureSecondaryButton(Btn2, converter.Button2); ConfigureSecondaryButton(Btn3, converter.Button3); - ShapeLine.StrokeThickness = ModBase.GetWPFSize(1d); + ShapeLine.StrokeThickness = DpiUtils.GetWpfSize(1d); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "普通弹窗初始化失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } @@ -44,7 +44,7 @@ public MyMsgMarkdown(ModMain.MyMsgBoxConverter converter) private void AppendUniqueNameSuffix(FrameworkElement element) { - element.Name += ModBase.GetUuid(); + element.Name += LauncherRuntime.GetUuid(); } private void ConfigurePrimaryButton(string text, bool isWarn) @@ -76,8 +76,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new ModBase.MyColor(140d, 80d, 0d, 0d) - : new ModBase.MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -90,15 +90,15 @@ private void Load(object sender, EventArgs e) new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)) }, "MyMsgBox " + uuid); // 记录日志 - ModBase.Log("[Control] 普通弹窗:" + LabTitle.Text + "\r\n" + LabCaption.Markdown); + LauncherLog.Log("[Control] 普通弹窗:" + LabTitle.Text + "\r\n" + LabCaption.Markdown); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "普通弹窗加载失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } } @@ -117,7 +117,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new ModBase.MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), @@ -187,10 +187,10 @@ private void Drag(object? sender = null, MouseButtonEventArgs? e = null) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "拖拽移动失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs index c48976225..0df63d3ed 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs @@ -3,15 +3,15 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; +using PCL.Core.App.Localization; using PCL.Core.UI.Controls; -using PCL.Core.App.Localization; namespace PCL; public partial class MyMsgSelect { private readonly ModMain.MyMsgBoxConverter myConverter; - private readonly int uuid = ModBase.GetUuid(); + private readonly int uuid = LauncherRuntime.GetUuid(); private int selectedIndex = -1; @@ -26,16 +26,16 @@ public MyMsgSelect(ModMain.MyMsgBoxConverter converter) LabTitle.Text = converter.Title; ConfigurePrimaryButton(converter.Button1, converter.IsWarn); ConfigureSecondaryButton(converter.Button2); - ShapeLine.StrokeThickness = ModBase.GetWPFSize(1d); + ShapeLine.StrokeThickness = DpiUtils.GetWpfSize(1d); InitializeSelectionList(converter.Content); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "选择弹窗初始化失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } @@ -48,7 +48,7 @@ public MyMsgSelect(ModMain.MyMsgBoxConverter converter) private void AppendUniqueNameSuffix(FrameworkElement element) { - element.Name += ModBase.GetUuid(); + element.Name += LauncherRuntime.GetUuid(); } private void ConfigurePrimaryButton(string text, bool isWarn) @@ -109,8 +109,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new ModBase.MyColor(140d, 80d, 0d, 0d) - : new ModBase.MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -123,15 +123,15 @@ private void Load(object sender, EventArgs e) new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)) }, "MyMsgBox " + uuid); // 记录日志 - ModBase.Log("[Control] 选择弹窗:" + LabTitle.Text); + LauncherLog.Log("[Control] 选择弹窗:" + LabTitle.Text); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "选择弹窗加载失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } } @@ -149,7 +149,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new ModBase.MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), @@ -195,10 +195,10 @@ private void Drag(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "拖拽移动失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs index ec7891685..1c491f27e 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs @@ -2,15 +2,15 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; +using PCL.Core.App.Localization; using PCL.Core.UI.Controls; -using PCL.Core.App.Localization; namespace PCL; public partial class MyMsgText { private readonly ModMain.MyMsgBoxConverter myConverter; - private readonly int uuid = ModBase.GetUuid(); + private readonly int uuid = LauncherRuntime.GetUuid(); public MyMsgText(ModMain.MyMsgBoxConverter converter) { @@ -26,15 +26,15 @@ public MyMsgText(ModMain.MyMsgBoxConverter converter) ConfigurePrimaryButton(converter.Button1, converter.IsWarn); ConfigureSecondaryButton(Btn2, converter.Button2); ConfigureSecondaryButton(Btn3, converter.Button3); - ShapeLine.StrokeThickness = ModBase.GetWPFSize(1d); + ShapeLine.StrokeThickness = DpiUtils.GetWpfSize(1d); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "普通弹窗初始化失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } @@ -43,7 +43,7 @@ public MyMsgText(ModMain.MyMsgBoxConverter converter) private void AppendUniqueNameSuffix(FrameworkElement element) { - element.Name += ModBase.GetUuid(); + element.Name += LauncherRuntime.GetUuid(); } private void ConfigurePrimaryButton(string text, bool isWarn) @@ -75,8 +75,8 @@ private void Load(object sender, RoutedEventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new ModBase.MyColor(140d, 80d, 0d, 0d) - : new ModBase.MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -89,15 +89,15 @@ private void Load(object sender, RoutedEventArgs e) new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)) }, "MyMsgBox " + uuid); // 记录日志 - ModBase.Log("[Control] 普通弹窗:" + LabTitle.Text + "\r\n" + LabCaption.Text); + LauncherLog.Log("[Control] 普通弹窗:" + LabTitle.Text + "\r\n" + LabCaption.Text); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "普通弹窗加载失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } } @@ -116,7 +116,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new ModBase.MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), @@ -186,10 +186,10 @@ private void Drag(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "拖拽移动失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.MessageBox.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Controls/MyPageLeft.cs b/Plain Craft Launcher 2/Controls/MyPageLeft.cs index 5a3984771..6b518f5e0 100644 --- a/Plain Craft Launcher 2/Controls/MyPageLeft.cs +++ b/Plain Craft Launcher 2/Controls/MyPageLeft.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -9,7 +9,7 @@ public class MyPageLeft : Grid public static DependencyProperty AnimatedControlProperty = DependencyProperty.Register("AnimatedControl", typeof(FrameworkElement), typeof(MyPageLeft)); - private readonly int uuid = ModBase.GetUuid(); + private readonly int uuid = LauncherRuntime.GetUuid(); private bool _animatedControlNullWarned; @@ -22,7 +22,7 @@ public FrameworkElement AnimatedControl if (res is null && !_animatedControlNullWarned) { _animatedControlNullWarned = true; - ModBase.Log($"[MyPageLeft] 获取到 AnimatedControl(来自 {Name}) 的值为 null", ModBase.LogLevel.Debug); + LauncherLog.Log($"[MyPageLeft] 获取到 AnimatedControl(来自 {Name}) 的值为 null", LauncherLogLevel.Debug); } return (FrameworkElement)res; diff --git a/Plain Craft Launcher 2/Controls/MyPageRight.cs b/Plain Craft Launcher 2/Controls/MyPageRight.cs index 4807f28bf..c4d02137e 100644 --- a/Plain Craft Launcher 2/Controls/MyPageRight.cs +++ b/Plain Craft Launcher 2/Controls/MyPageRight.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; @@ -28,7 +28,7 @@ public enum PageStates private bool _panScrollNullWarned; - public int pageUuid = ModBase.GetUuid(); + public int pageUuid = LauncherRuntime.GetUuid(); // “返回顶部” 按钮检测的滚动区域 public MyScrollViewer PanScroll @@ -39,7 +39,7 @@ public MyScrollViewer PanScroll if (res is null && !_panScrollNullWarned) { _panScrollNullWarned = true; - ModBase.Log($"[MyPageRight] 获取到 PanScroll(来自 {Name}) 的值为 null", ModBase.LogLevel.Debug); + LauncherLog.Log($"[MyPageRight] 获取到 PanScroll(来自 {Name}) 的值为 null", LauncherLogLevel.Debug); } return (MyScrollViewer)res; @@ -55,14 +55,14 @@ public PageStates PageState if (field == value) return; field = value; - if (ModBase.ModeDebug) - ModBase.Log("[UI] 页面状态切换为 " + ModBase.GetStringFromEnum(value)); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log($"[UI] 页面状态切换为 {LauncherText.GetStringFromEnum(value)}"); } } = PageStates.Empty; #region 加载器 - private ModLoader.LoaderBase pageLoader; + private LoaderBase pageLoader; private Func? pageLoaderInputInvoke; private MyLoading? pageLoaderUi; private FrameworkElement panLoader; @@ -80,9 +80,15 @@ public PageStates PageState /// 无论是否在加载总是要显示的容器。可以为 Nothing。 /// 在工作线程执行的加载器。 /// 当加载器执行完成,在 UI 线程触发的 UI 初始化事件。 - public void PageLoaderInit(MyLoading loaderUi, FrameworkElement panLoader, FrameworkElement panContent, - FrameworkElement? panAlways, ModLoader.LoaderBase realLoader, Action? finishedInvoke = null, - Func? inputInvoke = null, bool autoRun = true) + public void PageLoaderInit( + MyLoading loaderUi, + FrameworkElement panLoader, + FrameworkElement panContent, + FrameworkElement? panAlways, + LoaderBase realLoader, + Action? finishedInvoke = null, + Func? inputInvoke = null, + bool autoRun = true) { // 初始化参数 this.panLoader = panLoader; @@ -98,11 +104,11 @@ public void PageLoaderInit(MyLoading loaderUi, FrameworkElement panLoader, Frame { while (PageState == PageStates.PageExit || PageState == PageStates.ContentExit) Thread.Sleep(10); // 不在退出动画时执行 UI 线程操作,避免退出动画被重置 - ModBase.RunInUiWait(() => finishedInvoke(realLoader)); + UiThread.Invoke(() => finishedInvoke(realLoader)); Thread.Sleep(20); // 由于大量初始化控件会导致掉帧,延迟触发 State 改变事件 }; realLoader.OnStateChangedUi += (loader, newState, oldState) => - ModBase.RunInUi(() => PageLoaderState(loader, newState, oldState)); + UiThread.Post(() => PageLoaderState(loader, newState, oldState)); // 隐藏 UI panLoader.Visibility = Visibility.Collapsed; panContent.Visibility = Visibility.Collapsed; @@ -110,7 +116,7 @@ public void PageLoaderInit(MyLoading loaderUi, FrameworkElement panLoader, Frame // 初次运行加载器 if (pageLoaderAutoRun) { - if (pageLoader is ModLoader.LoaderTask task) + if (pageLoader is LoaderTask task) { task.Start(task.StartGetInputNoType(null, pageLoaderInputInvoke)); } @@ -123,13 +129,13 @@ public void PageLoaderInit(MyLoading loaderUi, FrameworkElement panLoader, Frame } } - if (pageLoader.State == ModBase.LoadState.Finished && finishedInvoke is not null) - ModBase.RunInUiWait(() => finishedInvoke(realLoader)); // 加载器已提前完成,直接触发事件 + if (pageLoader.State == LoadState.Finished && finishedInvoke is not null) + UiThread.Invoke(() => finishedInvoke(realLoader)); // 加载器已提前完成,直接触发事件 // 设置加载环 pageLoaderUi.State = realLoader; pageLoaderUi.Click += (_, _) => { - if (realLoader.State == ModBase.LoadState.Failed) PageLoaderRestart(); + if (realLoader.State == LoadState.Failed) PageLoaderRestart(); }; // 点击重试事件 } @@ -161,21 +167,21 @@ public void PageLoaderRestart(object input = null, bool isForceRestart = true) / /// public void PageOnEnter() { - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageOnEnter"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageOnEnter"); PageEnter?.Invoke(); switch (PageState) { case PageStates.Empty: { - if (pageLoader is null || pageLoader.State == ModBase.LoadState.Finished || - pageLoader.State == ModBase.LoadState.Waiting || pageLoader.State == ModBase.LoadState.Aborted) + if (pageLoader is null || pageLoader.State == LoadState.Finished || + pageLoader.State == LoadState.Waiting || pageLoader.State == LoadState.Aborted) { // 如果加载器在进入页面时不启动(例如联机),那么在此时就会有 State = Waiting PageState = PageStates.ContentEnter; TriggerEnterAnimation(panAlways, (FrameworkElement)(panContent ?? Child)); } - else if (pageLoader.State == ModBase.LoadState.Loading) + else if (pageLoader.State == LoadState.Loading) { PageState = PageStates.LoaderWait; ModAnimation.AniStart(ModAnimation.AaCode(PageOnLoaderWaitFinished, 400), @@ -192,13 +198,13 @@ public void PageOnEnter() case PageStates.ContentExit: { // 和上面的一样,但是不管 PanAlways - if (pageLoader is null || pageLoader.State == ModBase.LoadState.Finished || - pageLoader.State == ModBase.LoadState.Waiting || pageLoader.State == ModBase.LoadState.Aborted) + if (pageLoader is null || pageLoader.State == LoadState.Finished || + pageLoader.State == LoadState.Waiting || pageLoader.State == LoadState.Aborted) { PageState = PageStates.ContentEnter; TriggerEnterAnimation((FrameworkElement)(panContent ?? Child)); } - else if (pageLoader.State == ModBase.LoadState.Loading) + else if (pageLoader.State == LoadState.Loading) { PageState = PageStates.LoaderWait; ModAnimation.AniStart(ModAnimation.AaCode(PageOnLoaderWaitFinished, 400), @@ -219,7 +225,7 @@ public void PageOnEnter() default: { - throw new Exception("在状态为 " + ModBase.GetStringFromEnum(PageState) + " 时触发了 PageOnEnter 事件。"); + throw new Exception($"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnEnter 事件。"); } } } @@ -234,8 +240,8 @@ public void PageOnEnter() /// public void PageOnExit() { - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageOnExit"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageOnExit"); PageExit?.Invoke(); switch (PageState) { @@ -288,8 +294,8 @@ public void PageOnForceExit() { if (PageState == PageStates.Empty) return; - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageOnForceExit"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageOnForceExit"); PageState = PageStates.Empty; ModAnimation.AniStop("PageRight PageChange " + pageUuid); // 由于动画会被强制中止,所以需要手动进行隐藏 @@ -312,9 +318,9 @@ public void PageOnForceExit() /// public void PageOnContentExit() { - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageOnContentExit"); - if (pageLoader is not null && pageLoader.State == ModBase.LoadState.Loading) + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageOnContentExit"); + if (pageLoader is not null && pageLoader.State == LoadState.Loading) throw new Exception("在调用 PageOnContentExit 时,加载器不能为 Loading 状态"); // Loading 的加载器可能触发进一步变化,难以预测会触发子页面的动画还是加载器完成的动画 switch (PageState) @@ -355,8 +361,8 @@ public void PageOnContentExit() /// private void PageOnEnterAnimationFinished() { - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageOnEnterAnimationFinished"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageOnEnterAnimationFinished"); switch (PageState) { case PageStates.ContentEnter: @@ -374,8 +380,8 @@ private void PageOnEnterAnimationFinished() default: { - throw new Exception("在状态为 " + ModBase.GetStringFromEnum(PageState) + - " 时触发了 PageOnEnterAnimationFinished 事件。"); + throw new Exception( + $"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnEnterAnimationFinished 事件。"); } } } @@ -386,8 +392,8 @@ private void PageOnEnterAnimationFinished() /// private void PageOnExitAnimationFinished() { - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageOnExitAnimationFinished"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageOnExitAnimationFinished"); switch (PageState) { case PageStates.PageExit: @@ -409,8 +415,8 @@ private void PageOnExitAnimationFinished() default: { - throw new Exception("在状态为 " + ModBase.GetStringFromEnum(PageState) + - " 时触发了 PageOnExitAnimationFinished 事件。"); + throw new Exception( + $"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnExitAnimationFinished 事件。"); } } } @@ -421,8 +427,8 @@ private void PageOnExitAnimationFinished() /// private void PageOnLoaderWaitFinished() { - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageOnLoaderWaitFinished"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageOnLoaderWaitFinished"); switch (PageState) { case PageStates.LoaderWait: @@ -438,8 +444,8 @@ private void PageOnLoaderWaitFinished() default: { - throw new Exception("在状态为 " + ModBase.GetStringFromEnum(PageState) + - " 时触发了 PageOnLoaderWaitFinished 事件。"); + throw new Exception( + $"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnLoaderWaitFinished 事件。"); } } } @@ -450,13 +456,13 @@ private void PageOnLoaderWaitFinished() /// private void PageOnLoaderStayFinished() { - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageOnLoaderStayFinished"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageOnLoaderStayFinished"); switch (PageState) { case PageStates.LoaderStayForce: { - if (pageLoader.State == ModBase.LoadState.Finished) + if (pageLoader.State == LoadState.Finished) { PageState = PageStates.LoaderExit; TriggerExitAnimation(panLoader); @@ -471,8 +477,8 @@ private void PageOnLoaderStayFinished() default: { - throw new Exception("在状态为 " + ModBase.GetStringFromEnum(PageState) + - " 时触发了 PageOnLoaderWaitFinished 事件。"); + throw new Exception( + $"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnLoaderWaitFinished 事件。"); } } } @@ -480,17 +486,17 @@ private void PageOnLoaderStayFinished() /// /// 全局加载状态已改变。 /// - private void PageLoaderState(object sender, ModBase.LoadState newState, ModBase.LoadState oldState) + private void PageLoaderState(object sender, LoadState newState, LoadState oldState) { switch (newState) { - case ModBase.LoadState.Failed: - case ModBase.LoadState.Loading: + case LoadState.Failed: + case LoadState.Loading: { - if (oldState == ModBase.LoadState.Failed || oldState == ModBase.LoadState.Loading) + if (oldState is LoadState.Failed or LoadState.Loading) return; - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageLoaderState (Start/Refresh)"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageLoaderState (Start/Refresh)"); // (重新)开始运行 // 需要从部分状态切换到 ReloadExit switch (PageState) @@ -511,14 +517,14 @@ private void PageLoaderState(object sender, ModBase.LoadState newState, ModBase. break; } - case ModBase.LoadState.Finished: - case ModBase.LoadState.Aborted: - case ModBase.LoadState.Waiting: + case LoadState.Finished: + case LoadState.Aborted: + case LoadState.Waiting: { - if (oldState != ModBase.LoadState.Failed && oldState != ModBase.LoadState.Loading) + if (oldState != LoadState.Failed && oldState != LoadState.Loading) return; - if (ModBase.ModeDebug) - ModBase.Log("[UI] 已触发 PageLoaderState (Stop/Abort)"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[UI] 已触发 PageLoaderState (Stop/Abort)"); // 运行结束 // 需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit switch (PageState) diff --git a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.cs b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.cs index ed7345be4..2a5e56f1c 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.cs @@ -1,19 +1,18 @@ -using System.Collections; -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Markup; using System.Windows.Shapes; - using PCL.Core.App.Localization; + namespace PCL; [ContentProperty("Inlines")] public partial class MyRadioBox : IMyRadio { - public delegate void PreviewChangeEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void PreviewChangeEventHandler(object sender, RouteEventArgs e); - public delegate void PreviewCheckEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void PreviewCheckEventHandler(object sender, RouteEventArgs e); // 指向动画 @@ -44,7 +43,7 @@ public partial class MyRadioBox : IMyRadio // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyRadioBox() { @@ -89,7 +88,7 @@ public void SetChecked(bool value, bool user) // Preview 事件 if (value && user) { - var e = new ModBase.RouteEventArgs(user); + var e = new RouteEventArgs(user); PreviewCheck?.Invoke(this, e); if (e.handled) { @@ -101,7 +100,7 @@ public void SetChecked(bool value, bool user) // 自定义属性基础 var isChanged = false; if (IsLoaded && value != Checked) - PreviewChange?.Invoke(this, new ModBase.RouteEventArgs(user)); + PreviewChange?.Invoke(this, new RouteEventArgs(user)); if (value != Checked) { SetValue(CheckedProperty, value); @@ -161,8 +160,8 @@ public void SetChecked(bool value, bool user) if (isChanged) { if (Checked) - Check?.Invoke(this, new ModBase.RouteEventArgs(user)); - Changed?.Invoke(this, new ModBase.RouteEventArgs(user)); + Check?.Invoke(this, new RouteEventArgs(user)); + Changed?.Invoke(this, new RouteEventArgs(user)); ModMain.RaiseCustomEvent(this); } @@ -171,10 +170,10 @@ public void SetChecked(bool value, bool user) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "单选框勾选改变错误", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.Error.OperationFailed")); } } @@ -265,7 +264,7 @@ private void Radiobox_MouseUp() { if (!mouseDowned) return; - ModBase.Log("[Control] 按下单选框:" + Text); + LauncherLog.Log("[Control] 按下单选框:" + Text); SetChecked(true, true); mouseDowned = false; ModAnimation.AniStart(ModAnimation.AaColor(ShapeBorder, Shape.FillProperty, "ColorBrushHalfWhite", 100), diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs index 794c245cd..c0f4da34d 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs @@ -1,14 +1,13 @@ -using System.Collections; -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Shapes; using PCL.Core.App; +using PCL.Core.App.Localization; using PCL.Core.UI.Theme; -using PCL.Core.App.Localization; namespace PCL; [ContentProperty("Inlines")] @@ -18,7 +17,7 @@ public partial class MyRadioButton public delegate void CheckEventHandler(MyRadioButton sender, bool raiseByMouse); - public delegate void PreviewClickEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void PreviewClickEventHandler(object sender, RouteEventArgs e); public enum ColorState { @@ -44,7 +43,7 @@ public enum ColorState // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyRadioButton() { @@ -274,10 +273,10 @@ public void SetChecked(bool value, bool raiseByMouse, bool anime) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "单选按钮勾选改变错误", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.Error.OperationFailed")); } } @@ -292,9 +291,9 @@ private void Radiobox_MouseUp() return; if (!isMouseDown) return; - ModBase.Log("[Control] 按下单选按钮:" + Text); + LauncherLog.Log($"[Control] 按下单选按钮:{Text}"); isMouseDown = false; - var e = new ModBase.RouteEventArgs(true); + var e = new RouteEventArgs(true); PreviewClick?.Invoke(this, e); if (e.handled) return; @@ -328,7 +327,7 @@ private void RefreshColor(object obj = null, object e = null) if (Checked) { // 勾选 - var color3 = new ModBase.MyColor(ThemeManager.AppResources["ColorObject3"]); + var color3 = new MyColor(ThemeManager.AppResources["ColorObject3"]); ModAnimation.AniStart( new[] { @@ -339,7 +338,7 @@ private void RefreshColor(object obj = null, object e = null) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new ModBase.MyColor(255d, 255d, 255d) - Background, animationTimeOfCheck), + new MyColor(255d, 255d, 255d) - Background, animationTimeOfCheck), "MyRadioButton Color " + Uuid); } else if (isMouseDown) @@ -347,8 +346,8 @@ private void RefreshColor(object obj = null, object e = null) // 按下 ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new ModBase.MyColor(120d, - new ModBase.MyColor(ThemeManager.AppResources["ColorObject8"])) - Background, 60), + new MyColor(120d, + new MyColor(ThemeManager.AppResources["ColorObject8"])) - Background, 60), "MyRadioButton Color " + Uuid); } else if (IsMouseOver) @@ -358,15 +357,15 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new ModBase.MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseIn), + new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseIn), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new ModBase.MyColor(255d, 255d, 255d) - LabText.Foreground, + new MyColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfMouseIn) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new ModBase.MyColor(50d, - new ModBase.MyColor(ThemeManager.AppResources["ColorObject8"])) - Background, + new MyColor(50d, + new MyColor(ThemeManager.AppResources["ColorObject8"])) - Background, animationTimeOfMouseIn), "MyRadioButton Color " + Uuid); } else @@ -376,15 +375,15 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new ModBase.MyColor(255d, 255d, 255d) - ShapeLogo.Fill, + new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseOut), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new ModBase.MyColor(255d, 255d, 255d) - LabText.Foreground, + new MyColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfMouseOut) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new ModBase.MyColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - + new MyColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - Background, animationTimeOfMouseOut), "MyRadioButton Color " + Uuid); } @@ -399,9 +398,9 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new ModBase.MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfCheck), + new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfCheck), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new ModBase.MyColor(255d, 255d, 255d) - LabText.Foreground, + new MyColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfCheck) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( @@ -443,7 +442,7 @@ private void RefreshColor(object obj = null, object e = null) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new ModBase.MyColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - + new MyColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - Background, animationTimeOfMouseOut), "MyRadioButton Color " + Uuid); } @@ -463,15 +462,15 @@ private void RefreshColor(object obj = null, object e = null) { if (Checked) { - Background = new ModBase.MyColor(255d, 255d, 255d); + Background = new MyColor(255d, 255d, 255d); ShapeLogo.SetResourceReference(Shape.FillProperty, "ColorBrush3"); LabText.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush3"); } else { Background = (Brush)ThemeManager.AppResources["ColorBrushSemiTransparent"]; - ShapeLogo.Fill = new ModBase.MyColor(255d, 255d, 255d); - LabText.Foreground = new ModBase.MyColor(255d, 255d, 255d); + ShapeLogo.Fill = new MyColor(255d, 255d, 255d); + LabText.Foreground = new MyColor(255d, 255d, 255d); } break; @@ -481,8 +480,8 @@ private void RefreshColor(object obj = null, object e = null) if (Checked) { SetResourceReference(BackgroundProperty, "ColorBrush3"); - ShapeLogo.Fill = new ModBase.MyColor(255d, 255d, 255d); - LabText.Foreground = new ModBase.MyColor(255d, 255d, 255d); + ShapeLogo.Fill = new MyColor(255d, 255d, 255d); + LabText.Foreground = new MyColor(255d, 255d, 255d); } else { @@ -498,7 +497,7 @@ private void RefreshColor(object obj = null, object e = null) } catch (Exception ex) { - ModBase.Log(ex, "刷新单选按钮颜色出错"); + LauncherLog.Log(ex, "刷新单选按钮颜色出错"); } } diff --git a/Plain Craft Launcher 2/Controls/MyScrollBar.cs b/Plain Craft Launcher 2/Controls/MyScrollBar.cs index 04f18317f..8a11508cf 100644 --- a/Plain Craft Launcher 2/Controls/MyScrollBar.cs +++ b/Plain Craft Launcher 2/Controls/MyScrollBar.cs @@ -1,4 +1,4 @@ -using System.Windows.Controls.Primitives; +using System.Windows.Controls.Primitives; namespace PCL; @@ -6,7 +6,7 @@ public class MyScrollBar : ScrollBar { // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyScrollBar() { @@ -75,7 +75,7 @@ private void RefreshColor() catch (Exception ex) { - ModBase.Log(ex, "滚动条颜色改变出错"); + LauncherLog.Log(ex, "滚动条颜色改变出错"); } } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/MyScrollViewer.cs b/Plain Craft Launcher 2/Controls/MyScrollViewer.cs index 0a4b6dce1..fc3f596ab 100644 --- a/Plain Craft Launcher 2/Controls/MyScrollViewer.cs +++ b/Plain Craft Launcher 2/Controls/MyScrollViewer.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -56,7 +56,7 @@ public void PerformVerticalOffsetDelta(double delta) { ModAnimation.AniStart(ModAnimation.AaDouble(animDelta => { - realOffset = ModBase.MathClamp(realOffset + (double)animDelta, 0d, ExtentHeight - ActualHeight); + realOffset = LauncherMath.Clamp(realOffset + (double)animDelta, 0d, ExtentHeight - ActualHeight); ScrollToVerticalOffset(realOffset); }, delta * DeltaMult, 300, 0, new ModAnimation.AniEaseOutFluent((ModAnimation.AniEasePower)6), false)); } diff --git a/Plain Craft Launcher 2/Controls/MySlider.xaml.cs b/Plain Craft Launcher 2/Controls/MySlider.xaml.cs index 8f3525c36..eb415fb22 100644 --- a/Plain Craft Launcher 2/Controls/MySlider.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MySlider.xaml.cs @@ -2,15 +2,15 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; - using PCL.Core.App.Localization; + namespace PCL; public partial class MySlider { public delegate void ChangeEventHandler(object sender, bool user); - public delegate void PreviewChangeEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void PreviewChangeEventHandler(object sender, RouteEventArgs e); // 自定义属性 @@ -23,7 +23,7 @@ public partial class MySlider // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MySlider() { @@ -56,7 +56,7 @@ public int Value { try { - value = (int)Math.Round(ModBase.MathClamp(value, 0d, MaxValue)); + value = (int)Math.Round(LauncherMath.Clamp(value, 0d, MaxValue)); if (_Value == value) return; @@ -65,7 +65,7 @@ public int Value _Value = value; if (ModAnimation.AniControlEnabled == 0) { - var e = new ModBase.RouteEventArgs(); + var e = new RouteEventArgs(); PreviewChange?.Invoke(this, e); if (e.handled) { @@ -117,10 +117,10 @@ public int Value catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "滑动条进度改变出错", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Control.Error.OperationFailed")); } } @@ -141,7 +141,7 @@ private void RefreshWidth(object sender, SizeChangedEventArgs? e) LineFore.Width = Math.Max(0d, newWidth + (newWidth < 0.5d ? 0d : 0.5d)); LineBack.Width = Math.Max(0d, ActualWidth - ShapeDot.Width - newWidth + (ActualWidth - ShapeDot.Width - newWidth < 0.5d ? 0d : 0.5d)); - ModBase.SetLeft(ShapeDot, newWidth); + LayoutExtensions.SetLeft(ShapeDot, newWidth); } private void DragStart(object sender, MouseButtonEventArgs e) @@ -162,7 +162,8 @@ private void DragStart(object sender, MouseButtonEventArgs e) public void DragDoing() { var percent = - ModBase.MathClamp((Mouse.GetPosition(PanMain).X - ShapeDot.Width / 2d) / (ActualWidth - ShapeDot.Width), 0d, + LauncherMath.Clamp((Mouse.GetPosition(PanMain).X - ShapeDot.Width / 2d) / (ActualWidth - ShapeDot.Width), + 0d, 1d); var newValue = (int)Math.Round(percent * MaxValue); if (newValue != Value) Value = newValue; @@ -193,7 +194,7 @@ public void RefreshPopup() TextHint.Text = getHintText.DynamicInvoke(Value)?.ToString() ?? ""; var typeface = new Typeface(TextHint.FontFamily, TextHint.FontStyle, TextHint.FontWeight, TextHint.FontStretch); var formattedText = new FormattedText(TextHint.Text, Thread.CurrentThread.CurrentCulture, - TextHint.FlowDirection, typeface, TextHint.FontSize, TextHint.Foreground, ModBase.dpi); + TextHint.FlowDirection, typeface, TextHint.FontSize, TextHint.Foreground, DpiUtils.Dpi); TextHint.Width = formattedText.Width; // 使用手动测量的宽度修复 #1057 } @@ -251,7 +252,7 @@ private void RefreshColor() catch (Exception ex) { - ModBase.Log(ex, "滑动条颜色改变出错"); + LauncherLog.Log(ex, "滑动条颜色改变出错"); } } diff --git a/Plain Craft Launcher 2/Controls/MyTextBox.cs b/Plain Craft Launcher 2/Controls/MyTextBox.cs index 07aa40efa..c396eb805 100644 --- a/Plain Craft Launcher 2/Controls/MyTextBox.cs +++ b/Plain Craft Launcher 2/Controls/MyTextBox.cs @@ -4,8 +4,9 @@ using System.Windows.Input; using System.Windows.Media; using FluentValidation; - +using PCL.Core.App; using PCL.Core.App.Localization; + namespace PCL; public class MyTextBox : TextBox @@ -48,7 +49,7 @@ public class MyTextBox : TextBox // 事件 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyTextBox() { @@ -165,10 +166,10 @@ public void Validate() if (IsLoaded && labWrong is not null) ChangeValidateResult(IsValidated, true); else - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { Thread.Sleep(30); - ModBase.RunInUi(() => ChangeValidateResult(IsValidated, false)); + UiThread.Post(() => ChangeValidateResult(IsValidated, false)); }, "DelayedValidate Change"); } @@ -178,13 +179,13 @@ public void Validate() if (IsLoaded && labWrong is not null) labWrong.Text = ValidateResult; else - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { var isFinished = false; while (!isFinished) { Thread.Sleep(20); - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { if (labWrong is not null) { @@ -270,10 +271,10 @@ private void MyTextBox_TextChanged(MyTextBox sender, TextChangedEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "进行输入验证时出错", - ModBase.LogLevel.Critical, + LauncherLogLevel.Critical, userSummary: Lang.Text("Application.Control.Error.OperationFailed")); } } @@ -372,7 +373,7 @@ private void RefreshColor() catch (Exception ex) { - ModBase.Log(ex, "文本框颜色改变出错"); + LauncherLog.Log(ex, "文本框颜色改变出错"); } } diff --git a/Plain Craft Launcher 2/Controls/MyTextButton.cs b/Plain Craft Launcher 2/Controls/MyTextButton.cs index 28984347e..8d31e76ca 100644 --- a/Plain Craft Launcher 2/Controls/MyTextButton.cs +++ b/Plain Craft Launcher 2/Controls/MyTextButton.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -35,7 +35,7 @@ public class MyTextButton : Label // 基础 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public MyTextButton() { @@ -85,7 +85,7 @@ private void MyTextButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs { if (!isMouseDown) return; isMouseDown = false; - ModBase.Log("[Control] 按下文本按钮:" + Text); + LauncherLog.Log($"[Control] 按下文本按钮:{Text}"); Click?.Invoke(this, null); ModMain.RaiseCustomEvent(this); e.Handled = true; diff --git a/Plain Craft Launcher 2/Controls/MyToast.xaml.cs b/Plain Craft Launcher 2/Controls/MyToast.xaml.cs index 92d4efc7e..5a9ba7ac6 100644 --- a/Plain Craft Launcher 2/Controls/MyToast.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyToast.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; @@ -10,7 +10,7 @@ namespace PCL; public partial class MyToast { - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); /// 判定为拖动而非点击的最小水平位移(像素)。 private const double DragDeadzone = 4d; @@ -210,7 +210,7 @@ private void UpdateColors() _ => 210d }; var res = System.Windows.Application.Current.Resources; - var accent = new ModBase.MyColor().FromHSL2(baseHue, 75, 60); + var accent = new MyColor().FromHSL2(baseHue, 75, 60); var bg = ThemeService.IsDarkMode ? new SolidColorBrush(LabColor.FromLch(0.35)) : (Brush)res["ColorBrushBackground"]; diff --git a/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs b/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs index 7571422fc..97af0fc5f 100644 --- a/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs +++ b/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Media; using System.Windows.Shapes; using PCL.Core.UI; @@ -60,7 +60,7 @@ internal static void AnimateSvgIconBrushTo( internal static void AnimateSvgIconBrushTo( SvgIcon svgIcon, - ModBase.MyColor color, + MyColor color, int duration, string? animationKey = null) { diff --git a/Plain Craft Launcher 2/FormMain.xaml.cs b/Plain Craft Launcher 2/FormMain.xaml.cs index 81d510987..a1478eb65 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.cs +++ b/Plain Craft Launcher 2/FormMain.xaml.cs @@ -7,7 +7,6 @@ using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; -using System.Windows.Media.Effects; using PCL.Core.App; using PCL.Core.App.IoC; using PCL.Core.App.Localization; @@ -37,17 +36,19 @@ private void FormMain_MouseMove(object sender, MouseEventArgs e) // 更新日志 private void ShowUpdateLog() { - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { - var changelogFile = $"{ModBase.pathTemp}CEUpdateLog.md"; + var changelogFile = $"{LauncherPaths.TempWithSlash}CEUpdateLog.md"; string changelog; if (File.Exists(changelogFile)) - changelog = ModBase.ReadFile(changelogFile); + changelog = LegacyFileFacade.ReadText(changelogFile); else changelog = Lang.Text("Main.UpdateLog.Empty"); if (ModMain.MyMsgBoxMarkdown(changelog, - Lang.Text("Main.UpdateLog.Title", ModBase.VersionBranchName, ModBase.VersionBaseName), Lang.Text("Common.Action.Confirm"), Lang.Text("Main.UpdateLog.FullChangelog")) == - 2) ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases"); + Lang.Text("Main.UpdateLog.Title", LauncherEnvironment.VersionBranchName, + LauncherEnvironment.VersionBaseName), Lang.Text("Common.Action.Confirm"), + Lang.Text("Main.UpdateLog.FullChangelog")) == + 2) LauncherProcess.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases"); }, "UpdateLog Output"); } @@ -57,7 +58,7 @@ private void ShowUpdateLog() public FormMain() { - ModBase.applicationStartTick = TimeUtils.GetTimeTick(); + LauncherRuntime.ApplicationStartTick = TimeUtils.GetTimeTick(); // 刷新主题 // ThemeCheckAll(False) // ThemeRefreshColor() @@ -69,7 +70,7 @@ public FormMain() ModMain.frmLaunchRight = new PageLaunchRight(); // 版本号改变 var lastVersion = States.System.LastVersion; - if (lastVersion < ModBase.VersionCode) + if (lastVersion < LauncherEnvironment.VersionCode) { // 重新询问是否启用遥测数据收集 if (lastVersion <= 511) @@ -77,13 +78,13 @@ public FormMain() if (!Config.System.TelemetryConfig.IsDefault() && Config.System.Telemetry) { Config.System.TelemetryConfig.Reset(); - ModBase.Log("[Start] 遥测策略变更:由旧版本升级到含新版遥测的版本,已重置遥测设置"); + LauncherLog.Log("[Start] 遥测策略变更:由旧版本升级到含新版遥测的版本,已重置遥测设置"); } } // 触发升级 UpgradeSub(lastVersion); } - else if (lastVersion > ModBase.VersionCode) + else if (lastVersion > LauncherEnvironment.VersionCode) // 触发降级 DowngradeSub(lastVersion); @@ -105,10 +106,10 @@ public FormMain() } catch (Exception ex) // 修复 #2019 { - ModBase.Log( + LauncherLog.Log( ex, "读取窗口默认大小失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Main.Error.OperationFailed")); Height = MinHeight + 100d; Width = MinWidth + 100d; @@ -117,7 +118,7 @@ public FormMain() // 管理员权限下文件拖拽 if (ProcessInterop.IsAdmin()) { - ModBase.Log("[Start] PCL 当前正以管理员权限运行"); + LauncherLog.Log("[Start] PCL 当前正以管理员权限运行"); SourceInitialized += (_, _) => { var windowInterop = new WindowInteropHelper(this); @@ -138,13 +139,13 @@ public FormMain() pageRight = ModMain.frmLaunchRight; ModMain.frmLaunchRight.PageState = MyPageRight.PageStates.ContentStay; // 调试模式提醒 - if (ModBase.ModeDebug) + if (LauncherRuntime.ModeDebug) HintService.Hint(Lang.Text("Main.DebugMode.Hint")); // 尽早执行的加载池 ModFolder.mcFolderListLoader .Start(0); // 为了让下载已存在文件检测可以正常运行,必须跑一次;为了让启动按钮尽快可用,需要尽早执行;为了与 PageLaunchLeft 联动,需要为 0 而不是 GetUuid - ModBase.Log("[Start] 第二阶段加载用时:" + (TimeUtils.GetTimeTick() - ModBase.applicationStartTick) + " ms"); + LauncherLog.Log("[Start] 第二阶段加载用时:" + (TimeUtils.GetTimeTick() - LauncherRuntime.ApplicationStartTick) + " ms"); // 注册生命周期状态事件 Lifecycle.When(LifecycleState.WindowCreated, FormMain_Loaded); } @@ -152,8 +153,8 @@ public FormMain() private void FormMain_Loaded() // (sender As Object, e As RoutedEventArgs) Handles Me.Loaded { FormMain_SizeChanged(); - ModBase.applicationStartTick = TimeUtils.GetTimeTick(); - ModBase.frmHandle = new WindowInteropHelper(this).Handle; + LauncherRuntime.ApplicationStartTick = TimeUtils.GetTimeTick(); + LauncherEnvironment.MainWindowHandle = new WindowInteropHelper(this).Handle; // 读取设置 PageSetupUI.BackgroundRefresh(false, true); ModMusic.MusicRefreshPlay(false, true); @@ -211,15 +212,15 @@ private void FormMain_Loaded() // (sender As Object, e As RoutedEventArgs) Handl { RenderTransform = null; isWindowLoadFinished = true; - ModBase.Log( - $"[System] DPI:{ModBase.dpi},系统版本:{Environment.OSVersion.VersionString},PCL 位置:{Basics.ExecutablePath}"); + LauncherLog.Log( + $"[System] DPI:{DpiUtils.Dpi},系统版本:{Environment.OSVersion.VersionString},PCL 位置:{Basics.ExecutablePath}"); }, after: true) }, "Form Show"); // Timer 启动 ModAnimation.AniStart(); ModMain.TimerMainStart(); // 特殊版本提示 - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { // 特殊版本提示 try @@ -241,7 +242,7 @@ private void FormMain_Loaded() // (sender As Object, e As RoutedEventArgs) Handl $"{hint}{"\r\n"}{"\r\n"}{Lang.Text("Main.SpecialVersion.HideHintNotice")}", Lang.Text("Main.SpecialVersion.Title"), Lang.Text("Main.SpecialVersion.IUnderstand"), Lang.Text("Main.SpecialVersion.OpenDownloadPageAndExit"), isWarn: true, button2Action: () => { - ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases/latest"); + LauncherProcess.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases/latest"); EndProgram(false); }); } @@ -251,7 +252,8 @@ private void FormMain_Loaded() // (sender As Object, e As RoutedEventArgs) Handl // EULA 提示 if (!States.System.LauncherEula) switch (ModMain.MyMsgBox(Lang.Text("Main.Eula.Message"), Lang.Text("Main.Eula.Title"), Lang.Text("Common.Action.Agree"), Lang.Text("Common.Action.Decline"), Lang.Text("Main.Eula.View"), - button3Action: () => ModBase.OpenWebsite("https://shimo.im/docs/rGrd8pY8xWkt6ryW"))) + button3Action: () => + LauncherProcess.OpenWebsite("https://shimo.im/docs/rGrd8pY8xWkt6ryW"))) { case 1: { @@ -279,14 +281,14 @@ private void FormMain_Loaded() // (sender As Object, e As RoutedEventArgs) Handl ModDownload.dlClientListMojangLoader.Start(1); // PCL 会同时根据这里的加载结果决定是否使用官方源进行下载 RunCountSub(); UpdateManager.serverLoader.Start(1); - ModBase.RunInNewThread(ModMain.TryClearTaskTemp, "TryClearTaskTemp", ThreadPriority.BelowNormal); + Basics.RunInNewThread(ModMain.TryClearTaskTemp, "TryClearTaskTemp", ThreadPriority.BelowNormal); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "初始化加载池运行失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } @@ -294,15 +296,15 @@ private void FormMain_Loaded() // (sender As Object, e As RoutedEventArgs) Handl } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "初始弹窗提示运行失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } }, "Start Loader", ThreadPriority.BelowNormal); - ModBase.Log($"[Start] 第三阶段加载用时:{TimeUtils.GetTimeTick() - ModBase.applicationStartTick} ms"); + LauncherLog.Log($"[Start] 第三阶段加载用时:{TimeUtils.GetTimeTick() - LauncherRuntime.ApplicationStartTick} ms"); } // 根据打开次数触发的事件 @@ -314,23 +316,23 @@ private void RunCountSub() // 升级与降级事件 private void UpgradeSub(int lastVersionCode) { - ModBase.Log("[Start] 版本号从 " + lastVersionCode + " 升高到 " + ModBase.VersionCode); - States.System.LastVersion = ModBase.VersionCode; + LauncherLog.Log("[Start] 版本号从 " + lastVersionCode + " 升高到 " + LauncherEnvironment.VersionCode); + States.System.LastVersion = LauncherEnvironment.VersionCode; // 检查有记录的最高版本号 int lowerVersionCode; #if BETA lowerVersionCode = States.System.LastBetaVersion; - if (lowerVersionCode < ModBase.versionCode) + if (lowerVersionCode < LauncherEnvironment.VersionCode) { - States.System.LastBetaVersion = ModBase.versionCode; - ModBase.Log($"[Start] 最高版本号从 {lowerVersionCode} 升高到 {ModBase.versionCode}"); + States.System.LastBetaVersion = LauncherEnvironment.VersionCode; + LauncherLog.Log($"[Start] 最高版本号从 {lowerVersionCode} 升高到 {LauncherEnvironment.VersionCode}"); } #else lowerVersionCode = States.System.LastAlphaVersion; - if (lowerVersionCode < ModBase.VersionCode) + if (lowerVersionCode < LauncherEnvironment.VersionCode) { - States.System.LastAlphaVersion = ModBase.VersionCode; - ModBase.Log($"[Start] 最高版本号从 {lowerVersionCode} 升高到 {ModBase.VersionCode}"); + States.System.LastAlphaVersion = LauncherEnvironment.VersionCode; + LauncherLog.Log($"[Start] 最高版本号从 {lowerVersionCode} 升高到 {LauncherEnvironment.VersionCode}"); } #endif // 被移除的窗口设置选项 (Commit 3161488 2026/1/23) @@ -342,15 +344,15 @@ private void UpgradeSub(int lastVersionCode) // 输出更新日志 if (lastVersionCode <= 0) return; - if (lowerVersionCode >= ModBase.VersionCode) + if (lowerVersionCode >= LauncherEnvironment.VersionCode) return; ShowUpdateLog(); } private void DowngradeSub(int lastVersionCode) { - ModBase.Log("[Start] 版本号从 " + lastVersionCode + " 降低到 " + ModBase.VersionCode); - States.System.LastVersion = ModBase.VersionCode; + LauncherLog.Log("[Start] 版本号从 " + lastVersionCode + " 降低到 " + LauncherEnvironment.VersionCode); + States.System.LastVersion = LauncherEnvironment.VersionCode; } #endregion @@ -499,9 +501,9 @@ public void EndProgram(bool sendWarning, bool isUpdating = false) { if (ModMain.MyMsgBox(Lang.Text("Main.Exit.HasDownloadingTask"), Lang.Text("Common.Dialog.Title"), Lang.Text("Common.Action.Confirm"), Lang.Text("Common.Action.Cancel")) == 1) // 强行结束下载任务 - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { - ModBase.Log("[System] 正在强行停止任务"); + LauncherLog.Log("[System] 正在强行停止任务"); foreach (var Task in ModLoader.loaderTaskbar.ToList()) Task.Abort(); }, "强行停止下载任务"); @@ -514,7 +516,7 @@ public void EndProgram(bool sendWarning, bool isUpdating = false) // 存储上次使用的档案编号 ModProfile.SaveProfile(); // 关闭 - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { // 清理视频背景 VideoBack.Stop(); @@ -559,36 +561,37 @@ public void EndProgram(bool sendWarning, bool isUpdating = false) EndProgramForce(force: false, isUpdating: isUpdating); } - ModBase.Log("[System] 收到关闭指令"); + LauncherLog.Log("[System] 收到关闭指令"); }); } private static bool isLogShown; - public static void EndProgramForce(ModBase.ProcessReturnValues returnCode = ModBase.ProcessReturnValues.Success, + public static void EndProgramForce(LauncherExitCode returnCode = LauncherExitCode.Success, bool force = true, bool isUpdating = false) { // On Error Resume Next // 关闭联机大厅 // Await LobbyController.CloseAsync().ConfigureAwait(False) - ModBase.isProgramEnded = true; + LauncherRuntime.IsProgramEnded = true; ModAnimation.AniControlEnabled += 1; if (UpdateManager.isUpdateWaitingRestart && !isUpdating) UpdateManager.UpdateRestart(false, false); - if (returnCode == ModBase.ProcessReturnValues.Exception) + if (returnCode == LauncherExitCode.Exception) { if (!isLogShown) { - ModBase.FeedbackInfo(); - ModBase.Log("请在 https://github.com/PCL-Community/PCL2-CE/issues 提交错误报告,以便于社区解决此问题!(这也有可能是原版 PCL 的问题)"); + LauncherFeedbackService.FeedbackInfo(); + LauncherLog.Log( + "请在 https://github.com/PCL-Community/PCL2-CE/issues 提交错误报告,以便于社区解决此问题!(这也有可能是原版 PCL 的问题)"); isLogShown = true; - ModBase.ShellOnly(LogWrapper.CurrentLogger.CurrentLogFiles.Last()); + LauncherProcess.ShellOnly(LogWrapper.CurrentLogger.CurrentLogFiles.Last()); } Thread.Sleep(500); // 防止 PCL 在记事本打开前就被掐掉 } - ModBase.Log("[System] 程序已退出,返回值:" + ModBase.GetStringFromEnum(returnCode)); + LauncherLog.Log("[System] 程序已退出,返回值:" + LauncherText.GetStringFromEnum(returnCode)); // If ReturnCode <> ProcessReturnValues.Success Then Environment.Exit(ReturnCode) // Process.GetCurrentProcess.Kill() Lifecycle.Shutdown((int)returnCode, force); @@ -662,7 +665,7 @@ private void BtnTitleMin_Click(object sender, EventArgs e) private void BtnTitleHelp_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://www.bilibili.com/video/BV1uT4y1P7CX"); + LauncherProcess.OpenWebsite("https://www.bilibili.com/video/BV1uT4y1P7CX"); } #endregion @@ -848,10 +851,10 @@ private void FormMain_Activated(object sender, EventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "切回窗口时出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } } @@ -891,14 +894,14 @@ private void HandleDrag(object sender, DragEventArgs e) _HandleDrag_PrevData = e.Data; _HandleDrag_PrevEffects = e.Effects; - ModBase.Log("[System] 设置拖放类型:" + ModBase.GetStringFromEnum(e.Effects)); + LauncherLog.Log("[System] 设置拖放类型:" + LauncherText.GetStringFromEnum(e.Effects)); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "处理拖放时出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } } @@ -913,7 +916,7 @@ private void FrmMain_Drop(object sender, DragEventArgs e) try { var str = (string)e.Data.GetData(DataFormats.Text); - ModBase.Log("[System] 接受文本拖拽:" + str); + LauncherLog.Log("[System] 接受文本拖拽:" + str); if (str.StartsWithF("authlib-injector:yggdrasil-server:")) { // Authlib 拖拽 @@ -921,7 +924,7 @@ private void FrmMain_Drop(object sender, DragEventArgs e) e.Effects = DragDropEffects.Copy; var authlibServer = WebUtility.UrlDecode(str.Substring("authlib-injector:yggdrasil-server:".Length)); - ModBase.Log("[System] Authlib 拖拽:" + authlibServer); + LauncherLog.Log("[System] Authlib 拖拽:" + authlibServer); if (!new HttpValidator().Validate(authlibServer).IsValid) { HintService.Hint(Lang.Text("Main.FileDrag.AuthlibInvalid", authlibServer), HintType.Error); @@ -932,7 +935,7 @@ private void FrmMain_Drop(object sender, DragEventArgs e) Lang.Text("Common.Action.Confirm"), Lang.Text("Common.Action.Cancel")) == 2) return; ModProfile.selectedProfile = null; - ModBase.RunInUi(() => + UiThread.Post(() => { PageLoginAuth.draggedAuthServer = authlibServer; ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Auth); @@ -952,7 +955,7 @@ private void FrmMain_Drop(object sender, DragEventArgs e) } catch (Exception ex) { - ModBase.Log(ex, "无法接取文本拖拽事件", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "无法接取文本拖拽事件", LauncherLogLevel.Developer); } } else if (e.Data.GetDataPresent(DataFormats.FileDrop)) @@ -972,21 +975,22 @@ private void FrmMain_Drop(object sender, DragEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "接取拖拽事件失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } } private void FileDrag(IEnumerable filePathList) { - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { var filePath = filePathList.First(); - ModBase.Log("[System] 接受文件拖拽:" + filePath + (filePathList.Any() ? $" 等 {filePathList.Count()} 个文件" : ""), - ModBase.LogLevel.Developer); + LauncherLog.Log( + "[System] 接受文件拖拽:" + filePath + (filePathList.Any() ? $" 等 {filePathList.Count()} 个文件" : ""), + LauncherLogLevel.Developer); // 基础检查 if (Directory.Exists(filePathList.First()) && !File.Exists(filePathList.First())) { @@ -1024,13 +1028,13 @@ private void FileDrag(IEnumerable filePathList) var extension = filePath.AfterLast(".").ToLower(); if (extension == "xaml") { - ModBase.Log("[System] 文件后缀为 XAML,作为主页加载"); - if (File.Exists(ModBase.exePath + @"PCL\Custom.xaml")) + LauncherLog.Log("[System] 文件后缀为 XAML,作为主页加载"); + if (File.Exists(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Custom.xaml")) if (ModMain.MyMsgBox(Lang.Text("Main.FileDrag.HomepageExists"), Lang.Text("Main.FileDrag.OverwriteTitle"), Lang.Text("Common.Action.Overwrite"), Lang.Text("Common.Action.Cancel")) == 2) return; - ModBase.CopyFile(filePath, ModBase.exePath + @"PCL\Custom.xaml"); - ModBase.RunInUi(() => + LegacyFileFacade.CopyFile(filePath, LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Custom.xaml"); + UiThread.Post(() => { Config.Preference.Homepage.Type = 1; ModMain.frmLaunchRight.ForceRefresh(); @@ -1045,7 +1049,7 @@ private void FileDrag(IEnumerable filePathList) // 安装投影文件 if (new[] { "litematic", "nbt", "schematic", "schem" }.Contains(extension)) { - ModBase.Log($"[System] 文件为 {extension} 格式,尝试作为原理图安装"); + LauncherLog.Log($"[System] 文件为 {extension} 格式,尝试作为原理图安装"); // 获取当前文件夹路径(如果在资源管理页面) string targetFolderPath = null; if (pageCurrent == PageType.InstanceSetup && PageCurrentSub == PageSubType.VersionSchematic && @@ -1063,7 +1067,7 @@ ModMain.frmInstanceSchematic is not null && case PageSubType.VersionWorld: { var destFolder = PageInstanceLeft.McInstance.PathIndie + @"saves\" + - ModBase.GetFileNameWithoutExtentionFromPath(filePath); + LegacyFileFacade.GetFileNameWithoutExtensionFromPath(filePath); var destLevelDat = Path.Combine(destFolder, "level.dat"); if (Directory.Exists(destFolder)) { @@ -1071,10 +1075,11 @@ ModMain.frmInstanceSchematic is not null && return; } - var extractFolder = Path.Combine(ModBase.pathTemp, "Cache", "WorldImport", ModBase.GetUuid().ToString()); + var extractFolder = Path.Combine(LauncherPaths.TempWithSlash, "Cache", "WorldImport", + LauncherRuntime.GetUuid().ToString()); try { - ModBase.ExtractFile(filePath, extractFolder); + LegacyFileFacade.ExtractFile(filePath, extractFolder); var saveRoot = SaveImportHelper.GetSaveRootDirectory(extractFolder); if (saveRoot is null) { @@ -1082,11 +1087,11 @@ ModMain.frmInstanceSchematic is not null && return; } - ModBase.CopyDirectory(saveRoot, destFolder); + LegacyFileFacade.CopyDirectory(saveRoot, destFolder); if (!File.Exists(destLevelDat)) { if (Directory.Exists(destFolder)) - ModBase.DeleteDirectory(destFolder, true); + LegacyFileFacade.DeleteDirectory(destFolder, true); HintService.Hint(Lang.Text("Main.FileDrag.SaveInvalid"), HintType.Error); return; } @@ -1094,56 +1099,62 @@ ModMain.frmInstanceSchematic is not null && catch (Exception ex) { if (Directory.Exists(destFolder)) - ModBase.DeleteDirectory(destFolder, true); - ModBase.Log( + LegacyFileFacade.DeleteDirectory(destFolder, true); + LauncherLog.Log( ex, Lang.Text("Main.FileDrag.SaveImportFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Main.FileDrag.SaveImportFailed")); return; } finally { if (Directory.Exists(extractFolder)) - ModBase.DeleteDirectory(extractFolder, true); + LegacyFileFacade.DeleteDirectory(extractFolder, true); } - HintService.Hint(Lang.Text("Main.FileDrag.Imported", ModBase.GetFileNameWithoutExtentionFromPath(filePath)), + HintService.Hint( + Lang.Text("Main.FileDrag.Imported", + LegacyFileFacade.GetFileNameWithoutExtensionFromPath(filePath)), HintType.Success); if (ModMain.frmInstanceSaves is not null) - ModBase.RunInUi(() => ModMain.frmInstanceSaves.Reload()); + UiThread.Post(() => ModMain.frmInstanceSaves.Reload()); return; } case PageSubType.VersionResourcePack: { var destFile = PageInstanceLeft.McInstance.PathIndie + @"resourcepacks\" + - ModBase.GetFileNameFromPath(filePath); + LegacyFileFacade.GetFileNameFromPath(filePath); if (File.Exists(destFile)) { HintService.Hint(Lang.Text("Main.FileDrag.SameFileExists", destFile), HintType.Error); return; } - ModBase.CopyFile(filePath, destFile); - HintService.Hint(Lang.Text("Main.FileDrag.Imported", ModBase.GetFileNameFromPath(filePath)), HintType.Success); + LegacyFileFacade.CopyFile(filePath, destFile); + HintService.Hint( + Lang.Text("Main.FileDrag.Imported", LegacyFileFacade.GetFileNameFromPath(filePath)), + HintType.Success); if (ModMain.frmInstanceResourcePack is not null) - ModBase.RunInUi(() => ModMain.frmInstanceResourcePack.ReloadCompFileList()); + UiThread.Post(() => ModMain.frmInstanceResourcePack.ReloadCompFileList()); return; } case PageSubType.VersionShader: { var destFile = PageInstanceLeft.McInstance.PathIndie + @"shaderpacks\" + - ModBase.GetFileNameFromPath(filePath); + LegacyFileFacade.GetFileNameFromPath(filePath); if (File.Exists(destFile)) { HintService.Hint(Lang.Text("Main.FileDrag.SameFileExists", destFile), HintType.Error); return; } - ModBase.CopyFile(filePath, destFile); - HintService.Hint(Lang.Text("Main.FileDrag.Imported", ModBase.GetFileNameFromPath(filePath)), HintType.Success); + LegacyFileFacade.CopyFile(filePath, destFile); + HintService.Hint( + Lang.Text("Main.FileDrag.Imported", LegacyFileFacade.GetFileNameFromPath(filePath)), + HintType.Success); if (ModMain.frmInstanceShader is not null) - ModBase.RunInUi(() => ModMain.frmInstanceShader.ReloadCompFileList()); + UiThread.Post(() => ModMain.frmInstanceShader.ReloadCompFileList()); return; } } @@ -1154,7 +1165,7 @@ ModMain.frmInstanceSchematic is not null && PageCurrentSub == PageSubType.VersionSchematic) { var destFile = PageInstanceLeft.McInstance.PathIndie + @"schematics\" + - ModBase.GetFileNameFromPath(filePath); + LegacyFileFacade.GetFileNameFromPath(filePath); if (File.Exists(destFile)) { HintService.Hint(Lang.Text("Main.FileDrag.SameFileExists", destFile), HintType.Error); @@ -1162,10 +1173,11 @@ ModMain.frmInstanceSchematic is not null && } Directory.CreateDirectory(PageInstanceLeft.McInstance.PathIndie + @"schematics\"); - ModBase.CopyFile(filePath, destFile); - HintService.Hint(Lang.Text("Main.FileDrag.Imported", ModBase.GetFileNameFromPath(filePath)), HintType.Success); + LegacyFileFacade.CopyFile(filePath, destFile); + HintService.Hint(Lang.Text("Main.FileDrag.Imported", LegacyFileFacade.GetFileNameFromPath(filePath)), + HintType.Success); if (ModMain.frmInstanceSchematic is not null) - ModBase.RunInUi(() => ModMain.frmInstanceSchematic.ReloadCompFileList()); + UiThread.Post(() => ModMain.frmInstanceSchematic.ReloadCompFileList()); return; } @@ -1173,13 +1185,13 @@ ModMain.frmInstanceSchematic is not null && if (new[] { "zip", "rar", "mrpack" }.Any(t => (t ?? "") == (extension ?? ""))) // 部分压缩包是 zip 格式但后缀为 rar,总之试一试 { - ModBase.Log("[System] 文件为压缩包,尝试作为整合包安装"); + LauncherLog.Log("[System] 文件为压缩包,尝试作为整合包安装"); try { ModModpack.ModpackInstall(filePath); return; } - catch (ModBase.CancelledException ex) + catch (CancelledException ex) { return; // 用户主动取消 } @@ -1194,8 +1206,8 @@ ModMain.frmInstanceSchematic is not null && { try { - ModBase.Log("[System] 尝试进行错误报告分析"); - var analyzer = new CrashAnalyzer(ModBase.GetUuid()); + LauncherLog.Log("[System] 尝试进行错误报告分析"); + var analyzer = new CrashAnalyzer(LauncherRuntime.GetUuid()); analyzer.Import(filePath); if (!analyzer.Prepare()) break; @@ -1205,10 +1217,10 @@ ModMain.frmInstanceSchematic is not null && } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "自主错误报告分析失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } } while (false); @@ -1226,23 +1238,23 @@ private nint WndProc(nint hwnd, int msg, nint wParam, nint lParam, ref bool hand if (msg == 30) { var nowDate = DateTime.Now; - if (nowDate.Date == ModBase.applicationOpenTime.Date) + if (nowDate.Date == LauncherRuntime.ApplicationOpenTime.Date) { - ModBase.Log("[System] 系统时间微调为:" + nowDate.ToLongDateString() + " " + nowDate.ToLongTimeString()); + LauncherLog.Log("[System] 系统时间微调为:" + nowDate.ToLongDateString() + " " + nowDate.ToLongTimeString()); isSystemTimeChanged = false; } else { - ModBase.Log("[System] 系统时间修改为:" + nowDate.ToLongDateString() + " " + nowDate.ToLongTimeString()); + LauncherLog.Log("[System] 系统时间修改为:" + nowDate.ToLongDateString() + " " + nowDate.ToLongTimeString()); isSystemTimeChanged = true; } } else if (msg == 400 * 16 + 2) { - ModBase.Log("[System] 收到置顶信息:" + hwnd.ToInt64()); + LauncherLog.Log("[System] 收到置顶信息:" + hwnd.ToInt64()); if (!isWindowLoadFinished) { - ModBase.Log("[System] 窗口尚未加载完成,忽略置顶请求"); + LauncherLog.Log("[System] 窗口尚未加载完成,忽略置顶请求"); return nint.Zero; } @@ -1253,7 +1265,7 @@ private nint WndProc(nint hwnd, int msg, nint wParam, nint lParam, ref bool hand { if (Marshal.PtrToStringAuto(lParam) == "ImmersiveColorSet") { - ModBase.Log($"[System] 系统主题更改,深色模式:{SystemTheme.IsSystemInDarkMode()}"); + LauncherLog.Log($"[System] 系统主题更改,深色模式:{SystemTheme.IsSystemInDarkMode()}"); if (Config.Preference.Theme.ColorMode == ColorMode.System && (ThemeManager.IsDarkMode != SystemTheme.IsSystemInDarkMode())) ThemeService.RefreshColorMode(); } @@ -1277,7 +1289,7 @@ public bool Hidden Left -= 10000d; ShowInTaskbar = false; Visibility = Visibility.Hidden; - ModBase.Log("[System] 窗口已隐藏,位置:(" + Left + "," + Top + ")"); + LauncherLog.Log("[System] 窗口已隐藏,位置:(" + Left + "," + Top + ")"); } else { @@ -1302,7 +1314,7 @@ protected override void OnActivated(EventArgs e) /// public void ShowWindowToTop() { - ModBase.RunInUi(() => + UiThread.Post(() => { // 这一坨乱七八糟的,别改,改了指不定就炸了,自己电脑还复现不出来 Visibility = Visibility.Visible; @@ -1311,9 +1323,9 @@ public void ShowWindowToTop() Hidden = false; Topmost = true; // 偶尔 SetForegroundWindow 失效 Topmost = false; - ModMain.SetForegroundWindow(ModBase.frmHandle); + ModMain.SetForegroundWindow(LauncherEnvironment.MainWindowHandle); Focus(); - ModBase.Log($"[System] 窗口已置顶,位置:({Left}, {Top}), {Width} x {Height}"); + LauncherLog.Log($"[System] 窗口已置顶,位置:({Left}, {Top}), {Width} x {Height}"); }); } @@ -1492,7 +1504,8 @@ private string PageNameGet(PageStackData stack) } case PageType.VersionSaves: { - return Lang.Text("Main.Title.SaveManagement", ModBase.GetFolderNameFromPath(stack.additional.Value.SavePath)); + return Lang.Text("Main.Title.SaveManagement", + LegacyFileFacade.GetFolderNameFromPath(stack.additional.Value.SavePath)); } default: @@ -1663,7 +1676,7 @@ public void PageChange(PageStackData stack, PageSubType subType = PageSubType.De ModMain.frmDownloadLeft = new PageDownloadLeft(); foreach (var item in ModMain.frmDownloadLeft.PanItem.Children) if (item is MyListItem listItem && - ModBase.Val(listItem.Tag) == (double)subType) + LauncherText.Val(listItem.Tag) == (double)subType) { listItem.SetChecked(true, true, stack == pageCurrent); break; @@ -1677,7 +1690,7 @@ public void PageChange(PageStackData stack, PageSubType subType = PageSubType.De ModMain.frmSetupLeft = new PageSetupLeft(); foreach (var item in ModMain.frmSetupLeft.PanItem.Children) if (item is MyListItem listItem && - ModBase.Val(listItem.Tag) == (double)subType) + LauncherText.Val(listItem.Tag) == (double)subType) { listItem.SetChecked(true, true, stack == pageCurrent); break; @@ -1700,7 +1713,7 @@ public void PageChange(PageStackData stack, PageSubType subType = PageSubType.De ModMain.frmInstanceLeft = new PageInstanceLeft(); foreach (var item in ModMain.frmInstanceLeft.PanItem.Children) if (item is MyListItem listItem && - ModBase.Val(listItem.Tag) == (double)subType) + LauncherText.Val(listItem.Tag) == (double)subType) { listItem.SetChecked(true, true, stack == pageCurrent); break; @@ -1714,7 +1727,7 @@ public void PageChange(PageStackData stack, PageSubType subType = PageSubType.De ModMain.frmInstanceSavesLeft = new PageInstanceSavesLeft(); foreach (var item in ModMain.frmInstanceSavesLeft.PanItem.Children) if (item is MyListItem listItem && - ModBase.Val(listItem.Tag) == (double)subType) + LauncherText.Val(listItem.Tag) == (double)subType) { listItem.SetChecked(true, true, stack == pageCurrent); break; @@ -1913,14 +1926,14 @@ private void PageChangeActual(PageStackData stack, PageSubType subType) #endregion - ModBase.Log("[Control] 切换主要页面:" + ModBase.GetStringFromEnum(stack) + ", " + (int)subType); + LauncherLog.Log("[Control] 切换主要页面:" + LauncherText.GetStringFromEnum(stack) + ", " + (int)subType); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "切换主要页面失败(ID " + (int)pageCurrent.page + ")", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } finally @@ -1956,7 +1969,7 @@ private void PageChangeAnim(FrameworkElement targetLeft, FrameworkElement target pageLeft.Opacity = 0d; PanMainLeft.Background = null; ModAnimation.AniControlEnabled -= 1; - ModBase.RunInUi(() => PanMainLeft_Resize(PanMainLeft.ActualWidth), true); + UiThread.Post(() => PanMainLeft_Resize(PanMainLeft.ActualWidth), true); }, 110), ModAnimation.AaCode(() => { @@ -1976,7 +1989,7 @@ private void PageChangeAnim(FrameworkElement targetLeft, FrameworkElement target pageRight.Opacity = 0d; PanMainRight.Background = null; ModAnimation.AniControlEnabled -= 1; - ModBase.RunInUi(() => BtnExtraBack.ShowRefresh(), true); + UiThread.Post(() => BtnExtraBack.ShowRefresh(), true); }, 110), ModAnimation.AaCode(() => { @@ -2091,7 +2104,7 @@ private void PanBack_MouseMove(object sender, EventArgs e) public void DragStop() { // 存在其他线程调用的可能性,因此需要确保在 UI 线程运行 - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.dragControl is null) return; @@ -2174,10 +2187,10 @@ private void BtnExtraShutdown_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "强制关闭所有 Minecraft 失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } } @@ -2209,9 +2222,9 @@ public void BackToTop() if (realScroll is not null) realScroll.PerformVerticalOffsetDelta(-realScroll.VerticalOffset); else - ModBase.Log( + LauncherLog.Log( "[UI] 无法返回顶部,未找到合适的 RealScroll", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Main.Error.ScrollToTopFailed")); } diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs b/Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs index 47a04d6c7..e32b8ff70 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs @@ -1,7 +1,7 @@ -namespace PCL; +namespace PCL; /// -/// PCL2 进程退出码。ModBase.ProcessReturnValues 保留为旧 API 兼容层。 +/// PCL2 进程退出码。LauncherExitCode 保留为旧 API 兼容层。 /// public enum LauncherExitCode { diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs b/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs index 49aed767b..cd395ca63 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Runtime.InteropServices; using Microsoft.VisualBasic; using PCL.Core.App.Localization; @@ -95,7 +95,7 @@ public static void ShowFeedbackPrompt(string userMessage, string title, bool isC { if (isCritical && LauncherLog.MarkCriticalErrorTriggered()) { - FormMain.EndProgramForce(ModBase.ProcessReturnValues.Exception); + FormMain.EndProgramForce(LauncherExitCode.Exception); return; } diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs b/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs index 3883922e8..b91a380ba 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs @@ -1,4 +1,4 @@ -using PCL.Core.App.Localization; +using PCL.Core.App.Localization; namespace PCL; @@ -15,7 +15,7 @@ public static void SetLaunchFont(string? fontName = null) } catch (Exception ex) { - LauncherLog.Log(ex, "设置字体失败", ModBase.LogLevel.Hint); + LauncherLog.Log(ex, "设置字体失败", LauncherLogLevel.Hint); } } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs b/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs index dc19090ff..dce91a05f 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using System.Diagnostics; using PCL.Core.App.Localization; using PCL.Core.Logging; @@ -14,16 +14,16 @@ public static class LauncherLog public static void Log( string text, - ModBase.LogLevel level = ModBase.LogLevel.Normal, + LauncherLogLevel level = LauncherLogLevel.Normal, string? title = null, string? userSummary = null) { WriteTextLog(text, level); - if (LauncherRuntime.IsProgramEnded|| level is ModBase.LogLevel.Normal or ModBase.LogLevel.Developer) + if (LauncherRuntime.IsProgramEnded || level is LauncherLogLevel.Normal or LauncherLogLevel.Developer) return; - if (level == ModBase.LogLevel.Debug) + if (level == LauncherLogLevel.Debug) { ShowDebugHint(text); return; @@ -40,7 +40,7 @@ public static void Log( public static void Log( Exception ex, string desc, - ModBase.LogLevel level = ModBase.LogLevel.Debug, + LauncherLogLevel level = LauncherLogLevel.Debug, string? title = null, string? userSummary = null) { @@ -49,10 +49,10 @@ public static void Log( WriteExceptionLog(ex, desc, level); - if (LauncherRuntime.IsProgramEnded || level is ModBase.LogLevel.Normal or ModBase.LogLevel.Developer) + if (LauncherRuntime.IsProgramEnded || level is LauncherLogLevel.Normal or LauncherLogLevel.Developer) return; - if (level == ModBase.LogLevel.Debug) + if (level == LauncherLogLevel.Debug) { ShowDebugHint($"{desc}:{ex}"); return; @@ -92,62 +92,62 @@ public static string GetStackTrace() .Replace("\r\n\r\n", "\r\n"); } - private static void WriteTextLog(string text, ModBase.LogLevel level) + private static void WriteTextLog(string text, LauncherLogLevel level) { switch (level) { - case ModBase.LogLevel.Msgbox or ModBase.LogLevel.Hint: + case LauncherLogLevel.Msgbox or LauncherLogLevel.Hint: LogWrapper.Warn(text); break; - case ModBase.LogLevel.Feedback: + case LauncherLogLevel.Feedback: LogWrapper.Error(text); break; - case ModBase.LogLevel.Critical: + case LauncherLogLevel.Critical: LogWrapper.Fatal(text); break; - case ModBase.LogLevel.Debug: + case LauncherLogLevel.Debug: LogWrapper.Debug(text); break; - case ModBase.LogLevel.Developer: + case LauncherLogLevel.Developer: LogWrapper.Trace(text); break; - case ModBase.LogLevel.Normal: + case LauncherLogLevel.Normal: default: LogWrapper.Info(text); break; } } - private static void WriteExceptionLog(Exception ex, string desc, ModBase.LogLevel level) + private static void WriteExceptionLog(Exception ex, string desc, LauncherLogLevel level) { switch (level) { - case ModBase.LogLevel.Msgbox or ModBase.LogLevel.Hint: + case LauncherLogLevel.Msgbox or LauncherLogLevel.Hint: LogWrapper.Warn(ex, desc); break; - case ModBase.LogLevel.Feedback: + case LauncherLogLevel.Feedback: LogWrapper.Error(ex, desc); break; - case ModBase.LogLevel.Critical: + case LauncherLogLevel.Critical: LogWrapper.Fatal(ex, desc); break; - case ModBase.LogLevel.Debug: + case LauncherLogLevel.Debug: LogWrapper.Debug($"{desc}:{ex}"); break; - case ModBase.LogLevel.Developer: + case LauncherLogLevel.Developer: LogWrapper.Trace($"{desc}:{ex}"); break; - case ModBase.LogLevel.Normal: + case LauncherLogLevel.Normal: default: LogWrapper.Error(ex, desc); break; @@ -161,31 +161,31 @@ private static void ShowDebugHint(string message) } private static void ShowUserNotification( - ModBase.LogLevel level, + LauncherLogLevel level, string userMessage, string dialogTitle) { switch (level) { - case ModBase.LogLevel.Hint: + case LauncherLogLevel.Hint: HintService.Hint(userMessage, HintType.Error, false); break; - case ModBase.LogLevel.Msgbox: + case LauncherLogLevel.Msgbox: ModMain.MyMsgBox(userMessage, dialogTitle, isWarn: true); break; - case ModBase.LogLevel.Feedback: + case LauncherLogLevel.Feedback: LauncherFeedbackService.ShowFeedbackPrompt(userMessage, dialogTitle, false); break; - case ModBase.LogLevel.Critical: + case LauncherLogLevel.Critical: LauncherFeedbackService.ShowFeedbackPrompt(userMessage, dialogTitle, true); break; - case ModBase.LogLevel.Normal - or ModBase.LogLevel.Developer - or ModBase.LogLevel.Debug: + case LauncherLogLevel.Normal + or LauncherLogLevel.Developer + or LauncherLogLevel.Debug: default: return; } diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherLogLevel.cs b/Plain Craft Launcher 2/Infrastructure/LauncherLogLevel.cs new file mode 100644 index 000000000..cb1183b09 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherLogLevel.cs @@ -0,0 +1,43 @@ +namespace PCL; + +/// +/// PCL2 用户可见日志等级。LauncherLogLevel 仅保留为旧 API 兼容枚举。 +/// +public enum LauncherLogLevel +{ + /// + /// 不提示,只记录日志。 + /// + Normal = 0, + + /// + /// 只提示开发者。 + /// + Developer = 1, + + /// + /// 只提示开发者与调试模式用户。 + /// + Debug = 2, + + /// + /// 弹出提示所有用户。 + /// + Hint = 3, + + /// + /// 弹窗,不要求反馈。 + /// + Msgbox = 4, + + /// + /// 弹窗,要求反馈。 + /// + Feedback = 5, + + /// + /// 弹出 Windows 原生弹窗,要求反馈。在无法保证 WPF 窗口能正常运行时使用此级别。 + /// 在第二次触发后会直接结束程序。 + /// + Critical = 6 +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs b/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs new file mode 100644 index 000000000..40e13cf23 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs @@ -0,0 +1,35 @@ +using PCL.Core.Utils; + +namespace PCL; + +/// +/// PCL2 数值与旧颜色插值工具。用于替代调用点中的 ModBase 数学 API。 +/// +public static class LauncherMath +{ + public static double Clamp(double value, double min, double max) + { + return NumberUtils.Clamp(value, min, max); + } + + public static double Percent(double valueA, double valueB, double percent) + { + return NumberUtils.Lerp(valueA, valueB, percent); + } + + public static MyColor Percent(MyColor valueA, MyColor valueB, double percent) + { + return Round(valueA * (1d - percent) + valueB * percent, 6); + } + + public static MyColor Round(MyColor color, int digits = 0) + { + return new MyColor + { + a = Math.Round(color.a, digits), + r = Math.Round(color.r, digits), + g = Math.Round(color.g, digits), + b = Math.Round(color.b, digits) + }; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs index ccea566b8..58fe9ea92 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Windows; using PCL.Core.App.Localization; @@ -28,13 +28,13 @@ public static void ShellOnly(string fileName, string arguments = "") { LauncherLog.Log( ex, - "打开文件或程序失败:" + fileName, - ModBase.LogLevel.Msgbox, + $"打开文件或程序失败:{fileName}", + LauncherLogLevel.Msgbox, userSummary: Lang.Text("SystemDialog.File.OpenFailed.Message", fileName)); } } - public static ModBase.ProcessReturnValues ShellAndGetExitCode( + public static LauncherExitCode ShellAndGetExitCode( string fileName, string arguments = "", int timeout = 1000000) @@ -46,15 +46,15 @@ public static ModBase.ProcessReturnValues ShellAndGetExitCode( .CaptureAsync(fileName, arguments, timeout) .GetAwaiter() .GetResult(); - if (result.TimedOut) return ModBase.ProcessReturnValues.Timeout; + if (result.TimedOut) return LauncherExitCode.Timeout; return result.ExitCode.HasValue - ? (ModBase.ProcessReturnValues)result.ExitCode.Value - : ModBase.ProcessReturnValues.Fail; + ? (LauncherExitCode)result.ExitCode.Value + : LauncherExitCode.Fail; } catch (Exception ex) { - LauncherLog.Log(ex, $"执行命令失败:{fileName}", ModBase.LogLevel.Msgbox); - return ModBase.ProcessReturnValues.Fail; + LauncherLog.Log(ex, $"执行命令失败:{fileName}", LauncherLogLevel.Msgbox); + return LauncherExitCode.Fail; } } @@ -115,7 +115,7 @@ public static void OpenExplorer(string location) LauncherLog.Log( ex, "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("SystemDialog.Folder.OpenFailed.Message", location)); } } @@ -142,7 +142,7 @@ public static void ClipboardSet(string text, bool showSuccessHint = true) LauncherLog.Log( finalEx, "剪贴板被占用,文本复制失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Common.Hint.CopyFailed")); } @@ -211,7 +211,7 @@ public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool } catch (Exception ex) { - LauncherLog.Log(ex, "[System] 从剪切板粘贴文件失败", ModBase.LogLevel.Hint); + LauncherLog.Log(ex, "[System] 从剪切板粘贴文件失败", LauncherLogLevel.Hint); } return 0; diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherSearch.cs b/Plain Craft Launcher 2/Infrastructure/LauncherSearch.cs new file mode 100644 index 000000000..0285f0d19 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherSearch.cs @@ -0,0 +1,84 @@ +using CoreSimilaritySearch = PCL.Core.Utils.SimilaritySearch; + +namespace PCL; + +/// +/// PCL2 搜索调用点使用的兼容模型,内部使用 PCL.Core 的相似度搜索实现。 +/// +public static class LauncherSearch +{ + public const int MaxLocalSearchDepth = 25; + + public static List> Search( + List> entries, + string query, + int maxBlurCount = 5, + double minBlurSimilarity = 0.1d) + { + if (entries is null || entries.Count == 0) + return []; + + var coreEntries = entries + .Select((entry, index) => new Core.Utils.SearchEntry<(SearchEntry Entry, int Index)>( + (entry, index), + ToCoreSearchSources(entry.searchSource))) + .ToList(); + + var coreResults = CoreSimilaritySearch.Search(coreEntries, query, maxBlurCount, minBlurSimilarity); + foreach (var coreEntry in coreResults) + { + coreEntry.Item.Entry.absoluteRight = coreEntry.AbsoluteRight; + coreEntry.Item.Entry.similarity = coreEntry.Similarity; + } + + return coreResults.Select(result => result.Item.Entry).ToList(); + } + + private static List> ToCoreSearchSources(IEnumerable sources) + { + var result = new List>(); + if (sources is null) + return result; + + foreach (var source in sources) + { + if (source.aliases is null) + continue; + result.AddRange(source.aliases.Select(alias => new KeyValuePair(alias, source.weight))); + } + + return result; + } +} + +/// +/// 用于搜索的项目。 +/// +public class SearchEntry +{ + public bool absoluteRight; + public T item; + public List searchSource; + public double similarity; +} + +/// +/// 单个用于搜索的文本源。 +/// +public class SearchSource +{ + public string[] aliases; + public double weight; + + public SearchSource(string[] aliases, double weight = 1) + { + this.aliases = aliases; + this.weight = weight; + } + + public SearchSource(string text, double weight = 1) + { + aliases = [text]; + this.weight = weight; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherText.cs b/Plain Craft Launcher 2/Infrastructure/LauncherText.cs new file mode 100644 index 000000000..d3b99fb3d --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherText.cs @@ -0,0 +1,94 @@ +using System.Collections; +using System.Text.RegularExpressions; +using Microsoft.VisualBasic; +using PCL.Core.App.Localization; +using PCL.Core.IO; +using PCL.Core.Utils; +using PCL.Core.Utils.Hash; + +namespace PCL; + +/// +/// PCL2 文本、兼容解析与展示格式化工具。用于替代调用点中的 ModBase 文本相关 API。 +/// +public static class LauncherText +{ + public static char LeftQuote { get; } = Convert.ToChar(8220); + public static char RightQuote { get; } = Convert.ToChar(8221); + + public static string GetStringFromEnum(Enum enumData) + { + return Enum.GetName(enumData.GetType(), enumData) ?? enumData.ToString(); + } + + public static string GetReadableFileSize(long fileSize) + { + return ByteStream.GetReadableLength(fileSize, provider: Lang.Culture); + } + + public static double Val(object? value) + { + try + { + return value is "&" ? 0d : Conversion.Val(value); + } + catch + { + return 0d; + } + } + + public static string StrFill(string str, string code, byte length) + { + return TextUtils.LeftPadOrTrim(str, code, length); + } + + public static object StrTrim(string str, bool removeQuote = true) + { + return TextUtils.TrimDisplayName(str, removeQuote); + } + + public static ulong GetHash(string str) + { + var hash = 5381UL; + for (var i = 0; i < str.Length; i++) + hash = (hash << 5) ^ hash ^ str[i]; + return hash ^ 0xA98F501BC684032FUL; + } + + public static string GetStringMD5(string str) + { + return BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(str).AsSpan()); + } + + public static string EscapeXml(string value) + { + return TextUtils.EscapeXml(value); + } + + public static string EscapeLikePattern(string value) + { + return TextUtils.EscapeLikePattern(value); + } + + public static string RegexReplaceEach(string str, string regex, MatchEvaluator evaluator, + RegexOptions options = RegexOptions.None) + { + return Regex.Replace(str, regex, evaluator, options); + } + + public static List RegexSearch(string str, string regex, RegexOptions options = RegexOptions.None) + { + return Regex.Matches(str, regex, options).Select(match => match.Value).ToList(); + } + + public static List RegexSearch(string str, Regex regex) + { + return regex.Matches(str).Select(match => match.Value).ToList(); + } + + public static List GetFullList(IList data) + { + return CollectionUtils.FlattenMixedList(data); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs index 72c4d9ddf..11ba28977 100644 --- a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs +++ b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Text; using PCL.Core.IO; @@ -60,6 +60,22 @@ public static string ReadText(Stream stream, Encoding? encoding = null) return CoreFiles.ReadAllTextOrEmptyAsync(stream, encoding).GetAwaiter().GetResult(); } + + public static void WriteFile(string filePath, string text, bool append = false, Encoding? encoding = null) + { + WriteText(filePath, text, append, encoding); + } + + public static void WriteFile(string filePath, byte[] content, bool append = false) + { + WriteBytes(filePath, content, append); + } + + public static bool WriteFile(string filePath, Stream stream) + { + return WriteStream(filePath, stream); + } + public static void WriteText(string filePath, string text, bool append = false, Encoding? encoding = null) { CoreFiles.WriteFileAsync(ResolvePath(filePath), text, append, encoding).GetAwaiter().GetResult(); diff --git a/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs b/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs index 345ada84f..a48cd6d7c 100644 --- a/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs +++ b/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.IO; using System.Text; @@ -84,7 +84,7 @@ public void Write(string fileName, string key, string? value) } catch (Exception ex) { - LauncherLog.Log(ex, $"写入文件失败({fileName} → {key}:{value})", ModBase.LogLevel.Hint); + LauncherLog.Log(ex, $"写入文件失败({fileName} → {key}:{value})", LauncherLogLevel.Hint); } } @@ -117,7 +117,7 @@ public void Delete(string fileName, string key) } catch (Exception ex) { - LauncherLog.Log(ex, $"生成 ini 文件缓存失败({fileName})", ModBase.LogLevel.Hint); + LauncherLog.Log(ex, $"生成 ini 文件缓存失败({fileName})", LauncherLogLevel.Hint); return null; } } diff --git a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs index fb65ba210..8fd702211 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs @@ -5,10 +5,10 @@ using System.Windows.Controls; using System.Windows.Media; using PCL.Core.App; +using PCL.Core.App.Localization; using PCL.Core.Utils; using PCL.Network; -using PCL.Core.App.Localization; namespace PCL; public static partial class ModAnimation @@ -35,16 +35,16 @@ public static void AniStart() var minFrameGap = 1000d / (Config.System.AnimationFpsLimit + 1) / 2; - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { try { - ModBase.Log("[Animation] 动画线程开始"); + LauncherLog.Log("[Animation] 动画线程开始"); while (true) { // 两帧之间的间隔时间 var deltaTime = - (long)Math.Round(ModBase.MathClamp(TimeUtils.GetTimeTick() - aniLastTick, 0, 100000)); + (long)Math.Round(LauncherMath.Clamp(TimeUtils.GetTimeTick() - aniLastTick, 0, 100000)); if (deltaTime < minFrameGap) { // 限制 FPS @@ -54,9 +54,9 @@ public static void AniStart() aniLastTick = TimeUtils.GetTimeTick(); // 记录 FPS - if (ModBase.ModeDebug) + if (LauncherRuntime.ModeDebug) { - if (ModBase.MathClamp(aniLastTick - aniFPSTimer, 0d, 100000d) >= 500d) + if (LauncherMath.Clamp(aniLastTick - aniFPSTimer, 0d, 100000d) >= 500d) { aniFPS = aniFPSCounter; aniFPSCounter = 0; @@ -67,7 +67,7 @@ public static void AniStart() } // 执行动画 - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { aniCount = 0; AniTimer((int)Math.Round(deltaTime * aniSpeed)); @@ -76,11 +76,10 @@ public static void AniStart() // #Else // If ModeDebug Then FrmMain.Title = "FPS " & AniFPS & ", 动画 " & AniCount & ", 下载中 " & NetManage.FileRemain // #End If - if (RandomUtils.NextInt(0, 64 * (ModBase.ModeDebug ? 5 : 30)) == 0 && + if (RandomUtils.NextInt(0, 64 * (LauncherRuntime.ModeDebug ? 5 : 30)) == 0 && ((aniFPS < 62 && aniFPS > 0) || aniCount > 4 || ModNet.NetManager.FileRemain != 0)) - ModBase.Log("[Report] FPS " + aniFPS + ", 动画 " + aniCount + ", 下载中 " + - ModNet.NetManager.FileRemain + "(" + - ModBase.GetString(ModNet.NetManager.Speed) + "/s)"); + LauncherLog.Log( + $"[Report] FPS {aniFPS}, 动画 {aniCount}, 下载中 {ModNet.NetManager.FileRemain}({LauncherText.GetReadableFileSize(ModNet.NetManager.Speed)}/s)"); }); } } @@ -89,10 +88,10 @@ public static void AniStart() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "动画帧执行失败", - ModBase.LogLevel.Critical, + LauncherLogLevel.Critical, userSummary: Lang.Text("Application.Animation.Error.OperationFailed")); } }, "Animation", ThreadPriority.AboveNormal); @@ -106,7 +105,7 @@ public static void AniTimer(int deltaTick) try { if (deltaTick / aniSpeed > 100d) - ModBase.Log("[Animation] 两个动画帧间隔 " + deltaTick + " ms", ModBase.LogLevel.Developer); + LauncherLog.Log($"[Animation] 两个动画帧间隔 {deltaTick} ms", LauncherLogLevel.Developer); var i = -1; // 循环每个动画组 while (i + 1 < aniGroups.Count) @@ -189,10 +188,10 @@ public static void AniTimer(int deltaTick) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "动画刻执行失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Animation.Error.OperationFailed")); } } @@ -209,24 +208,24 @@ private static AniData AniRun(AniData ani) { case AniType.Number: { - var delta = ModBase.MathPercent(0d, (double)ani.value, + var delta = LauncherMath.Percent(0d, (double)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)); if (delta != 0d) switch (ani.typeSub) { case AniTypeSub.X: { - ModBase.DeltaLeft((FrameworkElement)ani.obj, delta); + LayoutExtensions.DeltaLeft((FrameworkElement)ani.obj, delta); break; } case AniTypeSub.Y: { - ModBase.DeltaTop((FrameworkElement)ani.obj, delta); + LayoutExtensions.DeltaTop((FrameworkElement)ani.obj, delta); break; } case AniTypeSub.Opacity: { - ((dynamic)ani.obj).Opacity = ModBase.MathClamp( + ((dynamic)ani.obj).Opacity = LauncherMath.Clamp( Convert.ToDouble(((dynamic)ani.obj).Opacity) + delta, 0d, 1d); break; } @@ -310,14 +309,14 @@ private static AniData AniRun(AniData ani) case AniType.Color: { // 利用 Last 记录了余下的小数值 - var delta = ModBase.MathPercent(new ModBase.MyColor(0d, 0d, 0d, 0d), (ModBase.MyColor)ani.value, + var delta = LauncherMath.Percent(new MyColor(0d, 0d, 0d, 0d), (MyColor)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)) + - (ModBase.MyColor)ani.valueLast; + (MyColor)ani.valueLast; var obj = (FrameworkElement)((dynamic)ani.obj)[0]; var prop = (DependencyProperty)((dynamic)ani.obj)[1]; - var newColor = new ModBase.MyColor(obj.GetValue(prop)) + delta; + var newColor = new MyColor(obj.GetValue(prop)) + delta; obj.SetValue(prop, prop.PropertyType.Name == "Color" ? (Color)newColor : (SolidColorBrush)newColor); - ani.valueLast = newColor - new ModBase.MyColor(obj.GetValue(prop)); + ani.valueLast = newColor - new MyColor(obj.GetValue(prop)); break; } @@ -327,17 +326,18 @@ private static AniData AniRun(AniData ani) var delta = ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent); obj.Margin = new Thickness( obj.Margin.Left + - ModBase.MathPercent(0d, Convert.ToDouble(((dynamic)ani.value).Left), delta), - obj.Margin.Top + ModBase.MathPercent(0d, Convert.ToDouble(((dynamic)ani.value).Top), delta), + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Left), delta), + obj.Margin.Top + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Top), delta), obj.Margin.Right + - ModBase.MathPercent(0d, Convert.ToDouble(((dynamic)ani.value).Left), delta), + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Left), delta), obj.Margin.Bottom + - ModBase.MathPercent(0d, Convert.ToDouble(((dynamic)ani.value).Top), delta)); + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Top), delta)); obj.Width = Math.Max( - obj.Width + ModBase.MathPercent(0d, Convert.ToDouble(((dynamic)ani.value).Width), delta), 0d); + obj.Width + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Width), delta), 0d); obj.Height = Math.Max( - obj.Height + ModBase.MathPercent(0d, Convert.ToDouble(((dynamic)ani.value).Height), delta), 0d); + obj.Height + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Height), delta), + 0d); break; } @@ -392,7 +392,7 @@ private static AniData AniRun(AniData ani) obj.RenderTransform = new ScaleTransform(1d, 1d); } - var delta = ModBase.MathPercent(0d, (double)ani.value, + var delta = LauncherMath.Percent(0d, (double)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)); ((ScaleTransform)obj.RenderTransform).ScaleX = Math.Max(((ScaleTransform)obj.RenderTransform).ScaleX + delta, 0d); @@ -410,7 +410,7 @@ private static AniData AniRun(AniData ani) obj.RenderTransform = new RotateTransform(0d); } - var delta = ModBase.MathPercent(0d, (double)ani.value, + var delta = LauncherMath.Percent(0d, (double)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)); ((RotateTransform)obj.RenderTransform).Angle = ((RotateTransform)obj.RenderTransform).Angle + delta; break; @@ -421,10 +421,10 @@ private static AniData AniRun(AniData ani) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, - "执行动画失败:" + ani, - ModBase.LogLevel.Hint, + $"执行动画失败:{ani}", + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Animation.Error.OperationFailed")); } @@ -447,7 +447,7 @@ public class AniGroupEntry { public List data; public long startTick; - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); } /// @@ -549,9 +549,8 @@ public struct AniData public override string ToString() { - return ModBase.GetStringFromEnum(typeMain) + " | " + timeFinished + "/" + timeTotal + "(" + - Math.Round(timePercent * 100d) + "%)" + - (obj is null ? "" : " | " + obj + "(" + obj.GetType().Name + ")"); + return + $"{LauncherText.GetStringFromEnum(typeMain)} | {timeFinished}/{timeTotal}({Math.Round(timePercent * 100d)}%){(obj is null ? "" : $" | {obj}({obj.GetType().Name})")}"; } } @@ -953,14 +952,20 @@ public static AniData AaDouble(ParameterizedThreadStart lambda, double value, in /// 是否等到以前的动画完成后才继续本动画。 /// /// - public static AniData AaColor(FrameworkElement obj, DependencyProperty prop, ModBase.MyColor value, int time = 400, - int delay = 0, AniEase ease = null, bool after = false) + public static AniData AaColor( + FrameworkElement obj, + DependencyProperty prop, + MyColor value, + int time = 400, + int delay = 0, + AniEase ease = null, + bool after = false) { return new AniData { typeMain = AniType.Color, timeTotal = time, ease = ease ?? new AniEaseLinear(), obj = new object[] { obj, prop, "" }, value = value, isAfter = after, timeFinished = -delay, - valueLast = new ModBase.MyColor(0d, 0d, 0d, 0d) + valueLast = new MyColor(0d, 0d, 0d, 0d) }; } @@ -983,9 +988,9 @@ public static AniData AaColor(FrameworkElement obj, DependencyProperty prop, str { typeMain = AniType.Color, timeTotal = time, ease = ease ?? new AniEaseLinear(), obj = new object[] { obj, prop, res }, - value = new ModBase.MyColor(System.Windows.Application.Current.FindResource(res)) - - new ModBase.MyColor(obj.GetValue(prop)), - isAfter = after, timeFinished = -delay, valueLast = new ModBase.MyColor(0d, 0d, 0d, 0d) + value = new MyColor(System.Windows.Application.Current.FindResource(res)) - + new MyColor(obj.GetValue(prop)), + isAfter = after, timeFinished = -delay, valueLast = new MyColor(0d, 0d, 0d, 0d) }; } @@ -1006,11 +1011,11 @@ public static AniData AaColor(FrameworkElement obj, DependencyProperty prop, str public static AniData AaScale(object obj, double value, int time = 400, int delay = 0, AniEase ease = null, bool after = false, bool absolute = false) { - ModBase.MyRect changeRect; + MyRect changeRect; if (absolute) - changeRect = new ModBase.MyRect(-0.5d * value, -0.5d * value, value, value); + changeRect = new MyRect(-0.5d * value, -0.5d * value, value, value); else - changeRect = new ModBase.MyRect( + changeRect = new MyRect( Convert.ToDouble(-0.5d * ((dynamic)obj).ActualWidth * value), Convert.ToDouble(-0.5d * ((dynamic)obj).ActualHeight * value), Convert.ToDouble(((dynamic)obj).ActualWidth * value), @@ -1259,12 +1264,12 @@ public class AniEaseLinear : AniEase { public override double GetValue(double t) { - return ModBase.MathClamp(t, 0d, 1d); + return LauncherMath.Clamp(t, 0d, 1d); } public override double GetDelta(double t1, double t0) { - return ModBase.MathClamp(t1, 0d, 1d) - ModBase.MathClamp(t0, 0d, 1d); + return LauncherMath.Clamp(t1, 0d, 1d) - LauncherMath.Clamp(t0, 0d, 1d); } } @@ -1283,7 +1288,7 @@ public AniEaseInFluent(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - return Math.Pow(ModBase.MathClamp(t, 0d, 1d), (double)p); + return Math.Pow(LauncherMath.Clamp(t, 0d, 1d), (double)p); } } @@ -1301,7 +1306,7 @@ public AniEaseOutFluent(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - return 1d - Math.Pow(ModBase.MathClamp(1d - t, 0d, 1d), (double)p); + return 1d - Math.Pow(LauncherMath.Clamp(1d - t, 0d, 1d), (double)p); } } @@ -1343,7 +1348,7 @@ public AniEaseOutFluentWithInitial(double initialPixelPerSecond, double totalSec public override double GetValue(double percent) { - var p = ModBase.MathClamp(percent, 0d, 1d); + var p = LauncherMath.Clamp(percent, 0d, 1d); if (alpha == 0d) return p; // 退化到线性 return (alpha + 1d) * p / (1d + alpha * p); @@ -1365,7 +1370,7 @@ public AniEaseInBack(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - t = ModBase.MathClamp(t, 0d, 1d); + t = LauncherMath.Clamp(t, 0d, 1d); return Math.Pow(t, p) * Math.Cos(1.5d * Math.PI * (1d - t)); } } @@ -1384,7 +1389,7 @@ public AniEaseOutBack(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - t = ModBase.MathClamp(t, 0d, 1d); + t = LauncherMath.Clamp(t, 0d, 1d); return 1d - Math.Pow(1d - t, p) * Math.Cos(1.5d * Math.PI * t); } } @@ -1441,7 +1446,7 @@ public AniEaseInElastic(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - t = ModBase.MathClamp(t, 0d, 1d); + t = LauncherMath.Clamp(t, 0d, 1d); return Math.Pow(t, (p - 1) * 0.25d) * Math.Cos((p - 3.5d) * Math.PI * Math.Pow(1d - t, 1.5d)); } } @@ -1460,7 +1465,7 @@ public AniEaseOutElastic(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - t = 1d - ModBase.MathClamp(t, 0d, 1d); + t = 1d - LauncherMath.Clamp(t, 0d, 1d); return 1d - Math.Pow(t, (p - 1) * 0.25d) * Math.Cos((p - 3.5d) * Math.PI * Math.Pow(1d - t, 1.5d)); } } @@ -1480,7 +1485,10 @@ public static void AniStart(IList aniGroup, string name = "", bool refreshTime = aniLastTick = TimeUtils.GetTimeTick(); // 避免处理动画时已经造成了极大的延迟,导致动画突然结束 // 添加到正在执行的动画组 var newEntry = new AniGroupEntry - { data = ModBase.GetFullList(aniGroup), startTick = TimeUtils.GetTimeTick() }; + { + data = LauncherText.GetFullList(aniGroup), + startTick = TimeUtils.GetTimeTick() + }; if (string.IsNullOrEmpty(name)) name = newEntry.Uuid.ToString(); else diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.cs b/Plain Craft Launcher 2/Modules/Base/ModLoader.cs index 16ec2d13f..56cc805e1 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModLoader.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.cs @@ -1,13 +1,11 @@ -using Microsoft.VisualBasic.CompilerServices; +using System.IO; +using System.Windows.Shell; +using Microsoft.VisualBasic.CompilerServices; using PCL.Core.App; +using PCL.Core.App.Localization; using PCL.Core.Utils; -using System.Collections; -using System.IO; -using System.Windows.Shell; using PCL.Network; -using PCL.Network.Loaders; -using PCL.Core.App.Localization; namespace PCL; public static class ModLoader @@ -20,7 +18,7 @@ public enum LoaderFolderRunType } // 任务栏进度条 - public static ModBase.SafeList loaderTaskbar = new(); + public static SafeList loaderTaskbar = new(); public static double loaderTaskbarProgress; // 平滑后的进度 private static TaskbarItemProgressState loaderTaskbarProgressLast = TaskbarItemProgressState.None; @@ -32,7 +30,7 @@ public static void LoaderTaskbarAdd(LoaderCombo loader) if (ModMain.frmSpeedLeft is not null) ModMain.frmSpeedLeft.TaskRemove(loader); loaderTaskbar.Add(loader); - ModBase.Log($"[Taskbar] {loader.name} 已加入任务列表"); + LauncherLog.Log($"[Taskbar] {loader.name} 已加入任务列表"); } public static void LoaderTaskbarProgressRefresh() @@ -43,12 +41,12 @@ public static void LoaderTaskbarProgressRefresh() var newProgress = LoaderTaskbarProgressGet(); // 若单个任务已中止,或全部任务已完成,则刷新并移除 foreach (var Task in loaderTaskbar) - if (loaderTaskbar.All(l => l.State != ModBase.LoadState.Loading) || - Task.State == ModBase.LoadState.Waiting || Task.State == ModBase.LoadState.Aborted) + if (loaderTaskbar.All(l => l.State != LoadState.Loading) || + Task.State == LoadState.Waiting || Task.State == LoadState.Aborted) { ModMain.frmSpeedLeft?.TaskRefresh(Task); loaderTaskbar.Remove(Task); - ModBase.Log($"[Taskbar] {Task.name} 已移出任务列表"); + LauncherLog.Log($"[Taskbar] {Task.name} 已移出任务列表"); } // 更新平滑后的进度 @@ -56,7 +54,7 @@ public static void LoaderTaskbarProgressRefresh() loaderTaskbarProgress = newProgress; else loaderTaskbarProgress = loaderTaskbarProgress * 0.9d + newProgress * 0.1d; - ModBase.RunInUi(() => ModMain.frmMain.BtnExtraDownload.Progress = loaderTaskbarProgress); + UiThread.Post(() => ModMain.frmMain.BtnExtraDownload.Progress = loaderTaskbarProgress); // 更新任务栏信息 if (!loaderTaskbar.Any() || loaderTaskbarProgress == 1d) { @@ -81,10 +79,10 @@ public static void LoaderTaskbarProgressRefresh() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "刷新任务栏进度显示失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Application.Loader.Error.OperationFailed")); } } @@ -96,7 +94,7 @@ public static double LoaderTaskbarProgressGet() if (!loaderTaskbar.Any()) return 1d; - return ModBase.MathClamp( + return LauncherMath.Clamp( loaderTaskbar.Select(l => l.Progress).Average(), 0, 1 @@ -104,10 +102,10 @@ public static double LoaderTaskbarProgressGet() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "获取任务栏进度出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Application.Loader.Error.OperationFailed")); return 0.5d; } @@ -146,7 +144,7 @@ public static bool LoaderFolderRun(LoaderBase loader, string folderPath, LoaderF } catch (Exception ex) { - ModBase.Log(ex, "文件夹加载器启动检测出错"); + LauncherLog.Log(ex, "文件夹加载器启动检测出错"); } // 写入检查数据 @@ -181,11 +179,11 @@ private static DateTime GetActualLastWriteTimeUtc(DirectoryInfo folderInfo, int /// public abstract class LoaderBase : ILoadingTrigger { - public delegate void OnStateChangedThreadEventHandler(LoaderBase loader, ModBase.LoadState newState, - ModBase.LoadState oldState); + public delegate void OnStateChangedThreadEventHandler(LoaderBase loader, LoadState newState, + LoadState oldState); - public delegate void OnStateChangedUiEventHandler(LoaderBase loader, ModBase.LoadState newState, - ModBase.LoadState oldState); + public delegate void OnStateChangedUiEventHandler(LoaderBase loader, LoadState newState, + LoadState oldState); public delegate void PreviewFinishEventHandler(LoaderBase loader); @@ -231,7 +229,7 @@ public delegate void OnStateChangedUiEventHandler(LoaderBase loader, ModBase.Loa /// /// 加载器的标识编号。 /// - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); public LoaderBase() { @@ -254,10 +252,10 @@ public LoaderBase RealParent } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, - "获取父加载器失败(" + name + ")", - ModBase.LogLevel.Feedback, + $"获取父加载器失败({name})", + LauncherLogLevel.Feedback, userSummary: Lang.Text("Application.Loader.Error.OperationFailed")); return null; } @@ -278,7 +276,7 @@ public Action OnStateChanged /// /// 加载器的状态。 /// - public ModBase.LoadState State + public LoadState State { get => field; set @@ -286,21 +284,21 @@ public ModBase.LoadState State if (field == value) return; var oldState = field; - if (value == ModBase.LoadState.Finished && Config.Debug.AddRandomDelay) + if (value == LoadState.Finished && Config.Debug.AddRandomDelay) Thread.Sleep(RandomUtils.NextInt(100, 2000)); field = value; - ModBase.Log("[Loader] 加载器 " + name + " 状态改变:" + ModBase.GetStringFromEnum(value)); + LauncherLog.Log($"[Loader] 加载器 {name} 状态改变:{LauncherText.GetStringFromEnum(value)}"); // 实现 ILoadingTrigger 接口与 OnStateChanged 回调 - ModBase.RunInUi(() => + UiThread.Post(() => { switch (value) { - case ModBase.LoadState.Loading: + case LoadState.Loading: { LoadingState = MyLoading.MyLoadingState.Run; break; } - case ModBase.LoadState.Failed: + case LoadState.Failed: { LoadingState = MyLoading.MyLoadingState.Error; break; @@ -316,9 +314,9 @@ public ModBase.LoadState State OnStateChangedUi?.Invoke(this, value, oldState); }); if (hasOnStateChangedThread) - ModBase.RunInThread(() => OnStateChangedThread?.Invoke(this, value, oldState)); + UiThread.RunInThread(() => OnStateChangedThread?.Invoke(this, value, oldState)); } - } = ModBase.LoadState.Waiting; + } = LoadState.Waiting; /// /// 若加载器出错,可提供给外部参考的异常。 @@ -335,11 +333,11 @@ public virtual double Progress { switch (State) { - case ModBase.LoadState.Waiting: + case LoadState.Waiting: { return 0d; } - case ModBase.LoadState.Loading: + case LoadState.Loading: { return field == -1 ? 0.02d : field; } @@ -421,28 +419,22 @@ public void WaitForExit(object input = null, LoaderBase loaderToSyncProgress = n bool isForceRestart = false) { Start(input, isForceRestart); - while (State == ModBase.LoadState.Loading) + while (State == LoadState.Loading) { if (loaderToSyncProgress is not null) loaderToSyncProgress.Progress = Progress; Thread.Sleep(10); } - if (State == ModBase.LoadState.Finished) - { - } - else if (State == ModBase.LoadState.Aborted) - { - throw new ThreadInterruptedException("加载器执行已中断。"); - } - else if (Error is null) - { - throw new Exception("未知错误!"); - } - else + if (State == LoadState.Finished) + return; + + throw State switch { - throw new Exception(Error.Message, Error); - } // 保留调用堆栈,同时不影响信息输出与单元测试 + LoadState.Aborted => new ThreadInterruptedException("加载器执行已中断。"), + _ when Error is null => new Exception("未知错误!"), + _ => new Exception(Error.Message, Error) + }; // 保留调用堆栈,同时不影响信息输出与单元测试 } /// @@ -454,7 +446,7 @@ public void WaitForExitTime(int timeout, object input = null, string timeoutMess object loaderToSyncProgress = null, bool isForceRestart = false) { Start(input, isForceRestart); - while (State == ModBase.LoadState.Loading) + while (State == LoadState.Loading) { if (loaderToSyncProgress is not null) ((dynamic)loaderToSyncProgress).Progress = Progress; @@ -464,21 +456,15 @@ public void WaitForExitTime(int timeout, object input = null, string timeoutMess throw new TimeoutException(timeoutMessage); } - if (State == ModBase.LoadState.Finished) - { - } - else if (State == ModBase.LoadState.Aborted) - { - throw new ThreadInterruptedException("加载器执行已中断。"); - } - else if (Error is null) - { - throw new Exception("未知错误!"); - } - else + if (State == LoadState.Finished) + return; + + throw State switch { - throw Error; - } + LoadState.Aborted => new ThreadInterruptedException("加载器执行已中断。"), + _ when Error is null => new Exception("未知错误!"), + _ => Error + }; } // 相同重载 @@ -519,7 +505,7 @@ public abstract class LoaderTask : LoaderBase public bool IsAbortedWithThread(int compareTaskId) { return lastRunningTask is null || compareTaskId != lastRunningTask.Id || - State == ModBase.LoadState.Aborted; + State == LoadState.Aborted; } public abstract bool ShouldStart(ref object? input, bool isForceRestart = false, bool ignoreReloadTimeout = false); @@ -562,7 +548,7 @@ public LoaderTask(string name, Action> loadDel // 按照龙猫的逻辑,此处将 input 与默认值直接进行等价比较,若相等则认为 input 未传入具体值,而调用 inputDelegate 获取 // 这种逻辑未考虑值类型恰好传入 default 值 (如 double 传了 0.0) 的情况,这是一个陷阱,可能会产生 undefined behavior if (EqualityComparer.Default.Equals(input, default) && inputDelegate is not null) - ModBase.RunInUiWait(() => input = inputDelegate()); + UiThread.Invoke(() => input = inputDelegate()); return input; } @@ -581,31 +567,32 @@ public override bool ShouldStart(ref object? input, bool isForceRestart = false, } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, - "加载输入获取失败(" + name + ")", - ModBase.LogLevel.Hint, + $"加载输入获取失败({name})", + LauncherLogLevel.Hint, userSummary: Lang.Text("Application.Loader.Error.OperationFailed")); Error = ex; lock (lockState) { - State = ModBase.LoadState.Failed; + State = LoadState.Failed; } } // 检验输入以确定情况 if (isForceRestart) - return true; // 强制要求重启 - if (input is null != this.input is null || (input is not null && !input.Equals(this.input))) - return true; // 输入不同 - if ((State == ModBase.LoadState.Loading || State == ModBase.LoadState.Finished) && (ignoreReloadTimeout || - reloadTimeout == -1 || lastFinishedTime == 0L || - TimeUtils.GetTimeTick() - lastFinishedTime < reloadTimeout)) // 正在加载或已结束 - // 没有超时 - return false; // 则不重试 - - return true; - // 需要开始 + return true; + + if (!Equals(input, this.input)) + return true; + + var isStateReloadable = State is not (LoadState.Loading or LoadState.Finished); + var isReloadTimedOut = !ignoreReloadTimeout + && reloadTimeout != -1 + && lastFinishedTime != 0L + && TimeUtils.GetTimeTick() - lastFinishedTime >= reloadTimeout; + + return isStateReloadable || isReloadTimedOut; } public override void Start(object input = null, bool isForceRestart = false) @@ -614,12 +601,12 @@ public override void Start(object input = null, bool isForceRestart = false) if (ShouldStart(ref input, isForceRestart)) { // 输入不同或失败,开始加载 - if (State == ModBase.LoadState.Loading) + if (State == LoadState.Loading) TriggerThreadAbort(); this.input = Conversions.ToGenericParameter(input); lock (lockState) { - State = ModBase.LoadState.Loading; + State = LoadState.Loading; Progress = -1; } } @@ -632,46 +619,46 @@ public override void Start(object input = null, bool isForceRestart = false) try { isForceRestarting = isForceRestart; - if (ModBase.ModeDebug) - ModBase.Log( + if (LauncherRuntime.ModeDebug) + LauncherLog.Log( $"[Loader] 加载线程 {name} ({Task.CurrentId}) 已{(isForceRestarting ? "强制" : "")}启动"); loadDelegate(this); if (IsAborted) { - ModBase.Log( + LauncherLog.Log( $"[Loader] 加载线程 {name} ({Task.CurrentId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{(lastRunningTask is null ? -1 : lastRunningTask.Id)})", - ModBase.LogLevel.Developer); + LauncherLogLevel.Developer); return; } - if (ModBase.ModeDebug) - ModBase.Log($"[Loader] 加载线程 {name} ({Task.CurrentId}) 已完成"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log($"[Loader] 加载线程 {name} ({Task.CurrentId}) 已完成"); RaisePreviewFinish(); - State = ModBase.LoadState.Finished; + State = LoadState.Finished; lastFinishedTime = TimeUtils.GetTimeTick(); } - catch (ModBase.CancelledException ex) + catch (CancelledException ex) { - if (ModBase.ModeDebug) - ModBase.Log(ex, + if (LauncherRuntime.ModeDebug) + LauncherLog.Log(ex, $"加载线程 {name} ({Task.CurrentId}) 已触发取消中断,已完成 {Math.Round(Progress * 100d)}%"); - if (!IsAborted) State = ModBase.LoadState.Aborted; + if (!IsAborted) State = LoadState.Aborted; } catch (ThreadInterruptedException ex) { - if (ModBase.ModeDebug) - ModBase.Log(ex, + if (LauncherRuntime.ModeDebug) + LauncherLog.Log(ex, $"加载线程 {name} ({Task.CurrentId}) 已触发线程中断,已完成 {Math.Round(Progress * 100d)}%"); - if (!IsAborted) State = ModBase.LoadState.Aborted; + if (!IsAborted) State = LoadState.Aborted; } catch (Exception ex) { if (IsAborted) return; - ModBase.Log(ex, + LauncherLog.Log(ex, $"加载线程 {name} ({Task.CurrentId}) 出错,已完成 {Math.Round(Progress * 100d)}%", - ModBase.LogLevel.Developer); + LauncherLogLevel.Developer); Error = ex; - State = ModBase.LoadState.Failed; + State = LoadState.Failed; } }, (cancelToken ??= new CancellationTokenSource()).Token); // 未中断,本次输出有效 // LastRunningTask.Start(); // 不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted @@ -679,11 +666,11 @@ public override void Start(object input = null, bool isForceRestart = false) public override void Abort() { - if (State != ModBase.LoadState.Loading) + if (State != LoadState.Loading) return; lock (lockState) { - State = ModBase.LoadState.Aborted; + State = LoadState.Aborted; } TriggerThreadAbort(); @@ -692,7 +679,7 @@ public override void Abort() private void TriggerThreadAbort() { if (lastRunningTask is null) return; - if (ModBase.ModeDebug) ModBase.Log($"[Loader] 加载线程 {name} ({lastRunningTask.Id}) 已中断"); + if (LauncherRuntime.ModeDebug) LauncherLog.Log($"[Loader] 加载线程 {name} ({lastRunningTask.Id}) 已中断"); if (!lastRunningTask.IsCompleted) cancelToken?.Cancel(); lastRunningTask = null; cancelToken = null; @@ -729,11 +716,11 @@ public override double Progress { switch (State) { - case ModBase.LoadState.Waiting: + case LoadState.Waiting: { return 0d; } - case ModBase.LoadState.Loading: + case LoadState.Loading: { var total = 0d; var finished = 0d; @@ -769,24 +756,24 @@ public override void Start(object input = null, bool isForceRestart = false) isForceRestarting = isForceRestart; lock (lockState) { - if (State == ModBase.LoadState.Loading) return; + if (State == LoadState.Loading) return; - State = ModBase.LoadState.Loading; + State = LoadState.Loading; } // 启动加载 this.input = input; if (isForceRestart) foreach (var Loader in loaders) - Loader.State = ModBase.LoadState.Waiting; - ModBase.RunInThread(Update); + Loader.State = LoadState.Waiting; + UiThread.RunInThread(Update); } public override void Abort() { lock (lockState) { - if (State != ModBase.LoadState.Loading && State != ModBase.LoadState.Waiting) + if (State != LoadState.Loading && State != LoadState.Waiting) return; } @@ -794,36 +781,36 @@ public override void Abort() lock (lockState) { - if (State == ModBase.LoadState.Loading || State == ModBase.LoadState.Waiting) - State = ModBase.LoadState.Aborted; + if (State == LoadState.Loading || State == LoadState.Waiting) + State = LoadState.Aborted; } } /// /// 子任务状态变更。 /// - private void SubTaskStateChanged(LoaderBase loader, ModBase.LoadState newState, ModBase.LoadState oldState) + private void SubTaskStateChanged(LoaderBase loader, LoadState newState, LoadState oldState) { switch (newState) { - case ModBase.LoadState.Loading: + case LoadState.Loading: { break; } // 开始,啥都不干 - case ModBase.LoadState.Waiting: + case LoadState.Waiting: { break; } // 子加载器可能由于外部输入改变而暂时变为 Waiting,之后会立即重新启动 // 所以啥都不干就行 - case ModBase.LoadState.Finished: + case LoadState.Finished: { // 正常结束,触发刷新 Update(); break; } - case ModBase.LoadState.Aborted: + case LoadState.Aborted: { // 被中断,这个任务也中断 Abort(); @@ -835,7 +822,7 @@ private void SubTaskStateChanged(LoaderBase loader, ModBase.LoadState newState, // 完蛋,出错了 lock (lockState) { - if (State >= ModBase.LoadState.Finished) + if (State >= LoadState.Finished) return; Error = new Exception(loader.name + "失败", loader.Error); State = loader.State; @@ -858,9 +845,7 @@ private void SubTaskStateChanged(LoaderBase loader, ModBase.LoadState newState, /// private void Update() { - if (State == ModBase.LoadState.Finished - || State == ModBase.LoadState.Failed - || State == ModBase.LoadState.Aborted) + if (State is LoadState.Finished or LoadState.Failed or LoadState.Aborted) return; var isFinished = true; @@ -870,7 +855,7 @@ private void Update() foreach (var loader in loaders) switch (loader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: { if (loader is LoaderTask task) { @@ -881,7 +866,7 @@ private void Update() if (task.ShouldStart(ref shouldInput, false, true)) { - ModBase.Log("[Loader] 由于输入条件变更,重启已完成的加载器 " + loader.name); + LauncherLog.Log("[Loader] 由于输入条件变更,重启已完成的加载器 " + loader.name); goto Restart; } @@ -894,7 +879,7 @@ private void Update() break; } - case ModBase.LoadState.Loading: + case LoadState.Loading: { if (loader is LoaderTask task) { @@ -904,8 +889,8 @@ private void Update() : null; if (task.ShouldStart(ref shouldInput, false, true)) { - ModBase.Log($"[Loader] 由于输入条件变更,重启进行中的加载器 {loader.name}", - ModBase.LogLevel.Developer); + LauncherLog.Log($"[Loader] 由于输入条件变更,重启进行中的加载器 {loader.name}", + LauncherLogLevel.Developer); goto Restart; } } @@ -959,7 +944,7 @@ private void Update() if (isFinished) { RaisePreviewFinish(); - State = ModBase.LoadState.Finished; + State = LoadState.Finished; ModMain.frmMain.BtnExtraDownload.ShowRefresh(); } } diff --git a/Plain Craft Launcher 2/Modules/Base/ModSetup.cs b/Plain Craft Launcher 2/Modules/Base/ModSetup.cs index 0527b5a05..38bf30d6b 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModSetup.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModSetup.cs @@ -4,12 +4,12 @@ using System.Windows.Media.Effects; using PCL.Core.App; using PCL.Core.App.Configuration; +using PCL.Core.App.Localization; using PCL.Core.IO.Net.Http; using PCL.Core.UI.Theme; using PCL.Core.Utils.Exts; using PCL.Network; -using PCL.Core.App.Localization; namespace PCL; public class ModSetup @@ -171,14 +171,15 @@ public static void ApplyAll() // 切换选择 public static void LaunchInstanceSelect(string value) { - ModBase.Log("[Setup] 当前选择的 Minecraft 版本:" + value); - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "Version", value); + LauncherLog.Log($"[Setup] 当前选择的 Minecraft 版本:{value}"); + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", value); } public static void LaunchFolderSelect(string value) { - ModBase.Log("[Setup] 当前选择的 Minecraft 文件夹:" + value.Replace("$", ModBase.exePath)); - ModFolder.mcFolderSelected = value.Replace("$", ModBase.exePath); + LauncherLog.Log( + $"[Setup] 当前选择的 Minecraft 文件夹:{value.Replace("$", LauncherPaths.ExecutableDirectoryWithSlash)}"); + ModFolder.mcFolderSelected = value.Replace("$", LauncherPaths.ExecutableDirectoryWithSlash); } // 游戏内存 @@ -370,14 +371,14 @@ public static void UiFont(string value) { try { - ModBase.SetLaunchFont(value); + LauncherFontService.SetLaunchFont(value); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "字体加载失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Setup.Error.OperationFailed")); } } @@ -540,15 +541,16 @@ public static void UiLogoType(int value) try { - ModMain.frmMain.ImageTitleLogo.Source = ModBase.exePath + @"PCL\Logo.png"; + ModMain.frmMain.ImageTitleLogo.Source = + LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"; } catch (Exception ex) { ModMain.frmMain.ImageTitleLogo.Source = null; - ModBase.Log( + LauncherLog.Log( ex, "显示标题栏图片失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Error.OperationFailed")); } @@ -594,14 +596,14 @@ public static void UiLogoLeft(bool value) // 调试选项 public static void SystemDebugMode(bool value) { - ModBase.ModeDebug = value; + LauncherRuntime.ModeDebug = value; } public static void SystemDebugAnim(int value) { ModAnimation.aniSpeed = value >= 30 ? 200d - : ModBase.MathClamp(value * 0.1d + 0.1d, 0.1d, 3d); + : LauncherMath.Clamp(value * 0.1d + 0.1d, 0.1d, 3d); } public static void SystemHttpProxy(string value) @@ -613,7 +615,7 @@ public static void SystemHttpProxy(string value) } catch (Exception ex) { - ModBase.Log(ex, "HTTP 代理应用出错"); + LauncherLog.Log(ex, "HTTP 代理应用出错"); } } @@ -664,7 +666,7 @@ public static void VersionServerLogin(int type) if (ModMain.frmInstanceSetup is null) return; // 为第三方登录清空缓存以更新描述 - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); if (PageInstanceLeft.McInstance is null) return; PageInstanceLeft.McInstance = new McInstance(PageInstanceLeft.McInstance.Name).Load(); diff --git a/Plain Craft Launcher 2/Modules/Base/MyBitmap.cs b/Plain Craft Launcher 2/Modules/Base/MyBitmap.cs index 077c9133c..ca21ba75d 100644 --- a/Plain Craft Launcher 2/Modules/Base/MyBitmap.cs +++ b/Plain Craft Launcher 2/Modules/Base/MyBitmap.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; @@ -34,8 +34,8 @@ public MyBitmap(string filePathOrResourceName) try { filePathOrResourceName = - filePathOrResourceName.Replace("pack://application:,,,/images/", ModBase.pathImage); - if (filePathOrResourceName.StartsWithF(ModBase.pathImage)) + filePathOrResourceName.Replace("pack://application:,,,/images/", LauncherPaths.ImageBaseUri); + if (filePathOrResourceName.StartsWithF(LauncherPaths.ImageBaseUri)) { if (_Cache.ContainsKey(filePathOrResourceName)) { @@ -80,7 +80,7 @@ public MyBitmap(string filePathOrResourceName) throw new Exception($"加载 MyBitmap 意外失败({filePathOrResourceName})", ex); } - ModBase.Log(ex, $"指定类型有误的 MyBitmap 加载({filePathOrResourceName})", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, $"指定类型有误的 MyBitmap 加载({filePathOrResourceName})", LauncherLogLevel.Developer); break; } } while (false); diff --git a/Plain Craft Launcher 2/Modules/Event/CustomEvent.cs b/Plain Craft Launcher 2/Modules/Event/CustomEvent.cs index 46f3f8e62..b17c23d43 100644 --- a/Plain Craft Launcher 2/Modules/Event/CustomEvent.cs +++ b/Plain Craft Launcher 2/Modules/Event/CustomEvent.cs @@ -27,7 +27,7 @@ public CustomEvent(EventType type, string data) public static void Raise(EventType type, string arg) { if (type == EventType.None) return; - ModBase.Log($"[Control] 执行自定义事件: {type}, {arg}"); + LauncherLog.Log($"[Control] 执行自定义事件: {type}, {arg}"); try { @@ -40,10 +40,10 @@ public static void Raise(EventType type, string arg) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Event.Error.ExecutionFailed", type, arg), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Event.Error.ExecutionFailed", type, arg)); } } @@ -94,7 +94,7 @@ public static string GetCustomVariable(string name, string defaultValue = "") => [EventType.WriteSetting] = _WriteSetting, [EventType.ModifyVariable] = _WriteVariable, [EventType.WriteVariable] = _WriteVariable, - [EventType.OpenHelp] = (_, __) => ModBase.OpenWebsite("https://docs.pclc.cc/ce"), + [EventType.OpenHelp] = (_, __) => LauncherProcess.OpenWebsite("https://docs.pclc.cc/ce") }; /// @@ -109,7 +109,7 @@ private static void _OpenUrl(string arg, EventType type) return; } HintService.Hint(Lang.Text("Event.OpenUrl.Opening", arg)); - ModBase.RunInThread(() => ModBase.OpenWebsite(arg)); + UiThread.RunInThread(() => LauncherProcess.OpenWebsite(arg)); } /// @@ -118,7 +118,7 @@ private static void _OpenUrl(string arg, EventType type) private static void _OpenFileOrCommand(string arg, EventType type) { var args = SplitArgs(arg); - ModBase.RunInThread(() => + UiThread.RunInThread(() => { try { @@ -129,10 +129,10 @@ private static void _OpenFileOrCommand(string arg, EventType type) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Event.Error.ExecutionFailed", type, arg), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Event.Error.ExecutionFailed", type, arg)); } }); @@ -150,7 +150,8 @@ private static void _LaunchGame(string arg, EventType type) throw new InvalidOperationException(Lang.Text("Event.LaunchGame.SelectVersion")); args[0] = ModInstanceList.McMcInstanceSelected.Name; } - ModBase.RunInUi(() => + + UiThread.Post(() => { var launchOptions = new ModLaunch.McLaunchOptions { @@ -165,7 +166,10 @@ private static void _LaunchGame(string arg, EventType type) /// /// 复制文本到剪贴板。 /// - private static void _CopyText(string arg, EventType _) => ModBase.ClipboardSet(arg); + private static void _CopyText(string arg, EventType _) + { + LauncherProcess.ClipboardSet(arg); + } /// /// 刷新主页 / 刷新当前页面。要求当前 pageRight 实现 IRefreshable。 @@ -174,7 +178,7 @@ private static void _Refresh(string arg, EventType _) { if (ModMain.frmMain?.pageRight is IRefreshable refreshable) { - ModBase.RunInUiWait(() => refreshable.Refresh()); + UiThread.Invoke(() => refreshable.Refresh()); if (string.IsNullOrEmpty(arg)) HintService.Hint(Lang.Text("Event.Refresh.Success"), HintType.Success); } @@ -191,7 +195,7 @@ private static void _Refresh(string arg, EventType _) /// 清理垃圾。异步执行 RubbishClear。 /// private static void _ClearTrash(string _, EventType __) => - ModBase.RunInThread(PageToolsTest.RubbishClear); + UiThread.RunInThread(PageToolsTest.RubbishClear); /// /// 弹出消息框。参数:Title|Content[|ButtonText]。 @@ -235,7 +239,7 @@ private static void _ShowHint(string arg, EventType _) private static void _SwitchPage(string arg, EventType _) { var args = SplitArgs(arg); - ModBase.RunInUi(() => + UiThread.Post(() => { var page = (FormMain.PageType)Enum.Parse(typeof(FormMain.PageType), args[0], true); var sub = args.Length == 1 @@ -249,7 +253,7 @@ private static void _SwitchPage(string arg, EventType _) /// 导入 / 安装整合包。触发 ModModpack.ModpackInstall()。 /// private static void _ModpackInstall(string _, EventType __) => - ModBase.RunInUi(ModModpack.ModpackInstall); + UiThread.Post(ModModpack.ModpackInstall); /// /// 下载文件。参数:Url[|SavePath[|FileName]],校验 http/https 前缀并弹安全确认。 @@ -269,7 +273,7 @@ private static void _DownloadFile(string arg, EventType _) try { PageToolsTest.StartCustomDownload(args[0], - args.Length >= 2 ? args[1] : ModBase.GetFileNameFromPath(args[0]), + args.Length >= 2 ? args[1] : LegacyFileFacade.GetFileNameFromPath(args[0]), args.Length >= 3 ? args[2] : null); } catch @@ -299,7 +303,7 @@ private static bool CanWriteSettingFromCustomEvent(string key) { if (!SecuritySensitiveSettingKeys.Contains(key)) return true; - ModBase.Log($"[Control] 已阻止自定义事件写入高危设置:{key}", ModBase.LogLevel.Developer); + LauncherLog.Log($"[Control] 已阻止自定义事件写入高危设置:{key}", LauncherLogLevel.Developer); HintService.Hint(Lang.Text("Event.Safety.DangerousSettingBlocked", key), HintType.Error); return false; } @@ -325,7 +329,7 @@ public static string[] GetAbsoluteUrls(string relativeUrl, EventType type) if (relativeUrl.Contains(":\\")) { - ModBase.Log($"[Control] 自定义事件中由绝对路径 {type}: {relativeUrl}"); + LauncherLog.Log($"[Control] 自定义事件中由绝对路径 {type}: {relativeUrl}"); return [relativeUrl, pclDir]; } if (File.Exists(Path.Combine(pclDir, relativeUrl))) @@ -334,12 +338,12 @@ public static string[] GetAbsoluteUrls(string relativeUrl, EventType type) var resolved = Path.GetFullPath(fullPath); if (!resolved.StartsWith(pclDir, StringComparison.OrdinalIgnoreCase)) throw new UnauthorizedAccessException(Lang.Text("Event.Error.FileNotFound", relativeUrl)); - ModBase.Log($"[Control] 自定义事件中由相对 PCL 文件夹的路径 {type}: {fullPath}"); + LauncherLog.Log($"[Control] 自定义事件中由相对 PCL 文件夹的路径 {type}: {fullPath}"); return [fullPath, pclDir]; } if (type is EventType.OpenFile or EventType.ExecuteCommand) { - ModBase.Log($"[Control] 自定义事件中直接 {type}: {relativeUrl}"); + LauncherLog.Log($"[Control] 自定义事件中直接 {type}: {relativeUrl}"); return [relativeUrl, pclDir]; } throw new FileNotFoundException(Lang.Text("Event.Error.FileNotFound", relativeUrl), relativeUrl); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/CrashAnalysis/Export/CrashReportExporter.cs b/Plain Craft Launcher 2/Modules/Minecraft/CrashAnalysis/Export/CrashReportExporter.cs index 206bdd8b6..7e2c96b35 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/CrashAnalysis/Export/CrashReportExporter.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/CrashAnalysis/Export/CrashReportExporter.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.IO.Compression; using System.Text; using PCL.Core.App; @@ -30,7 +30,7 @@ public void Export( if (File.Exists(targetZipPath)) File.Delete(targetZipPath); - ModBase.FeedbackInfo(); + LauncherFeedbackService.FeedbackInfo(); var reportFolder = Path.Combine(context.TempFolder, ReportFolderName); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/CrashAnalysis/Presentation/CrashDialogPresenter.cs b/Plain Craft Launcher 2/Modules/Minecraft/CrashAnalysis/Presentation/CrashDialogPresenter.cs index c66f40f7e..02e8cab9e 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/CrashAnalysis/Presentation/CrashDialogPresenter.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/CrashAnalysis/Presentation/CrashDialogPresenter.cs @@ -97,7 +97,7 @@ private void _OpenModLoaderInstallPage() { PageInstanceLeft.McInstance = context.Instance; - ModBase.RunInUi(() => ModMain.frmMain.PageChange( + UiThread.Post(() => ModMain.frmMain.PageChange( FormMain.PageType.InstanceSetup, FormMain.PageSubType.VersionInstall)); } @@ -149,7 +149,7 @@ private void _ExportReport(List? extraFiles) new MsgBoxButtonInfo( Lang.Text("Crash.Export.Failed.CopyDetails"), 2, - () => ModBase.ClipboardSet(message, false))); + () => LauncherProcess.ClipboardSet(message, false))); } } @@ -168,7 +168,7 @@ private static string _CreateExportFailureMessage( { string? fileAddress = null; - ModBase.RunInUiWait(() => fileAddress = SystemDialogs.SelectSaveFile( + UiThread.Invoke(() => fileAddress = SystemDialogs.SelectSaveFile( Lang.Text("Crash.Report.SaveDialog.Title"), _GetDefaultReportFileName(), Lang.Text("Crash.Report.SaveDialog.Filter"))); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs b/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs index 41e20a2b5..390d32da7 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs @@ -77,7 +77,7 @@ bool ShouldBeIndie() // 从老的实例独立设置中迁移:-1 未决定,0 使用全局设置,1 手动开启,2 手动关闭 if (!Config.Instance.IndieV1Config.IsDefault(PathInstance) && Config.Instance.IndieV1[PathInstance] > 0) { - ModBase.Log($"[Minecraft] 版本隔离初始化({Name}):从老的实例独立设置中迁移"); + LauncherLog.Log($"[Minecraft] 版本隔离初始化({Name}):从老的实例独立设置中迁移"); return Config.Instance.IndieV1[PathInstance] == 1; } @@ -87,15 +87,15 @@ bool ShouldBeIndie() if ((modFolder.Exists && modFolder.EnumerateFiles().Any()) || (saveFolder.Exists && saveFolder.EnumerateDirectories().Any())) { - ModBase.Log($"[Minecraft] 版本隔离初始化({Name}):实例文件夹下存在 mods 或 saves 文件夹,自动开启"); + LauncherLog.Log($"[Minecraft] 版本隔离初始化({Name}):实例文件夹下存在 mods 或 saves 文件夹,自动开启"); return true; } // 根据全局的默认设置决定是否隔离 var isRelease = state != McInstanceState.Fool && state != McInstanceState.Old && state != McInstanceState.Snapshot; - ModBase.Log( - $"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Config.Launch.IndieSolutionV2})判断,State {ModBase.GetStringFromEnum(state)},IsRelease {isRelease},Modable {Modable}"); + LauncherLog.Log( + $"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Config.Launch.IndieSolutionV2})判断,State {LauncherText.GetStringFromEnum(state)},IsRelease {isRelease},Modable {Modable}"); return Config.Launch.IndieSolutionV2 switch { @@ -122,7 +122,7 @@ public string Name get { if (field is null && !string.IsNullOrEmpty(PathInstance)) - field = ModBase.GetFolderNameFromPath(PathInstance); + field = LegacyFileFacade.GetFolderNameFromPath(PathInstance); return field; } } @@ -285,7 +285,7 @@ public McInstanceInfo Info if (jsonVerName.Length < 32) // 因为 wiki 说这玩意儿可能是个 hash,虽然我没发现 { field.VanillaName = jsonVerName; - ModBase.Log("[Minecraft] 从版本 jar 中的 version.json 获取到版本号:" + jsonVerName); + LauncherLog.Log("[Minecraft] 从版本 jar 中的 version.json 获取到版本号:" + jsonVerName); goto VersionSearchFinish; } } @@ -300,7 +300,7 @@ public McInstanceInfo Info } // 非准确的版本判断警告 - ModBase.Log("[Minecraft] 无法完全确认 MC 版本号的版本:" + Name); + LauncherLog.Log("[Minecraft] 无法完全确认 MC 版本号的版本:" + Name); field.Reliable = false; // 从文件夹名中获取 regex = Name.RegexSeek(RegexPatterns.MinecraftJsonVersion, RegexOptions.IgnoreCase); @@ -327,7 +327,7 @@ public McInstanceInfo Info } catch (Exception ex) { - ModBase.Log(ex, "识别 Minecraft 版本时出错"); + LauncherLog.Log(ex, "识别 Minecraft 版本时出错"); field.VanillaName = "Unknown"; Desc = Lang.Text("Minecraft.Error.Unrecognizable", ex.Message); } @@ -346,15 +346,16 @@ public McInstanceInfo Info if (field.VanillaName.StartsWithF("1.")) { var segments = field.VanillaName.Split(" _-.".ToCharArray()); - field.vanilla = new Version((int)Math.Round(ModBase.Val(segments.Count() >= 2 ? segments[1] : "0")), - 0, (int)Math.Round(ModBase.Val(segments.Count() >= 3 ? segments[2] : "0"))); + field.vanilla = new Version( + (int)Math.Round(LauncherText.Val(segments.Count() >= 2 ? segments[1] : "0")), + 0, (int)Math.Round(LauncherText.Val(segments.Count() >= 3 ? segments[2] : "0"))); } else if (field.VanillaName.RegexCheck(@"^[2-9][0-9]\.")) { var segments = field.VanillaName.Split(" _-.".ToCharArray()); - field.vanilla = new Version((int)Math.Round(ModBase.Val(segments[0])), - (int)Math.Round(ModBase.Val(segments.Count() >= 2 ? segments[1] : "0")), - (int)Math.Round(ModBase.Val(segments.Count() >= 3 ? segments[2] : "0"))); + field.vanilla = new Version((int)Math.Round(LauncherText.Val(segments[0])), + (int)Math.Round(LauncherText.Val(segments.Count() >= 2 ? segments[1] : "0")), + (int)Math.Round(LauncherText.Val(segments.Count() >= 3 ? segments[2] : "0"))); } else { @@ -391,7 +392,7 @@ bool FastJsonCheck(string json) if (jsonFiles.Count() == 1) { jsonPath = jsonFiles[0]; - ModBase.Log("[Minecraft] 未找到同名实例 JSON,自动换用 " + jsonPath, ModBase.LogLevel.Debug); + LauncherLog.Log("[Minecraft] 未找到同名实例 JSON,自动换用 " + jsonPath, LauncherLogLevel.Debug); } else { @@ -400,24 +401,25 @@ bool FastJsonCheck(string json) } } - field = ModBase.ReadFile(jsonPath); + field = LegacyFileFacade.ReadText(jsonPath); // 如果 ReadFile 失败会返回空字符串;这可能是由于文件被临时占用,故延时后重试 if (!FastJsonCheck(field)) { - if (ModBase.RunInUi()) + if (UiThread.CheckAccess()) { - ModBase.Log($"[Minecraft] 实例 JSON 文件为空或有误,将进行短暂重试({jsonPath})", ModBase.LogLevel.Debug); + LauncherLog.Log($"[Minecraft] 实例 JSON 文件为空或有误,将进行短暂重试({jsonPath})", LauncherLogLevel.Debug); Thread.Sleep(200); - field = ModBase.ReadFile(jsonPath); + field = LegacyFileFacade.ReadText(jsonPath); } else { - ModBase.Log($"[Minecraft] 实例 JSON 文件为空或有误,将在 2s 后重试读取({jsonPath})", ModBase.LogLevel.Debug); + LauncherLog.Log($"[Minecraft] 实例 JSON 文件为空或有误,将在 2s 后重试读取({jsonPath})", + LauncherLogLevel.Debug); Thread.Sleep(2000); - field = ModBase.ReadFile(jsonPath); + field = LegacyFileFacade.ReadText(jsonPath); } if (!FastJsonCheck(field)) - ModBase.GetJson(field); + JsonCompat.ParseNode(field); } } @@ -439,7 +441,7 @@ public JsonObject JsonObject var text = JsonText; // 触发 JsonText 的 Get 事件 try { - field = (JsonObject)ModBase.GetJson(text); + field = (JsonObject)JsonCompat.ParseNode(text); // 转换 HMCL 关键项 if (field.ContainsKey("patches") && !field.ContainsKey("time")) { @@ -452,8 +454,8 @@ public JsonObject JsonObject subjsonList.Add(subjson); } subjsonList.Sort((left, right) => { - var leftVal = ModBase.Val((left["priority"] ?? "0").ToString()); - var rightVal = ModBase.Val((right["priority"] ?? "0").ToString()); + var leftVal = LauncherText.Val((left["priority"] ?? "0").ToString()); + var rightVal = LauncherText.Val((right["priority"] ?? "0").ToString()); return leftVal.CompareTo(rightVal); }); foreach (var Subjson in subjsonList) @@ -462,7 +464,7 @@ public JsonObject JsonObject if (id is not null) { // 合并 JSON - ModBase.Log("[Minecraft] 合并 HMCL 分支项:" + id); + LauncherLog.Log("[Minecraft] 合并 HMCL 分支项:" + id); if (currentObject is not null) currentObject.Merge(Subjson); else @@ -470,7 +472,7 @@ public JsonObject JsonObject } else { - ModBase.Log("[Minecraft] 存在为空的 HMCL 分支项"); + LauncherLog.Log("[Minecraft] 存在为空的 HMCL 分支项"); } } @@ -492,7 +494,7 @@ public JsonObject JsonObject : field["inheritsFrom"].ToString(); if (Equals(inheritInstanceName, Name)) { - ModBase.Log("[Minecraft] 自引用的继承实例:" + Name, ModBase.LogLevel.Debug); + LauncherLog.Log("[Minecraft] 自引用的继承实例:" + Name, LauncherLogLevel.Debug); inheritInstanceName = ""; break; } @@ -516,7 +518,7 @@ public JsonObject JsonObject } catch (Exception ex) { - ModBase.Log(ex, "合并实例依赖项 JSON 失败(" + (inheritInstanceName ?? "null") + ")"); + LauncherLog.Log(ex, "合并实例依赖项 JSON 失败(" + (inheritInstanceName ?? "null") + ")"); } } while (false); } @@ -566,13 +568,13 @@ public JsonObject JsonVersion if (versionJson is not null) using (var versionJsonStream = new StreamReader(versionJson.Open())) { - field = (JsonObject)ModBase.GetJson(versionJsonStream.ReadToEnd()); + field = (JsonObject)JsonCompat.ParseNode(versionJsonStream.ReadToEnd()); } } } catch (Exception ex) { - ModBase.Log(ex, $"从实例 JAR 中读取 version.json 失败 ({PathInstance}{Name}.jar)"); + LauncherLog.Log(ex, $"从实例 JAR 中读取 version.json 失败 ({PathInstance}{Name}.jar)"); } } while (false); } @@ -624,13 +626,13 @@ public bool Check() try { Directory.CreateDirectory(PathInstance + @"PCL\"); - ModBase.CheckPermissionWithException(PathInstance + @"PCL\"); + LegacyFileFacade.CheckPermissionWithException(PathInstance + @"PCL\"); } catch (Exception ex) { state = McInstanceState.Error; Desc = Lang.Text("Select.Instance.Description.NoPermission"); - ModBase.Log(ex, "没有访问实例文件夹的权限"); + LauncherLog.Log(ex, "没有访问实例文件夹的权限"); return false; } @@ -641,7 +643,7 @@ public bool Check() } catch (Exception ex) { - ModBase.Log(ex, "实例 JSON 可用性检查失败(" + PathInstance + ")"); + LauncherLog.Log(ex, "实例 JSON 可用性检查失败(" + PathInstance + ")"); JsonText = ""; JsonObject = null; Desc = ex.Message; @@ -657,7 +659,7 @@ public bool Check() } catch (Exception ex) { - ModBase.Log(ex, "版本号获取失败(" + Name + ")"); + LauncherLog.Log(ex, "版本号获取失败(" + Name + ")"); state = McInstanceState.Error; Desc = Lang.Text("Minecraft.Error.VersionNumberFetchFailed", ex); return false; @@ -667,7 +669,8 @@ public bool Check() try { if (!string.IsNullOrEmpty(InheritInstanceName)) - if (!File.Exists(Path.Combine(ModBase.GetPathFromFullPath(PathInstance), InheritInstanceName, InheritInstanceName + ".json"))) + if (!File.Exists(Path.Combine(LegacyFileFacade.GetPathFromFullPath(PathInstance), + InheritInstanceName, InheritInstanceName + ".json"))) { state = McInstanceState.Error; Desc = Lang.Text("Select.Instance.Description.NeedInherit", InheritInstanceName); @@ -676,7 +679,7 @@ public bool Check() } catch (Exception ex) { - ModBase.Log(ex, "依赖实例检查出错(" + Name + ")"); + LauncherLog.Log(ex, "依赖实例检查出错(" + Name + ")"); state = McInstanceState.Error; Desc = Lang.Text("Select.Instance.Description.UnknownError") + ": " + ex; return false; @@ -809,73 +812,73 @@ public McInstance Load() { case McInstanceState.Original: { - Logo = ModBase.pathImage + "Blocks/Grass.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/Grass.png"; break; } case McInstanceState.Snapshot: { - Logo = ModBase.pathImage + "Blocks/CommandBlock.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/CommandBlock.png"; break; } case McInstanceState.Old: { - Logo = ModBase.pathImage + "Blocks/CobbleStone.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/CobbleStone.png"; break; } case McInstanceState.Forge: { - Logo = ModBase.pathImage + "Blocks/Anvil.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/Anvil.png"; break; } case McInstanceState.NeoForge: { - Logo = ModBase.pathImage + "Blocks/NeoForge.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/NeoForge.png"; break; } case McInstanceState.Cleanroom: { - Logo = ModBase.pathImage + "Blocks/Cleanroom.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/Cleanroom.png"; break; } case McInstanceState.Fabric: { - Logo = ModBase.pathImage + "Blocks/Fabric.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/Fabric.png"; break; } case McInstanceState.LegacyFabric: { - Logo = ModBase.pathImage + "Blocks/Fabric.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/Fabric.png"; break; } case McInstanceState.Quilt: { - Logo = ModBase.pathImage + "Blocks/Quilt.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/Quilt.png"; break; } case McInstanceState.OptiFine: { - Logo = ModBase.pathImage + "Blocks/GrassPath.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/GrassPath.png"; break; } case McInstanceState.LiteLoader: { - Logo = ModBase.pathImage + "Blocks/Egg.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/Egg.png"; break; } case McInstanceState.Fool: { - Logo = ModBase.pathImage + "Blocks/GoldBlock.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/GoldBlock.png"; break; } case McInstanceState.LabyMod: { - Logo = ModBase.pathImage + "Blocks/LabyMod.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/LabyMod.png"; break; } default: { - Logo = ModBase.pathImage + "Blocks/RedstoneBlock.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/RedstoneBlock.png"; break; } } @@ -923,12 +926,12 @@ public McInstance Load() catch (Exception ex) { Desc = Lang.Text("Select.Instance.Description.UnknownError") + ": " + ex; - Logo = ModBase.pathImage + "Blocks/RedstoneBlock.png"; + Logo = LauncherPaths.ImageBaseUri + "Blocks/RedstoneBlock.png"; state = McInstanceState.Error; - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Instance.Error.Load", Name), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Instance.Error.Load", Name)); } finally diff --git a/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs b/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs index 1a6a53ec6..8a88eb360 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs @@ -1,4 +1,4 @@ -using PCL.Core.App.Localization; +using PCL.Core.App.Localization; namespace PCL; @@ -157,7 +157,7 @@ public int OptiFineCode // 末尾数字,如 C5 beta4 中的 5 result *= 100; result = (int)Math.Round(result + - ModBase.Val(OptiFine[1..].RegexSeek("[0-9]+"))); + LauncherText.Val(OptiFine[1..].RegexSeek("[0-9]+"))); // 测试标记(正式版为 99,Pre[x] 为 50+x,Beta[x] 为 x) result *= 100; if (OptiFine.ContainsF("pre", true)) @@ -165,12 +165,13 @@ public int OptiFineCode if (OptiFine.ContainsF("pre", true) || OptiFine.ContainsF("beta", true)) { var lastChar = OptiFine[^1..]; - if (ModBase.Val(lastChar) == 0d && lastChar != "0") + if (LauncherText.Val(lastChar) == 0d && lastChar != "0") result += 1; // 为 pre 或 beta 结尾,视作 1 else result = (int)Math.Round(result + - ModBase.Val(OptiFine.ToLower().RegexSeek("(?<=((pre)|(beta)))[0-9]+"))); + LauncherText.Val(OptiFine.ToLower() + .RegexSeek("(?<=((pre)|(beta)))[0-9]+"))); } else { @@ -205,22 +206,25 @@ public int ForgelikeCode { case var @case when @case > 4: { - return (int)Math.Round(ModBase.Val(segments[0]) * 1000000d + ModBase.Val(segments[1]) * 10000d + - ModBase.Val(segments[3])); + return (int)Math.Round(LauncherText.Val(segments[0]) * 1000000d + + LauncherText.Val(segments[1]) * 10000d + + LauncherText.Val(segments[3])); } case 3: { - return (int)Math.Round(ModBase.Val(segments[0]) * 1000000d + ModBase.Val(segments[1]) * 10000d + - ModBase.Val(segments[2])); + return (int)Math.Round(LauncherText.Val(segments[0]) * 1000000d + + LauncherText.Val(segments[1]) * 10000d + + LauncherText.Val(segments[2])); } case 2: { - return (int)Math.Round(ModBase.Val(segments[0]) * 1000000d + ModBase.Val(segments[1]) * 10000d); + return (int)Math.Round(LauncherText.Val(segments[0]) * 1000000d + + LauncherText.Val(segments[1]) * 10000d); } default: { - return (int)Math.Round(ModBase.Val(segments[0]) * 1000000d); + return (int)Math.Round(LauncherText.Val(segments[0]) * 1000000d); } } } @@ -280,7 +284,7 @@ public static bool IsFormatFit(string version) return false; if (version.RegexCheck(@"^1\.\d")) return true; - if (ModBase.Val(version.RegexSeek(@"^[2-9]\d\.\d+")) > 25d) + if (LauncherText.Val(version.RegexSeek(@"^[2-9]\d\.\d+")) > 25d) return true; return false; } @@ -298,8 +302,8 @@ public static int VersionToDrop(string? version, bool allowSnapshot = false) var segments = version.BeforeFirst("-").Split("."); if (segments.Length < 2) return 0; - var major = (int)Math.Round(ModBase.Val(segments[0])); - var minor = (int)Math.Round(ModBase.Val(segments[1])); + var major = (int)Math.Round(LauncherText.Val(segments[0])); + var minor = (int)Math.Round(LauncherText.Val(segments[1])); if (major == 1) return minor * 10; if (major < 25) return 0; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/McVersionComparer.cs b/Plain Craft Launcher 2/Modules/Minecraft/McVersionComparer.cs index ed709a99a..e89522031 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/McVersionComparer.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/McVersionComparer.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using PCL.Core.App.Localization; +using PCL.Core.App.Localization; namespace PCL; @@ -64,7 +63,7 @@ public static int CompareVersion(string left, string right) leftValue = (-3).ToString(); if (leftValue == "experimental") leftValue = (-4).ToString(); - var leftValValue = ModBase.Val(leftValue); + var leftValValue = LauncherText.Val(leftValue); if (rightValue == "rc") rightValue = (-1).ToString(); if (rightValue == "pre") @@ -73,7 +72,7 @@ public static int CompareVersion(string left, string right) rightValue = (-3).ToString(); if (rightValue == "experimental") rightValue = (-4).ToString(); - var rightValValue = ModBase.Val(rightValue); + var rightValValue = LauncherText.Val(rightValue); if (leftValValue == 0d && rightValValue == 0d) { // 如果没有数值则直接比较字符串 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs index 93da5d989..b2f55e3c1 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs @@ -1,10 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +using System.IO; using System.Runtime.InteropServices; -using System.Text.Json.Nodes; -using PCL; using PCL.Core.App.Localization; using PCL.Core.Utils; using PCL.Network; @@ -50,8 +45,8 @@ public static JsonNode McAssetsGetIndex(McInstance mcInstance, bool returnLegacy // Log("[Minecraft] 无法获取资源文件索引下载地址,使用 assets 项提供的资源文件名:" & AssetsName) // Return GetJson("{""id"": """ & AssetsName & """}") // Else - ModBase.Log("[Minecraft] 无法获取资源文件索引下载地址,使用默认的 legacy 下载地址"); - return (JsonNode)ModBase.GetJson(@"{ + LauncherLog.Log("[Minecraft] 无法获取资源文件索引下载地址,使用默认的 legacy 下载地址"); + return (JsonNode)JsonCompat.ParseNode(@"{ ""id"": ""legacy"", ""sha1"": ""c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729"", ""size"": 134284, @@ -84,7 +79,7 @@ public static string McAssetsGetIndexName(McInstance mcInstance) } catch (Exception ex) { - ModBase.Log(ex, "获取资源文件索引名失败"); + LauncherLog.Log(ex, "获取资源文件索引名失败"); } return "legacy"; @@ -115,7 +110,7 @@ public struct McAssetsToken public override string ToString() { - return ModBase.GetString(size) + " | " + localPath; + return $"{LauncherText.GetReadableFileSize(size)} | {localPath}"; } } @@ -142,8 +137,8 @@ internal static List McAssetsListGet(McInstance mcInstance) throw new FileNotFoundException(Lang.Text("Minecraft.Error.AssetIndexNotFound"), Path.Combine(ModFolder.mcFolderSelected, "assets", "indexes", indexName + ".json")); var result = new List(); - var json = (JsonObject)ModBase.GetJson( - ModBase.ReadFile($@"{ModFolder.mcFolderSelected}assets\indexes\{indexName}.json")); + var json = (JsonObject)JsonCompat.ParseNode( + LegacyFileFacade.ReadText($@"{ModFolder.mcFolderSelected}assets\indexes\{indexName}.json")); // 读取列表 foreach (var file in json["objects"].AsObject()) @@ -175,7 +170,7 @@ internal static List McAssetsListGet(McInstance mcInstance) catch (Exception ex) { - ModBase.Log(ex, "获取资源文件列表失败:" + indexName); + LauncherLog.Log(ex, $"获取资源文件列表失败:{indexName}"); throw; } } @@ -195,7 +190,7 @@ public static List McAssetsFixList(McInstance mcInstance, bool che return new DownloadFile( ModDownload.DlSourceAssetsGet(McAssetsUrl(hash)), token.localPath, - new ModBase.FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: hash)); + new FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: hash)); }).ToList(); // 如果不检查 Hash,则立即处理 var result = new List(); @@ -222,12 +217,12 @@ public static List McAssetsFixList(McInstance mcInstance, bool che result.Add(new DownloadFile( ModDownload.DlSourceAssetsGet(McAssetsUrl(hash)), token.localPath, - new ModBase.FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: hash))); + new FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: hash))); } } catch (Exception ex) { - ModBase.Log(ex, "获取实例缺失的资源文件下载列表失败"); + LauncherLog.Log(ex, "获取实例缺失的资源文件下载列表失败"); } if (progressFeed is not null) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs index 5f70fe7f6..11ac2046c 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs @@ -5,24 +5,21 @@ using System.Net; using System.Net.Http; using System.Text; -using System.Text.Json; -using System.Text.Json.Nodes; using System.Text.Json.Serialization; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; -using System.Windows.Media; using Dapper; using Microsoft.Data.Sqlite; using PCL.Core.App; +using PCL.Core.App.Localization; using PCL.Core.Logging; +using PCL.Core.UI; using PCL.Core.Utils; using PCL.Core.Utils.Hash; using PCL.Network; using PCL.Network.Loaders; using ProtoBuf; -using PCL.Core.App.Localization; -using PCL.Core.UI; namespace PCL; @@ -309,7 +306,7 @@ public static string GetShareCode(HashSet data) } catch (Exception ex) { - ModBase.Log(ex, "[CompFavorites] 生成分享出错"); + LauncherLog.Log(ex, "[CompFavorites] 生成分享出错"); } return ""; @@ -323,7 +320,7 @@ public static HashSet GetIdsByShareCode(string code) } catch (Exception ex) { - ModBase.Log(ex, "[CompFavorites] 通过分享获取 ID 出错"); + LauncherLog.Log(ex, "[CompFavorites] 通过分享获取 ID 出错"); } return new HashSet(); @@ -372,7 +369,7 @@ public static void ShowMenu(CompProject project, UIElement pos, Action closedCal } catch (Exception ex) { - ModBase.Log(ex, "[CompFavorites] 改变收藏项出错"); + LauncherLog.Log(ex, "[CompFavorites] 改变收藏项出错"); } }; body.Items.Add(item); @@ -415,7 +412,7 @@ public static void ShowMenu(List project, UIElement pos, Action clo } catch (Exception ex) { - ModBase.Log(ex, "[CompFavorites] 改变收藏项出错"); + LauncherLog.Log(ex, "[CompFavorites] 改变收藏项出错"); } }; body.Items.Add(item); @@ -530,7 +527,7 @@ await Task.Run(() => } catch (Exception ex) { - ModBase.Log(ex, "从 Modrinth 获取数据失败"); + LauncherLog.Log(ex, "从 Modrinth 获取数据失败"); } return res; @@ -576,7 +573,7 @@ await Task.Run(() => } catch (Exception ex) { - ModBase.Log(ex, "Failed to get project data from CurseForge"); + LauncherLog.Log(ex, "Failed to get project data from CurseForge"); } return res; @@ -626,20 +623,20 @@ public class CompClipboard public static void GetClipboardResource() { string? text = null; - ModBase.RunInUiWait(() => text = Clipboard.GetText()); + UiThread.Invoke(() => text = Clipboard.GetText()); if (string.IsNullOrEmpty(text) || text == currentText) return; currentText = text; // 在新线程中处理网络请求 - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { try { var projectId = ResolveLinkToProjectId(text); if (string.IsNullOrEmpty(projectId)) return; - ModBase.Log($"[Clipboard] Found ProjectId: {projectId}"); + LauncherLog.Log($"[Clipboard] Found ProjectId: {projectId}"); // 3. UI 交互:跳转到详情页 System.Windows.Application.Current.Dispatcher.BeginInvoke(new Func(async () => @@ -673,7 +670,7 @@ public static void GetClipboardResource() } catch (Exception ex) { - ModBase.Log(ex, "Error processing clipboard resource"); + LauncherLog.Log(ex, "Error processing clipboard resource"); } }, "Clipboard Resource Processing"); } @@ -689,8 +686,8 @@ public static void GetClipboardResource() private static string InitializeModDbAndGetConnectionString() { - ModBase.Log("[DB] 解压 ModData (SQLite) 中"); - using (var compressedDbData = ModBase.GetResourceStream("Resources/mcmod.buf")) + LauncherLog.Log("[DB] 解压 ModData (SQLite) 中"); + using (var compressedDbData = Basics.GetResourceStream("Resources/mcmod.buf")) { using (var trueDbFile = new GZipStream(compressedDbData, CompressionMode.Decompress)) { @@ -699,8 +696,8 @@ private static string InitializeModDbAndGetConnectionString() // 这里提取文件资源 trueDbFile.CopyTo(ms); ms.Seek(0L, SeekOrigin.Begin); - var fileHash = ModBase.GetHexString(SHA1Provider.Instance.ComputeHash(ms)); - var dbDir = Path.Combine(ModBase.pathTemp, "Cache"); + var fileHash = LegacyFileFacade.GetHexString(SHA1Provider.Instance.ComputeHash(ms)); + var dbDir = Path.Combine(LauncherPaths.TempWithSlash, "Cache"); var dbPath = Path.Combine(dbDir, $"ModData{fileHash}.sqlite"); if (File.Exists(dbPath) && !IsDatabaseValid(dbPath)) @@ -779,7 +776,7 @@ private static bool IsDatabaseValid(string dbPath) } catch (Exception ex) { - ModBase.Log(ex, "检查模组翻译数据库有效性失败"); + LauncherLog.Log(ex, "检查模组翻译数据库有效性失败"); return false; } } @@ -807,10 +804,10 @@ private static CompDatabaseEntry GetCompWikiEntryBySlug(string slug) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "获取模组翻译信息失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Minecraft.Comp.Error.OperationFailed")); return null; } @@ -1448,12 +1445,12 @@ private async Task GetChineseDescriptionAsync() var para = FromCurseForge ? "modId" : "project_id"; string result = null; - var descHash = $"{Id}{ModBase.GetStringMD5(Description)}"; - var cacheFilePath = $@"{ModBase.pathTemp}Cache\CompTranslation.ini"; - var cacheTranslation = ModBase.ReadIni(cacheFilePath, descHash); + var descHash = $"{Id}{LauncherText.GetStringMD5(Description)}"; + var cacheFilePath = $@"{LauncherPaths.TempWithSlash}Cache\CompTranslation.ini"; + var cacheTranslation = LegacyIniStore.Shared.Read(cacheFilePath, descHash); if (!string.IsNullOrWhiteSpace(cacheTranslation)) { - result = ModBase.Base64Decode(cacheTranslation); + result = Base64Utils.DecodeToString(cacheTranslation); return result; } @@ -1464,7 +1461,7 @@ private async Task GetChineseDescriptionAsync() if (jsonObject.ContainsKey("translated")) { result = jsonObject["translated"].ToString(); - ModBase.WriteIni(cacheFilePath, descHash, ModBase.Base64Encode(result)); + LegacyIniStore.Shared.Write(cacheFilePath, descHash, Base64Utils.EncodeString(result)); } } catch (HttpRequestException ex) @@ -1475,18 +1472,18 @@ private async Task GetChineseDescriptionAsync() return null; } - ModBase.Log( + LauncherLog.Log( ex, "获取中文描述时出现错误", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Minecraft.Comp.Error.OperationFailed")); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "获取中文描述时出现错误", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Minecraft.Comp.Error.OperationFailed")); } @@ -1686,7 +1683,7 @@ public MyListItem ToListItem() { Title = TranslatedName, Info = Description.Replace("\r", "").Replace("\n", ""), - Logo = string.IsNullOrEmpty(LogoUrl) ? $"{ModBase.pathImage}Icons/NoIcon.png" : LogoUrl, + Logo = string.IsNullOrEmpty(LogoUrl) ? $"{LauncherPaths.ImageBaseUri}Icons/NoIcon.png" : LogoUrl, Tags = Tags, Tag = this, LogoCornerRadius = new CornerRadius(6) @@ -1698,7 +1695,7 @@ public void ApplyLogoToMyImage(MyImage img) { if (string.IsNullOrEmpty(LogoUrl)) { - img.Source = ModBase.pathImage + "Icons/NoIcon.png"; + img.Source = LauncherPaths.ImageBaseUri + "Icons/NoIcon.png"; } else { @@ -1850,7 +1847,7 @@ string GetRaw(string data) (RawName ?? "") == (project.RawName ?? "") || (Description ?? "") == (project.Description ?? "") || (GetRaw(Slug) ?? "") == (GetRaw(project.Slug) ?? "")) { - ModBase.Log($"[Comp] 将 {RawName} ({Slug}) 与 {project.RawName} ({project.Slug}) 认定为相似工程"); + LauncherLog.Log($"[Comp] 将 {RawName} ({Slug}) 与 {project.RawName} ({project.Slug}) 认定为相似工程"); // 如果只有一个有 DatabaseEntry,设置给另外一个 if (DatabaseEntry is null && project.DatabaseEntry is not null) DatabaseEntry = project.DatabaseEntry; @@ -2123,11 +2120,11 @@ public string GetModrinthAddress() address += "&offset=" + storage.modrinthOffset; // facets=[["categories:'game-mechanics'"],["categories:'forge'"],["versions:1.19.3"],["project_type:mod"]] var facets = new List(); - facets.Add($"[\"project_type:{ModBase.GetStringFromEnum(type).ToLower()}\"]"); + facets.Add($"[\"project_type:{LauncherText.GetStringFromEnum(type).ToLower()}\"]"); if (!string.IsNullOrEmpty(tag)) facets.Add($"[\"categories:'{tag.AfterLast("/")}'\"]"); if (modLoader != CompLoaderType.Any) - facets.Add($"[\"categories:'{ModBase.GetStringFromEnum(modLoader).ToLower()}'\"]"); + facets.Add($"[\"categories:'{LauncherText.GetStringFromEnum(modLoader).ToLower()}'\"]"); if (!string.IsNullOrEmpty(gameVersion)) facets.Add($"[\"versions:'{gameVersion}'\"]"); address += "&facets=[" + string.Join(",", facets) + "]"; @@ -2335,7 +2332,7 @@ public static void CompProjectsGet(ModLoader.LoaderTask } catch (Exception ex) { - ModBase.Log(ex, "[Comp] 解析资源链接失败"); + LauncherLog.Log(ex, "[Comp] 解析资源链接失败"); throw new Exception(Lang.Text("Download.Comp.Link.ResolveFailed")); } @@ -2391,7 +2388,7 @@ public static void CompProjectsGet(ModLoader.LoaderTask !string.IsNullOrEmpty(rawFilter); if (isChineseSearch && request.type is CompType.Mod or CompType.DataPack) { - var searchEntries = new List>(); + var searchEntries = new List>(); using (var conn = CompDB) { var sql = @@ -2400,10 +2397,10 @@ public static void CompProjectsGet(ModLoader.LoaderTask foreach (var searchItem in searchRes) { if (searchItem.ChineseName.Contains("动态的树")) continue; - searchEntries.Add(new ModBase.SearchEntry + searchEntries.Add(new SearchEntry { item = searchItem, - searchSource = new List + searchSource = new List { new(searchItem.ChineseName.BeforeFirst(" (").Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries), 1), new(searchItem.ChineseName.AfterFirst(" (") + (searchItem.CurseForgeSlug ?? "") + (searchItem.ModrinthSlug ?? ""), 0.5) @@ -2412,10 +2409,10 @@ public static void CompProjectsGet(ModLoader.LoaderTask } } - var searchResults = ModBase.Search(searchEntries, request.searchText, 40, 0.2); + var searchResults = LauncherSearch.Search(searchEntries, request.searchText, 40, 0.2); if (!searchResults.Any()) throw new Exception(Lang.Text("Download.Comp.List.NoResults")); - string[] ExtractWords(ModBase.SearchEntry result) + string[] ExtractWords(SearchEntry result) { var word = ""; if (result.item.CurseForgeSlug is not null) @@ -2430,7 +2427,7 @@ string[] ExtractWords(ModBase.SearchEntry result) { if (w.Length <= 1) return false; if (new[] { "the", "of", "mod", "and" }.Contains(w)) return false; - if (ModBase.Val(w) > 0) return false; + if (LauncherText.Val(w) > 0) return false; if (w.Split(' ').Length > 3 && w.Contains("ftb")) return false; return true; }).Distinct().ToArray(); @@ -2649,16 +2646,16 @@ void processKeywords(ref string text) } else { - var searchEntries = new List>(); + var searchEntries = new List>(); foreach (var res in realResults) { scores.Add(res, (Lang.IsChineseMainland && res.WikiId > 0 ? 0.2 : 0) + Math.Log10(Math.Max(res.DownloadCount, 1) * getDownloadCountMult(res)) / 9); - searchEntries.Add(new ModBase.SearchEntry + searchEntries.Add(new SearchEntry { item = res, - searchSource = new List + searchSource = new List { new((isChineseSearch ? res.TranslatedName : res.RawName).Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries), 1), new(res.Description, 0.05) @@ -2666,7 +2663,7 @@ void processKeywords(ref string text) }); } - var searchRes = ModBase.Search(searchEntries, rawFilter, 101, -1); + var searchRes = LauncherSearch.Search(searchEntries, rawFilter, 101, -1); foreach (var item in searchRes) scores[item.item] += (item.absoluteRight ? 10 : item.similarity) / @@ -3093,7 +3090,7 @@ public string StatusDescription public DownloadFile ToNetFile(string localAddress) { return new DownloadFile(DownloadUrls, localAddress + (localAddress.EndsWithF(@"\") ? CompFileNameSanitize(FileName) : ""), - new ModBase.FileChecker(hash: Hash), true); + new FileChecker(hash: Hash), true); } /// @@ -3181,9 +3178,9 @@ public MyVirtualizingElement ToListItem(MyListItem.ClickEventHandler // 使用 switch 表达式精简 Logo 选择喵! Logo = Status switch { - CompFileStatus.Release => ModBase.pathImage + "Icons/R.png", - CompFileStatus.Beta => ModBase.pathImage + "Icons/B.png", - _ => ModBase.pathImage + "Icons/A.png" + CompFileStatus.Release => LauncherPaths.ImageBaseUri + "Icons/R.png", + CompFileStatus.Beta => LauncherPaths.ImageBaseUri + "Icons/B.png", + _ => LauncherPaths.ImageBaseUri + "Icons/A.png" } }; newItem.Click += onClick; @@ -3245,7 +3242,7 @@ public static List CompFilesGet(string projectId, bool fromCurseForge) // 2. 获取并缓存文件列表 if (!compFilesCache.ContainsKey(projectId)) { - ModBase.Log("[Comp] 开始获取文件列表:" + projectId); + LauncherLog.Log("[Comp] 开始获取文件列表:" + projectId); JsonArray resultJsonArray; if (fromCurseForge) { @@ -3277,7 +3274,7 @@ public static List CompFilesGet(string projectId, bool fromCurseForge) // 4. 批量请求缺失的前置工程信息 if (undoneDeps.Any()) { - ModBase.Log($"[Comp] {projectId} 需要补全信息的依赖项共 {undoneDeps.Count} 个"); + LauncherLog.Log($"[Comp] {projectId} 需要补全信息的依赖项共 {undoneDeps.Count} 个"); JsonArray projects; if (fromCurseForge) { @@ -3388,7 +3385,7 @@ _ when char.IsControl(c) => '_', /// public static void QuickDownload(CompProject project) { - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { try { @@ -3406,7 +3403,7 @@ public static void QuickDownload(CompProject project) if (behavior == 0) { // 总是询问:弹「方式选择」 - int? choice = ModBase.RunInUiWait(() => + int? choice = UiThread.Invoke(() => { var options = new List { @@ -3442,10 +3439,10 @@ public static void QuickDownload(CompProject project) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "[Comp] 快速下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Comp.Error.OperationFailed")); } }, "Comp QuickDownload"); @@ -3479,7 +3476,7 @@ private static void _QuickDownloadToInstance(CompProject project, List /// 弹实例列表让用户选择,返回选中的实例(兼容者优先、当前选中实例居首);取消或无兼容实例返回 null。 private static McInstance? _QuickDownloadPickInstance(CompProject project, List files) { - var needLoad = ModInstanceList.mcInstanceListLoader.State != ModBase.LoadState.Finished; + var needLoad = ModInstanceList.mcInstanceListLoader.State != LoadState.Finished; if (needLoad) { HintService.Hint(Lang.Text("Download.Comp.QuickDownload.Hint.Loading"), HintType.Info); @@ -3502,7 +3499,7 @@ private static void _QuickDownloadToInstance(CompProject project, List .OrderBy(v => v == current ? 0 : 1) .ThenBy(v => v.Name) .ToList(); - int? idx = ModBase.RunInUiWait(() => + int? idx = UiThread.Invoke(() => { var options = compatible .Select(v => (IMyRadio)new MyRadioBox { Text = v.Name }) @@ -3525,7 +3522,8 @@ private static void _QuickDownloadToFolder(CompProject project, List f HintService.Hint(Lang.Text("Download.Comp.QuickDownload.Hint.NoFile"), HintType.Info); return; } - var saveFolder = ModBase.RunInUiWait(() => + + var saveFolder = UiThread.Invoke(() => SystemDialogs.SelectFolder(Lang.Text("Download.Comp.QuickDownload.Hint.SelectFolder"))); if (string.IsNullOrWhiteSpace(saveFolder)) return; // 取消 var target = Path.Combine(saveFolder, CompFileNameGet(project, file)); @@ -3546,7 +3544,7 @@ private static void _StartQuickDownload(CompFile file, string target) _ => Lang.Text("Download.Comp.Type.Mod") }; var loaderName = Lang.Text("Download.Comp.Detail.DownloadResource", desc, - ModBase.GetFileNameWithoutExtentionFromPath(target)); + LegacyFileFacade.GetFileNameWithoutExtensionFromPath(target)); var loaders = new List { new LoaderDownload(Lang.Text("Download.Comp.Detail.DownloadFile"), @@ -3561,14 +3559,14 @@ private static void _StartQuickDownload(CompFile file, string target) var extractDir = Path.GetDirectoryName(target); loaders.Add(new ModLoader.LoaderTask( Lang.Text("Download.Comp.Detail.InstallWorld"), - _ => ModBase.ExtractFile(target, extractDir, Encoding.UTF8)) + _ => LegacyFileFacade.ExtractFile(target, extractDir, Encoding.UTF8)) { ProgressWeight = 0.1d, block = true }); loaders.Add(new ModLoader.LoaderTask( Lang.Text("Download.Comp.Detail.CleanCache"), - _ => System.IO.File.Delete(target))); + _ => File.Delete(target))); } var loader = new ModLoader.LoaderCombo(loaderName, loaders) { @@ -3686,7 +3684,7 @@ private static void _AddDependencyBar(StackPanel stack, List depIds, str if (compProjectCache.TryGetValue(dep, out var project)) projects.Add(project); else - ModBase.Log($"[Comp] 未找到 ID {dep} 的前置信息", ModBase.LogLevel.Debug); + LauncherLog.Log($"[Comp] 未找到 ID {dep} 的前置信息", LauncherLogLevel.Debug); } if (!projects.Any()) return; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModCompDependency.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModCompDependency.cs index 8ac5c3c4b..1c26bb2ef 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModCompDependency.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModCompDependency.cs @@ -1,12 +1,12 @@ -using System.IO; +using System.IO; +using PCL.Core.App.Localization; +using PCL.Core.Minecraft.ResourceProject; +using PCL.Network; using CompFile = PCL.ModComp.CompFile; using CompFileStatus = PCL.ModComp.CompFileStatus; using CompLoaderType = PCL.ModComp.CompLoaderType; using CompProject = PCL.ModComp.CompProject; using LocalCompFile = PCL.ModLocalComp.LocalCompFile; -using PCL.Core.Minecraft.ResourceProject; -using PCL.Core.App.Localization; -using PCL.Network; namespace PCL; @@ -223,7 +223,7 @@ public static ModComp.CompDepsInstallTypes ConfirmDependencyInstall(ModDependenc if (result.Unresolved is { Count: > 0 }) { - ModBase.Log($"[CompDeps] 无法解析: {result.Unresolved.Count} 个必需前置"); + LauncherLog.Log($"[CompDeps] 无法解析: {result.Unresolved.Count} 个必需前置"); var dependencies = string.Join( Lang.Text("Download.Comp.Dependency.ListSeparator"), result.Unresolved.Select(dep => Lang.Text( diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs index 50377447d..03d2343ab 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs @@ -2,7 +2,6 @@ using System.IO; using System.Net; using System.Text; -using System.Text.Json.Nodes; using PCL.Core.App; using PCL.Core.App.Localization; using PCL.Core.IO.Net.Http; @@ -30,7 +29,7 @@ public static DownloadFile DlClientJarGet(McInstance version, bool returnNothing } catch (Exception ex) { - ModBase.Log(ex, "获取底层继承实例失败"); + LauncherLog.Log(ex, "获取底层继承实例失败"); } // 检查 Json 是否标准 @@ -38,7 +37,7 @@ public static DownloadFile DlClientJarGet(McInstance version, bool returnNothing version.JsonObject["downloads"]["client"]["url"] is null) throw new Exception(Lang.Text("Minecraft.Download.Error.NoJarDownloadInfo", version.Name)); // 检查文件 - var checker = new ModBase.FileChecker(1024L, (long)(version.JsonObject["downloads"]["client"]["size"] ?? -1), + var checker = new FileChecker(1024L, (long)(version.JsonObject["downloads"]["client"]["size"] ?? -1), (string)version.JsonObject["downloads"]["client"]["sha1"]); if (returnNothingOnFileUseable && checker.Check(version.PathInstance + version.Name + ".jar") is null) return null; // 通过校验 @@ -60,12 +59,12 @@ public static DownloadFile DlClientAssetIndexGet(McInstance version) // 获取信息 var indexInfo = ModAssets.McAssetsGetIndex(version, true, true); var indexAddress = Path.Combine(ModFolder.mcFolderSelected, "assets", "indexes", indexInfo["id"] + ".json"); - ModBase.Log("[Download] 实例 " + version.Name + " 对应的资源文件索引为 " + indexInfo["id"]); + LauncherLog.Log($"[Download] 实例 {version.Name} 对应的资源文件索引为 {indexInfo["id"]}"); var indexUrl = (string)(indexInfo["url"] ?? ""); if (string.IsNullOrEmpty(indexUrl)) return null; return new DownloadFile(DlSourceLauncherOrMetaGet(indexUrl), indexAddress, - new ModBase.FileChecker(canUseExistsFile: false)); + new FileChecker(canUseExistsFile: false)); } /// @@ -80,7 +79,7 @@ public static DownloadFile DlClientAssetIndexGet(McInstance version) if (ModLibrary.ShouldIgnoreFileCheck(version)) { - ModBase.Log("[Download] 已跳过所有 Libraries 检查"); + LauncherLog.Log("[Download] 已跳过所有 Libraries 检查"); } else { @@ -105,7 +104,7 @@ public static DownloadFile DlClientAssetIndexGet(McInstance version) if (ModLibrary.ShouldIgnoreFileCheck(version)) { - ModBase.Log("[Download] 已跳过所有 Assets 检查"); + LauncherLog.Log("[Download] 已跳过所有 Assets 检查"); } else { @@ -144,14 +143,14 @@ public static DownloadFile DlClientAssetIndexGet(McInstance version) { var backAssetsFile = DlClientAssetIndexGet(version); realAddress = backAssetsFile.LocalPath; - tempAddress = ModBase.pathTemp + @"Cache\" + backAssetsFile.LocalName; + tempAddress = LauncherPaths.TempWithSlash + @"Cache\" + backAssetsFile.LocalName; backAssetsFile.LocalPath = tempAddress; task.output = new List { backAssetsFile }; // 检查是否需要更新:每天只更新一次 if (File.Exists(realAddress) && Math.Abs((File.GetLastWriteTime(realAddress).Date - DateTime.Now.Date).TotalDays) < 1d) { - ModBase.Log("[Download] 无需更新资源文件索引,取消"); + LauncherLog.Log("[Download] 无需更新资源文件索引,取消"); task.Abort(); } })); @@ -160,12 +159,12 @@ public static DownloadFile DlClientAssetIndexGet(McInstance version) loadersAssetsUpdate.Add(new ModLoader.LoaderTask, string>( Lang.Text("Minecraft.Download.Stage.CopyAssetsIndex.Background"), task => { - ModBase.CopyFile(tempAddress, realAddress); + LegacyFileFacade.CopyFile(tempAddress, realAddress); ModLaunch.McLaunchLog("后台更新资源文件索引成功:" + tempAddress); })); var updater = new ModLoader.LoaderCombo( Lang.Text("Minecraft.Download.Stage.UpdateAssetsIndex.Background"), loadersAssetsUpdate); - ModBase.Log("[Download] 开始后台检查资源文件索引"); + LauncherLog.Log("[Download] 开始后台检查资源文件索引"); updater.Start(); } @@ -235,7 +234,7 @@ public static List AllDrops field = new List(); else field = rawData.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) - .Select(d => (int)Math.Round(ModBase.Val(d))).ToList(); + .Select(d => (int)Math.Round(LauncherText.Val(d))).ToList(); } return field.Count != 0 ? field : null; @@ -343,7 +342,7 @@ private static void DlClientListMojangMain(ModLoader.LoaderTask GetNeoForgeEntries(string latestJson, string latestLegacyJson) { - var versionNames = ModBase.RegexSearch(latestLegacyJson + latestJson, RegexPatterns.DlNeoForgeVersion); + var versionNames = LauncherText.RegexSearch(latestLegacyJson + latestJson, RegexPatterns.DlNeoForgeVersion); var versions = versionNames.Where(name => name != "47.1.82").Select(name => new DlNeoForgeListEntry(name)) .OrderByDescending(a => a).ToList(); // 这个版本虽然在版本列表中,但不能下载 if (!versions.Any()) @@ -2034,7 +2034,7 @@ private static void DlLabyModListOfficialMain(ModLoader.LoaderTask(string url) UseBrowserUserAgent = true }); if (typeof(T) == typeof(string)) return (T)(object)json; - return (T)(object)ModBase.GetJson(json); + return (T)(object)JsonCompat.ParseNode(json); } catch (Exception ex) { @@ -2192,7 +2192,7 @@ public static T DlModRequest(string url, string method, string data, string c Timeout = Source.Value * 1000 }); if (typeof(T) == typeof(string)) return (T)(object)json; // 沟槽的,为什么不能写 T is string - return (T)(object)ModBase.GetJson(json); + return (T)(object)JsonCompat.ParseNode(json); } catch (Exception ex) { @@ -2390,9 +2390,9 @@ private static void DlSourceLoader(ModLoader.LoaderTask(ModLoader.LoaderTask(ModLoader.LoaderTask l.Key.State == ModBase.LoadState.Failed)) + if (i < loaderList.Count - 1 && loaderList.Any(l => l.Key.State != LoadState.Failed)) { // 若还有下一个源,则启动下一个源 loaderList[i + 1].Key.Start(mainLoader.input, isForceRestart); @@ -2461,7 +2461,7 @@ private static void DlSourceLoaderAbort( List, int>> loaderList) { foreach (var Loader in loaderList) - if (Loader.Key.State == ModBase.LoadState.Loading) + if (Loader.Key.State == LoadState.Loading) Loader.Key.Abort(); } @@ -2587,7 +2587,7 @@ public static void McDownloadClientUpdateHint(string versionName, JsonObject jso // 弹窗结果 if (msgResult == 2) // 下载 - ModBase.RunInUi(() => + UiThread.Post(() => { PageDownloadInstall.mcVersionWaitingForSelect = versionName; ModMain.frmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall); @@ -2596,10 +2596,10 @@ public static void McDownloadClientUpdateHint(string versionName, JsonObject jso catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Error.UpdateNotify", versionName ?? "Nothing"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Error.UpdateNotify", versionName ?? "Nothing")); } } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModFolder.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModFolder.cs index a70474300..27595ff94 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModFolder.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModFolder.cs @@ -1,13 +1,10 @@ -using System; -using System.Collections; -using System.Collections.Generic; +using System.Collections; using System.Globalization; using System.IO; using System.Text; using PCL.Core.App; using PCL.Core.App.Localization; using PCL.Core.Utils; -using PCL.Core.Utils.Exts; namespace PCL; @@ -86,7 +83,7 @@ private static void McFolderListLoadSub() var path = folder.Split(">")[1]; try { - ModBase.CheckPermissionWithException(path); + LegacyFileFacade.CheckPermissionWithException(path); cacheMcFolderList.Add(new McFolder { Name = name, Location = path, type = McFolder.Types.Custom }); } catch (Exception ex) @@ -94,7 +91,7 @@ private static void McFolderListLoadSub() ModMain.MyMsgBox( Lang.Text("Select.Folder.Invalid.WithDetail", path, ex.ToString()), Lang.Text("Select.Folder.InvalidTitle"), isWarn: true); - ModBase.Log(ex, $"无法访问 Minecraft 文件夹 {path}"); + LauncherLog.Log(ex, $"无法访问 Minecraft 文件夹 {path}"); } } @@ -107,10 +104,13 @@ private static void McFolderListLoadSub() // 扫描当前文件夹 try { - if (Directory.Exists(ModBase.exePath + @"versions\")) + if (Directory.Exists(LauncherPaths.ExecutableDirectoryWithSlash + @"versions\")) originalMcFolderList.Add(new McFolder - { Name = Lang.Text("Select.Folder.CurrentFolder"), Location = ModBase.exePath, type = McFolder.Types.Original }); - foreach (var folder in new DirectoryInfo(ModBase.exePath).GetDirectories()) + { + Name = Lang.Text("Select.Folder.CurrentFolder"), + Location = LauncherPaths.ExecutableDirectoryWithSlash, type = McFolder.Types.Original + }); + foreach (var folder in new DirectoryInfo(LauncherPaths.ExecutableDirectoryWithSlash).GetDirectories()) if (Directory.Exists(Path.Combine(folder.FullName, "versions")) || folder.Name == ".minecraft") { var newCurrentFolder = new McFolder @@ -121,7 +121,7 @@ private static void McFolderListLoadSub() } catch (Exception ex) { - ModBase.Log(ex, "扫描 PCL 所在文件夹中是否有 MC 文件夹失败"); + LauncherLog.Log(ex, "扫描 PCL 所在文件夹中是否有 MC 文件夹失败"); } // 扫描官启文件夹 @@ -132,7 +132,7 @@ private static void McFolderListLoadSub() originalMcFolderList.Add(new McFolder { Name = Lang.Text("Select.Folder.OfficialLauncherFolder"), Location = mojangPath, type = McFolder.Types.Original }); - ModBase.Log(cacheMcFolderList.Count + " 个自定义文件夹," + originalMcFolderList.Count + " 个原始文件夹"); + LauncherLog.Log($"{cacheMcFolderList.Count} 个自定义文件夹,{originalMcFolderList.Count} 个原始文件夹"); foreach (var newOriginalFolder in originalMcFolderList) { @@ -168,9 +168,13 @@ private static void McFolderListLoadSub() // 若没有可用文件夹,则创建 .minecraft if (!cacheMcFolderList.Any()) { - Directory.CreateDirectory(ModBase.exePath + @".minecraft\versions\"); + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\versions\"); cacheMcFolderList.Add(new McFolder - { Name = Lang.Text("Select.Folder.CurrentFolder"), Location = ModBase.exePath + @".minecraft\", type = McFolder.Types.Original }); + { + Name = Lang.Text("Select.Folder.CurrentFolder"), + Location = LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\", + type = McFolder.Types.Original + }); } foreach (var Folder in cacheMcFolderList) McFolderLauncherProfilesJsonCreate(Folder.Location); @@ -183,10 +187,10 @@ private static void McFolderListLoadSub() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.Load"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Folder.Error.Load")); } } @@ -215,15 +219,16 @@ public static void McFolderLauncherProfilesJsonCreate(string folder) ""selectedProfile"": ""PCL"", ""clientToken"": ""23323323323323323323323323323333"" }"; - ModBase.WriteFile(Path.Combine(folder, "launcher_profiles.json"), resultJson, encoding: Encoding.GetEncoding("GB18030")); - ModBase.Log("[Minecraft] 已创建 launcher_profiles.json:" + folder); + LegacyFileFacade.WriteFile(Path.Combine(folder, "launcher_profiles.json"), resultJson, + encoding: Encoding.GetEncoding("GB18030")); + LauncherLog.Log($"[Minecraft] 已创建 launcher_profiles.json:{folder}"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, - "创建 launcher_profiles.json 失败(" + folder + ")", - ModBase.LogLevel.Feedback, + $"创建 launcher_profiles.json 失败({folder})", + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Folder.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs index 20d3bfb34..874fac5fd 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs @@ -1,14 +1,8 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; +using System.IO; using PCL.Core.App; using PCL.Core.App.Localization; -using PCL.Core.UI; using PCL.Core.Utils; using PCL.Core.Utils.Exts; -using PCL.Network; namespace PCL; @@ -42,7 +36,7 @@ public static McInstance McMcInstanceSelected /// /// 当前按卡片分类的所有版本列表。 /// - public static Dictionary> mcInstanceList = new(); + public static Dictionary> mcInstanceList = new(); #endregion @@ -71,7 +65,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) try { // 初始化 - mcInstanceList = new Dictionary>(); + mcInstanceList = new Dictionary>(); var versionsPath = Path.Combine(path, "versions"); var folderList = new List(); @@ -90,20 +84,21 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) // 如果没有可用实例,清空缓存并跳过后续处理 if (!folderList.Any()) { - ModBase.WriteIni(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); + LegacyIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); McMcInstanceSelected = null; States.Game.SelectedInstance = ""; - ModBase.Log("[Minecraft] 未找到可用 Minecraft 实例"); + LauncherLog.Log("[Minecraft] 未找到可用 Minecraft 实例"); return; } // 根据文件夹名列表生成辨识码 - var folderListHash = ModBase.GetHash(mcInstanceCacheVersion + "#" + string.Join("#", folderList)); + var folderListHash = LauncherText.GetHash(mcInstanceCacheVersion + "#" + string.Join("#", folderList)); var folderListCheck = (int)(folderListHash % (int.MaxValue - 1)); // 尝试使用缓存 var useCache = !mcInstanceListForceRefresh && - ModBase.Val(ModBase.ReadIni(Path.Combine(path, "PCL.ini"), "InstanceCache")) == + LauncherText.Val(LegacyIniStore.Shared.Read(Path.Combine(path, "PCL.ini"), + "InstanceCache")) == folderListCheck; if (useCache) @@ -119,8 +114,8 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) if (!useCache) { mcInstanceListForceRefresh = false; - ModBase.Log("[Minecraft] 文件夹列表变更或缓存无效,重载所有实例"); - ModBase.WriteIni(Path.Combine(path, "PCL.ini"), "InstanceCache", folderListCheck.ToString()); + LauncherLog.Log("[Minecraft] 文件夹列表变更或缓存无效,重载所有实例"); + LegacyIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", folderListCheck.ToString()); mcInstanceList = InitMcInstanceListWithoutCache(path); } @@ -130,7 +125,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) return; // 尝试读取已储存的选择 - var savedSelection = ModBase.ReadIni(Path.Combine(path, "PCL.ini"), "Version"); + var savedSelection = LegacyIniStore.Shared.Read(Path.Combine(path, "PCL.ini"), "Version"); if (!string.IsNullOrEmpty(savedSelection)) foreach (var card in mcInstanceList) foreach (var instance in card.Value) @@ -138,7 +133,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) { McMcInstanceSelected = instance; States.Game.SelectedInstance = McMcInstanceSelected.Name; - ModBase.Log("[Minecraft] 选择该文件夹储存的 Minecraft 实例:" + McMcInstanceSelected.PathInstance); + LauncherLog.Log($"[Minecraft] 选择该文件夹储存的 Minecraft 实例:{McMcInstanceSelected.PathInstance}"); return; } @@ -151,13 +146,13 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) { McMcInstanceSelected = firstInstance; States.Game.SelectedInstance = McMcInstanceSelected.Name; - ModBase.Log("[Launch] 自动选择 Minecraft 实例:" + McMcInstanceSelected.PathInstance); + LauncherLog.Log($"[Launch] 自动选择 Minecraft 实例:{McMcInstanceSelected.PathInstance}"); } else { McMcInstanceSelected = null; States.Game.SelectedInstance = ""; - ModBase.Log("[Minecraft] 未找到可用 Minecraft 实例"); + LauncherLog.Log("[Minecraft] 未找到可用 Minecraft 实例"); } // 调试延迟 @@ -170,33 +165,34 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) } catch (Exception ex) { - ModBase.WriteIni(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); // 要求下次重新加载 - ModBase.Log( + LegacyIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); // 要求下次重新加载 + LauncherLog.Log( ex, Lang.Text("Select.Instance.Error.ListLoad"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Instance.Error.ListLoad")); } } // 获取实例列表 - private static Dictionary> InitMcInstanceListWithCache(string path) + private static Dictionary> InitMcInstanceListWithCache(string path) { - var results = new Dictionary>(); + var results = new Dictionary>(); try { - var cardCount = int.Parse(ModBase.ReadIni(path + "PCL.ini", "CardCount", (-1).ToString())); + var cardCount = int.Parse(LegacyIniStore.Shared.Read(path + "PCL.ini", "CardCount", (-1).ToString())); if (cardCount == -1) return null; for (int i = 0, loopTo = cardCount - 1; i <= loopTo; i++) { var cardType = - (McInstanceCardType)int.Parse(ModBase.ReadIni(path + "PCL.ini", "CardKey" + (i + 1), + (McInstanceCardType)int.Parse(LegacyIniStore.Shared.Read(path + "PCL.ini", "CardKey" + (i + 1), "0")); - var instanceList = new List(); + var instanceList = new List(); // 循环读取实例 - foreach (var folder in ModBase.ReadIni(path + "PCL.ini", "CardValue" + (i + 1), ":").Split(":")) + foreach (var folder in LegacyIniStore.Shared.Read(path + "PCL.ini", "CardValue" + (i + 1), ":") + .Split(":")) { if (string.IsNullOrEmpty(folder)) continue; @@ -205,12 +201,12 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) { if (_isFirstMcInstanceListLoad) { - ModBase.Log("[Minecraft] 清理残留的忽略项目:" + versionFolder); // #2781 + LauncherLog.Log($"[Minecraft] 清理残留的忽略项目:{versionFolder}"); // #2781 File.Delete(versionFolder + ".pclignore"); } else { - ModBase.Log("[Minecraft] 跳过要求忽略的项目:" + versionFolder); + LauncherLog.Log($"[Minecraft] 跳过要求忽略的项目:{versionFolder}"); continue; } } @@ -218,7 +214,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) try { // 读取单个实例 - var instance = new PCL.McInstance(versionFolder); + var instance = new McInstance(versionFolder); instanceList.Add(instance); var instanceCfg = States.Instance; instance.Desc = instanceCfg.CustomInfo[instance.PathInstance]; @@ -277,7 +273,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) !((oldDesc ?? "") == (instance.Desc ?? "")))) { - ModBase.Log("[Minecraft] 实例 " + instance.Name + " 的错误状态已变更,新的状态为:" + instance.Desc); + LauncherLog.Log($"[Minecraft] 实例 {instance.Name} 的错误状态已变更,新的状态为:{instance.Desc}"); return null; } } @@ -285,14 +281,14 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) // 校验未加载的实例 if (string.IsNullOrEmpty(instance.Logo)) { - ModBase.Log("[Minecraft] 实例 " + instance.Name + " 未被加载"); + LauncherLog.Log($"[Minecraft] 实例 {instance.Name} 未被加载"); return null; } } catch (Exception ex) { - ModBase.Log(ex, "读取实例加载缓存失败(" + folder + ")"); + LauncherLog.Log(ex, "读取实例加载缓存失败(" + folder + ")"); return null; } } @@ -305,14 +301,14 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) } catch (Exception ex) { - ModBase.Log(ex, "读取实例缓存失败"); + LauncherLog.Log(ex, "读取实例缓存失败"); return null; } } - private static Dictionary> InitMcInstanceListWithoutCache(string path) + private static Dictionary> InitMcInstanceListWithoutCache(string path) { - var instanceList = new List(); + var instanceList = new List(); #region 循环加载每个实例的信息 @@ -320,14 +316,14 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) { if (!folder.Exists || !folder.EnumerateFiles().Any()) { - ModBase.Log("[Minecraft] 跳过空文件夹:" + folder.FullName); + LauncherLog.Log($"[Minecraft] 跳过空文件夹:{folder.FullName}"); continue; } if ((folder.Name == "cache" || folder.Name == "BLClient" || folder.Name == "PCL") && !File.Exists(Path.Combine(folder.FullName, folder.Name + ".json"))) { - ModBase.Log("[Minecraft] 跳过可能不是实例文件夹的项目:" + folder.FullName); + LauncherLog.Log($"[Minecraft] 跳过可能不是实例文件夹的项目:{folder.FullName}"); continue; } @@ -336,45 +332,45 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) { if (_isFirstMcInstanceListLoad) { - ModBase.Log("[Minecraft] 清理残留的忽略项目:" + instanceFolder); // #2781 + LauncherLog.Log($"[Minecraft] 清理残留的忽略项目:{instanceFolder}"); // #2781 try { - File.Delete(instanceFolder + ".pclignore"); + File.Delete($"{instanceFolder}.pclignore"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.Cleanup", instanceFolder), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Select.Folder.Error.Cleanup", instanceFolder)); } } else { - ModBase.Log("[Minecraft] 跳过要求忽略的项目:" + instanceFolder); + LauncherLog.Log($"[Minecraft] 跳过要求忽略的项目:{instanceFolder}"); continue; } } - var instance = new PCL.McInstance(instanceFolder); + var instance = new McInstance(instanceFolder); instanceList.Add(instance); instance.Load(); } #endregion - var results = new Dictionary>(); + var results = new Dictionary>(); #region 将实例分类到各个卡片 try { // 未经过自定义的实例列表 - var instanceListOriginal = new Dictionary>(); + var instanceListOriginal = new Dictionary>(); // 单独列出收藏的实例 - var staredInstances = new List(); + var staredInstances = new List(); foreach (var instance in instanceList.ToList()) { if (!instance.IsStar) @@ -404,8 +400,8 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) }, McInstanceCardType.API); // 将老实例预先分类入不常用,只剩余原版、快照、OptiFine - var instanceUseful = new List(); - var instanceRubbish = new List(); + var instanceUseful = new List(); + var instanceRubbish = new List(); McInstanceFilter(ref instanceList, new[] { McInstanceState.Old }, ref instanceRubbish); // 确认最新实例,若为快照则加入常用列表 @@ -422,7 +418,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) McInstanceFilter(ref instanceList, new[] { McInstanceState.Snapshot }, ref instanceRubbish); // 获取每个 Drop 下最新的原版与 OptiFine - var newerInstance = new Dictionary(); + var newerInstance = new Dictionary(); var existDrops = new List(); foreach (var instance in instanceList) { @@ -494,7 +490,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) ? instancePair.Key : instance.displayType; if (!results.ContainsKey(realType)) - results.Add(realType, new List()); + results.Add(realType, new List()); results[realType].Add(instance); } } @@ -502,10 +498,10 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) catch (Exception ex) { results.Clear(); - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Instance.Error.Classify"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Instance.Error.Classify")); } @@ -514,7 +510,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) #region 对卡片与实例进行排序 // 卡片排序 - var sortedInstanceList = new Dictionary>(); + var sortedInstanceList = new Dictionary>(); foreach (var sortRule in new[] { McInstanceCardType.Star, McInstanceCardType.API, McInstanceCardType.OriginalLike, @@ -536,7 +532,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) if (!results.ContainsKey(cardType)) continue; - int getComponentCode(PCL.McInstance instance) + int getComponentCode(McInstance instance) { if (instance.Info.ForgelikeCode > 0) return instance.Info.ForgelikeCode; @@ -583,15 +579,15 @@ int getComponentCode(PCL.McInstance instance) #region 保存卡片缓存 - ModBase.WriteIni(path + "PCL.ini", "CardCount", results.Count.ToString()); + LegacyIniStore.Shared.Write(path + "PCL.ini", "CardCount", results.Count.ToString()); for (int i = 0, loopTo = results.Count - 1; i <= loopTo; i++) { - ModBase.WriteIni(path + "PCL.ini", "CardKey" + (i + 1), + LegacyIniStore.Shared.Write(path + "PCL.ini", "CardKey" + (i + 1), ((int)results.Keys.ElementAtOrDefault(i)).ToString()); var value = ""; foreach (var Instance in results.Values.ElementAtOrDefault(i)) value += Instance.Name + ":"; - ModBase.WriteIni(path + "PCL.ini", "CardValue" + (i + 1), value); + LegacyIniStore.Shared.Write(path + "PCL.ini", "CardValue" + (i + 1), value); } #endregion @@ -605,8 +601,8 @@ int getComponentCode(PCL.McInstance instance) /// 用于筛选的列表。 /// 需要筛选出的实例类型。-2 代表隐藏的实例。 /// 卡片的名称。 - private static void McInstanceFilter(ref List instanceList, - ref Dictionary> target, McInstanceState[] formula, + private static void McInstanceFilter(ref List instanceList, + ref Dictionary> target, McInstanceState[] formula, McInstanceCardType cardType) { var keepList = instanceList.Where(v => formula.Contains(v.state)).ToList(); @@ -624,7 +620,7 @@ private static void McInstanceFilter(ref List instanceList, /// 用于筛选的列表。 /// 需要筛选出的实例类型。-2 代表隐藏的实例。 /// 传入需要增加入的列表。 - private static void McInstanceFilter(ref List instanceList, McInstanceState[] formula, + private static void McInstanceFilter(ref List instanceList, McInstanceState[] formula, ref List keepList) { keepList.AddRange(instanceList.Where(v => formula.Contains(v.state))); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs index f4f2188c9..3109b2aba 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs @@ -1,14 +1,13 @@ using System.IO; -using System.Text.Json; using PCL.Core.App; +using PCL.Core.App.Localization; using PCL.Core.IO; using PCL.Core.Minecraft; using PCL.Core.Minecraft.Java.UserPreference; +using PCL.Core.Utils; +using PCL.Core.Utils.OS; using PCL.Network; using PCL.Network.Loaders; -using PCL.Core.App.Localization; -using PCL.Core.Utils.OS; -using PCL.Core.Utils; namespace PCL; @@ -34,7 +33,7 @@ public static class ModJava public static JavaEntry JavaSelect(string cancelException, Version minVersion = null, Version maxVersion = null, McInstance relatedInstance = null) { - ModBase.Log( + LauncherLog.Log( $"[Java] 要求选择合适 Java,要求最低版本 {(minVersion is not null ? minVersion.ToString() : "未指定")},要求选择的最高版本 {(maxVersion is not null ? maxVersion.ToString() : "未指定")},关联实例 {(relatedInstance is not null ? relatedInstance.Name : "未指定")}"); // 版本范围验证函数(安全处理 null 边界) @@ -69,11 +68,11 @@ bool IsVersionSuitable(Version ver) candidate.Installation.Version, minVersion, maxVersion)); - ModBase.Log($"[Java] 返回实例 '{relatedInstance.Name}' 指定的 Java: {candidate}"); + LauncherLog.Log($"[Java] 返回实例 '{relatedInstance.Name}' 指定的 Java: {candidate}"); return candidate; } - ModBase.Log($"[Java] 警告:实例指定的 Java 路径无效或不可用: {existPref.JavaExePath}"); + LauncherLog.Log($"[Java] 警告:实例指定的 Java 路径无效或不可用: {existPref.JavaExePath}"); break; } @@ -96,14 +95,14 @@ bool IsVersionSuitable(Version ver) minVersion, maxVersion), HintType.Error); - ModBase.Log( + LauncherLog.Log( $"[Java] 返回实例 '{relatedInstance.Name}' 相对路径指定的 Java ({relPref.RelativePath}): {candidate}"); return candidate; } } else { - ModBase.Log($"[Java] 警告:实例相对路径指定的 Java 无效: {absPath}"); + LauncherLog.Log($"[Java] 警告:实例相对路径指定的 Java 无效: {absPath}"); } break; @@ -112,22 +111,22 @@ bool IsVersionSuitable(Version ver) case object _ when preference is UseGlobalPreference: // "global" { // 不返回,继续到全局设置检查 - ModBase.Log($"[Java] 实例 '{relatedInstance.Name}' 配置为使用全局 Java 设置,继续检查全局配置"); + LauncherLog.Log($"[Java] 实例 '{relatedInstance.Name}' 配置为使用全局 Java 设置,继续检查全局配置"); break; } default: { - ModBase.Log($"[Java] 警告:未知的 Java 偏好类型 '{preference}',跳过处理"); + LauncherLog.Log($"[Java] 警告:未知的 Java 偏好类型 '{preference}',跳过处理"); break; } } else - ModBase.Log($"[Java] 实例 '{relatedInstance.Name}' 未指定 Java 偏好(空值),使用自动选择策略"); + LauncherLog.Log($"[Java] 实例 '{relatedInstance.Name}' 未指定 Java 偏好(空值),使用自动选择策略"); } else { - ModBase.Log($"[Java] 实例 '{relatedInstance.Name}' 无 Java 偏好配置,使用自动选择策略"); + LauncherLog.Log($"[Java] 实例 '{relatedInstance.Name}' 无 Java 偏好配置,使用自动选择策略"); } } @@ -146,19 +145,19 @@ bool IsVersionSuitable(Version ver) candidate.Installation.Version, minVersion, maxVersion)); - ModBase.Log($"[Java] 返回全局指定的 Java: {candidate}"); + LauncherLog.Log($"[Java] 返回全局指定的 Java: {candidate}"); return candidate; } - ModBase.Log($"[Java] 警告:全局指定的 Java 路径无效或不可用: {globalJavaPath}"); + LauncherLog.Log($"[Java] 警告:全局指定的 Java 路径无效或不可用: {globalJavaPath}"); } else { - ModBase.Log("[Java] 无全局 Java 配置,使用自动选择策略"); + LauncherLog.Log("[Java] 无全局 Java 配置,使用自动选择策略"); } // ===== 优先级 3:自动搜索合适版本 ===== - ModBase.Log("[Java] 开始自动搜索符合版本要求的 Java 运行时"); + LauncherLog.Log("[Java] 开始自动搜索符合版本要求的 Java 运行时"); Javas.CheckAllAvailability(); var reqMin = minVersion ?? new Version(1, 0, 0); @@ -169,16 +168,16 @@ bool IsVersionSuitable(Version ver) if (ret is null && candidates.Length == 0) { - ModBase.Log("[Java] 未找到符合版本要求的 Java,触发全盘重新扫描"); + LauncherLog.Log("[Java] 未找到符合版本要求的 Java,触发全盘重新扫描"); Javas.ScanJavaAsync().GetAwaiter().GetResult(); candidates = Javas.SelectSuitableJavaAsync(reqMin, reqMax).GetAwaiter().GetResult(); ret = candidates.FirstOrDefault(); } if (ret is not null) - ModBase.Log($"[Java] 返回自动选择的 Java: {ret}"); + LauncherLog.Log($"[Java] 返回自动选择的 Java: {ret}"); else - ModBase.Log("[Java] 最终未能确定可用的 Java 运行时"); + LauncherLog.Log("[Java] 最终未能确定可用的 Java 运行时"); return ret; } @@ -265,7 +264,7 @@ public static bool IsGameSet64BitJava(McInstance relatedVersion = null) var userSetup = Config.Launch.SelectedJava; if (userSetup.StartsWith("{")) // 旧版本 Json 格式 { - var js = ModBase.GetJson(userSetup); + var js = JsonCompat.ParseNode(userSetup); userSetup = $"{js["Path"]}java.exe"; Config.Launch.SelectedJava = userSetup; } @@ -312,10 +311,10 @@ public static bool IsGameSet64BitJava(McInstance relatedVersion = null) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "检查 Java 类别时出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Launch.Java.Compatibility.CheckFailed")); if (relatedVersion is not null) Config.Instance.SelectedJava[relatedVersion.PathInstance] = "使用全局设置"; @@ -374,15 +373,15 @@ public static ModLoader.LoaderCombo GetJavaDownloadLoader() { switch (newState) { - case ModBase.LoadState.Failed or ModBase.LoadState.Aborted + case LoadState.Failed or LoadState.Aborted when lastJavaBaseDir is not null: - ModBase.Log( + LauncherLog.Log( $"[Java] 由于下载未完成,清理未下载完成的 Java 文件:{lastJavaBaseDir}", - ModBase.LogLevel.Debug); + LauncherLogLevel.Debug); - ModBase.DeleteDirectory(lastJavaBaseDir); + LegacyFileFacade.DeleteDirectory(lastJavaBaseDir); break; - case ModBase.LoadState.Finished: + case LoadState.Finished: Javas.ScanJavaAsync().GetAwaiter().GetResult(); lastJavaBaseDir = null; break; @@ -403,7 +402,7 @@ public static ModLoader.LoaderCombo GetJavaDownloadLoader() private static void JavaFileList(ModLoader.LoaderTask> loader) { - ModBase.Log("[Java] 开始获取 Java 下载信息"); + LauncherLog.Log("[Java] 开始获取 Java 下载信息"); var indexFileStr = ModNet.NetGetCodeByLoader( ModDownload.DlVersionListOrder( new[] @@ -418,7 +417,8 @@ private static void JavaFileList(ModLoader.LoaderTask string? targetName = null; JsonNode? targetValue = null; var components = - (JsonObject)((JsonObject)ModBase.GetJson(indexFileStr))[$"windows-x{(SystemInfo.Is32BitSystem ? "86" : "64")}"]; + (JsonObject)((JsonObject)JsonCompat.ParseNode(indexFileStr))[ + $"windows-x{(SystemInfo.Is32BitSystem ? "86" : "64")}"]; if (components.ContainsKey(loader.input)) // 精确匹配 { targetName = loader.input; @@ -456,7 +456,7 @@ private static void JavaFileList(ModLoader.LoaderTask if (ignoreHash.Contains((string)checkHash)) continue; // 跳过 3 个无意义大量重复文件(#3827) - var checker = new ModBase.FileChecker(actualSize: (long)info["size"], hash: (string)info["sha1"]); + var checker = new FileChecker(actualSize: (long)info["size"], hash: (string)info["sha1"]); var filePath = Path.GetFullPath(Path.Combine(lastJavaBaseDir, File.Key)); if (!Files.IsPathWithinDirectory(filePath, lastJavaBaseDir)) throw new Exception($"{filePath} 不在 {lastJavaBaseDir} 中"); @@ -470,7 +470,7 @@ private static void JavaFileList(ModLoader.LoaderTask } loader.output = results; - ModBase.Log($"[Java] 需要下载 {results.Count} 个文件,目标文件夹:{lastJavaBaseDir}"); + LauncherLog.Log($"[Java] 需要下载 {results.Count} 个文件,目标文件夹:{lastJavaBaseDir}"); } #endregion diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs index e0aedbbb9..8e167ec5b 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs @@ -1,24 +1,23 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.IO; using System.IO.Compression; using System.Net; using System.Net.Http; using System.Text; -using System.Text.Json; -using System.Text.Json.Nodes; using System.Windows; using PCL.Core.App; using PCL.Core.App.Localization; +using PCL.Core.IO.Net.Http; using PCL.Core.Minecraft; +using PCL.Core.Minecraft.IdentityModel.Yggdrasil; using PCL.Core.Minecraft.Launch.Utils; using PCL.Core.Utils; +using PCL.Core.Utils.Codecs; using PCL.Core.Utils.OS; using PCL.Core.Utils.Secret; using PCL.Network; -using PCL.Core.IO.Net.Http; -using PCL.Core.Minecraft.IdentityModel.Yggdrasil; -using System.Globalization; namespace PCL; @@ -39,7 +38,7 @@ private static void McLaunchPrecheck() if (ModInstanceList.McMcInstanceSelected.PathInstance.Contains("!") || ModInstanceList.McMcInstanceSelected.PathInstance.Contains(";")) throw new Exception(Lang.Text("Minecraft.Launch.Precheck.InvalidPathChars", ModInstanceList.McMcInstanceSelected.PathInstance)); - if (ModBase.IsUtf8CodePage() && !States.Hint.NonAsciiGamePath && + if (EncodingUtils.IsDefaultEncodingUtf8() && !States.Hint.NonAsciiGamePath && !ModInstanceList.McMcInstanceSelected.PathInstance.IsASCII()) { var userChoice = ModMain.MyMsgBox( @@ -57,7 +56,7 @@ private static void McLaunchPrecheck() throw new Exception(Lang.Text("Minecraft.Launch.Precheck.InstanceError", ModInstanceList.McMcInstanceSelected.Desc)); // 检查输入信息 var checkResult = ""; - ModBase.RunInUiWait(() => checkResult = ModProfile.IsProfileValid()); + UiThread.Invoke(() => checkResult = ModProfile.IsProfileValid()); if (ModProfile.selectedProfile is null) // 没选档案 { checkResult = Lang.Text("Minecraft.Launch.Precheck.NoProfile"); @@ -91,7 +90,7 @@ private static void McLaunchPrecheck() #if BETA if (currentLaunchOptions?.SaveBatch is null) // 保存脚本时不提示 { - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { switch (States.System.LaunchCount) { @@ -125,7 +124,7 @@ private static void McLaunchPrecheck() Lang.Text("Minecraft.Launch.Donate.Support"), Lang.Text("Minecraft.Launch.Donate.Decline")) == 1) { - ModBase.OpenWebsite("https://afdian.com/a/LTCat"); + LauncherProcess.OpenWebsite("https://afdian.com/a/LTCat"); } break; } @@ -146,7 +145,7 @@ private static void McLaunchPrecheck() Lang.Text("Minecraft.Launch.PurchaseHint.Message"), Lang.Text("Minecraft.Launch.PurchaseHint.Title"), Lang.Text("Minecraft.Launch.PurchaseHint.Purchase"), Lang.Text("Minecraft.Launch.PurchaseHint.Later")) == 1) - ModBase.OpenWebsite( + LauncherProcess.OpenWebsite( "https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj"); } else @@ -157,7 +156,7 @@ private static void McLaunchPrecheck() Lang.Text("Minecraft.Launch.AccountVerification.Demo"), Lang.Text("Minecraft.Launch.AccountVerification.Back"), button1Action: () => - ModBase.OpenWebsite( + LauncherProcess.OpenWebsite( "https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj"))) { case 2: @@ -231,9 +230,9 @@ public static bool McLaunchStart(McLaunchOptions options = null) isLaunching = true; currentLaunchOptions = options ?? new McLaunchOptions(); // 预检查 - if (!ModBase.RunInUi()) + if (!UiThread.CheckAccess()) throw new Exception("McLaunchStart 必须在 UI 线程调用!"); - if (mcLaunchLoader.State == ModBase.LoadState.Loading) + if (mcLaunchLoader.State == LoadState.Loading) { HintService.Hint(Lang.Text("Minecraft.Launch.Error.AlreadyLaunching"), HintType.Error); isLaunching = false; @@ -276,9 +275,9 @@ public static bool McLaunchStart(McLaunchOptions options = null) public static void McLaunchLog(string text) { text = McLogFilter.FilterUserName(McLogFilter.FilterAccessToken(text, '*'), '*'); - ModBase.RunInUi(() => + UiThread.Post(() => ModMain.frmLaunchRight.LabLog.Text += "\r\n" + "[" + TimeUtils.GetTimeNow() + "] " + text); - ModBase.Log("[Launch] " + text); + LauncherLog.Log("[Launch] " + text); } // 启动状态切换 @@ -293,15 +292,15 @@ private static void McLaunchState(ModLoader.LoaderTask { switch (mcLaunchLoader.State) { - case ModBase.LoadState.Finished: - case ModBase.LoadState.Failed: - case ModBase.LoadState.Waiting: - case ModBase.LoadState.Aborted: + case LoadState.Finished: + case LoadState.Failed: + case LoadState.Waiting: + case LoadState.Aborted: { ModMain.frmLaunchLeft.PageChangeToLogin(); break; } - case ModBase.LoadState.Loading: + case LoadState.Loading: { // 在预检测结束后再触发动画 ModMain.frmLaunchRight.LabLog.Text = ""; @@ -319,7 +318,7 @@ private static void McLaunchState(ModLoader.LoaderTask private static void McLaunchStart(ModLoader.LoaderTask loader) { // 开始动画 - ModBase.RunInUiWait(ModMain.frmLaunchLeft.PageChangeToLaunching); + UiThread.Invoke(ModMain.frmLaunchLeft.PageChangeToLaunching); // 预检测(预检测的错误将直接抛出) try { @@ -357,15 +356,15 @@ private static void McLaunchStart(ModLoader.LoaderTask }; // .ProgressWeight = 15, .Block = False var launchLoader = new ModLoader.LoaderCombo(Lang.Text("Minecraft.Launch.Stage.Root"), loaders) { show = false }; - if (mcLoginLoader.State == ModBase.LoadState.Finished) - mcLoginLoader.State = ModBase.LoadState.Waiting; // 要求重启登录主加载器,它会自行决定是否启动副加载器 + if (mcLoginLoader.State == LoadState.Finished) + mcLoginLoader.State = LoadState.Waiting; // 要求重启登录主加载器,它会自行决定是否启动副加载器 // 等待加载器执行并更新 UI mcLaunchLoaderReal = launchLoader; abortHint = null; launchLoader.Start(); // 任务栏进度条 ModLoader.LoaderTaskbarAdd(launchLoader); - while (launchLoader.State == ModBase.LoadState.Loading) + while (launchLoader.State == LoadState.Loading) { ModMain.frmLaunchLeft.Dispatcher.Invoke(ModMain.frmLaunchLeft.LaunchingRefresh); Thread.Sleep(100); @@ -375,12 +374,12 @@ private static void McLaunchStart(ModLoader.LoaderTask // 成功与失败处理 switch (launchLoader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: { HintService.Hint(Lang.Text("Minecraft.Launch.Success", ModInstanceList.McMcInstanceSelected.Name), HintType.Success); break; } - case ModBase.LoadState.Aborted: + case LoadState.Aborted: { if (abortHint is null) HintService.Hint(currentLaunchOptions?.SaveBatch is null ? Lang.Text("Minecraft.Launch.Cancelled") : Lang.Text("Minecraft.Launch.ExportScript.Cancelled")); @@ -389,14 +388,15 @@ private static void McLaunchStart(ModLoader.LoaderTask break; } - case ModBase.LoadState.Failed: + case LoadState.Failed: { throw launchLoader.Error; } default: { - throw new Exception(Lang.Text("Minecraft.Launch.Error.InvalidState", ModBase.GetStringFromEnum(launchLoader.State))); + throw new Exception(Lang.Text("Minecraft.Launch.Error.InvalidState", + LauncherText.GetStringFromEnum(launchLoader.State))); } } @@ -430,12 +430,12 @@ private static void McLaunchStart(ModLoader.LoaderTask // 没有特殊处理过的错误信息 McLaunchLog("错误:" + ex); - ModBase.Log( + LauncherLog.Log( ex, currentLaunchOptions?.SaveBatch is null ? "Minecraft launch failed" : "Export script failed", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, currentLaunchOptions?.SaveBatch is null ? Lang.Text("Launch.Error.Title") : Lang.Text("Launch.Error.ExportScriptTitle"), @@ -515,7 +515,7 @@ public McLoginServer(McLoginType type) public override int GetHashCode() { - return (int)Math.Round(ModBase.GetHash(UserName + Password + BaseUrl + (int)LoginType) % + return (int)Math.Round(LauncherText.GetHash(UserName + Password + BaseUrl + (int)LoginType) % (decimal)int.MaxValue); } } @@ -544,7 +544,8 @@ public McLoginMs() public override int GetHashCode() { - return (int)Math.Round(ModBase.GetHash(OAuthRefreshToken + AccessToken + Uuid + UserName + ProfileJson) % + return (int)Math.Round( + LauncherText.GetHash(OAuthRefreshToken + AccessToken + Uuid + UserName + ProfileJson) % (decimal)int.MaxValue); } } @@ -583,7 +584,7 @@ public McLoginLegacy() public override int GetHashCode() { return (int)Math.Round( - ModBase.GetHash(UserName + SkinType + SkinName + (int)LoginType) % (decimal)int.MaxValue); + LauncherText.GetHash(UserName + SkinType + SkinName + (int)LoginType) % (decimal)int.MaxValue); } } @@ -618,10 +619,10 @@ public static McLoginData McLoginInput() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Launch.Login.Error.Input"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Launch.Login.Error.Input")); } @@ -630,7 +631,7 @@ public static McLoginData McLoginInput() private static void McLoginStart(ModLoader.LoaderTask data) { - ModBase.Log("[Profile] 开始加载选定档案"); + LauncherLog.Log("[Profile] 开始加载选定档案"); // 校验登录信息 var checkResult = ModProfile.IsProfileValid(); if (!string.IsNullOrEmpty(checkResult)) @@ -659,8 +660,8 @@ private static void McLoginStart(ModLoader.LoaderTask ModMain.frmLaunchLeft.RefreshPage(false)); // 刷新自动填充列表 - ModBase.Log("[Profile] 选定档案加载完成"); + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(false)); // 刷新自动填充列表 + LauncherLog.Log("[Profile] 选定档案加载完成"); } #endregion @@ -903,7 +904,7 @@ private static string[] MsLoginStep1New(ModLoader.LoaderTask ModBase.OpenWebsite("https://account.live.com/password/Change")) == + button2Action: () => LauncherProcess.OpenWebsite("https://account.live.com/password/Change")) == 1) goto Retry; throw new Exception("$$"); @@ -966,7 +968,7 @@ private static string[] MsLoginStep1Refresh(string code) } catch (ThreadInterruptedException ex) { - ModBase.Log(ex, "加载线程已终止"); + LauncherLog.Log(ex, "加载线程已终止"); } catch (Exception ex) { @@ -977,7 +979,7 @@ private static string[] MsLoginStep1Refresh(string code) ModProfile.ProfileLog("正版验证 Step 1/6 获取 OAuth Token 失败:" + ex); var isIgnore = false; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { if (!isLaunching) return; @@ -991,7 +993,7 @@ private static string[] MsLoginStep1Refresh(string code) throw new Exception("$$"); } - var resultJson = (JsonObject)ModBase.GetJson(result); + var resultJson = (JsonObject)JsonCompat.ParseNode(result); var accessToken = resultJson["access_token"].ToString(); var refreshToken = resultJson["refresh_token"].ToString(); return new[] { accessToken, refreshToken }; @@ -1051,7 +1053,7 @@ private static string MsLoginStep2(string accessToken) { ModProfile.ProfileLog("正版验证 Step 2/6 获取 XBLToken 失败:" + ex); var isIgnore = false; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { if (!isLaunching) return; @@ -1063,7 +1065,7 @@ private static string MsLoginStep2(string accessToken) if (isIgnore) return "Ignore"; } - var resultJson = (JsonObject)ModBase.GetJson(result); + var resultJson = (JsonObject)JsonCompat.ParseNode(result); var xBLToken = resultJson["Token"].ToString(); return xBLToken; } @@ -1123,7 +1125,7 @@ private static string[] MsLoginStep3(string xBLToken) if (result.Contains("2148916233")) { if (ModMain.MyMsgBox(Lang.Text("Minecraft.Launch.Login.Microsoft.XboxNotRegistered"), Lang.Text("Minecraft.Launch.Login.Hint"), Lang.Text("Minecraft.Launch.Login.Register"), Lang.Text("Common.Action.Cancel")) == 1) - ModBase.OpenWebsite("https://signup.live.com/signup"); + LauncherProcess.OpenWebsite("https://signup.live.com/signup"); throw new Exception("$$"); } @@ -1138,14 +1140,14 @@ private static string[] MsLoginStep3(string xBLToken) if (ModMain.MyMsgBox(Lang.Text("Minecraft.Launch.Login.Microsoft.Underage.Message"), Lang.Text("Minecraft.Launch.Login.Hint"), Lang.Text("Minecraft.Launch.Login.Microsoft.Underage.AgeOver13"), Lang.Text("Minecraft.Launch.Login.Microsoft.Underage.AgeUnder13"), Lang.Text("Common.Option.IDontKnow")) == 1) { - ModBase.OpenWebsite("https://account.live.com/editprof.aspx"); + LauncherProcess.OpenWebsite("https://account.live.com/editprof.aspx"); ModMain.MyMsgBox( Lang.Text("Minecraft.Launch.Login.Microsoft.ChangeBirthDate.Message"), Lang.Text("Minecraft.Launch.Login.Hint")); } else { - ModBase.OpenWebsite( + LauncherProcess.OpenWebsite( "https://support.microsoft.com/zh-cn/account-billing/如何更改-microsoft-帐户上的出生日期-837badbc-999e-54d2-2617-d19206b9540a"); ModMain.MyMsgBox( Lang.Text("Minecraft.Launch.Login.Microsoft.ChangeBirthDate.SupportMessage"), @@ -1157,7 +1159,7 @@ private static string[] MsLoginStep3(string xBLToken) ModProfile.ProfileLog("正版验证 Step 3/6 获取 XSTSToken 失败:" + response.StatusCode); var isIgnore = false; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { if (!isLaunching) return; @@ -1176,7 +1178,7 @@ private static string[] MsLoginStep3(string xBLToken) } } - var resultJson = (JsonObject)ModBase.GetJson(result); + var resultJson = (JsonObject)JsonCompat.ParseNode(result); var xSTSToken = resultJson["Token"].ToString(); var uhs = resultJson["DisplayClaims"]["xui"][0]["uhs"].ToString(); return new[] { xSTSToken, uhs }; @@ -1212,19 +1214,19 @@ private static string MsLoginStep4(string[] tokens) var message = ex.Message; if (ex.StatusCode.Equals(HttpStatusCode.TooManyRequests)) { - ModBase.Log(ex, "正版验证 Step 4 汇报 429"); + LauncherLog.Log(ex, "正版验证 Step 4 汇报 429"); throw new Exception(Lang.Text("Minecraft.Launch.Login.Microsoft.TooManyRequests")); } if (ex.StatusCode is { } arg1 && arg1 == HttpStatusCode.Forbidden) { - ModBase.Log(ex, "正版验证 Step 4 汇报 403"); + LauncherLog.Log(ex, "正版验证 Step 4 汇报 403"); throw new Exception(Lang.Text("Minecraft.Launch.Login.Microsoft.AbnormalIp")); } ModProfile.ProfileLog("正版验证 Step 4/6 获取 MC AccessToken 失败:" + ex); var isIgnore = false; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { if (!isLaunching) return; @@ -1242,7 +1244,7 @@ private static string MsLoginStep4(string[] tokens) throw; } - var resultJson = (JsonObject)ModBase.GetJson(result); + var resultJson = (JsonObject)JsonCompat.ParseNode(result); var accessToken = resultJson["access_token"].ToString(); if (string.IsNullOrWhiteSpace(accessToken)) throw new Exception("获取到的 Minecraft AccessToken 为空,登录流程异常!"); @@ -1272,7 +1274,7 @@ private static void MsLoginStep5(string accessToken) result = response.AsString(); } - var resultJson = (JsonObject)ModBase.GetJson(result); + var resultJson = (JsonObject)JsonCompat.ParseNode(result); if (!(resultJson.ContainsKey("items") && resultJson["items"].AsArray().Any(x => x["name"]?.ToString() == "product_minecraft" || x["name"]?.ToString() == "game_minecraft"))) { @@ -1281,7 +1283,7 @@ private static void MsLoginStep5(string accessToken) { case 1: { - ModBase.OpenWebsite( + LauncherProcess.OpenWebsite( "https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj"); break; } @@ -1292,7 +1294,7 @@ private static void MsLoginStep5(string accessToken) } catch (Exception ex) { - ModBase.Log(ex, "正版验证 Step 5 异常:" + result); + LauncherLog.Log(ex, "正版验证 Step 5 异常:" + result); throw; } } @@ -1326,20 +1328,21 @@ private static string[] MsLoginStep6(string accessToken) var message = ex.Message; if (ex.StatusCode.Equals(HttpStatusCode.TooManyRequests)) { - ModBase.Log(ex, "正版验证 Step 6 汇报 429"); + LauncherLog.Log(ex, "正版验证 Step 6 汇报 429"); throw new Exception(Lang.Text("Minecraft.Launch.Login.Microsoft.TooManyRequests")); } if (ex.StatusCode is { } arg2 && arg2 == HttpStatusCode.NotFound) { - ModBase.Log(ex, "正版验证 Step 6 汇报 404"); - ModBase.RunInNewThread(() => + LauncherLog.Log(ex, "正版验证 Step 6 汇报 404"); + Basics.RunInNewThread(() => { switch (ModMain.MyMsgBox(Lang.Text("Minecraft.Launch.Login.Microsoft.CreateProfile.Message"), Lang.Text("Minecraft.Launch.Login.Failed"), Lang.Text("Minecraft.Launch.Login.Microsoft.CreateProfile.Button"), Lang.Text("Common.Action.Cancel"))) { case 1: { - ModBase.OpenWebsite("https://www.minecraft.net/zh-hans/msaprofile/mygames/editprofile"); + LauncherProcess.OpenWebsite( + "https://www.minecraft.net/zh-hans/msaprofile/mygames/editprofile"); break; } } @@ -1349,7 +1352,7 @@ private static string[] MsLoginStep6(string accessToken) ModProfile.ProfileLog("正版验证 Step 6/6 获取玩家档案信息失败:" + ex); var isIgnore = false; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { if (!isLaunching) return; @@ -1367,7 +1370,7 @@ private static string[] MsLoginStep6(string accessToken) throw; } - var resultJson = (JsonObject)ModBase.GetJson(result); + var resultJson = (JsonObject)JsonCompat.ParseNode(result); var uuid = resultJson["id"].ToString(); var userName = resultJson["name"].ToString(); return new[] { uuid, userName, result }; @@ -1586,7 +1589,7 @@ private static void McLoginRequestRefresh(ref ModLoader.LoaderTask + UiThread.Invoke(() => { var selectionControl = new List(); var selectionJson = new List(); @@ -1707,7 +1710,8 @@ private static bool McLoginRequestLogin(ref ModLoader.LoaderTask task) ModInstanceList.McMcInstanceSelected.Info.vanilla >= new Version(20, 0, 5))) { // 1.20.5+ (24w14a+):至少 Java 21 - if (ModBase.ModeDebug) - ModBase.Log("[Launch] [Debug] MC 1.20.5+ (24w14a+) 要求至少 Java 21"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Launch] [Debug] MC 1.20.5+ (24w14a+) 要求至少 Java 21"); minVer = new Version(21, 0, 0, 0); } else if ((!ModInstanceList.McMcInstanceSelected.Info.Valid && @@ -1830,8 +1834,8 @@ private static void McLaunchJava(ModLoader.LoaderTask task) ModInstanceList.McMcInstanceSelected.Info.vanilla.Major >= 18)) { // 1.18 pre2+:至少 Java 17 - if (ModBase.ModeDebug) - ModBase.Log("[Launch] [Debug] MC 1.18 pre2+ 要求至少 Java 17"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Launch] [Debug] MC 1.18 pre2+ 要求至少 Java 17"); minVer = new Version(17, 0, 0, 0); } else if ((!ModInstanceList.McMcInstanceSelected.Info.Valid && @@ -1840,23 +1844,23 @@ private static void McLaunchJava(ModLoader.LoaderTask task) ModInstanceList.McMcInstanceSelected.Info.vanilla.Major >= 17)) { // 1.17+ (21w19a+):至少 Java 16 - if (ModBase.ModeDebug) - ModBase.Log("[Launch] [Debug] MC 1.17+ (21w19a+) 要求至少 Java 16"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Launch] [Debug] MC 1.17+ (21w19a+) 要求至少 Java 16"); minVer = new Version(16, 0, 0, 0); } else if (ModInstanceList.McMcInstanceSelected.releaseTime.Year >= 2017) // Minecraft 1.12 与 1.11 的分界线正好是 2017 年,太棒了 { // 1.12+:至少 Java 8 - if (ModBase.ModeDebug) - ModBase.Log("[Launch] [Debug] MC 1.12+ 要求至少 Java 8"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Launch] [Debug] MC 1.12+ 要求至少 Java 8"); minVer = new Version(1, 8, 0, 0); } else if (ModInstanceList.McMcInstanceSelected.releaseTime <= new DateTime(2013, 5, 1) && ModInstanceList.McMcInstanceSelected.releaseTime.Year >= 2001) // 避免某些版本写个 1960 年 { // 1.5.2-:最高 Java 8 - if (ModBase.ModeDebug) - ModBase.Log("[Launch] [Debug] MC 1.5.2- 要求最高 Java 12"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Launch] [Debug] MC 1.5.2- 要求最高 Java 12"); maxVer = new Version(1, 8, 999, 999); } @@ -1948,12 +1952,12 @@ private static void McLaunchJava(ModLoader.LoaderTask task) throw new FormatException("无法解析 Cleanroom 版本号:" + ModInstanceList.McMcInstanceSelected.Info.Cleanroom); if (cleanroomVersion < new Version(0, 5, 0, 0)) { - if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] Cleanroom 版本低于 0.5,要求至少 Java 21"); + if (LauncherRuntime.ModeDebug) LauncherLog.Log("[Launch] [Debug] Cleanroom 版本低于 0.5,要求至少 Java 21"); minVer = new Version(21, 0, 0, 0) > minVer ? new Version(21, 0, 0, 0) : minVer; } else { - if (ModBase.ModeDebug) ModBase.Log("[Launch] [Debug] Cleanroom 版本高于 0.5,要求至少 Java 25"); + if (LauncherRuntime.ModeDebug) LauncherLog.Log("[Launch] [Debug] Cleanroom 版本高于 0.5,要求至少 Java 25"); minVer = new Version(25, 0, 0, 0) > minVer ? new Version(25, 0, 0, 0) : minVer; } } @@ -1974,16 +1978,16 @@ private static void McLaunchJava(ModLoader.LoaderTask task) if (ModInstanceList.McMcInstanceSelected.Info.HasLiteLoader && ModInstanceList.McMcInstanceSelected.Info.Valid) { // 最高 Java 8 - if (ModBase.ModeDebug) - ModBase.Log("[Launch] [Debug] LiteLoader 要求最高 Java 8"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Launch] [Debug] LiteLoader 要求最高 Java 8"); maxVer = new Version(8, 999, 999, 999) < maxVer ? new Version(8, 999, 999, 999) : maxVer; } // LabyMod 检测 if (ModInstanceList.McMcInstanceSelected.Info.HasLabyMod) { - if (ModBase.ModeDebug) - ModBase.Log("[Launch] [Debug] LabyMod 要求至少 Java 21"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Launch] [Debug] LabyMod 要求至少 Java 21"); minVer = new Version(21, 0, 0, 0) > minVer ? new Version(21, 0, 0, 0) : minVer; maxVer = new Version(999, 999, 999, 999); } @@ -1991,9 +1995,10 @@ private static void McLaunchJava(ModLoader.LoaderTask task) // JSON 中要求的版本 if (ModInstanceList.McMcInstanceSelected.JsonObject["javaVersion"] is not null) { - var majorVersion = ModBase.Val(ModInstanceList.McMcInstanceSelected.JsonObject["javaVersion"]["majorVersion"]); - if (ModBase.ModeDebug) - ModBase.Log("[Launch] [Debug] JSON 中参数要求至少 Java " + majorVersion); + var majorVersion = + LauncherText.Val(ModInstanceList.McMcInstanceSelected.JsonObject["javaVersion"]["majorVersion"]); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Launch] [Debug] JSON 中参数要求至少 Java " + majorVersion); if (majorVersion <= 8d) minVer = new Version(1, (int)Math.Round(majorVersion), 0, 0) > minVer ? new Version(1, (int)Math.Round(majorVersion), 0, 0) @@ -2067,7 +2072,7 @@ private static void McLaunchJava(ModLoader.LoaderTask task) try { javaLoader.Start(recommendedComponent ?? javaCode, true); // 在 Java 22+ 时优先使用 Mojang 提供的 Component 字段 - while (javaLoader.State == ModBase.LoadState.Loading && !task.IsAborted) + while (javaLoader.State == LoadState.Loading && !task.IsAborted) { task.Progress = javaLoader.Progress; Thread.Sleep(10); @@ -2122,7 +2127,7 @@ internal static void SecretLaunchJvmArgs(ref List dataList) } double availableGb = KernelInterop.GetAvailablePhysicalMemoryBytes() / 1073741824.0; - ModLaunch.McLaunchLog($"当前剩余内存:{availableGb.ToString("N1", CultureInfo.InvariantCulture)}G"); + McLaunchLog($"当前剩余内存:{availableGb.ToString("N1", CultureInfo.InvariantCulture)}G"); double totalRamMb = PageInstanceSetup.GetRam(ModInstanceList.McMcInstanceSelected) * 1024d; dataList.Add("-Xmn" + Math.Floor(totalRamMb * 0.15).ToString(CultureInfo.InvariantCulture) + "m"); dataList.Add("-Xmx" + Math.Floor(totalRamMb).ToString(CultureInfo.InvariantCulture) + "m"); @@ -2166,8 +2171,8 @@ public object HasArguments(string key) /// public static string ExtractJavaWrapper() { - var wrapperPath = Path.Combine(ModBase.pathPure, "JavaWrapper.jar"); - ModBase.Log("[Java] 选定的 Java Wrapper 路径:" + wrapperPath); + var wrapperPath = Path.Combine(LauncherPaths.PureAsciiDirectory, "JavaWrapper.jar"); + LauncherLog.Log("[Java] 选定的 Java Wrapper 路径:" + wrapperPath); lock (extractJavaWrapperLock) // 避免 OptiFine 和 Forge 安装时同时释放 Java Wrapper 导致冲突 { try @@ -2179,7 +2184,7 @@ public static string ExtractJavaWrapper() if (File.Exists(wrapperPath)) { // 因为未知原因 Java Wrapper 可能变为只读文件(#4243) - ModBase.Log(ex, "Java Wrapper 文件释放失败,但文件已存在,将在删除后尝试重新生成", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "Java Wrapper 文件释放失败,但文件已存在,将在删除后尝试重新生成", LauncherLogLevel.Developer); try { File.Delete(wrapperPath); @@ -2187,8 +2192,8 @@ public static string ExtractJavaWrapper() } catch (Exception ex2) { - ModBase.Log(ex2, "Java Wrapper 文件重新释放失败,将尝试更换文件名重新生成", ModBase.LogLevel.Developer); - wrapperPath = Path.Combine(ModBase.pathPure, "JavaWrapper2.jar"); + LauncherLog.Log(ex2, "Java Wrapper 文件重新释放失败,将尝试更换文件名重新生成", LauncherLogLevel.Developer); + wrapperPath = Path.Combine(LauncherPaths.PureAsciiDirectory, "JavaWrapper2.jar"); try { WriteJavaWrapper(wrapperPath); @@ -2213,7 +2218,7 @@ public static string ExtractJavaWrapper() private static void WriteJavaWrapper(string path) { - ModBase.WriteFile(path, ModBase.GetResourceStream("Resources/java-wrapper.jar")); + LegacyFileFacade.WriteFile(path, Basics.GetResourceStream("Resources/java-wrapper.jar")); } /// @@ -2221,7 +2226,7 @@ private static void WriteJavaWrapper(string path) /// public static string ExtractLinkD() { - var linkDPath = Path.Combine(ModBase.pathPure, "linkd.exe"); + var linkDPath = Path.Combine(LauncherPaths.PureAsciiDirectory, "linkd.exe"); lock (extractLinkDLock) // 避免 OptiFine 和 Forge 安装时同时释放 Java Wrapper 导致冲突 { try @@ -2232,7 +2237,7 @@ public static string ExtractLinkD() { if (File.Exists(linkDPath)) { - ModBase.Log(ex, "linkd 文件释放失败,但文件已存在,将在删除后尝试重新生成", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "linkd 文件释放失败,但文件已存在,将在删除后尝试重新生成", LauncherLogLevel.Developer); try { File.Delete(linkDPath); @@ -2257,7 +2262,7 @@ public static string ExtractLinkD() private static void WriteLinkD(string path) { - ModBase.WriteFile(path, ModBase.GetResourceStream("Resources/linkd.exe")); + LegacyFileFacade.WriteFile(path, Basics.GetResourceStream("Resources/linkd.exe")); } /// @@ -2267,7 +2272,7 @@ private static bool McLaunchNeedsLegacyFix(McInstance mc) { if (Config.Launch.DisableLF || Config.Instance.DisableLF[mc.PathInstance]) { - ModBase.Log("[Launch] LegacyFix 已被禁用"); + LauncherLog.Log("[Launch] LegacyFix 已被禁用"); return false; } if (mc.releaseTime < new DateTime(2013, 6, 25) && mc.releaseTime.Year > 2000) @@ -2467,7 +2472,8 @@ private static string McLaunchArgumentsJvmOld(McInstance instance) { var response = Requester.FetchString(server); dataList.Insert(0, - "-javaagent:\"" + Path.Combine(ModBase.pathPure, "authlib-injector.jar") + "\"=" + server + + "-javaagent:\"" + Path.Combine(LauncherPaths.PureAsciiDirectory, "authlib-injector.jar") + "\"=" + + server + " -Dauthlibinjector.side=client" + " -Dauthlibinjector.yggdrasil.prefetched=" + Convert.ToBase64String(Encoding.UTF8.GetBytes(response))); } @@ -2499,7 +2505,8 @@ private static string McLaunchArgumentsJvmOld(McInstance instance) else renderer = Config.Launch.Renderer; var mesaLoaderWindowsTargetFile = - Path.Combine(ModBase.pathPure, "mesa-loader-windows", mesaLoaderWindowsVersion, "Loader.jar"); + Path.Combine(LauncherPaths.PureAsciiDirectory, "mesa-loader-windows", mesaLoaderWindowsVersion, + "Loader.jar"); if (renderer != 0) dataList.Insert(0, @@ -2519,17 +2526,17 @@ private static string McLaunchArgumentsJvmOld(McInstance instance) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Launch.Error.Proxy"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Minecraft.Launch.Error.Proxy")); } // 添加 LegacyFix 相关参数 if (McLaunchNeedsLegacyFix(instance)) { - var legacyFixPath = Path.Combine(ModBase.pathPure, "legacyfix.jar"); + var legacyFixPath = Path.Combine(LauncherPaths.PureAsciiDirectory, "legacyfix.jar"); dataList.Add("-javaagent:\"" + legacyFixPath + "\""); // Beta 1.6 以前版本需要添加的参数 @@ -2540,12 +2547,12 @@ private static string McLaunchArgumentsJvmOld(McInstance instance) } // 添加 Java Wrapper 作为主 Jar - if (ModBase.IsUtf8CodePage() && !Config.Launch.DisableJlw && + if (EncodingUtils.IsDefaultEncodingUtf8() && !Config.Launch.DisableJlw && !Config.Instance.DisableJlw[ModInstanceList.McMcInstanceSelected?.PathInstance]) { if (mcLaunchJavaSelected.Installation.MajorVersion >= 9) dataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED"); - dataList.Add("-Doolloo.jlw.tmpdir=\"" + ModBase.pathPure.TrimEnd('\\') + "\""); + dataList.Add("-Doolloo.jlw.tmpdir=\"" + LauncherPaths.PureAsciiDirectory.TrimEnd('\\') + "\""); dataList.Add("-jar \"" + ExtractJavaWrapper() + "\""); } @@ -2603,7 +2610,8 @@ private static string McLaunchArgumentsJvmNew(McInstance instance) { var response = ModNet.NetGetCodeByRequestRetry(server, Encoding.UTF8)?.ToString(); dataList.Insert(0, - "-javaagent:\"" + Path.Combine(ModBase.pathPure, "authlib-injector.jar") + "\"=" + server + + "-javaagent:\"" + Path.Combine(LauncherPaths.PureAsciiDirectory, "authlib-injector.jar") + "\"=" + + server + " -Dauthlibinjector.side=client" + " -Dauthlibinjector.yggdrasil.prefetched=" + Convert.ToBase64String(Encoding.UTF8.GetBytes(response))); } @@ -2616,8 +2624,8 @@ private static string McLaunchArgumentsJvmNew(McInstance instance) // LWJGL Unsafe Agent if (McLaunchUsesLwjglUnsafeAgent(ModInstanceList.McMcInstanceSelected)) { - ModBase.Log($"获取到的 LWJGL 版本:{McLaunchGetLwjglVersion(ModInstanceList.McMcInstanceSelected)}"); - dataList.Insert(0, $"-javaagent:\"{ModBase.pathPure}lwjgl-unsafe-agent.jar\""); + LauncherLog.Log($"获取到的 LWJGL 版本:{McLaunchGetLwjglVersion(ModInstanceList.McMcInstanceSelected)}"); + dataList.Insert(0, $"-javaagent:\"{LauncherPaths.PureAsciiDirectory}lwjgl-unsafe-agent.jar\""); } if (Config.Instance.UseDebugLof4j2Config[instance.PathIndie]) @@ -2637,7 +2645,8 @@ private static string McLaunchArgumentsJvmNew(McInstance instance) else renderer = Config.Launch.Renderer; var mesaLoaderWindowsTargetFile = - Path.Combine(ModBase.pathPure, "mesa-loader-windows", mesaLoaderWindowsVersion, "Loader.jar"); + Path.Combine(LauncherPaths.PureAsciiDirectory, "mesa-loader-windows", mesaLoaderWindowsVersion, + "Loader.jar"); if (renderer != 0) dataList.Insert(0, @@ -2657,20 +2666,20 @@ private static string McLaunchArgumentsJvmNew(McInstance instance) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Launch.Error.Proxy"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Minecraft.Launch.Error.Proxy")); } // 添加 Java Wrapper 作为主 Jar - if (ModBase.IsUtf8CodePage() && !Config.Launch.DisableJlw && + if (EncodingUtils.IsDefaultEncodingUtf8() && !Config.Launch.DisableJlw && !Config.Instance.DisableJlw[ModInstanceList.McMcInstanceSelected?.PathInstance]) { if (mcLaunchJavaSelected.Installation.MajorVersion >= 9) dataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED"); - dataList.Add("-Doolloo.jlw.tmpdir=\"" + ModBase.pathPure.TrimEnd('\\') + "\""); + dataList.Add("-Doolloo.jlw.tmpdir=\"" + LauncherPaths.PureAsciiDirectory.TrimEnd('\\') + "\""); dataList.Add("-jar \"" + ExtractJavaWrapper() + "\""); } @@ -2726,7 +2735,7 @@ private static string McLaunchArgumentsGameOld(McInstance version) // 把 OptiFineForgeTweaker 放在最后,不然会导致崩溃! if (result.Contains("--tweakClass optifine.OptiFineForgeTweaker")) { - ModBase.Log("[Launch] 发现正确的 OptiFineForge TweakClass,目前参数:" + result); + LauncherLog.Log("[Launch] 发现正确的 OptiFineForge TweakClass,目前参数:" + result); result = result.Replace(" --tweakClass optifine.OptiFineForgeTweaker", "") .Replace("--tweakClass optifine.OptiFineForgeTweaker ", "") + " --tweakClass optifine.OptiFineForgeTweaker"; @@ -2734,19 +2743,19 @@ private static string McLaunchArgumentsGameOld(McInstance version) if (result.Contains("--tweakClass optifine.OptiFineTweaker")) { - ModBase.Log("[Launch] 发现错误的 OptiFineForge TweakClass,目前参数:" + result); + LauncherLog.Log("[Launch] 发现错误的 OptiFineForge TweakClass,目前参数:" + result); result = result.Replace(" --tweakClass optifine.OptiFineTweaker", "") .Replace("--tweakClass optifine.OptiFineTweaker ", "") + " --tweakClass optifine.OptiFineForgeTweaker"; try { - ModBase.WriteFile(Path.Combine(version.PathInstance, version.Name + ".json"), - ModBase.ReadFile(Path.Combine(version.PathInstance, version.Name + ".json")) + LegacyFileFacade.WriteFile(Path.Combine(version.PathInstance, version.Name + ".json"), + LegacyFileFacade.ReadText(Path.Combine(version.PathInstance, version.Name + ".json")) .Replace("optifine.OptiFineTweaker", "optifine.OptiFineForgeTweaker")); } catch (Exception ex) { - ModBase.Log(ex, "替换 OptiFineForge TweakClass 失败"); + LauncherLog.Log(ex, "替换 OptiFineForge TweakClass 失败"); } } } @@ -2815,7 +2824,7 @@ private static string McLaunchArgumentsGameNew(McInstance instance) // 把 OptiFineForgeTweaker 放在最后,不然会导致崩溃! if (mcLaunchArgumentsGameNewRet.Contains("--tweakClass optifine.OptiFineForgeTweaker")) { - ModBase.Log("[Launch] 发现正确的 OptiFineForge TweakClass,目前参数:" + mcLaunchArgumentsGameNewRet); + LauncherLog.Log("[Launch] 发现正确的 OptiFineForge TweakClass,目前参数:" + mcLaunchArgumentsGameNewRet); mcLaunchArgumentsGameNewRet = mcLaunchArgumentsGameNewRet.Replace(" --tweakClass optifine.OptiFineForgeTweaker", "") .Replace("--tweakClass optifine.OptiFineForgeTweaker ", "") + @@ -2824,20 +2833,20 @@ private static string McLaunchArgumentsGameNew(McInstance instance) if (mcLaunchArgumentsGameNewRet.Contains("--tweakClass optifine.OptiFineTweaker")) { - ModBase.Log("[Launch] 发现错误的 OptiFineForge TweakClass,目前参数:" + mcLaunchArgumentsGameNewRet); + LauncherLog.Log("[Launch] 发现错误的 OptiFineForge TweakClass,目前参数:" + mcLaunchArgumentsGameNewRet); mcLaunchArgumentsGameNewRet = mcLaunchArgumentsGameNewRet.Replace(" --tweakClass optifine.OptiFineTweaker", "") .Replace("--tweakClass optifine.OptiFineTweaker ", "") + " --tweakClass optifine.OptiFineForgeTweaker"; try { - ModBase.WriteFile(Path.Combine(instance.PathInstance, instance.Name + ".json"), - ModBase.ReadFile(Path.Combine(instance.PathInstance, instance.Name + ".json")) + LegacyFileFacade.WriteFile(Path.Combine(instance.PathInstance, instance.Name + ".json"), + LegacyFileFacade.ReadText(Path.Combine(instance.PathInstance, instance.Name + ".json")) .Replace("optifine.OptiFineTweaker", "optifine.OptiFineForgeTweaker")); } catch (Exception ex) { - ModBase.Log(ex, "替换 OptiFineForge TweakClass 失败"); + LauncherLog.Log(ex, "替换 OptiFineForge TweakClass 失败"); } } } @@ -2853,11 +2862,13 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in // 基础参数 gameArguments.Add("${classpath_separator}", ";"); - gameArguments.Add("${natives_directory}", ModBase.ShortenPath(GetNativesFolder())); - gameArguments.Add("${library_directory}", ModBase.ShortenPath(ModFolder.mcFolderSelected + "libraries")); - gameArguments.Add("${libraries_directory}", ModBase.ShortenPath(ModFolder.mcFolderSelected + "libraries")); + gameArguments.Add("${natives_directory}", LegacyFileFacade.ShortenPath(GetNativesFolder())); + gameArguments.Add("${library_directory}", + LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected + "libraries")); + gameArguments.Add("${libraries_directory}", + LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected + "libraries")); gameArguments.Add("${launcher_name}", "PCLCE"); - gameArguments.Add("${launcher_version}", ModBase.VersionCode.ToString()); + gameArguments.Add("${launcher_version}", LauncherEnvironment.VersionCode.ToString()); gameArguments.Add("${version_name}", instance.Name); var argumentInfo = Config.Instance.TypeInfo[ModInstanceList.McMcInstanceSelected?.PathInstance]; gameArguments.Add("${version_type}", @@ -2865,8 +2876,8 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in ? Config.Launch.TypeInfo : argumentInfo); gameArguments.Add("${game_directory}", - ModBase.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie[..^1])); - gameArguments.Add("${assets_root}", ModBase.ShortenPath(ModFolder.mcFolderSelected + "assets")); + LegacyFileFacade.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie[..^1])); + gameArguments.Add("${assets_root}", LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected + "assets")); gameArguments.Add("${user_properties}", "{}"); gameArguments.Add("${auth_player_name}", mcLoginLoader.output.Name); gameArguments.Add("${auth_uuid}", mcLoginLoader.output.Uuid); @@ -2882,10 +2893,10 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in case GameWindowSizeMode.Launcher: // 与启动器尺寸一致 { Size result; - ModBase.RunInUiWait(() => result = new Size(ModBase.GetPixelSize(ModMain.frmMain.PanForm.ActualWidth), - ModBase.GetPixelSize(ModMain.frmMain.PanForm.ActualHeight))); + UiThread.Invoke(() => result = new Size(DpiUtils.GetPixelSize(ModMain.frmMain.PanForm.ActualWidth), + DpiUtils.GetPixelSize(ModMain.frmMain.PanForm.ActualHeight))); gameSize = result; - gameSize.Height -= 29.5d * ModBase.dpi / 96d; // 标题栏高度 + gameSize.Height -= 29.5d * DpiUtils.Dpi / 96d; // 标题栏高度 break; } case GameWindowSizeMode.Custom: // 自定义 @@ -2909,8 +2920,8 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in { // 修复 #3463:1.12.2-,JRE 8u200~321 下窗口大小为设置大小的 DPI% 倍 McLaunchLog($"已应用窗口大小过大修复({mcLaunchJavaSelected.Installation.Version.Revision})"); - gameSize.Width /= ModBase.dpi / 96d; - gameSize.Height /= ModBase.dpi / 96d; + gameSize.Width /= DpiUtils.Dpi / 96d; + gameSize.Height /= DpiUtils.Dpi / 96d; } gameArguments.Add("${resolution_width}", Math.Round(gameSize.Width).ToString(CultureInfo.InvariantCulture)); @@ -2918,8 +2929,8 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in // Assets 相关参数 gameArguments.Add("${game_assets}", - ModBase.ShortenPath(ModFolder.mcFolderSelected + - @"assets\virtual\legacy")); // 1.5.2 的 pre-1.6 资源索引应与 legacy 合并 + LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected + + @"assets\virtual\legacy")); // 1.5.2 的 pre-1.6 资源索引应与 legacy 合并 gameArguments.Add("${assets_index_name}", ModAssets.McAssetsGetIndexName(instance)); // 支持库参数 @@ -2931,29 +2942,29 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in // LegacyFix 释放 if (McLaunchNeedsLegacyFix(instance)) { - var legacyFixPath = Path.Combine(ModBase.pathPure, "legacyfix.jar"); + var legacyFixPath = Path.Combine(LauncherPaths.PureAsciiDirectory, "legacyfix.jar"); try { - ModBase.WriteFile(legacyFixPath, ModBase.GetResourceStream("Resources/legacyfix.jar")); + LegacyFileFacade.WriteFile(legacyFixPath, Basics.GetResourceStream("Resources/legacyfix.jar")); } catch (Exception ex) { - ModBase.Log(ex, "LegacyFix 释放失败"); + LauncherLog.Log(ex, "LegacyFix 释放失败"); } } // LWJGL Unsafe Agent 释放 if (McLaunchUsesLwjglUnsafeAgent(instance)) { - string agentPath = Path.Combine(ModBase.pathPure, "lwjgl-unsafe-agent.jar"); + var agentPath = Path.Combine(LauncherPaths.PureAsciiDirectory, "lwjgl-unsafe-agent.jar"); try { - ModBase.WriteFile(agentPath, ModBase.GetResourceStream("Resources/lwjgl-unsafe-agent.jar")); + LegacyFileFacade.WriteFile(agentPath, Basics.GetResourceStream("Resources/lwjgl-unsafe-agent.jar")); cpStrings.Add(agentPath); } catch (Exception ex) { - ModBase.Log(ex, "LWJGL Unsafe Agent 释放失败"); + LauncherLog.Log(ex, "LWJGL Unsafe Agent 释放失败"); } } @@ -2982,7 +2993,7 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in if (optiFineCp is not null) cpStrings.Insert(cpStrings.Count - 2, optiFineCp); // OptiFine 的总是需要放到倒数第二位 - gameArguments.Add("${classpath}", cpStrings.Select(c => ModBase.ShortenPath(c)).Join(";")); + gameArguments.Add("${classpath}", cpStrings.Select(c => LegacyFileFacade.ShortenPath(c)).Join(";")); return gameArguments; } @@ -3011,7 +3022,7 @@ private static void McLaunchNatives(ModLoader.LoaderTask loader) $"{(mcLaunchJavaSelected.Installation.MajorVersion > 8 ? "chcp 65001>nul" + "\r\n" : "")}" + "@echo off" + "\r\n" + $"title 启动 - {ModInstanceList.McMcInstanceSelected.Name}" + "\r\n" + "echo 游戏正在启动,请稍候。" + "\r\n" + - $"cd /D \"{ModBase.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie)}\"" + "\r\n" + + $"cd /D \"{LegacyFileFacade.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie)}\"" + "\r\n" + customCommandGlobal + "\r\n" + customCommandVersion + "\r\n" + $"\"{mcLaunchJavaSelected.Installation.JavaExePath}\" {mcLaunchArgument}" + "\r\n" + "echo 游戏已退出。" + "\r\n" + "pause"; - ModBase.WriteFile(currentLaunchOptions.SaveBatch ?? ModBase.exePath + @"PCL\LatestLaunch.bat", + LegacyFileFacade.WriteFile( + currentLaunchOptions.SaveBatch ?? LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\LatestLaunch.bat", McLogFilter.FilterAccessToken(cmdString, 'F'), encoding: mcLaunchJavaSelected.Installation.MajorVersion > 8 ? Encoding.UTF8 : Encoding.Default); if (currentLaunchOptions.SaveBatch is not null) { McLaunchLog("导出启动脚本完成,强制结束启动过程"); abortHint = Lang.Text("Minecraft.Launch.ExportScript.Success"); - ModBase.OpenExplorer(currentLaunchOptions.SaveBatch); + LauncherProcess.OpenExplorer(currentLaunchOptions.SaveBatch); loader.parent.Abort(); return; // 导出脚本完成 } } catch (Exception ex) { - ModBase.Log(ex, "输出启动脚本失败"); + LauncherLog.Log(ex, "输出启动脚本失败"); if (currentLaunchOptions.SaveBatch is not null) throw; // 直接触发启动失败 } @@ -3397,7 +3410,7 @@ private static void McLaunchCustom(ModLoader.LoaderTask loader) { customProcess.StartInfo.FileName = "cmd.exe"; customProcess.StartInfo.Arguments = "/c \"" + customCommandGlobal + "\""; - customProcess.StartInfo.WorkingDirectory = ModBase.ShortenPath(ModFolder.mcFolderSelected); + customProcess.StartInfo.WorkingDirectory = LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected); customProcess.StartInfo.UseShellExecute = false; customProcess.StartInfo.CreateNoWindow = true; customProcess.Start(); @@ -3407,10 +3420,10 @@ private static void McLaunchCustom(ModLoader.LoaderTask loader) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Launch.Error.CustomCommand"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Minecraft.Launch.Error.CustomCommand")); } finally @@ -3431,7 +3444,7 @@ private static void McLaunchCustom(ModLoader.LoaderTask loader) { customProcess.StartInfo.FileName = "cmd.exe"; customProcess.StartInfo.Arguments = "/c \"" + customCommandVersion + "\""; - customProcess.StartInfo.WorkingDirectory = ModBase.ShortenPath(ModFolder.mcFolderSelected); + customProcess.StartInfo.WorkingDirectory = LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected); customProcess.StartInfo.UseShellExecute = false; customProcess.StartInfo.CreateNoWindow = true; customProcess.Start(); @@ -3441,10 +3454,10 @@ private static void McLaunchCustom(ModLoader.LoaderTask loader) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Launch.Error.CustomCommand"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Minecraft.Launch.Error.CustomCommand")); } finally @@ -3471,12 +3484,12 @@ private static void McLaunchRun(ModLoader.LoaderTask loader) // 设置环境变量 var paths = new List(startInfo.EnvironmentVariables["Path"].Split(";")); - paths.Add(ModBase.ShortenPath(mcLaunchJavaSelected.Installation.JavaFolder)); + paths.Add(LegacyFileFacade.ShortenPath(mcLaunchJavaSelected.Installation.JavaFolder)); startInfo.EnvironmentVariables["Path"] = paths.Distinct().ToList().Join(";"); - startInfo.EnvironmentVariables["appdata"] = ModBase.ShortenPath(ModFolder.mcFolderSelected); + startInfo.EnvironmentVariables["appdata"] = LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected); // 设置其他参数 - startInfo.WorkingDirectory = ModBase.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie); + startInfo.WorkingDirectory = LegacyFileFacade.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie); startInfo.UseShellExecute = false; startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; @@ -3526,10 +3539,10 @@ private static void McLaunchRun(ModLoader.LoaderTask loader) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Launch.Error.PrioritySet"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Launch.Error.PrioritySet")); } } @@ -3539,7 +3552,7 @@ private static void McLaunchWait(ModLoader.LoaderTask loader) // 输出信息 McLaunchLog(""); McLaunchLog("~ 基础参数 ~"); - McLaunchLog("PCL 版本:" + ModBase.VersionBaseName + " (" + ModBase.VersionCode + ")"); + McLaunchLog("PCL 版本:" + LauncherEnvironment.VersionBaseName + " (" + LauncherEnvironment.VersionCode + ")"); McLaunchLog( $"游戏版本:{ModInstanceList.McMcInstanceSelected.Info.VanillaName}({ModInstanceList.McMcInstanceSelected.Info.vanilla},Drop {ModInstanceList.McMcInstanceSelected.Info.Drop}{(ModInstanceList.McMcInstanceSelected.Info.Reliable ? "" : ",无法完全确定")})"); McLaunchLog("资源版本:" + ModAssets.McAssetsGetIndexName(ModInstanceList.McMcInstanceSelected)); @@ -3587,9 +3600,9 @@ private static void McLaunchWait(ModLoader.LoaderTask loader) if (currentLaunchOptions.IsTest) { if (ModMain.frmLogLeft is null) - ModBase.RunInUiWait(() => ModMain.frmLogLeft = new PageLogLeft()); + UiThread.Invoke(() => ModMain.frmLogLeft = new PageLogLeft()); if (ModMain.frmLogRight is null) - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { ModAnimation.AniControlEnabled += 1; ModMain.frmLogRight = new PageLogRight(); @@ -3611,14 +3624,14 @@ private static void McLaunchEnd() // 暂停或开始音乐播放 if (Config.Preference.Music.StopInGame) - ModBase.RunInUi(() => + UiThread.Post(() => { - if (ModMusic.MusicPause()) ModBase.Log("[Music] 已根据设置,在启动后暂停音乐播放"); + if (ModMusic.MusicPause()) LauncherLog.Log("[Music] 已根据设置,在启动后暂停音乐播放"); }); else if (Config.Preference.Music.StartInGame) - ModBase.RunInUi(() => + UiThread.Post(() => { - if (ModMusic.MusicResume()) ModBase.Log("[Music] 已根据设置,在启动后开始音乐播放"); + if (ModMusic.MusicResume()) LauncherLog.Log("[Music] 已根据设置,在启动后开始音乐播放"); }); // 暂停视频背景播放 ModVideoBack.IsGaming = true; @@ -3632,7 +3645,7 @@ private static void McLaunchEnd() { // 直接关闭 McLaunchLog("已根据设置,在启动后关闭启动器"); - ModBase.RunInUi(() => ModMain.frmMain.EndProgram(false)); + UiThread.Post(() => ModMain.frmMain.EndProgram(false)); break; } case LauncherVisibility.HideAndExit: @@ -3640,14 +3653,14 @@ private static void McLaunchEnd() { // 隐藏 McLaunchLog("已根据设置,在启动后隐藏启动器"); - ModBase.RunInUi(() => ModMain.frmMain.Hidden = true); + UiThread.Post(() => ModMain.frmMain.Hidden = true); break; } case LauncherVisibility.MinimizeAndReopen: { // 最小化 McLaunchLog("已根据设置,在启动后最小化启动器"); - ModBase.RunInUi(() => ModMain.frmMain.WindowState = WindowState.Minimized); + UiThread.Post(() => ModMain.frmMain.WindowState = WindowState.Minimized); break; } case LauncherVisibility.DoNothing: @@ -3680,19 +3693,19 @@ string replacer(string s) if (escapeHandler is null) return s; if (s.Contains(@":\")) - s = ModBase.ShortenPath(s); + s = LegacyFileFacade.ShortenPath(s); return escapeHandler(s); } ; // 基础 - text = text.Replace("{pcl_version}", replacer(ModBase.VersionBaseName)); - text = text.Replace("{pcl_version_code}", replacer(ModBase.VersionCode.ToString())); - text = text.Replace("{pcl_version_branch}", replacer(ModBase.VersionBranchName)); + text = text.Replace("{pcl_version}", replacer(LauncherEnvironment.VersionBaseName)); + text = text.Replace("{pcl_version_code}", replacer(LauncherEnvironment.VersionCode.ToString())); + text = text.Replace("{pcl_version_branch}", replacer(LauncherEnvironment.VersionBranchName)); text = text.Replace("{identify}", replacer(Identify.LauncherId)); text = text.Replace("{path}", replacer(Basics.CurrentDirectory)); text = text.Replace("{path_with_name}", replacer(Basics.ExecutablePath)); - text = text.Replace("{path_temp}", replacer(ModBase.pathTemp)); + text = text.Replace("{path_temp}", replacer(LauncherPaths.TempWithSlash)); // 时间 if (replaceTime) // 在窗口标题中,时间会被后续动态替换,所以此时不应该替换 { @@ -3727,7 +3740,7 @@ string replacer(string s) } // 登录信息 - if (mcLoginLoader.State == ModBase.LoadState.Finished) + if (mcLoginLoader.State == LoadState.Finished) { text = text.Replace("{user}", replacer(mcLoginLoader.output.Name)); text = text.Replace("{uuid}", replacer(mcLoginLoader.output.Uuid?.ToLower())); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs index 7807de7d9..2595fa171 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs @@ -1,10 +1,6 @@ -using System; -using System.IO; -using System.Linq; -using System.Text.Json.Nodes; +using System.IO; using PCL.Core.App; using PCL.Core.Utils; -using PCL.Core.Utils.Exts; using PCL.Core.Utils.OS; using PCL.Network; @@ -74,7 +70,7 @@ public string Name public override string ToString() { - return (IsNatives ? "[Native] " : "") + ModBase.GetString(size) + " | " + LocalPath; + return (IsNatives ? "[Native] " : "") + LauncherText.GetReadableFileSize(size) + " | " + LocalPath; } } @@ -149,7 +145,7 @@ public static bool McJsonRuleCheck(JsonNode ruleToken) public static List McLibListGet(McInstance mcInstance, bool includeInstanceJar) { // 获取当前支持库列表 - ModBase.Log("[Minecraft] 获取支持库列表:" + mcInstance.Name); + LauncherLog.Log("[Minecraft] 获取支持库列表:" + mcInstance.Name); var result = McLibListGetWithJson(mcInstance.JsonObject, targetMcInstance: mcInstance); // 需要添加原版 Jar @@ -188,7 +184,8 @@ public static List McLibListGet(McInstance mcInstance, bool includeI if (!File.Exists(realMcInstance.PathInstance + realMcInstance.Name + ".json")) { realMcInstance = mcInstance; - ModBase.Log("[Minecraft] 可能缺少前置实例 " + realMcInstance.Name + ",找不到对应的 JSON 文件", ModBase.LogLevel.Debug); + LauncherLog.Log("[Minecraft] 可能缺少前置实例 " + realMcInstance.Name + ",找不到对应的 JSON 文件", + LauncherLogLevel.Debug); } // 获取详细下载信息 @@ -272,7 +269,7 @@ public static List McLibListGetWithJson(JsonObject jsonObject, ? McLibGet((string)library["name"], customMcFolder: customMcFolder) : McLibGetByArtifactPath(artifactPath.ToString(), customMcFolder), init.size = (long)Math.Round( - ModBase.Val(library["downloads"]["artifact"]["size"].ToString())), + LauncherText.Val(library["downloads"]["artifact"]["size"].ToString())), init.IsNatives = false, init.Sha1 = library["downloads"]["artifact"]["sha1"]?.ToString(), init.IsLocal = isLocal, init).init); } @@ -287,12 +284,12 @@ public static List McLibListGetWithJson(JsonObject jsonObject, } catch (Exception ex) when (artifactPath is not null && (ex is ArgumentException || ex is IOException)) { - ModBase.Log(ex, "支持库下载路径非法,已跳过(无 Natives," + (library["name"] ?? "Nothing") + ")"); + LauncherLog.Log(ex, "支持库下载路径非法,已跳过(无 Natives," + (library["name"] ?? "Nothing") + ")"); continue; } catch (Exception ex) { - ModBase.Log(ex, "处理实际支持库列表失败(无 Natives," + (library["name"] ?? "Nothing") + ")"); + LauncherLog.Log(ex, "处理实际支持库列表失败(无 Natives," + (library["name"] ?? "Nothing") + ")"); basicArray.Add(new McLibToken { OriginalName = (string)library["name"], Url = rootUrl, LocalPath = localPath, size = 0L, @@ -320,7 +317,8 @@ public static List McLibListGetWithJson(JsonObject jsonObject, .Replace("${arch}", Environment.Is64BitOperatingSystem ? "64" : "32") : McLibGetByArtifactPath(nativePath.ToString(), customMcFolder), size = (long)Math.Round( - ModBase.Val(library["downloads"]["classifiers"]["natives-windows"]["size"].ToString())), + LauncherText.Val(library["downloads"]["classifiers"]["natives-windows"]["size"] + .ToString())), IsNatives = true, Sha1 = library["downloads"]["classifiers"]["natives-windows"]["sha1"].ToString(), IsLocal = isLocal @@ -337,12 +335,12 @@ public static List McLibListGetWithJson(JsonObject jsonObject, } catch (Exception ex) when (nativePath is not null && (ex is ArgumentException || ex is IOException)) { - ModBase.Log(ex, "支持库下载路径非法,已跳过(有 Natives," + (library["name"] ?? "Nothing") + ")"); + LauncherLog.Log(ex, "支持库下载路径非法,已跳过(有 Natives," + (library["name"] ?? "Nothing") + ")"); continue; } catch (Exception ex) { - ModBase.Log(ex, "处理实际支持库列表失败(有 Natives," + (library["name"] ?? "Nothing") + ")"); + LauncherLog.Log(ex, "处理实际支持库列表失败(有 Natives," + (library["name"] ?? "Nothing") + ")"); basicArray.Add(new McLibToken { OriginalName = (string)library["name"], Url = rootUrl, @@ -364,7 +362,7 @@ public static List McLibListGetWithJson(JsonObject jsonObject, // D:\Minecraft\test\libraries\com\google\guava\guava\31.1-jre\guava-31.1-jre.jar string GetVersion(McLibToken token) { - return ModBase.GetFolderNameFromPath(ModBase.GetPathFromFullPath(token.LocalPath)); + return LegacyFileFacade.GetFolderNameFromPath(LegacyFileFacade.GetPathFromFullPath(token.LocalPath)); } for (int i = 0, loopTo = basicArray.Count - 1; i <= loopTo; i++) @@ -376,13 +374,13 @@ string GetVersion(McLibToken token) var resultArrayVersion = GetVersion(resultArray[key]); if ((basicArrayVersion ?? "") != (resultArrayVersion ?? "") && keepSameNameDifferentVersionResult) { - ModBase.Log( + LauncherLog.Log( $"[Minecraft] 发现疑似重复的支持库:{basicArray[i]} ({basicArrayVersion}) 与 {resultArray[key]} ({resultArrayVersion})"); - resultArray.Add(key + ModBase.GetUuid(), basicArray[i]); + resultArray.Add(key + LauncherRuntime.GetUuid(), basicArray[i]); } else { - ModBase.Log( + LauncherLog.Log( $"[Minecraft] 发现重复的支持库:{basicArray[i]} ({basicArrayVersion}) 与 {resultArray[key]} ({resultArrayVersion}),已忽略其中之一"); if (McVersionComparer.CompareVersionGe(basicArrayVersion, resultArrayVersion)) resultArray[key] = basicArray[i]; } @@ -416,19 +414,19 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance } catch (Exception ex) { - ModBase.Log(ex, "实例缺失主 Jar 文件所必须的信息", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "实例缺失主 Jar 文件所必须的信息", LauncherLogLevel.Developer); } // Library 文件 result.AddRange(McLibNetFilesFromTokens(McLibListGet(mcInstance, false))); // Authlib-Injector 文件 - var authlibTargetFile = Path.Combine(ModBase.pathPure, "authlib-injector.jar"); + var authlibTargetFile = Path.Combine(LauncherPaths.PureAsciiDirectory, "authlib-injector.jar"); JsonObject authlibDownloadInfo = null; try { - ModBase.Log("[Minecraft] 开始获取 Authlib-Injector 下载信息"); - authlibDownloadInfo = (JsonObject)ModBase.GetJson(ModNet.NetGetCodeByLoader( + LauncherLog.Log("[Minecraft] 开始获取 Authlib-Injector 下载信息"); + authlibDownloadInfo = (JsonObject)JsonCompat.ParseNode(ModNet.NetGetCodeByLoader( new[] { "https://authlib-injector.yushi.moe/artifact/latest.json", @@ -437,19 +435,19 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance } catch (Exception ex) { - ModBase.Log(ex, "获取 Authlib-Injector 下载信息失败"); + LauncherLog.Log(ex, "获取 Authlib-Injector 下载信息失败"); } // 校验文件 if (authlibDownloadInfo is not null) { - var checker = new ModBase.FileChecker(hash: authlibDownloadInfo["checksums"]["sha256"].ToString()); + var checker = new FileChecker(hash: authlibDownloadInfo["checksums"]["sha256"].ToString()); if (checker.Check(authlibTargetFile) is not null) { // 开始下载 var downloadAddress = authlibDownloadInfo["download_url"].ToString() .Replace("bmclapi2.bangbang93.com/mirrors/authlib-injector", "authlib-injector.yushi.moe"); - ModBase.Log("[Minecraft] Authlib-Injector 需要更新:" + downloadAddress, ModBase.LogLevel.Developer); + LauncherLog.Log("[Minecraft] Authlib-Injector 需要更新:" + downloadAddress, LauncherLogLevel.Developer); result.Add(new DownloadFile( new[] { @@ -457,13 +455,14 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance downloadAddress.Replace("authlib-injector.yushi.moe", "bmclapi2.bangbang93.com/mirrors/authlib-injector") }, authlibTargetFile, - new ModBase.FileChecker(hash: authlibDownloadInfo["checksums"]["sha256"].ToString()))); + new FileChecker(hash: authlibDownloadInfo["checksums"]["sha256"].ToString()))); } } // 修改渲染器 var mesaLoaderWindowsTargetFile = - Path.Combine(ModBase.pathPure, "mesa-loader-windows", ModLaunch.mesaLoaderWindowsVersion, "Loader.jar"); + Path.Combine(LauncherPaths.PureAsciiDirectory, "mesa-loader-windows", ModLaunch.mesaLoaderWindowsVersion, + "Loader.jar"); var renderer = -1; if (ModInstanceList.McMcInstanceSelected is not null) renderer = Config.Instance.Renderer[ModInstanceList.McMcInstanceSelected?.PathInstance] - 1; @@ -485,7 +484,8 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance { if (Directory.Exists(Path.Combine(mcInstance.PathInstance, "labymod-neo"))) Directory.Delete(Path.Combine(mcInstance.PathInstance, "labymod-neo"), true); - ModBase.CreateSymbolicLink(Path.Combine(mcInstance.PathInstance, "labymod-neo"), Path.Combine(ModFolder.mcFolderSelected, "labymod-neo"), + LegacyFileFacade.CreateSymbolicLink(Path.Combine(mcInstance.PathInstance, "labymod-neo"), + Path.Combine(ModFolder.mcFolderSelected, "labymod-neo"), 0x2); } @@ -493,7 +493,7 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance { var channelType = mcInstance.JsonObject["labymod_data"]["channelType"].ToString(); Directory.CreateDirectory($@"{ModFolder.mcFolderSelected}labymod-neo\libraries"); - ModBase.Log("[Minecraft] 开始获取 LabyMod 信息"); + LauncherLog.Log("[Minecraft] 开始获取 LabyMod 信息"); var labyManifest = (JsonObject)ModNet.NetGetCodeByRequestRetry( $"https://releases.r2.labymod.net/api/v1/manifest/{channelType}/latest.json", isJson: true); var labyAssets = (JsonObject)labyManifest["assets"]; @@ -505,7 +505,7 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance var assetPath = $@"{ModFolder.mcFolderSelected}labymod-neo\assets\{assetName}.jar"; var assetUrl = $"https://releases.r2.labymod.net/api/v1/download/assets/labymod4/{channelType}/{labyModCommitRef}/{assetName}/{assetSHA1}.jar"; - var checker = new ModBase.FileChecker(hash: assetSHA1); + var checker = new FileChecker(hash: assetSHA1); if (checker.Check(assetPath) is null) continue; result.Add(new DownloadFile(new[] { assetUrl }, assetPath, checker)); @@ -513,19 +513,19 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance } catch (Exception ex) { - ModBase.Log(ex, "获取 LabyMod 信息失败,跳过检查"); + LauncherLog.Log(ex, "获取 LabyMod 信息失败,跳过检查"); } } // 跳过校验 if (ShouldIgnoreFileCheck(mcInstance)) { - ModBase.Log("[Minecraft] 用户要求尽量忽略文件检查,这可能会保留有误的文件"); + LauncherLog.Log("[Minecraft] 用户要求尽量忽略文件检查,这可能会保留有误的文件"); result = result.Where(f => { if (File.Exists(f.LocalPath)) { - ModBase.Log("[Minecraft] 跳过下载的支持库文件:" + f.LocalPath, ModBase.LogLevel.Debug); + LauncherLog.Log("[Minecraft] 跳过下载的支持库文件:" + f.LocalPath, LauncherLogLevel.Debug); return false; } @@ -547,12 +547,12 @@ public static List McLibNetFilesFromTokens(List libs, foreach (var token in libs) { // 检查文件 - var checker = new ModBase.FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: token.Sha1); + var checker = new FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: token.Sha1); if (checker.Check(token.LocalPath) is null) continue; if (token.IsLocal) { - ModBase.Log("[Download] 已跳过被标记为本地文件的支持库: " + token.OriginalName); + LauncherLog.Log("[Download] 已跳过被标记为本地文件的支持库: " + token.OriginalName); continue; } @@ -586,8 +586,8 @@ public static List McLibNetFilesFromTokens(List libs, { // Transformer 文件释放 if (!File.Exists(token.LocalPath)) - ModBase.WriteFile(token.LocalPath, ModBase.GetResourceStream("Resources/transformer.jar")); - ModBase.Log("[Download] 已自动释放 Transformer Discovery Service", ModBase.LogLevel.Developer); + LegacyFileFacade.WriteFile(token.LocalPath, Basics.GetResourceStream("Resources/transformer.jar")); + LauncherLog.Log("[Download] 已自动释放 Transformer Discovery Service", LauncherLogLevel.Developer); continue; } @@ -596,7 +596,7 @@ public static List McLibNetFilesFromTokens(List libs, // OptiFine 主 Jar var optiFineBase = token.LocalPath.Replace(Path.Combine(customMcFolder, "libraries", "optifine", "OptiFine") + @"\", "").Split("_")[0] + "/" + - ModBase.GetFileNameFromPath(token.LocalPath).Replace("-", "_"); + LegacyFileFacade.GetFileNameFromPath(token.LocalPath).Replace("-", "_"); optiFineBase = "/maven/com/optifine/" + optiFineBase; if (optiFineBase.Contains("_pre")) optiFineBase = optiFineBase.Replace("com/optifine/", "com/optifine/preview_"); @@ -606,9 +606,9 @@ public static List McLibNetFilesFromTokens(List libs, { // LabyMod 只有一个下载源 urls.Add(token.Url); - ModBase.Log( + LauncherLog.Log( $"[Download] 获取到 LabyMod 主要库文件的 Size = {token.size},SHA1 = {token.Sha1},由于 LabyMod 乱写 Size,已忽略 Size"); - checker = new ModBase.FileChecker(hash: token.Sha1); // 只校验 SHA1 + checker = new FileChecker(hash: token.Sha1); // 只校验 SHA1 } else if (urls.Count <= 2) { @@ -642,9 +642,9 @@ public static string McLibGet(string original, bool withHead = true, bool ignore // 判断 OptiFine 是否应该使用 installer if (mcLibGetRet.Contains(@"optifine\OptiFine\1.") && splited[2].Split(".").Count() > 1) { - var majorVersion = (int)Math.Round(ModBase.Val(splited[2].Split(".")[1].BeforeFirst("_"))); + var majorVersion = (int)Math.Round(LauncherText.Val(splited[2].Split(".")[1].BeforeFirst("_"))); var minorVersion = (int)Math.Round(splited[2].Split(".").Count() > 2 - ? ModBase.Val(splited[2].Split(".")[2].BeforeFirst("_")) + ? LauncherText.Val(splited[2].Split(".")[2].BeforeFirst("_")) : 0d); if ((majorVersion == 12 || (majorVersion == 20 && minorVersion >= 4) || majorVersion >= 21) && File.Exists( $@"{customMcFolder}libraries\{splited[0].Replace(".", @"\")}\{splited[1]}\{splited[2]}\{splited[1]}-{splited[2]}-installer.jar")) // 仅在 1.12 (无法追溯) 和 1.20.4+ (#5376) 遇到此问题 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs index 4aaafae21..ce2c06e2a 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.IO.Compression; using System.Text; using System.Text.RegularExpressions; @@ -18,7 +18,7 @@ public static class ModLocalComp private const int localModCacheVersion = 7; private static readonly Lazy _hashCache = new(() => - new HashCache(ModBase.pathTemp + @"Cache\HashCache.db")); + new HashCache(LauncherPaths.TempWithSlash + @"Cache\HashCache.db")); public class LocalCompFile { @@ -96,7 +96,7 @@ public string GetLogo() // 为文件夹设置特定图标 if (IsFolder) return "pack://application:,,,/images/Icons/Folder.png"; - return ModBase.pathImage + "Icons/NoIcon.png"; + return LauncherPaths.ImageBaseUri + "Icons/NoIcon.png"; } #region Litematic 文件处理 @@ -108,7 +108,7 @@ private void LoadLitematicNbtData() { try { - ModBase.Log($"开始读取 Litematic NBT 数据:{path}", ModBase.LogLevel.Debug); + LauncherLog.Log($"开始读取 Litematic NBT 数据:{path}", LauncherLogLevel.Debug); using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { var scheNbt = new NbtFile(); @@ -121,7 +121,7 @@ private void LoadLitematicNbtData() var metadataTag = scheNbt.RootTag.Get("Metadata"); if (metadataTag is not null) { - ModBase.Log("找到 Litematic Metadata 节点", ModBase.LogLevel.Debug); + LauncherLog.Log("找到 Litematic Metadata 节点", LauncherLogLevel.Debug); // 读取名称 var nameTag = metadataTag.Get("Name"); @@ -170,15 +170,15 @@ private void LoadLitematicNbtData() } else { - ModBase.Log("未找到 Litematic Metadata 节点", ModBase.LogLevel.Debug); + LauncherLog.Log("未找到 Litematic Metadata 节点", LauncherLogLevel.Debug); } } - ModBase.Log("Litematic NBT 数据读取完成", ModBase.LogLevel.Debug); + LauncherLog.Log("Litematic NBT 数据读取完成", LauncherLogLevel.Debug); } catch (Exception ex) { - ModBase.Log(ex, "读取 Litematic NBT 数据时出错(" + path + ")"); + LauncherLog.Log(ex, "读取 Litematic NBT 数据时出错(" + path + ")"); } } @@ -193,7 +193,7 @@ private void LoadSchemNbtData() { try { - ModBase.Log($"开始读取 Schem NBT 数据:{path}", ModBase.LogLevel.Debug); + LauncherLog.Log($"开始读取 Schem NBT 数据:{path}", LauncherLogLevel.Debug); // 使用自动检测压缩格式 using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) @@ -247,11 +247,11 @@ private void LoadSchemNbtData() } } - ModBase.Log("Schem NBT 数据读取完成", ModBase.LogLevel.Debug); + LauncherLog.Log("Schem NBT 数据读取完成", LauncherLogLevel.Debug); } catch (Exception ex) { - ModBase.Log(ex, "读取 Schem NBT 数据时出错(" + path + ")"); + LauncherLog.Log(ex, "读取 Schem NBT 数据时出错(" + path + ")"); } } @@ -266,7 +266,7 @@ private void LoadSchematicNbtData() { try { - ModBase.Log($"开始读取 Schematic NBT 数据:{path}", ModBase.LogLevel.Debug); + LauncherLog.Log($"开始读取 Schematic NBT 数据:{path}", LauncherLogLevel.Debug); using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { var scheNbt = new NbtFile(); @@ -284,14 +284,14 @@ private void LoadSchematicNbtData() // 读取材料列表 var materialsTag = scheNbt.RootTag.Get("Materials"); if (materialsTag is not null) - ModBase.Log($"Schematic 材料类型:{materialsTag.Value}", ModBase.LogLevel.Debug); + LauncherLog.Log($"Schematic 材料类型:{materialsTag.Value}", LauncherLogLevel.Debug); - ModBase.Log("Schematic NBT 数据读取完成", ModBase.LogLevel.Debug); + LauncherLog.Log("Schematic NBT 数据读取完成", LauncherLogLevel.Debug); } } catch (Exception ex) { - ModBase.Log(ex, "读取 Schematic NBT 数据时出错(" + path + ")"); + LauncherLog.Log(ex, "读取 Schematic NBT 数据时出错(" + path + ")"); } } @@ -306,7 +306,7 @@ private void LoadStructureNbtData() { try { - ModBase.Log($"开始读取 NBT 结构文件数据:{path}", ModBase.LogLevel.Debug); + LauncherLog.Log($"开始读取 NBT 结构文件数据:{path}", LauncherLogLevel.Debug); using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { var scheNbt = new NbtFile(); @@ -345,7 +345,7 @@ private void LoadStructureNbtData() } catch (Exception ex) { - ModBase.Log(ex, "读取 NBT 结构文件数据时出错(" + path + ")"); + LauncherLog.Log(ex, "读取 NBT 结构文件数据时出错(" + path + ")"); } } @@ -389,7 +389,7 @@ public LocalCompFile(string path) /// /// Mod 资源的完整路径,去除最后的 .disabled 和 .old。 /// - public string RawPath => ModBase.GetPathFromFullPath(path) + RawFileName; + public string RawPath => LegacyFileFacade.GetPathFromFullPath(path) + RawFileName; /// /// 资源的完整文件名。 @@ -400,7 +400,7 @@ public string FileName { if (IsFolder && !string.IsNullOrEmpty(Name)) return Name; - return ModBase.GetFileNameFromPath(path); + return LegacyFileFacade.GetFileNameFromPath(path); } } @@ -450,9 +450,9 @@ public string Name if (_Name is null) { if (IsFolder) - _Name = ModBase.GetFolderNameFromPath(ActualPath); + _Name = LegacyFileFacade.GetFolderNameFromPath(ActualPath); else - _Name = ModBase.GetFileNameWithoutExtentionFromPath(path); + _Name = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(path); } return _Name; @@ -460,7 +460,7 @@ public string Name set { if (_Name is null && value is not null && !value.Contains("modname") && value.ToLower() != "name" && - value.Length > 1 && (ModBase.Val(value).ToString() ?? "") != (value ?? "")) _Name = value; + value.Length > 1 && (LauncherText.Val(value).ToString() ?? "") != (value ?? "")) _Name = value; } } @@ -577,7 +577,7 @@ public string ModId if (value is null) return; value = value.RegexSeek(RegexPatterns.ModIdMatch); - if (value is null || value.Length <= 1 || (ModBase.Val(value).ToString() ?? "") == (value ?? "")) + if (value is null || value.Length <= 1 || (LauncherText.Val(value).ToString() ?? "") == (value ?? "")) return; if (value.ContainsF("name", true) || value.ContainsF("modid", true)) return; @@ -838,7 +838,7 @@ private void AddDependency(string modID, string versionRequirement = null) if (modID is null || modID.Length < 2) return; modID = modID.ToLower(); - if (modID == "name" || (ModBase.Val(modID).ToString() ?? "") == (modID ?? "")) + if (modID == "name" || (LauncherText.Val(modID).ToString() ?? "") == (modID ?? "")) return; // 跳过 name 与纯数字 id if (versionRequirement is null || (!versionRequirement.Contains(".") && !versionRequirement.Contains("-")) || @@ -965,7 +965,7 @@ public void LoadBasicInfo() if (path.EndsWithF(".litematic", true) || path.EndsWithF(".nbt", true) || path.EndsWithF(".schem", true) || path.EndsWithF(".schematic", true)) { - _Name = ModBase.GetFileNameWithoutExtentionFromPath(path); + _Name = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(path); isLoaded = true; return; } @@ -975,7 +975,7 @@ public void LoadBasicInfo() } catch (Exception ex) { - ModBase.Log(ex, $"加载基本信息失败:{path}"); + LauncherLog.Log(ex, $"加载基本信息失败:{path}"); } } @@ -1003,7 +1003,7 @@ public void LoadNbtDataIfNeeded() } catch (Exception ex) { - ModBase.Log(ex, $"延迟加载NBT数据失败:{path}"); + LauncherLog.Log(ex, $"延迟加载NBT数据失败:{path}"); } } @@ -1053,7 +1053,7 @@ public void Load(bool forceReload = false) { try { - _Name = ModBase.GetFileNameWithoutExtentionFromPath(path); + _Name = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(path); // 根据文件类型加载数据 if (path.EndsWithF(".litematic", true)) { @@ -1075,7 +1075,7 @@ public void Load(bool forceReload = false) } catch (Exception ex) { - ModBase.Log(ex, "投影文件信息获取失败(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "投影文件信息获取失败(" + path + ")", LauncherLogLevel.Developer); _FileUnavailableReason = ex; } @@ -1093,12 +1093,12 @@ public void Load(bool forceReload = false) } catch (UnauthorizedAccessException ex) { - ModBase.Log(ex, "资源文件由于无权限无法打开(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "资源文件由于无权限无法打开(" + path + ")", LauncherLogLevel.Developer); _FileUnavailableReason = new UnauthorizedAccessException("没有读取此文件的权限,请尝试右键以管理员身份运行 PCL", ex); } catch (Exception ex) { - ModBase.Log(ex, "资源文件无法打开(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "资源文件无法打开(" + path + ")", LauncherLogLevel.Developer); _FileUnavailableReason = ex; } finally @@ -1127,7 +1127,7 @@ private void LookupMetadata(ZipArchive jar) string infoString = null; if (infoEntry is not null) { - infoString = ModBase.ReadFile(infoEntry.Open()); + infoString = LegacyFileFacade.ReadText(infoEntry.Open()); if (infoString.Length < 15) infoString = null; } @@ -1136,7 +1136,7 @@ private void LookupMetadata(ZipArchive jar) break; // 获取可用 Json 项 JsonObject infoObject; - var jsonObject = (JsonNode)ModBase.GetJson(infoString); + var jsonObject = (JsonNode)PCL.Core.Utils.JsonCompat.ParseNode(infoString); if (jsonObject.GetValueKind() == JsonValueKind.Array) infoObject = (JsonObject)jsonObject[0]; else @@ -1163,11 +1163,11 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = ModBase.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); - Logo = System.IO.Path.Combine(ModBase.pathTemp, "Cache", "Images", $"{md5}.png"); + var md5 = LauncherText.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); + Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { - ModBase.WriteFile(Logo, entryStream); + LegacyFileFacade.WriteFile(Logo, entryStream); } } } @@ -1212,7 +1212,7 @@ private void LookupMetadata(ZipArchive jar) } catch (Exception ex) { - ModBase.Log(ex, "读取 mcmod.info 时出现未知错误(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "读取 mcmod.info 时出现未知错误(" + path + ")", LauncherLogLevel.Developer); } } while (false); @@ -1228,13 +1228,13 @@ private void LookupMetadata(ZipArchive jar) string fabricText = null; if (fabricEntry is not null) { - fabricText = ModBase.ReadFile(fabricEntry.Open(), Encoding.UTF8); + fabricText = LegacyFileFacade.ReadText(fabricEntry.Open(), Encoding.UTF8); if (!fabricText.Contains("schemaVersion")) fabricText = null; } if (fabricText is null) break; - var fabricObject = (JsonObject)ModBase.GetJson(fabricText); + var fabricObject = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(fabricText); if (fabricObject.ContainsKey("name")) Name = fabricObject["name"].ToString(); if (fabricObject.ContainsKey("version")) Version = fabricObject["version"].ToString(); @@ -1256,11 +1256,11 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = ModBase.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); - Logo = System.IO.Path.Combine(ModBase.pathTemp, "Cache", "Images", $"{md5}.png"); + var md5 = LauncherText.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); + Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { - ModBase.WriteFile(Logo, entryStream); + LegacyFileFacade.WriteFile(Logo, entryStream); } } } @@ -1272,7 +1272,7 @@ private void LookupMetadata(ZipArchive jar) } catch (Exception ex) { - ModBase.Log(ex, "读取 fabric.mod.json 时出错(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "读取 fabric.mod.json 时出错(" + path + ")", LauncherLogLevel.Developer); } } while (false); @@ -1289,14 +1289,14 @@ private void LookupMetadata(ZipArchive jar) string quiltText = null; if (quiltEntry is not null) { - quiltText = ModBase.ReadFile(quiltEntry.Open(), Encoding.UTF8); + quiltText = LegacyFileFacade.ReadText(quiltEntry.Open(), Encoding.UTF8); if (!quiltText.Contains("schema_version")) quiltText = null; } if (quiltText is null) break; - var quiltObject = (JsonObject)((JsonObject)ModBase.GetJson(quiltText))["quilt_loader"]; + var quiltObject = (JsonObject)((JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(quiltText))["quilt_loader"]; // 从文件中获取 Mod 信息项 if (quiltObject.ContainsKey("id")) ModId = (string)quiltObject["id"]; @@ -1321,11 +1321,11 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = ModBase.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); - Logo = System.IO.Path.Combine(ModBase.pathTemp, "Cache", "Images", $"{md5}.png"); + var md5 = LauncherText.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); + Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { - ModBase.WriteFile(Logo, entryStream); + LegacyFileFacade.WriteFile(Logo, entryStream); } } } @@ -1335,7 +1335,7 @@ private void LookupMetadata(ZipArchive jar) } catch (Exception ex) { - ModBase.Log(ex, "读取 quilt.mod.json 时出现未知错误(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "读取 quilt.mod.json 时出现未知错误(" + path + ")", LauncherLogLevel.Developer); } } while (false); @@ -1496,7 +1496,7 @@ private void LookupMetadata(ZipArchive jar) } catch (Exception ex) { - ModBase.Log(ex, "读取 mods.toml 时出现未知错误(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "读取 mods.toml 时出现未知错误(" + path + ")", LauncherLogLevel.Developer); } #endregion @@ -1512,14 +1512,14 @@ private void LookupMetadata(ZipArchive jar) string fmlText = null; if (fmlEntry is not null) { - fmlText = ModBase.ReadFile(fmlEntry.Open(), Encoding.UTF8); + fmlText = LegacyFileFacade.ReadText(fmlEntry.Open(), Encoding.UTF8); if (!fmlText.Contains("Lnet/minecraftforge/fml/common/Mod;")) fmlText = null; } if (fmlText is null) break; - var fmlJson = (JsonObject)ModBase.GetJson(fmlText); + var fmlJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(fmlText); // 获取可用 Json 项 JsonObject fmlObject = null; foreach (var ModFilePair in fmlJson) @@ -1551,7 +1551,7 @@ private void LookupMetadata(ZipArchive jar) break; value = value.ToLower().RegexSeek(RegexPatterns.ModIdMatch); if (value is not null && value.ToLower() != "name" && value.Length > 1 && - (ModBase.Val(value).ToString() ?? "") != (value ?? "")) + (LauncherText.Val(value).ToString() ?? "") != (value ?? "")) if (!possibleModId.Contains(value)) possibleModId.Add(value); break; @@ -1599,7 +1599,7 @@ private void LookupMetadata(ZipArchive jar) } catch (Exception ex) { - ModBase.Log(ex, "读取 fml_cache_annotation.json 时出现未知错误(" + path + ")"); + LauncherLog.Log(ex, "读取 fml_cache_annotation.json 时出现未知错误(" + path + ")"); } } while (false); @@ -1614,23 +1614,23 @@ private void LookupMetadata(ZipArchive jar) if (packPngEntry is not null) try { - var md5 = ModBase.GetStringMD5(packPngEntry.Length + packPngEntry.CompressedLength + path); - Logo = System.IO.Path.Combine(ModBase.pathTemp, "Cache", "Images", $"{md5}.png"); + var md5 = LauncherText.GetStringMD5(packPngEntry.Length + packPngEntry.CompressedLength + path); + Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = packPngEntry.Open()) { - ModBase.WriteFile(Logo, entryStream); + LegacyFileFacade.WriteFile(Logo, entryStream); } - ModBase.Log("成功提取资源包图标:" + path, ModBase.LogLevel.Debug); + LauncherLog.Log("成功提取资源包图标:" + path, LauncherLogLevel.Debug); } catch (Exception logoEx) { - ModBase.Log(logoEx, "提取 pack.png 图标失败(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(logoEx, "提取 pack.png 图标失败(" + path + ")", LauncherLogLevel.Developer); } } catch (Exception ex) { - ModBase.Log(ex, "识别资源包图标时出现未知错误(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "识别资源包图标时出现未知错误(" + path + ")", LauncherLogLevel.Developer); } #endregion @@ -1645,7 +1645,7 @@ private void LookupMetadata(ZipArchive jar) var metaEntry = jar.GetEntry("META-INF/MANIFEST.MF"); if (metaEntry is not null) { - var metaString = ModBase.ReadFile(metaEntry.Open()).Replace(" :", ":").Replace(": ", ":"); + var metaString = LegacyFileFacade.ReadText(metaEntry.Open()).Replace(" :", ":").Replace(": ", ":"); if (metaString.Contains("Implementation-Version:")) { metaString = metaString.Substring(metaString.IndexOfF("Implementation-Version:") + @@ -1658,7 +1658,7 @@ private void LookupMetadata(ZipArchive jar) } catch (Exception ex) { - ModBase.Log("获取 META-INF 中的版本信息失败(" + path + ")", ModBase.LogLevel.Developer); + LauncherLog.Log("获取 META-INF 中的版本信息失败(" + path + ")", LauncherLogLevel.Developer); Version = null; } @@ -1825,7 +1825,7 @@ private static string GetFolderDescription(string folderPath) } catch (Exception ex) { - ModBase.Log(ex, $"获取文件夹描述失败:{folderPath}"); + LauncherLog.Log(ex, $"获取文件夹描述失败:{folderPath}"); return "文件夹"; } } @@ -1849,7 +1849,7 @@ private static void CompResourceListLoad(LoaderTask + UiThread.Invoke(() => { if (loader.input.frm is not null) loader.input.frm.Load.ShowProgress = false; }); @@ -1857,10 +1857,10 @@ private static void CompResourceListLoad(LoaderTask + UiThread.Invoke(() => { if (loader.input.frm is not null) loader.input.frm.Load.Text = Lang.Text("Instance.Resource.Update.WaitingForUpdate"); @@ -1874,7 +1874,7 @@ private static void CompResourceListLoad(LoaderTask + UiThread.Invoke(() => { if (loader.input.frm is not null) loader.input.frm.Load.Text = Lang.Text("Instance.Resource.List.Loading"); @@ -1912,19 +1912,19 @@ private static void CompResourceListLoad(LoaderTask 50) - ModBase.RunInUi(() => + UiThread.Post(() => { if (loader.input.frm is not null) loader.input.frm.Load.ShowProgress = true; }); // 获取本地文件缓存 - var cachePath = ModBase.pathTemp + @"Cache\LocalComp.json"; + var cachePath = LauncherPaths.TempWithSlash + @"Cache\LocalComp.json"; var cache = new JsonObject(); try { - var cacheContent = ModBase.ReadFile(cachePath); + var cacheContent = LegacyFileFacade.ReadText(cachePath); if (!string.IsNullOrWhiteSpace(cacheContent)) { - cache = (JsonObject)ModBase.GetJson(cacheContent); + cache = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(cacheContent); if (!cache.ContainsKey("version") || cache["version"].ToObject() != localModCacheVersion) { - ModBase.Log("[Mod] 本地 Mod 信息缓存版本已过期,将弃用这些缓存信息", ModBase.LogLevel.Debug); + LauncherLog.Log("[Mod] 本地 Mod 信息缓存版本已过期,将弃用这些缓存信息", LauncherLogLevel.Debug); cache = new JsonObject(); } } } catch (Exception ex) { - ModBase.Log(ex, "读取本地 Mod 信息缓存失败,已重置"); + LauncherLog.Log(ex, "读取本地 Mod 信息缓存失败,已重置"); cache = new JsonObject(); } @@ -2017,7 +2017,7 @@ private static void CompResourceListLoad(LoaderTask m.Comp is null).Count()} 个需要联网获取信息,{modUpdateList.Where(m => m.Comp is not null).Count()} 个需要更新信息"); // 排序 @@ -2046,7 +2046,7 @@ private static void CompResourceListLoad(LoaderTask lo var mcInstance = loader.input.gameVersion.Info.VanillaName; // 开始网络获取 - ModBase.Log($"[Mod] 目标加载器:{string.Join("/", modLoaders)},版本:{mcInstance}"); + LauncherLog.Log($"[Mod] 目标加载器:{string.Join("/", modLoaders)},版本:{mcInstance}"); var endedThreadCount = 0; var isFailed = false; var currentTaskId = Task.CurrentId ?? -1; // 从 Modrinth 获取信息 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { // 步骤 1:获取 Hash 与对应的工程 ID var modrinthHashes = mods.Select(m => m.ModrinthHash).ToList(); - var modrinthVersion = (JsonObject)ModBase.GetJson(ModDownload.DlModRequest( + var modrinthVersion = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ModDownload.DlModRequest( "https://api.modrinth.com/v2/version_files", "POST", $"{{\"hashes\": [\"{string.Join("\",\"", modrinthHashes)}\"], \"algorithm\": \"sha1\"}}", "application/json")); - ModBase.Log($"[Mod] 从 Modrinth 获取到 {modrinthVersion.Count} 个本地 Mod 的对应信息"); + LauncherLog.Log($"[Mod] 从 Modrinth 获取到 {modrinthVersion.Count} 个本地 Mod 的对应信息"); // 步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系 if (modrinthVersion.Count == 0) return; @@ -2107,11 +2107,11 @@ private static void CompUpdateDetailLoad(LoaderTask lo } if (loader.IsAbortedWithThread(currentTaskId)) return; - ModBase.Log($"[Mod] 需要从 Modrinth 获取 {modrinthMapping.Count} 个本地 Mod 的工程信息"); + LauncherLog.Log($"[Mod] 需要从 Modrinth 获取 {modrinthMapping.Count} 个本地 Mod 的工程信息"); // 步骤 3:获取工程信息 if (!modrinthMapping.Any()) return; - var modrinthProject = (JsonArray)ModBase.GetJson(ModDownload.DlModRequest( + var modrinthProject = (JsonArray)PCL.Core.Utils.JsonCompat.ParseNode(ModDownload.DlModRequest( $"https://api.modrinth.com/v2/projects?ids=[\"{string.Join("\",\"", modrinthMapping.Keys)}\"]", "GET", "", "application/json")); @@ -2121,13 +2121,13 @@ private static void CompUpdateDetailLoad(LoaderTask lo foreach (var Entry in modrinthMapping[project.Id]) Entry.Comp = project; } - ModBase.Log("[Mod] 已从 Modrinth 获取本地 Mod 信息,继续获取更新信息"); + LauncherLog.Log("[Mod] 已从 Modrinth 获取本地 Mod 信息,继续获取更新信息"); // 步骤 4:获取更新信息 var targetLoaders = compType == CompType.DataPack ? "datapack" : string.Join("\",\"", modLoaders).ToLower(); - var modrinthUpdate = (JsonObject)ModBase.GetJson(ModDownload.DlModRequest( + var modrinthUpdate = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ModDownload.DlModRequest( "https://api.modrinth.com/v2/version_files/update", "POST", $"{{\"hashes\": [\"{string.Join("\",\"", modrinthMapping.SelectMany(l => l.Value.Select(m => m.ModrinthHash)))}\"], \"algorithm\": \"sha1\", " + $"\"loaders\": [\"{targetLoaders}\"],\"game_versions\": [\"{mcInstance}\"]}}", "application/json")); @@ -2138,8 +2138,8 @@ private static void CompUpdateDetailLoad(LoaderTask lo var updateFile = new CompFile((JsonObject)modrinthUpdate[Entry.ModrinthHash], CompType.Mod); if (!updateFile.Available) continue; - if (ModBase.ModeDebug) - ModBase.Log($"[Mod] 本地文件 {Entry.compFile.FileName} 在 Modrinth 上的最新版为 {updateFile.FileName}"); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log($"[Mod] 本地文件 {Entry.compFile.FileName} 在 Modrinth 上的最新版为 {updateFile.FileName}"); if (Entry.compFile.ReleaseDate >= updateFile.ReleaseDate || Entry.compFile.Hash == updateFile.Hash) continue; @@ -2161,11 +2161,11 @@ private static void CompUpdateDetailLoad(LoaderTask lo } } - ModBase.Log("[Mod] 从 Modrinth 获取本地 Mod 信息结束"); + LauncherLog.Log("[Mod] 从 Modrinth 获取本地 Mod 信息结束"); } catch (Exception ex) { - ModBase.Log(ex, "从 Modrinth 获取本地 Mod 信息失败"); + LauncherLog.Log(ex, "从 Modrinth 获取本地 Mod 信息失败"); isFailed = true; } finally @@ -2175,17 +2175,17 @@ private static void CompUpdateDetailLoad(LoaderTask lo }, "Mod List Detail Loader Modrinth"); // CurseForge 部分转换逻辑类似,注意其 ID 多为 Integer 类型 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { // 步骤 1:获取 Hash 与对应的工程 ID var curseForgeHashes = mods.Select(m => m.CurseForgeHash).ToList(); - var curseForgeResponse = (JsonObject)ModBase.GetJson(ModDownload.DlModRequest( + var curseForgeResponse = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ModDownload.DlModRequest( "https://api.curseforge.com/v1/fingerprints/432", "POST", $"{{\"fingerprints\": [{string.Join(",", curseForgeHashes)}]}}", "application/json")); var curseForgeRaw = (JsonArray)curseForgeResponse["data"]["exactMatches"]; - ModBase.Log($"[Mod] 从 CurseForge 获取到 {curseForgeRaw.Count} 个本地 Mod 的对应信息"); + LauncherLog.Log($"[Mod] 从 CurseForge 获取到 {curseForgeRaw.Count} 个本地 Mod 的对应信息"); // 步骤 2:构建映射 (此处省略具体循环,逻辑同 Modrinth,注意 ProjectId 转换) // ... @@ -2195,7 +2195,7 @@ private static void CompUpdateDetailLoad(LoaderTask lo } catch (Exception ex) { - ModBase.Log(ex, "从 CurseForge 获取本地 Mod 信息失败"); + LauncherLog.Log(ex, "从 CurseForge 获取本地 Mod 信息失败"); isFailed = true; } finally @@ -2213,7 +2213,7 @@ private static void CompUpdateDetailLoad(LoaderTask lo // 保存缓存 var cachedMods = mods.Where(m => m.Comp is not null).ToList(); - ModBase.Log($"[Mod] 联网获取本地 Mod 信息完成,为 {cachedMods.Count} 个 Mod 更新缓存"); + LauncherLog.Log($"[Mod] 联网获取本地 Mod 信息完成,为 {cachedMods.Count} 个 Mod 更新缓存"); if (!cachedMods.Any()) return; foreach (var Entry in cachedMods) @@ -2222,11 +2222,11 @@ private static void CompUpdateDetailLoad(LoaderTask lo cache[Entry.ModrinthHash + mcInstance + string.Join("", modLoaders)] = Entry.ToJson(); } - ModBase.WriteFile(Path.Combine(ModBase.pathTemp, "Cache", "LocalComp.json"), - cache.ToJsonString(ModBase.ModeDebug ? new JsonSerializerOptions(JsonCompat.SerializerOptions) { WriteIndented = true } : null)); + LegacyFileFacade.WriteFile(Path.Combine(LauncherPaths.TempWithSlash, "Cache", "LocalComp.json"), + cache.ToJsonString(LauncherRuntime.ModeDebug ? new JsonSerializerOptions(JsonCompat.SerializerOptions) { WriteIndented = true } : null)); // 刷新 UI - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.frmInstanceMod?.Filter == PageInstanceCompResource.FilterType.CanUpdate) ModMain.frmInstanceMod?.RefreshUI(); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs index 52a1e935d..221a87886 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs @@ -26,21 +26,21 @@ public static void ModpackInstall() Lang.Text("Minecraft.Download.Modpack.FileDialog.Title")); // 选择整合包文件 if (string.IsNullOrEmpty(file)) return; - ModBase.RunInThread(() => + UiThread.RunInThread(() => { try { ModpackInstall(file); } - catch (ModBase.CancelledException ex) + catch (CancelledException ex) { } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "手动安装整合包失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Minecraft.Download.Modpack.Error.OperationFailed")); } }); @@ -50,11 +50,11 @@ public static void ModpackInstall() /// 构建并启动安装给定的整合包文件的加载器,并返回该加载器。若失败则抛出异常。 /// 必须在工作线程执行。 /// - /// + /// public static LoaderCombo ModpackInstall(string file, string instanceName = null, string logo = null, string resourceId = null, bool isOnlineInstall = false) { - ModBase.Log("[ModPack] 整合包安装请求:" + (file ?? "null")); + LauncherLog.Log("[ModPack] 整合包安装请求:" + (file ?? "null")); ZipArchive archive = null; var archiveBaseFolder = ""; try @@ -65,7 +65,7 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.InvalidGamePathChars", targetFolder), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 获取整合包种类与关键 Json @@ -98,7 +98,7 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam if (archive.GetEntry("manifest.json") is not null) { - var json = (JsonObject)ModBase.GetJson(ModBase.ReadFile(archive.GetEntry("manifest.json").Open(), + var json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(archive.GetEntry("manifest.json").Open(), Encoding.UTF8)); if (json["addons"] is null) { @@ -156,7 +156,7 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam if (fullNames[1] == "manifest.json") { - var json = (JsonObject)ModBase.GetJson(ModBase.ReadFile(Entry.Open(), Encoding.UTF8)); + var json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(Entry.Open(), Encoding.UTF8)); if (json["addons"] is null) { packType = 0; @@ -204,40 +204,40 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam { case 0: { - ModBase.Log("[ModPack] 整合包种类:CurseForge"); + LauncherLog.Log("[ModPack] 整合包种类:CurseForge"); return InstallPackCurseForge(file, archive, archiveBaseFolder, instanceName, logo, resourceId, isOnlineInstall); } case 1: { - ModBase.Log("[ModPack] 整合包种类:HMCL"); + LauncherLog.Log("[ModPack] 整合包种类:HMCL"); return InstallPackHMCL(file, archive, archiveBaseFolder); } case 2: { - ModBase.Log("[ModPack] 整合包种类:MMC"); + LauncherLog.Log("[ModPack] 整合包种类:MMC"); return InstallPackMMC(file, archive, archiveBaseFolder); } case 3: { - ModBase.Log("[ModPack] 整合包种类:MCBBS"); + LauncherLog.Log("[ModPack] 整合包种类:MCBBS"); return InstallPackMCBBS(file, archive, archiveBaseFolder, instanceName); } case 4: { - ModBase.Log("[ModPack] 整合包种类:Modrinth"); + LauncherLog.Log("[ModPack] 整合包种类:Modrinth"); return InstallPackModrinth(file, archive, archiveBaseFolder, instanceName, logo, resourceId, isOnlineInstall); } case 9: { - ModBase.Log("[ModPack] 整合包种类:带启动器的压缩包"); + LauncherLog.Log("[ModPack] 整合包种类:带启动器的压缩包"); return InstallPackLauncherPack(file, archive, archiveBaseFolder); } default: { - ModBase.Log("[ModPack] 整合包种类:未能识别,假定为压缩包"); + LauncherLog.Log("[ModPack] 整合包种类:未能识别,假定为压缩包"); return InstallPackCompress(file, archive); } } @@ -263,10 +263,10 @@ private static void ExtractModpackFiles(string installTemp, string fileAddress, loader.Progress = initialProgress; // 删除旧目录 - ModBase.DeleteDirectory(installTemp); + LegacyFileFacade.DeleteDirectory(installTemp); // 解压文件,ProgressIncrementHandler 通过 Lambda 更新进度 - ModBase.ExtractFile(fileAddress, installTemp, encode, + LegacyFileFacade.ExtractFile(fileAddress, installTemp, encode, delta => loader.Progress += delta * progressIncrement); // 解压成功,更新进度并退出循环 @@ -275,12 +275,12 @@ private static void ExtractModpackFiles(string installTemp, string fileAddress, } catch (Exception ex) { - ModBase.Log(ex, $"第 {retryCount} 次解压尝试失败"); + LauncherLog.Log(ex, $"第 {retryCount} 次解压尝试失败"); if (ex is ArgumentException || ex is IOException) { encode = Encoding.UTF8; - ModBase.Log("[ModPack] 已切换压缩包解压编码为 UTF8"); + LauncherLog.Log("[ModPack] 已切换压缩包解压编码为 UTF8"); } // 检查加载器状态,决定是否中止 @@ -312,13 +312,13 @@ private static void CopyOverrideDirectory(string overridesFolder, string version // 复制文件 if (Directory.Exists(overridesFolder)) { - ModBase.Log($"[ModPack] 处理整合包覆写文件夹:{overridesFolder} → {versionFolder}"); - ModBase.CopyDirectory(overridesFolder, versionFolder, + LauncherLog.Log($"[ModPack] 处理整合包覆写文件夹:{overridesFolder} → {versionFolder}"); + LegacyFileFacade.CopyDirectory(overridesFolder, versionFolder, delta => loader.Progress += delta * progressIncrement); } else { - ModBase.Log($"[ModPack] 整合包中没有覆写文件夹:{overridesFolder}"); + LauncherLog.Log($"[ModPack] 整合包中没有覆写文件夹:{overridesFolder}"); loader.Progress += progressIncrement; } @@ -327,17 +327,17 @@ private static void CopyOverrideDirectory(string overridesFolder, string version var versionIni = $@"{versionFolder}PCL\Setup.ini"; if (File.Exists(overridesIni)) { - ModBase.WriteIni(overridesIni, "VersionArgumentIndie", 1.ToString()); // 开启版本隔离 - ModBase.WriteIni(overridesIni, "VersionArgumentIndieV2", true.ToString()); - ModBase.CopyFile(overridesIni, versionIni); // 覆写已有的 ini + LegacyIniStore.Shared.Write(overridesIni, "VersionArgumentIndie", 1.ToString()); // 开启版本隔离 + LegacyIniStore.Shared.Write(overridesIni, "VersionArgumentIndieV2", true.ToString()); + LegacyFileFacade.CopyFile(overridesIni, versionIni); // 覆写已有的 ini } else { - ModBase.WriteIni(versionIni, "VersionArgumentIndie", 1.ToString()); // 开启版本隔离 - ModBase.WriteIni(versionIni, "VersionArgumentIndieV2", true.ToString()); + LegacyIniStore.Shared.Write(versionIni, "VersionArgumentIndie", 1.ToString()); // 开启版本隔离 + LegacyIniStore.Shared.Write(versionIni, "VersionArgumentIndieV2", true.ToString()); } - ModBase.IniClearCache(versionIni); // 重置缓存,避免被安装过程中写入的 ini 覆盖 + LegacyIniStore.Shared.ClearCache(versionIni); // 重置缓存,避免被安装过程中写入的 ini 覆盖 } #region CurseForge @@ -350,8 +350,8 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip JsonObject json; try { - json = (JsonObject)ModBase.GetJson( - ModBase.ReadFile(archive.GetEntry(archiveBaseFolder + "manifest.json").Open())); + json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( + LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "manifest.json").Open())); } catch (Exception ex) { @@ -372,7 +372,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); if (string.IsNullOrEmpty(instanceName)) - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 获取 Mod API 版本信息 @@ -388,13 +388,13 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip // Forge 指定 if (id.Contains("recommended")) throw new Exception(Lang.Text("Minecraft.Download.Modpack.TooOldUnsupported")); - ModBase.Log("[ModPack] 整合包 Forge 版本:" + id); + LauncherLog.Log("[ModPack] 整合包 Forge 版本:" + id); forgeVersion = id.Replace("forge-", ""); } else if (id.StartsWithF("neoforge-")) { // NeoForge 指定 - ModBase.Log("[ModPack] 整合包 NeoForge 版本:" + id); + LauncherLog.Log("[ModPack] 整合包 NeoForge 版本:" + id); neoForgeVersion = id.Replace("neoforge-", ""); } else if (id.StartsWithF("fabric-")) @@ -402,13 +402,13 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip // Fabric 指定 try { - ModBase.Log("[ModPack] 整合包 Fabric 版本:" + id); + LauncherLog.Log("[ModPack] 整合包 Fabric 版本:" + id); fabricVersion = id.Replace("fabric-", ""); break; } catch (Exception ex) { - ModBase.Log(ex, "读取整合包 Fabric 版本失败:" + id); + LauncherLog.Log(ex, "读取整合包 Fabric 版本失败:" + id); } } else if (id.StartsWithF("quilt-")) @@ -416,13 +416,13 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip // Quilt 指定 try { - ModBase.Log("[ModPack] 整合包 Quilt 版本:" + id); + LauncherLog.Log("[ModPack] 整合包 Quilt 版本:" + id); quiltVersion = id.Replace("quilt-", ""); break; } catch (Exception ex) { - ModBase.Log(ex, "读取整合包 Quilt 版本失败:" + id); + LauncherLog.Log(ex, "读取整合包 Quilt 版本失败:" + id); } } } @@ -473,18 +473,18 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip do { tryCount += 1; - ret = (JsonArray)((JsonObject)ModBase.GetJson(ModDownload.DlModRequest( + ret = (JsonArray)((JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ModDownload.DlModRequest( "https://api.curseforge.com/v1/mods/files", "POST", "{\"fileIds\": [" + modList.Join(",") + "]}", "application/json", allowMirror)))["data"]; if (modList.Count <= ret.Count) { - ModBase.Log("[Modpack] 已获取到的模组数量足够,开始进行下一步"); + LauncherLog.Log("[Modpack] 已获取到的模组数量足够,开始进行下一步"); break; } allowMirror = false; - ModBase.Log($"[Modpack] 获取模组数量不达标,设置镜像源允许状态为: {allowMirror}"); + LauncherLog.Log($"[Modpack] 获取模组数量不达标,设置镜像源允许状态为: {allowMirror}"); if (tryCount > 3) throw new Exception(Lang.Text("Minecraft.Download.Modpack.SomeModsDeleted")); } while (true); @@ -602,20 +602,20 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip File.Copy(logo, Path.Combine(versionFolder, "PCL", "Logo.png"), true); States.Instance.LogoPath[versionFolder] = @"PCL\Logo.png"; States.Instance.IsLogoCustom[versionFolder] = true; - ModBase.Log("[ModPack] 已设置整合包 Logo:" + logo); + LauncherLog.Log("[ModPack] 已设置整合包 Logo:" + logo); } // 删除原始整合包文件 foreach (var Target in new[] { Path.Combine(versionFolder, "原始整合包.zip"), Path.Combine(versionFolder, "原始整合包.mrpack") }) if (File.Exists(Target)) { - ModBase.Log("[ModPack] 删除原始整合包文件:" + Target); + LauncherLog.Log("[ModPack] 删除原始整合包文件:" + Target); File.Delete(Target); } - if (File.Exists(fileAddress) && ModBase.GetFileNameWithoutExtentionFromPath(fileAddress) == "modpack") + if (File.Exists(fileAddress) && LegacyFileFacade.GetFileNameWithoutExtensionFromPath(fileAddress) == "modpack") { - ModBase.Log("[ModPack] 删除安装整合包文件:" + fileAddress); + LauncherLog.Log("[ModPack] 删除安装整合包文件:" + fileAddress); File.Delete(fileAddress); } @@ -634,7 +634,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip } catch (Exception ex) { - ModBase.Log(ex, "[ModPack] 获取整合包描述文本失败"); + LauncherLog.Log(ex, "[ModPack] 获取整合包描述文本失败"); } } while (false); }) @@ -648,7 +648,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip if (loaderTaskbar.Any(l => (l.name ?? "") == (loaderName ?? ""))) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 启动 @@ -657,7 +657,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip LoaderTaskbarAdd(loader); ModMain.frmMain.BtnExtraDownload.ShowRefresh(); if (!isOnlineInstall) - ModBase.RunInUi(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); + UiThread.Post(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); return loader; } @@ -673,8 +673,8 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr JsonObject json; try { - json = (JsonObject)ModBase.GetJson( - ModBase.ReadFile(archive.GetEntry(archiveBaseFolder + "modrinth.index.json").Open())); + json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( + LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "modrinth.index.json").Open())); } catch (Exception ex) { @@ -700,26 +700,26 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr case "forge": // eg. 14.23.5.2859 / 1.19-41.1.0 { forgeVersion = Entry.Value?.ToObject(); - ModBase.Log("[ModPack] 整合包 Forge 版本:" + forgeVersion); + LauncherLog.Log("[ModPack] 整合包 Forge 版本:" + forgeVersion); break; } case "neoforge": case "neo-forge": // eg. 20.6.98-beta { neoForgeVersion = Entry.Value?.ToObject(); - ModBase.Log("[ModPack] 整合包 NeoForge 版本:" + neoForgeVersion); + LauncherLog.Log("[ModPack] 整合包 NeoForge 版本:" + neoForgeVersion); break; } case "fabric-loader": // eg. 0.14.14 { fabricVersion = Entry.Value?.ToObject(); - ModBase.Log("[ModPack] 整合包 Fabric 版本:" + fabricVersion); + LauncherLog.Log("[ModPack] 整合包 Fabric 版本:" + fabricVersion); break; } case "quilt-loader": // eg. 0.26.0 { quiltVersion = Entry.Value?.ToObject(); - ModBase.Log("[ModPack] 整合包 Quilt 版本:" + quiltVersion); + LauncherLog.Log("[ModPack] 整合包 Quilt 版本:" + quiltVersion); break; } @@ -742,7 +742,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); if (string.IsNullOrEmpty(instanceName)) - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 解压 @@ -773,7 +773,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr { if (ModMain.MyMsgBox( Lang.Text("Minecraft.Download.Modpack.OptionalFile.Message", - ModBase.GetFileNameFromPath(File["path"].ToString())), + LegacyFileFacade.GetFileNameFromPath(File["path"].ToString())), Lang.Text("Minecraft.Download.Modpack.OptionalFile.Title"), Lang.Text("Minecraft.Download.Modpack.OptionalFile.Download"), Lang.Text("Minecraft.Download.Modpack.OptionalFile.Skip") @@ -800,11 +800,11 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr { ModMain.MyMsgBox(Lang.Text("Minecraft.Download.Modpack.PathOutsideInstance.Message", targetPath), Lang.Text("Minecraft.Download.Modpack.PathOutsideInstance.Title"), isWarn: true); - throw new ModBase.CancelledException(); + throw new CancelledException(); } fileList.Add(new DownloadFile(urls, targetPath, - new ModBase.FileChecker(actualSize: ((JsonNode)File["fileSize"]).ToObject(), + new FileChecker(actualSize: ((JsonNode)File["fileSize"]).ToObject(), hash: File["hashes"]["sha1"].ToString()), true)); } @@ -841,20 +841,20 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr File.Copy(logo, Path.Combine(versionFolder, "PCL", "Logo.png"), true); States.Instance.LogoPath[versionFolder] = @"PCL\Logo.png"; States.Instance.IsLogoCustom[versionFolder] = true; - ModBase.Log("[ModPack] 已设置整合包 Logo:" + logo); + LauncherLog.Log("[ModPack] 已设置整合包 Logo:" + logo); } // 删除原始整合包文件 foreach (var Target in new[] { Path.Combine(versionFolder, "原始整合包.zip"), Path.Combine(versionFolder, "原始整合包.mrpack") }) if (File.Exists(Target)) { - ModBase.Log("[ModPack] 删除原始整合包文件:" + Target); + LauncherLog.Log("[ModPack] 删除原始整合包文件:" + Target); File.Delete(Target); } - if (File.Exists(fileAddress) && ModBase.GetFileNameWithoutExtentionFromPath(fileAddress) == "modpack") + if (File.Exists(fileAddress) && LegacyFileFacade.GetFileNameWithoutExtensionFromPath(fileAddress) == "modpack") { - ModBase.Log("[ModPack] 删除安装整合包文件:" + fileAddress); + LauncherLog.Log("[ModPack] 删除安装整合包文件:" + fileAddress); File.Delete(fileAddress); } @@ -874,7 +874,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr } catch (Exception ex) { - ModBase.Log(ex, "[ModPack] 获取整合包描述文本失败"); + LauncherLog.Log(ex, "[ModPack] 获取整合包描述文本失败"); } } while (false); }) @@ -888,7 +888,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr if (loaderTaskbar.Any(l => (l.name ?? "") == (loaderName ?? ""))) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 启动 @@ -897,7 +897,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr LoaderTaskbarAdd(loader); ModMain.frmMain.BtnExtraDownload.ShowRefresh(); if (!isOnlineInstall) - ModBase.RunInUi(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); + UiThread.Post(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); return loader; } @@ -911,8 +911,8 @@ private static LoaderCombo InstallPackHMCL(string fileAddress, ZipArchiv JsonObject json; try { - json = (JsonObject)ModBase.GetJson( - ModBase.ReadFile(archive.GetEntry(archiveBaseFolder + "modpack.json").Open(), Encoding.UTF8)); + json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( + LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "modpack.json").Open(), Encoding.UTF8)); } catch (Exception ex) { @@ -928,7 +928,7 @@ private static LoaderCombo InstallPackHMCL(string fileAddress, ZipArchiv instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); if (string.IsNullOrEmpty(instanceName)) - throw new ModBase.CancelledException(); + throw new CancelledException(); // 解压 var installTemp = ModMain.RequestTaskTempFolder(); var installLoaders = new List(); @@ -966,7 +966,7 @@ private static LoaderCombo InstallPackHMCL(string fileAddress, ZipArchiv if (loaderTaskbar.Any(l => (l.name ?? "") == (loaderName ?? ""))) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 启动 @@ -974,7 +974,7 @@ private static LoaderCombo InstallPackHMCL(string fileAddress, ZipArchiv loader.Start(request.targetInstanceFolder); LoaderTaskbarAdd(loader); ModMain.frmMain.BtnExtraDownload.ShowRefresh(); - ModBase.RunInUi(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); + UiThread.Post(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); return loader; } @@ -994,7 +994,7 @@ private static LoaderCombo InstallPackMCBBS(string fileAddress, ZipArchi archive.GetEntry(archiveBaseFolder + "manifest.json"); using (var stream = entry.Open()) { - json = (JsonObject)ModBase.GetJson(ModBase.ReadFile(stream, Encoding.UTF8)); + json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(stream, Encoding.UTF8)); } } catch (Exception ex) @@ -1014,7 +1014,7 @@ private static LoaderCombo InstallPackMCBBS(string fileAddress, ZipArchi instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); - if (string.IsNullOrEmpty(instanceName)) throw new ModBase.CancelledException(); + if (string.IsNullOrEmpty(instanceName)) throw new CancelledException(); } // 解压与路径准备 @@ -1096,7 +1096,7 @@ private static LoaderCombo InstallPackMCBBS(string fileAddress, ZipArchi if (loaderTaskbar.Any(l => l.name == loaderName)) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 启动任务 @@ -1107,7 +1107,7 @@ private static LoaderCombo InstallPackMCBBS(string fileAddress, ZipArchi LoaderTaskbarAdd(loader); ModMain.frmMain.BtnExtraDownload.ShowRefresh(); - ModBase.RunInUi(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); + UiThread.Post(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); return loader; } @@ -1124,11 +1124,11 @@ private static LoaderCombo InstallPackLauncherPack(string fileAddress, Z Lang.Text("Common.Action.Install"), Lang.Text("Common.Action.Continue"), forceWait: true); var targetFolder = SystemDialogs.SelectFolder(Lang.Text("Minecraft.Download.Modpack.SelectTargetFolder.Title")); if (string.IsNullOrEmpty(targetFolder)) - throw new ModBase.CancelledException(); + throw new CancelledException(); if (Directory.GetFileSystemEntries(targetFolder).Length > 0) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.TargetFolderMustBeEmpty"), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 解压 @@ -1143,11 +1143,11 @@ private static LoaderCombo InstallPackLauncherPack(string fileAddress, Z foreach (var ExeFile in Directory.GetFiles(targetFolder, "*.exe", SearchOption.TopDirectoryOnly)) { var info = FileVersionInfo.GetVersionInfo(ExeFile); - ModBase.Log($"[Modpack] 文件 {ExeFile} 的产品名标识为 {info.ProductName}"); + LauncherLog.Log($"[Modpack] 文件 {ExeFile} 的产品名标识为 {info.ProductName}"); if (info.ProductName == "Plain Craft Launcher") { launcher = ExeFile; - ModBase.Log($"[Modpack] 发现整合包附带的 PCL 启动器:{ExeFile}"); + LauncherLog.Log($"[Modpack] 发现整合包附带的 PCL 启动器:{ExeFile}"); } else if ((info.ProductName.ContainsF("Launcher", true) || info.ProductName.ContainsF("启动", true)) && !(info.ProductName == "Plain Craft Launcher Admin Manager")) @@ -1155,7 +1155,7 @@ private static LoaderCombo InstallPackLauncherPack(string fileAddress, Z if (launcher is null) { launcher = ExeFile; - ModBase.Log($"[Modpack] 发现整合包附带的疑似第三方启动器:{ExeFile}"); + LauncherLog.Log($"[Modpack] 发现整合包附带的疑似第三方启动器:{ExeFile}"); } } } @@ -1164,35 +1164,35 @@ private static LoaderCombo InstallPackLauncherPack(string fileAddress, Z // 尝试使用附带的启动器打开 if (launcher is not null) { - ModBase.Log("[Modpack] 找到压缩包中附带的启动器:" + launcher); + LauncherLog.Log("[Modpack] 找到压缩包中附带的启动器:" + launcher); if (ModMain.MyMsgBox(Lang.Text("Minecraft.Download.Modpack.BundledLauncher.Message", launcher), Lang.Text("Minecraft.Download.Modpack.BundledLauncher.Title"), Lang.Text("Minecraft.Download.Modpack.BundledLauncher.UseBundled"), Lang.Text("Minecraft.Download.Modpack.BundledLauncher.DoNotUse") ) == 1) { - ModBase.OpenExplorer(targetFolder); - ModBase.ShellOnly(launcher, "--wait"); // 要求等待已有的 PCL 退出 - ModBase.Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序"); + LauncherProcess.OpenExplorer(targetFolder); + LauncherProcess.ShellOnly(launcher, "--wait"); // 要求等待已有的 PCL 退出 + LauncherLog.Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序"); ModMain.frmMain.EndProgram(false); return; } } else { - ModBase.Log("[Modpack] 未找到压缩包中附带的启动器"); + LauncherLog.Log("[Modpack] 未找到压缩包中附带的启动器"); } - ModBase.OpenExplorer(targetFolder); + LauncherProcess.OpenExplorer(targetFolder); // 加入文件夹列表 - var instanceName = ModBase.GetFolderNameFromPath(targetFolder); + var instanceName = LegacyFileFacade.GetFolderNameFromPath(targetFolder); Directory.CreateDirectory(Path.Combine(targetFolder, ".minecraft")); PageSelectLeft.AddFolder( Path.Combine(targetFolder, ".minecraft", archiveBaseFolder.Replace("/", @"\").TrimStart('\\')), instanceName, false); // 格式例如:包裹文件夹\.minecraft\(最短为空字符串) // 调用 modpack 文件进行安装 var modpackFile = Directory.GetFiles(targetFolder, "modpack.*", SearchOption.AllDirectories).First(); - ModBase.Log("[Modpack] 调用 modpack 文件继续安装:" + modpackFile); + LauncherLog.Log("[Modpack] 调用 modpack 文件继续安装:" + modpackFile); ModpackInstall(modpackFile); }) }); @@ -1226,24 +1226,24 @@ private static LoaderCombo InstallPackCompress(string fileAddress, ZipAr throw new Exception(Lang.Text("Minecraft.Download.Modpack.UnknownArchiveStructure")); // 没有匹配 var archiveBaseFolder = match.Value.Replace("/", @"\").TrimStart('\\'); // 格式例如:包裹文件夹\.minecraft\(最短为空字符串) var instanceName = match.Groups[1].Value; - ModBase.Log("[ModPack] 检测到压缩包的 .minecraft 根目录:" + archiveBaseFolder + ",命中的实例名:" + instanceName); + LauncherLog.Log("[ModPack] 检测到压缩包的 .minecraft 根目录:" + archiveBaseFolder + ",命中的实例名:" + instanceName); // 获取解压路径 ModMain.MyMsgBox(Lang.Text("Minecraft.Download.Modpack.SelectEmptyFolder.Message"), Lang.Text("Common.Action.Install"), Lang.Text("Common.Action.Continue"), forceWait: true); var targetFolder = SystemDialogs.SelectFolder(Lang.Text("Minecraft.Download.Modpack.SelectTargetFolder.Title")); if (string.IsNullOrEmpty(targetFolder)) - throw new ModBase.CancelledException(); + throw new CancelledException(); if (targetFolder.Contains("!") || targetFolder.Contains(";")) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.InvalidGamePathChars", targetFolder), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } if (Directory.GetFileSystemEntries(targetFolder).Length > 0) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.TargetFolderMustBeEmpty"), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 解压 @@ -1253,10 +1253,10 @@ private static LoaderCombo InstallPackCompress(string fileAddress, ZipAr { ExtractModpackFiles(targetFolder, fileAddress, task, 0.95d); // 加入文件夹列表 - PageSelectLeft.AddFolder(Path.Combine(targetFolder, archiveBaseFolder), ModBase.GetFolderNameFromPath(targetFolder), + PageSelectLeft.AddFolder(Path.Combine(targetFolder, archiveBaseFolder), LegacyFileFacade.GetFolderNameFromPath(targetFolder), false); Thread.Sleep(400); // 避免文件争用 - ModBase.RunInUi(() => ModMain.frmMain.PageChange(FormMain.PageType.InstanceSelect)); + UiThread.Post(() => ModMain.frmMain.PageChange(FormMain.PageType.InstanceSelect)); }) }) { @@ -1297,9 +1297,9 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive MMCPackInfo packInfo = null; try { - packJson = (JsonObject)ModBase.GetJson( - ModBase.ReadFile(archive.GetEntry(archiveBaseFolder + "mmc-pack.json").Open(), Encoding.UTF8)); - packInstance = ModBase.ReadFile(archive.GetEntry(archiveBaseFolder + "instance.cfg").Open(), Encoding.UTF8); + packJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( + LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "mmc-pack.json").Open(), Encoding.UTF8)); + packInstance = LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "instance.cfg").Open(), Encoding.UTF8); #region JSON Patches @@ -1311,13 +1311,13 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive if (!archive.Entries.Any(e => e.FullName.Equals(archiveBaseFolder + "patches/", StringComparison.OrdinalIgnoreCase))) break; - ModBase.Log("[ModPack] 安装的 MultiMC 整合包存在 JSON Patches"); + LauncherLog.Log("[ModPack] 安装的 MultiMC 整合包存在 JSON Patches"); // 排序预处理 var patches = new List>(); foreach (var entry in archive.Entries) if (!entry.FullName.EndsWith("/") && entry.FullName.StartsWith(archiveBaseFolder + "patches/")) { - var patch = (JsonObject)ModBase.GetJson(ModBase.ReadFile( + var patch = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText( archive.GetEntry(entry.FullName).Open(), Encoding.UTF8)); patches.Add(new KeyValuePair(patch, (int)(patch["order"] is not null ? patch["order"] : 0))); @@ -1374,7 +1374,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive if (patchJson["+jvmArgs"] is not null) { jvmArguments.Merge(patchJson["+jvmArgs"]); - ModBase.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 JVM 参数"); + LauncherLog.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 JVM 参数"); } // Libraries @@ -1410,21 +1410,21 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive } libJson.Merge(libs); - ModBase.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 Libraries"); + LauncherLog.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 Libraries"); } // Tweakers if (patchJson["+tweakers"] is not null) { tweakers = (string)patchJson["+tweakers"][0]; - ModBase.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 Tweakers"); + LauncherLog.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 Tweakers"); } // AssetIndex if (patchJson["assetIndex"] is not null) { assetIndex = patchJson["assetIndex"]?.DeepClone().AsObject(); - ModBase.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 AssetIndex"); + LauncherLog.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 AssetIndex"); } // minecraftArguments -> arguments.game @@ -1433,7 +1433,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive foreach (var Arg in patchJson["minecraftArguments"].ToString().Split(" ")) gameArguments.Add(Arg); packInfo.isMcArgsEdited = true; - ModBase.Log( + LauncherLog.Log( $"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 minecraftArguments 至 arguments.game"); } @@ -1441,7 +1441,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive if (patchJson["mainClass"] is not null) { mainClass = (string)patchJson["mainClass"]; - ModBase.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 mainClass"); + LauncherLog.Log($"[ModPack] 已应用 JSON-Patch {patchJson["uid"]} 的 mainClass"); } // Java 版本要求 @@ -1452,25 +1452,25 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive var javaMajors = (JsonArray)patchJson["compatibleJavaMajors"]; foreach (var Java in javaMajors) { - if (javaVersion > ModBase.Val(Java)) + if (javaVersion > LauncherText.Val(Java)) continue; // 优先选择主要的版本 - if (ModBase.Val(Java) == 21d) + if (LauncherText.Val(Java) == 21d) { javaVersion = 21; javaComponent = "java-runtime-delta"; } - else if (ModBase.Val(Java) == 17d) + else if (LauncherText.Val(Java) == 17d) { javaVersion = 17; javaComponent = "java-runtime-gamma"; } - else if (ModBase.Val(Java) == 11d) + else if (LauncherText.Val(Java) == 11d) { javaVersion = 11; javaComponent = null; } - else if (ModBase.Val(Java) == 8d) + else if (LauncherText.Val(Java) == 8d) { javaVersion = 8; javaComponent = "jre-legacy"; @@ -1485,7 +1485,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive javaVerJson = new JsonObject { { "majorVersion", javaVersion } }; if (javaComponent is not null) javaVerJson.Add("component", javaComponent); - ModBase.Log($"[ModPack] JSON-Patch {patchJson["uid"]} 要求 Java 版本: " + javaVersion); + LauncherLog.Log($"[ModPack] JSON-Patch {patchJson["uid"]} 要求 Java 版本: " + javaVersion); } } @@ -1520,7 +1520,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive } catch (Exception ex) { - ModBase.Log(ex, "应用 MMC JSON-Patches 失败"); + LauncherLog.Log(ex, "应用 MMC JSON-Patches 失败"); } } while (false); } @@ -1541,7 +1541,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); if (string.IsNullOrEmpty(instanceName)) - throw new ModBase.CancelledException(); + throw new CancelledException(); // 解压 var installTemp = ModMain.RequestTaskTempFolder(); var versionFolder = $@"{ModFolder.mcFolderSelected}versions\{instanceName}"; @@ -1565,7 +1565,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive if (File.Exists(mMCSetupFile)) { List lines = []; - foreach (var Line in ModBase.ReadFile(mMCSetupFile).Split(new[] { "\r", "\n" }, + foreach (var Line in LegacyFileFacade.ReadText(mMCSetupFile).Split(new[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries)) { if (!Line.Contains("=")) @@ -1573,12 +1573,12 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive lines.Add(Line.BeforeFirst("=") + ":" + Line.AfterFirst("=")); } - ModBase.WriteFile(mMCSetupFile, lines.Join("\r\n")); + LegacyFileFacade.WriteFile(mMCSetupFile, lines.Join("\r\n")); // 读取文件 - if (Convert.ToBoolean(ModBase.ReadIni(mMCSetupFile, "OverrideCommands", + if (Convert.ToBoolean(LegacyIniStore.Shared.Read(mMCSetupFile, "OverrideCommands", false.ToString()))) { - var preLaunchCommand = ModBase.ReadIni(mMCSetupFile, "PreLaunchCommand"); + var preLaunchCommand = LegacyIniStore.Shared.Read(mMCSetupFile, "PreLaunchCommand"); if (!string.IsNullOrEmpty(preLaunchCommand)) { preLaunchCommand = preLaunchCommand.Replace(@"\""", "\"") @@ -1587,45 +1587,45 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive .Replace("$INST_DIR", "{verpath}").Replace("$INST_ID", "{name}") .Replace("$INST_NAME", "{name}"); Config.Instance.PreLaunchCommand[versionFolder] = preLaunchCommand; - ModBase.Log("[ModPack] 迁移 MultiMC 实例独立设置:启动前执行命令:" + preLaunchCommand); + LauncherLog.Log("[ModPack] 迁移 MultiMC 实例独立设置:启动前执行命令:" + preLaunchCommand); } } - if (Convert.ToBoolean(ModBase.ReadIni(mMCSetupFile, "JoinServerOnLaunch", + if (Convert.ToBoolean(LegacyIniStore.Shared.Read(mMCSetupFile, "JoinServerOnLaunch", false.ToString()))) { - var serverAddress = ModBase.ReadIni(mMCSetupFile, "JoinServerOnLaunchAddress") + var serverAddress = LegacyIniStore.Shared.Read(mMCSetupFile, "JoinServerOnLaunchAddress") .Replace(@"\""", "\""); Config.Instance.ServerToEnter[versionFolder] = serverAddress; - ModBase.Log("[ModPack] 迁移 MultiMC 实例独立设置:自动进入服务器:" + serverAddress); + LauncherLog.Log("[ModPack] 迁移 MultiMC 实例独立设置:自动进入服务器:" + serverAddress); } - if (Convert.ToBoolean(ModBase.ReadIni(mMCSetupFile, "IgnoreJavaCompatibility", + if (Convert.ToBoolean(LegacyIniStore.Shared.Read(mMCSetupFile, "IgnoreJavaCompatibility", false.ToString()))) { Config.Instance.IgnoreJavaCompatibility[versionFolder] = true; - ModBase.Log("[ModPack] 迁移 MultiMC 实例独立设置:忽略 Java 兼容性警告"); + LauncherLog.Log("[ModPack] 迁移 MultiMC 实例独立设置:忽略 Java 兼容性警告"); } - var logo = Path.GetFileName(ModBase.ReadIni(mMCSetupFile, "iconKey")); + var logo = Path.GetFileName(LegacyIniStore.Shared.Read(mMCSetupFile, "iconKey")); if (!string.IsNullOrEmpty(logo) && File.Exists($"{installTemp}{archiveBaseFolder}{logo}.png")) { States.Instance.IsLogoCustom[versionFolder] = true; States.Instance.LogoPath[versionFolder] = @"PCL\Logo.png"; - ModBase.CopyFile($"{installTemp}{archiveBaseFolder}{logo}.png", + LegacyFileFacade.CopyFile($"{installTemp}{archiveBaseFolder}{logo}.png", $@"{ModFolder.mcFolderSelected}versions\{instanceName}\PCL\Logo.png"); - ModBase.Log($"[ModPack] 迁移 MultiMC 实例独立设置:实例图标({logo}.png)"); + LauncherLog.Log($"[ModPack] 迁移 MultiMC 实例独立设置:实例图标({logo}.png)"); } // JVM 参数 - var jvmArgs = ModBase.ReadIni(mMCSetupFile, "JvmArgs"); + var jvmArgs = LegacyIniStore.Shared.Read(mMCSetupFile, "JvmArgs"); if (!string.IsNullOrEmpty(jvmArgs)) { - if (Convert.ToBoolean(ModBase.ReadIni(mMCSetupFile, "OverrideJavaArgs", + if (Convert.ToBoolean(LegacyIniStore.Shared.Read(mMCSetupFile, "OverrideJavaArgs", false.ToString()))) { Config.Instance.JvmArgs[versionFolder] = jvmArgs; - ModBase.Log("[ModPack] 迁移 MultiMC 实例独立设置:JVM 参数(覆盖):" + jvmArgs); + LauncherLog.Log("[ModPack] 迁移 MultiMC 实例独立设置:JVM 参数(覆盖):" + jvmArgs); } else { @@ -1633,14 +1633,14 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive " " + Config.Launch.JvmArgs; Config.Instance.JvmArgs[versionFolder] = jvmArgs; - ModBase.Log("[ModPack] 迁移 MultiMC 实例独立设置:JVM 参数(追加):" + jvmArgs); + LauncherLog.Log("[ModPack] 迁移 MultiMC 实例独立设置:JVM 参数(追加):" + jvmArgs); } } } } catch (Exception ex) { - ModBase.Log(ex, $"读取 MMC 配置文件失败({installTemp}{archiveBaseFolder}instance.cfg)"); + LauncherLog.Log(ex, $"读取 MMC 配置文件失败({installTemp}{archiveBaseFolder}instance.cfg)"); } #endregion @@ -1662,7 +1662,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive { case "org.lwjgl": { - ModBase.Log("[ModPack] 已跳过 LWJGL 项"); + LauncherLog.Log("[ModPack] 已跳过 LWJGL 项"); break; } case "net.minecraft": @@ -1713,7 +1713,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive if (loaderTaskbar.Any(l => (l.name ?? "") == (loaderName ?? ""))) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } // 启动 @@ -1721,7 +1721,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive loader.Start(request.targetInstanceFolder); LoaderTaskbarAdd(loader); ModMain.frmMain.BtnExtraDownload.ShowRefresh(); - ModBase.RunInUi(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); + UiThread.Post(() => ModMain.frmMain.PageChange(FormMain.PageType.TaskManager)); return loader; } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs index ad695cb61..9d615b25b 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs @@ -33,10 +33,10 @@ public static class ModProfile /// /// 档案操作日志 /// - public static void ProfileLog(string content, ModBase.LogLevel level = ModBase.LogLevel.Normal) + public static void ProfileLog(string content, LauncherLogLevel level = LauncherLogLevel.Normal) { var output = "[Profile] " + content; - ModBase.Log(output, level); + LauncherLog.Log(output, level); } #region 获取正版档案 UUID @@ -48,9 +48,9 @@ public static void ProfileLog(string content, ModBase.LogLevel level = ModBase.L public static object McLoginMojangUuid(string name, bool throwOnNotFound) { if (name.Trim().Length == 0) - return ModBase.StrFill("", "0", 32); + return LauncherText.StrFill("", "0", 32); // 从缓存获取 - var uuid = ModBase.ReadIni(ModBase.pathTemp + @"Cache\Uuid\Mojang.ini", name); + var uuid = LegacyIniStore.Shared.Read(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini", name); if ((uuid?.Length ?? 0) == 32) return uuid; // 从官网获取 @@ -58,7 +58,7 @@ public static object McLoginMojangUuid(string name, bool throwOnNotFound) { JsonObject gotJson = null; var finished = false; - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -81,7 +81,7 @@ public static object McLoginMojangUuid(string name, bool throwOnNotFound) } catch (Exception ex) { - ModBase.Log(ex, "从官网获取正版 UUID 失败(" + name + ")"); + LauncherLog.Log(ex, "从官网获取正版 UUID 失败(" + name + ")"); if (!throwOnNotFound && ex is FileNotFoundException) uuid = GetOfflineUuid(name, isLegacy: true); // 玩家档案不存在 else @@ -91,7 +91,7 @@ public static object McLoginMojangUuid(string name, bool throwOnNotFound) // 写入缓存 if ((uuid?.Length ?? 0) != 32) throw new Exception("获取的正版 UUID 长度不足(" + uuid + ")"); - ModBase.WriteIni(ModBase.pathTemp + @"Cache\Uuid\Mojang.ini", name, uuid); + LegacyIniStore.Shared.Write(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini", name, uuid); return uuid; } @@ -176,18 +176,18 @@ public static void GetProfile() { ProfileLog("开始获取本地档案"); profileList.Clear(); - var profilePath = Path.Combine(ModBase.pathAppdataConfig, "profiles.json"); + var profilePath = Path.Combine(LauncherPaths.SharedConfigWithSlash, "profiles.json"); try { - if (!Directory.Exists(ModBase.pathAppdataConfig)) - Directory.CreateDirectory(ModBase.pathAppdataConfig); + if (!Directory.Exists(LauncherPaths.SharedConfigWithSlash)) + Directory.CreateDirectory(LauncherPaths.SharedConfigWithSlash); if (!File.Exists(profilePath)) { File.Create(profilePath).Close(); - ModBase.WriteFile(profilePath, "{\"lastUsed\":0,\"profiles\":[]}"); // 创建档案列表文件 + LegacyFileFacade.WriteFile(profilePath, "{\"lastUsed\":0,\"profiles\":[]}"); // 创建档案列表文件 } - var profileJobj = ModBase.GetJson(ModBase.ReadFile(profilePath)); + var profileJobj = PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(profilePath)); lastUsedProfile = (int)profileJobj["lastUsed"]; var profileListJobj = (JsonArray)profileJobj["profiles"]; foreach (var Profile in profileListJobj) @@ -242,17 +242,17 @@ public static void GetProfile() try { var profilePathBak = - Path.Combine(ModBase.pathAppdataConfig, $"profiles.json.bak{DateTime.Now.ToBinary()}"); + Path.Combine(LauncherPaths.SharedConfigWithSlash, $"profiles.json.bak{DateTime.Now.ToBinary()}"); File.Move(profilePath, profilePathBak); } catch (Exception ex1) { } - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.Profile.Error.Corrupted"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Launch.Account.Profile.Error.Corrupted")); } } @@ -310,7 +310,7 @@ public static void SaveProfile(JsonArray listJson = null) json = new JsonObject { { "lastUsed", lastUsedProfile }, { "profiles", list } }; } - var actualFile = Path.Combine(ModBase.pathAppdataConfig, "profiles.json"); + var actualFile = Path.Combine(LauncherPaths.SharedConfigWithSlash, "profiles.json"); var tempFile = actualFile + ".tmp"; var bakFile = actualFile + ".bak"; File.WriteAllBytes(tempFile, Encoding.UTF8.GetBytes(json.ToJsonString())); @@ -322,10 +322,10 @@ public static void SaveProfile(JsonArray listJson = null) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.Profile.Error.Write"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Launch.Account.Profile.Error.Write")); } } @@ -340,7 +340,7 @@ public static void SaveProfile(JsonArray listJson = null) public static void CreateProfile() { int? selectedAuthTypeNum = default; // 验证类型序号 - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { List authTypeList; #if DEBUG || DEBUGCI @@ -362,11 +362,11 @@ public static void CreateProfile() return; isCreatingProfile = true; if (selectedAuthTypeNum.HasValue && selectedAuthTypeNum.Value == 0) // 正版验证 - ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Ms)); + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Ms)); else if (selectedAuthTypeNum.HasValue && selectedAuthTypeNum.Value == 1) // 第三方验证 - ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Auth)); + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Auth)); else // 离线验证 - ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Legacy)); + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Legacy)); } private static List _GetAvailableProfileSelection(bool includeOfflineAndThirdParty) => includeOfflineAndThirdParty switch @@ -414,7 +414,7 @@ public static void EditProfileId() if (selectedProfile.Type == ModLaunch.McLoginType.Ms) { string newUsername = null; - ModBase.RunInUiWait(() => newUsername = ModMain.MyMsgBoxInput(Lang.Text("Launch.Account.Profile.EditPlayerId.Title"), Lang.Text("Launch.Account.Profile.EditPlayerId.MicrosoftWarning"), + UiThread.Invoke(() => newUsername = ModMain.MyMsgBoxInput(Lang.Text("Launch.Account.Profile.EditPlayerId.Title"), Lang.Text("Launch.Account.Profile.EditPlayerId.MicrosoftWarning"), selectedProfile.Username, [new StringLengthValidator(3, 16), new RegexValidator("([A-z]|[0-9]|_)+")], Lang.Text("Launch.Account.Profile.EditPlayerId.Hint"), Lang.Text("Common.Action.Confirm"))); @@ -430,11 +430,11 @@ public static void EditProfileId() return; // 更新档案信息 // 刷新页面信息 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { - var checkResult = (JsonObject)ModBase.GetJson(Requester.Fetch( + var checkResult = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(Requester.Fetch( $"https://api.minecraftservices.com/minecraft/profile/name/{newUsername}/available", new FetchParam { @@ -462,7 +462,7 @@ public static void EditProfileId() Headers = new Dictionary { { "Authorization", "Bearer " + selectedProfile.AccessToken } } }); - var resultJson = (JsonObject)ModBase.GetJson(result); + var resultJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(result); HintService.Hint(Lang.Text("Launch.Account.Profile.EditPlayerId.Success", resultJson["name"]), HintType.Success); profileList.Remove(selectedProfile); selectedProfile.Username = (string)resultJson["name"]; @@ -477,10 +477,10 @@ public static void EditProfileId() if (exSummary.Contains("403")) ModMain.MyMsgBox(Lang.Text("Launch.Account.Profile.EditPlayerId.Cooldown"), Lang.Text("Launch.Account.Profile.EditPlayerId.Failed.Title"), Lang.Text("Common.Action.Confirm")); else - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.Profile.Error.ChangeId"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Launch.Account.Profile.Error.ChangeId")); } }); @@ -490,13 +490,13 @@ public static void EditProfileId() else if (selectedProfile.Type == ModLaunch.McLoginType.Auth) { var server = selectedProfile.Server; - ModBase.OpenWebsite(server.Replace("/api/yggdrasil/authserver" + (server.EndsWithF("/") ? "/" : ""), + LauncherProcess.OpenWebsite(server.Replace("/api/yggdrasil/authserver" + (server.EndsWithF("/") ? "/" : ""), "/user/profile")); } else { string newUsername = null; - ModBase.RunInUiWait(() => newUsername = ModMain.MyMsgBoxInput(Lang.Text("Launch.Account.Profile.EditPlayerId.Title"), + UiThread.Invoke(() => newUsername = ModMain.MyMsgBoxInput(Lang.Text("Launch.Account.Profile.EditPlayerId.Title"), defaultInput: selectedProfile.Username, validateRules: [new StringLengthValidator(3, 16), new RegexValidator("([A-z]|[0-9]|_)+")], hintText: Lang.Text("Launch.Account.Profile.EditPlayerId.Hint"), button1: Lang.Text("Common.Action.Confirm"), button2: Lang.Text("Common.Action.Cancel"))); @@ -522,7 +522,7 @@ public static void EditOfflineUuid(McProfile profile, string uuid = null) int uuidType; int? uuidTypeInput = default; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { var uuidTypeList = new List { @@ -591,8 +591,8 @@ public static string GetOfflineUuid(string userName, bool isSplited = false, boo { if (isLegacy) { - var fullUuid = ModBase.StrFill(userName.Length.ToString("X"), "0", 16) + - ModBase.StrFill(ModBase.GetHash(userName).ToString("X"), "0", 16); + var fullUuid = LauncherText.StrFill(userName.Length.ToString("X"), "0", 16) + + LauncherText.StrFill(LauncherText.GetHash(userName).ToString("X"), "0", 16); return fullUuid.Substring(0, 12) + "3" + fullUuid.Substring(13, 3) + "9" + fullUuid.Substring(17, 15); } @@ -699,7 +699,7 @@ public static ModLaunch.McLoginData GetLoginData(ModLaunch.McLoginType targetAut if (authType == ModLaunch.McLoginType.Ms) { - if (ModLaunch.mcLoginMsLoader.State == ModBase.LoadState.Finished) + if (ModLaunch.mcLoginMsLoader.State == LoadState.Finished) return new ModLaunch.McLoginMs { OAuthRefreshToken = selectedProfile.RefreshToken, @@ -762,7 +762,7 @@ public static void ChangeSkinMs() return; } - if (ModLaunch.mcLoginLoader.State == ModBase.LoadState.Failed) + if (ModLaunch.mcLoginLoader.State == LoadState.Failed) { HintService.Hint(Lang.Text("Launch.Skin.Change.LoginFailed"), HintType.Error); return; @@ -778,16 +778,16 @@ public static void ChangeSkinMs() // 获取登录信息 // 获取新皮肤地址 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { Retry: ; - if (ModLaunch.mcLoginMsLoader.State == ModBase.LoadState.Loading) + if (ModLaunch.mcLoginMsLoader.State == LoadState.Loading) ModLaunch.mcLoginMsLoader.WaitForExit(); - if (ModLaunch.mcLoginMsLoader.State != ModBase.LoadState.Finished) + if (ModLaunch.mcLoginMsLoader.State != LoadState.Finished) ModLaunch.mcLoginMsLoader.WaitForExit(GetLoginData()); - if (ModLaunch.mcLoginMsLoader.State != ModBase.LoadState.Finished) + if (ModLaunch.mcLoginMsLoader.State != LoadState.Finished) { HintService.Hint(Lang.Text("Launch.Skin.Change.LoginFailed"), HintType.Error); return; @@ -802,8 +802,8 @@ public static void ChangeSkinMs() { { new StringContent(skinInfo.IsSlim ? "slim" : "classic"), "variant" }, { - new ByteArrayContent(ModBase.ReadFileBytes(skinInfo.LocalFile)), "file", - ModBase.GetFileNameFromPath(skinInfo.LocalFile) + new ByteArrayContent(LegacyFileFacade.ReadBytes(skinInfo.LocalFile)), "file", + LegacyFileFacade.GetFileNameFromPath(skinInfo.LocalFile) } }; var res = Requester.Fetch("https://api.minecraftservices.com/minecraft/profile/skins", @@ -825,13 +825,13 @@ public static void ChangeSkinMs() HintService.Hint( Lang.Text( "Launch.Skin.Change.FailedWithDetail", - ((JsonObject)ModBase.GetJson(res))["error"]?.ToString() ?? res), + ((JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(res))["error"]?.ToString() ?? res), HintType.Error); return; } - ModBase.Log("[Skin] 皮肤修改返回值:" + "\r\n" + res); - var resultJson = (JsonObject)ModBase.GetJson(res); + LauncherLog.Log("[Skin] 皮肤修改返回值:" + "\r\n" + res); + var resultJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(res); if (resultJson.ContainsKey("errorMessage")) throw new Exception(resultJson["errorMessage"].ToString()); foreach (var skinNode in resultJson["skins"].AsArray()) { var skin = skinNode.AsObject(); if (skin["state"].ToString() == "ACTIVE") @@ -849,10 +849,10 @@ public static void ChangeSkinMs() Lang.Text("Launch.Skin.Change.Timeout.WithDetail", ex.ToString()), HintType.Error); else - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.Profile.Error.ChangeSkin"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Account.Profile.Error.ChangeSkin")); } finally diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs index 8cfcce247..5192073f0 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs @@ -1,8 +1,6 @@ -using System; -using System.Globalization; +using System.Globalization; using System.IO; using System.Text; -using System.Text.Json.Nodes; using Microsoft.VisualBasic; using PCL.Core.App.Localization; using PCL.Core.UI; @@ -49,10 +47,10 @@ public static McSkinInfo McSkinSelect() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Skin.File.Error"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Skin.File.Error")); return new McSkinInfo { IsVaild = false }; } @@ -81,8 +79,8 @@ public static string McSkinGetAddress(string uuid, string type) throw new Exception(Lang.Text("Minecraft.Skin.Error.OfflineNoSkin")); // 尝试读取缓存 - var cachePath = Path.Combine(ModBase.pathTemp, $"Cache\\Skin\\Index{type}.ini"); - var cacheSkinAddress = ModBase.ReadIni(cachePath, uuid); + var cachePath = Path.Combine(LauncherPaths.TempWithSlash, $"Cache\\Skin\\Index{type}.ini"); + var cacheSkinAddress = LegacyIniStore.Shared.Read(cachePath, uuid); if (!string.IsNullOrEmpty(cacheSkinAddress)) return cacheSkinAddress; @@ -104,7 +102,7 @@ public static string McSkinGetAddress(string uuid, string type) string skinValue = null; try { - var json = (JsonObject)ModBase.GetJson((string)skinString); + var json = (JsonObject)JsonCompat.ParseNode((string)skinString); foreach (var property in json["properties"].AsArray()) if (property["name"]?.ToString() == "textures") { @@ -117,15 +115,15 @@ public static string McSkinGetAddress(string uuid, string type) } catch (Exception ex) { - ModBase.Log(ex, + LauncherLog.Log(ex, $"无法完成解析的皮肤返回值,可能是未设置自定义皮肤的用户:{skinString}", - ModBase.LogLevel.Developer); + LauncherLogLevel.Developer); throw new Exception(Lang.Text("Minecraft.Skin.Error.NoSkinData"), ex); } // 解码 Base64 并解析 JSON var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(skinValue)); - var skinJson = (JsonObject)ModBase.GetJson(decoded.ToLowerInvariant()); + var skinJson = (JsonObject)JsonCompat.ParseNode(decoded.ToLowerInvariant()); if (skinJson["textures"]?["skin"]?["url"] is null) throw new Exception(Lang.Text("Minecraft.Skin.Error.NoCustomSkin")); @@ -134,8 +132,8 @@ public static string McSkinGetAddress(string uuid, string type) skinUrl = skinUrl.Contains("minecraft.net/") ? skinUrl.Replace("http://", "https://") : skinUrl; // 保存缓存 - ModBase.WriteIni(cachePath, uuid, skinUrl); - ModBase.Log($"[Skin] UUID {uuid} 对应的皮肤文件为 {skinUrl}"); + LegacyIniStore.Shared.Write(cachePath, uuid, skinUrl); + LauncherLog.Log($"[Skin] UUID {uuid} 对应的皮肤文件为 {skinUrl}"); return skinUrl; } @@ -147,8 +145,8 @@ public static string McSkinGetAddress(string uuid, string type) /// public static string McSkinDownload(string address) { - var skinName = ModBase.GetFileNameFromPath(address); - var fileAddress = ModBase.pathTemp + @"Cache\Skin\" + ModBase.GetHash(address) + ".png"; + var skinName = LegacyFileFacade.GetFileNameFromPath(address); + var fileAddress = LauncherPaths.TempWithSlash + @"Cache\Skin\" + LauncherText.GetHash(address) + ".png"; lock (mcSkinDownloadLock) { if (!File.Exists(fileAddress)) @@ -156,7 +154,7 @@ public static string McSkinDownload(string address) FileDownloader.DownloadAsync(address, fileAddress + ModNet.netDownloadEnd).GetAwaiter().GetResult(); File.Delete(fileAddress); FileSystem.Rename(fileAddress + ModNet.netDownloadEnd, fileAddress); - ModBase.Log("[Minecraft] 皮肤下载成功:" + fileAddress); + LauncherLog.Log("[Minecraft] 皮肤下载成功:" + fileAddress); } return fileAddress; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs index 019a3c727..3e9ac5ef1 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs @@ -92,9 +92,9 @@ public void StartTimer() { if (Dispatcher is null) { - ModBase.Log( + LauncherLog.Log( "[TimerRun] Dispatcher is null, unable to run", - ModBase.LogLevel.Critical, + LauncherLogLevel.Critical, userSummary: Lang.Text("Minecraft.Launch.Error.DispatcherUnavailable")); return; } @@ -172,7 +172,7 @@ public static void SetColorfulTextLab(string text, TextBlock lab, bool isDarkMod { if (lab is null) { - ModBase.Log("[Style] SetColorfulTextLab: lab is null"); + LauncherLog.Log("[Style] SetColorfulTextLab: lab is null"); return; } @@ -259,7 +259,7 @@ public static void SetColorfulTextLab(string text, TextBlock lab, bool isDarkMod lab.Inlines.Add(curRun); } - curRun.Foreground = new SolidColorBrush(new ModBase.MyColor(color)); + curRun.Foreground = new SolidColorBrush(new MyColor(color)); curRun.FontWeight = hasBlodProperty ? FontWeights.Bold : FontWeights.Normal; curRun.FontStyle = hasItalicProperty ? FontStyles.Italic : FontStyles.Normal; curRun.TextDecorations = hasStrickThroughProperty ? TextDecorations.Strikethrough : null; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.cs index 8ce8b3b11..3f9782f4c 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.cs @@ -4,8 +4,8 @@ using System.Text; using System.Windows.Media; using PCL.Core.App; -using PCL.Core.Logging; using PCL.Core.App.Localization; +using PCL.Core.Logging; namespace PCL; @@ -55,14 +55,14 @@ private static void MinecraftStop(bool triggerLauncherShutdown) ModMain.frmMain.BtnExtraShutdown.ShowRefresh(); // 音乐播放 if (Config.Preference.Music.StopInGame) - ModBase.RunInUi(() => + UiThread.Post(() => { - if (ModMusic.MusicResume()) ModBase.Log("[Music] 已根据设置,在结束后开始音乐播放"); + if (ModMusic.MusicResume()) LauncherLog.Log("[Music] 已根据设置,在结束后开始音乐播放"); }); else if (Config.Preference.Music.StartInGame) - ModBase.RunInUi(() => + UiThread.Post(() => { - if (ModMusic.MusicPause()) ModBase.Log("[Music] 已根据设置,在结束后暂停音乐播放"); + if (ModMusic.MusicPause()) LauncherLog.Log("[Music] 已根据设置,在结束后暂停音乐播放"); }); // 开始视频背景播放 ModVideoBack.IsGaming = false; @@ -73,13 +73,13 @@ private static void MinecraftStop(bool triggerLauncherShutdown) case LauncherVisibility.HideAndExit: // 直接关闭 if (triggerLauncherShutdown) - ModBase.RunInUi(() => ModMain.frmMain.EndProgram(false)); + UiThread.Post(() => ModMain.frmMain.EndProgram(false)); else - ModBase.RunInUi(() => ModMain.frmMain.Hidden = false); + UiThread.Post(() => ModMain.frmMain.Hidden = false); break; case LauncherVisibility.HideAndReopen: // 恢复 - ModBase.RunInUi(() => ModMain.frmMain.Hidden = false); + UiThread.Post(() => ModMain.frmMain.Hidden = false); break; } } @@ -266,12 +266,12 @@ public Watcher(ModLoader.LoaderTask loader, McInstance version, st // 初始化时钟 // 设置窗口标题 - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { try { while (State != MinecraftState.Ended && State != MinecraftState.Crashed && - State != MinecraftState.Canceled && loader.State != ModBase.LoadState.Aborted) + State != MinecraftState.Canceled && loader.State != LoadState.Aborted) { TimerWindow(); TimerLog(); @@ -295,10 +295,10 @@ public Watcher(ModLoader.LoaderTask loader, McInstance version, st } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "Minecraft 日志监控主循环出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Launch.Error.WatcherOperationFailed")); State = MinecraftState.Ended; } @@ -450,10 +450,10 @@ private void TimerLog() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "输出 Minecraft 日志失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Launch.Error.WatcherOperationFailed")); } } @@ -573,10 +573,10 @@ private void TimerWindow() catch (Win32Exception ex) { // 拒绝访问(#1062) - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Watcher.SecurityBlocked"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Watcher.SecurityBlocked")); isWindowFinished = true; } @@ -596,7 +596,7 @@ private void TimerWindow() if (Config.Launch.GameWindowMode == GameWindowSizeMode.Maximized) // 如果最大化导致屏幕渲染大小不对,那是 MC 的 Bug,不是我的 Bug // ……虽然我很想这样说,但总有人反馈,算了 - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { try { @@ -606,7 +606,7 @@ private void TimerWindow() } catch (Exception ex) { - ModBase.Log(ex, "最大化 Minecraft 窗口时出现错误"); + LauncherLog.Log(ex, "最大化 Minecraft 窗口时出现错误"); } }, "MinecraftWindowMaximize"); } @@ -620,10 +620,10 @@ private void TimerWindow() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "检查 Minecraft 窗口失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Launch.Error.WatcherOperationFailed")); } } @@ -708,8 +708,8 @@ private void Crashed() WatcherLog(Lang.Text("Watcher.Crash.Detected")); HintService.Hint(Lang.Text("Watcher.Crash.Hint")); - ModBase.FeedbackInfo(); - ModBase.RunInNewThread(() => + LauncherFeedbackService.FeedbackInfo(); + Basics.RunInNewThread(() => { try { @@ -724,15 +724,15 @@ private void Crashed() [ version.PathInstance + version.Name + ".json", LogWrapper.CurrentLogger.CurrentLogFiles.Last(), - ModBase.exePath + @"PCL\LatestLaunch.bat" + LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\LatestLaunch.bat" ]); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "崩溃分析失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Crash.Analysis.Error.Failed")); } }, "Crash Analyzer"); @@ -757,7 +757,7 @@ public bool CheckAlive(Process p) public void Kill() { State = MinecraftState.Canceled; - ModBase.RunInNewThread(() => + Basics.RunInNewThread(() => { WatcherLog(Lang.Text("Watcher.Kill.Attempt")); try @@ -797,10 +797,10 @@ public void Kill() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Watcher.Kill.Failed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Watcher.Kill.Failed")); } }); @@ -812,7 +812,7 @@ public List ExportStackDump(string savePath) var dump = new List(); for (var i = 1; i <= 3; i++) { - dump.Add(ModBase.ShellAndGetOutput(jStackPath, "-l -e " + gameProcess.Id)); + dump.Add(LauncherProcess.ShellAndGetOutput(jStackPath, "-l -e " + gameProcess.Id)); Thread.Sleep(3000); } diff --git a/Plain Craft Launcher 2/Modules/ModLink.cs b/Plain Craft Launcher 2/Modules/ModLink.cs index bdc621191..e21d1d34a 100644 --- a/Plain Craft Launcher 2/Modules/ModLink.cs +++ b/Plain Craft Launcher 2/Modules/ModLink.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using PCL.Core.App; @@ -50,7 +50,7 @@ public static bool LobbyPrecheck() } catch (Exception ex) { - ModBase.Log("[Link] 刷新 Natayark ID 信息失败,需要重新登录"); + LauncherLog.Log("[Link] 刷新 Natayark ID 信息失败,需要重新登录"); HintService.Hint(Lang.Text("Link.Mod.ReLoginRequired"), HintType.Error); return false; } @@ -98,14 +98,14 @@ public static bool LobbyPrecheck() if (dlEasyTierLoader is not null) { - if (dlEasyTierLoader.State == ModBase.LoadState.Loading) + if (dlEasyTierLoader.State == LoadState.Loading) { HintService.Hint(Lang.Text("Link.Mod.EasyTierNotReady")); return false; } - if (dlEasyTierLoader.State == ModBase.LoadState.Failed || - dlEasyTierLoader.State == ModBase.LoadState.Aborted) + if (dlEasyTierLoader.State == LoadState.Failed || + dlEasyTierLoader.State == LoadState.Aborted) { HintService.Hint(Lang.Text("Link.Mod.DownloadingEasyTier")); DownloadEasyTier(); @@ -192,7 +192,7 @@ public static async Task>> MCInstanceFindi foreach (var TargetJava in javaNames) { var javaProcesses = Process.GetProcessesByName(TargetJava); - ModBase.Log($"[MCDetect] 找到 {TargetJava} 进程 {javaProcesses.Length} 个"); + LauncherLog.Log($"[MCDetect] 找到 {TargetJava} 进程 {javaProcesses.Length} 个"); if (javaProcesses is null || javaProcesses.Length == 0) { @@ -201,7 +201,7 @@ public static async Task>> MCInstanceFindi { foreach (var p in javaProcesses) { - ModBase.Log("[MCDetect] 检测到 Java 进程,PID: " + p.Id); + LauncherLog.Log("[MCDetect] 检测到 Java 进程,PID: " + p.Id); pIDLookupResult.Add(p.Id.ToString()); } } @@ -222,12 +222,12 @@ public static async Task>> MCInstanceFindi lookupList.AddRange(infos); } - ModBase.Log($"[MCDetect] 获取到端口数量 {lookupList.Count}"); + LauncherLog.Log($"[MCDetect] 获取到端口数量 {lookupList.Count}"); // 并行查找本地,超时 3s 自动放弃 var checkTasks = lookupList.Select( lookup => Task.Run(async () => { - ModBase.Log($"[MCDetect] 找到疑似端口,开始验证:{lookup}"); + LauncherLog.Log($"[MCDetect] 找到疑似端口,开始验证:{lookup}"); using (var test = McPingServiceFactory.CreateService("127.0.0.1", lookup.Item1, 3000)) { try @@ -236,7 +236,7 @@ public static async Task>> MCInstanceFindi var launcher = GetLauncherBrand(lookup.Item2); if (!string.IsNullOrWhiteSpace(info?.Version.Name)) { - ModBase.Log($"[MCDetect] 端口 {lookup} 为有效 Minecraft 世界"); + LauncherLog.Log($"[MCDetect] 端口 {lookup} 为有效 Minecraft 世界"); res.Add(new Tuple(lookup.Item1, info, launcher)); return Task.CompletedTask; } @@ -245,11 +245,11 @@ public static async Task>> MCInstanceFindi { if (ex.InnerException is ObjectDisposedException) { - ModBase.Log($"[McDetect] {lookup} 验证超时,已强制断开连接,将尝试旧版检测"); + LauncherLog.Log($"[McDetect] {lookup} 验证超时,已强制断开连接,将尝试旧版检测"); } else { - ModBase.Log(ex, $"[McDetect] {lookup} 验证出错,将尝试旧版检测"); + LauncherLog.Log(ex, $"[McDetect] {lookup} 验证出错,将尝试旧版检测"); } } } @@ -260,7 +260,7 @@ public static async Task>> MCInstanceFindi var info = await test.PingAsync(); if (!string.IsNullOrWhiteSpace(info?.Version.Name)) { - ModBase.Log($"[MCDetect] 端口 {lookup} 为有效 Minecraft 世界"); + LauncherLog.Log($"[MCDetect] 端口 {lookup} 为有效 Minecraft 世界"); res.Add(new Tuple(lookup.Item1, info, string.Empty)); return Task.CompletedTask; } @@ -269,11 +269,11 @@ public static async Task>> MCInstanceFindi { if (ex.InnerException is ObjectDisposedException) { - ModBase.Log($"[McDetect] {lookup} 验证超时,已强制断开连接"); + LauncherLog.Log($"[McDetect] {lookup} 验证超时,已强制断开连接"); } else { - ModBase.Log(ex, $"[McDetect] {lookup} 验证出错"); + LauncherLog.Log(ex, $"[McDetect] {lookup} 验证出错"); } } } @@ -283,7 +283,7 @@ public static async Task>> MCInstanceFindi } catch (Exception ex) { - ModBase.Log(ex, "[MCDetect] 获取端口信息错误"); + LauncherLog.Log(ex, "[MCDetect] 获取端口信息错误"); } return res; @@ -301,7 +301,7 @@ public static string GetLauncherBrand(int pid) } catch (Exception ex) { - ModBase.Log(ex, $"[MCDetect] 检测 PID {pid} 进程的启动参数失败"); + LauncherLog.Log(ex, $"[MCDetect] 检测 PID {pid} 进程的启动参数失败"); return ""; } } @@ -314,7 +314,7 @@ public static string GetLauncherBrand(int pid) public static int DownloadEasyTier() { - var dlTargetPath = $"{ModBase.pathTemp}EasyTier\\EasyTier-{ETInfoProvider.ETVersion}.zip"; + var dlTargetPath = $"{LauncherPaths.TempWithSlash}EasyTier\\EasyTier-{ETInfoProvider.ETVersion}.zip"; Basics.RunInNewThread(() => { @@ -334,12 +334,12 @@ public static int DownloadEasyTier() // 1. Download EasyTier loaders.Add(new LoaderDownload(Lang.Text("Link.Mod.Task.DownloadEasyTier"), new List { - new(addresses.ToArray(), dlTargetPath, new ModBase.FileChecker(1024 * 64)) + new(addresses.ToArray(), dlTargetPath, new FileChecker(1024 * 64)) }) { ProgressWeight = 15 }); // 2. Extract files loaders.Add(new ModLoader.LoaderTask(Lang.Text("Link.Mod.Task.ExtractFiles"), _ => - ModBase.ExtractFile(dlTargetPath, + LegacyFileFacade.ExtractFile(dlTargetPath, Path.Combine(Paths.SharedLocalData, "EasyTier", ETInfoProvider.ETVersion)) ) { block = true }); @@ -388,7 +388,7 @@ private static void CleanupEasyTierCache() } catch (Exception ex) { - ModBase.Log(ex, "[Link] 清理旧版本 EasyTier 出错"); + LauncherLog.Log(ex, "[Link] 清理旧版本 EasyTier 出错"); } } } diff --git a/Plain Craft Launcher 2/Modules/ModMain.cs b/Plain Craft Launcher 2/Modules/ModMain.cs index c929c5bdd..68773e901 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.cs +++ b/Plain Craft Launcher 2/Modules/ModMain.cs @@ -116,10 +116,10 @@ private static void TimerMain() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "短程主时钟执行异常", - ModBase.LogLevel.Critical, + LauncherLogLevel.Critical, userSummary: Lang.Text("Main.Error.OperationFailed")); } @@ -136,7 +136,7 @@ private static void TimerMain() catch (Exception ex) { - ModBase.Log(ex, "中程主时钟执行异常"); + LauncherLog.Log(ex, "中程主时钟执行异常"); } } @@ -151,7 +151,7 @@ private static void TimerMain() if (frmMain!.BtnExtraApril_ShowCheck() && aprilDistance != 0) frmMain.BtnExtraApril.Ribble(); // 以未知原因窗口被丢到一边去的修复(Top、Left = -25600),还有 #745 - ModBase.RunInUi(() => + UiThread.Post(() => { if (!frmMain.Hidden) { @@ -165,10 +165,10 @@ private static void TimerMain() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "长程主时钟执行异常", - ModBase.LogLevel.Critical, + LauncherLogLevel.Critical, userSummary: Lang.Text("Main.Error.OperationFailed")); } } @@ -176,28 +176,28 @@ private static void TimerMain() public static void TimerMainStart() { - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { while (true) { - ModBase.RunInUiWait(TimerMain); + UiThread.Invoke(TimerMain); Thread.Sleep((int)Math.Round(50d * 0.98d)); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "程序主时钟出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } }, "Timer Main"); if (!isAprilEnabled) return; - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -207,7 +207,7 @@ public static void TimerMainStart() if (lastTime != Environment.TickCount) { lastTime = Environment.TickCount; - ModBase.RunInUiWait(TimerFool); + UiThread.Invoke(TimerFool); } Thread.Sleep(1); @@ -215,10 +215,10 @@ public static void TimerMainStart() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "愚人节主时钟出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } }, "Timer Main Fool"); @@ -342,13 +342,13 @@ public static int MyMsgBox(string caption, string? title = null, string? button1 Button2Action = button2Action, Button3Action = button3Action }; WaitingMyMsgBox.Add(converter); - if (ModBase.RunInUi()) + if (UiThread.CheckAccess()) // 若为 UI 线程,立即执行弹窗刻, 避免快速(连点器)点击时多次弹窗 MyMsgBoxTick(); if (button2.Length > 0 || forceWait) { // 若有多个按钮则开始等待 - if (frmMain is null || (frmMain.PanMsg is null && ModBase.RunInUi())) + if (frmMain is null || (frmMain.PanMsg is null && UiThread.CheckAccess())) { // 主窗体尚未加载,用老土的弹窗来替代 WaitingMyMsgBox.Remove(converter); @@ -384,8 +384,8 @@ public static int MyMsgBox(string caption, string? title = null, string? button1 converter.Result = 1; } - ModBase.Log("[Control] 主窗体加载完成前出现意料外的等待弹窗:" + button1 + "," + button2 + "," + button3, - ModBase.LogLevel.Debug); + LauncherLog.Log("[Control] 主窗体加载完成前出现意料外的等待弹窗:" + button1 + "," + button2 + "," + button3, + LauncherLogLevel.Debug); } else { @@ -401,7 +401,7 @@ public static int MyMsgBox(string caption, string? title = null, string? button1 } } - ModBase.Log($"[Control] 普通弹框返回:{converter.Result ?? "null"}"); + LauncherLog.Log($"[Control] 普通弹框返回:{converter.Result ?? "null"}"); return (int)converter.Result; } @@ -437,13 +437,13 @@ public static int MyMsgBoxMarkdown(string caption, string? title = null, string? Button2Action = button2Action, Button3Action = button3Action }; WaitingMyMsgBox.Add(converter); - if (ModBase.RunInUi()) + if (UiThread.CheckAccess()) // 若为 UI 线程,立即执行弹窗刻, 避免快速(连点器)点击时多次弹窗 MyMsgBoxTick(); if (button2.Length > 0 || forceWait) { // 若有多个按钮则开始等待 - if (frmMain is null || (frmMain.PanMsg is null && ModBase.RunInUi())) + if (frmMain is null || (frmMain.PanMsg is null && UiThread.CheckAccess())) { // 主窗体尚未加载,用老土的弹窗来替代 WaitingMyMsgBox.Remove(converter); @@ -479,8 +479,8 @@ public static int MyMsgBoxMarkdown(string caption, string? title = null, string? converter.Result = 1; } - ModBase.Log("[Control] 主窗体加载完成前出现意料外的等待弹窗:" + button1 + "," + button2 + "," + button3, - ModBase.LogLevel.Debug); + LauncherLog.Log("[Control] 主窗体加载完成前出现意料外的等待弹窗:" + button1 + "," + button2 + "," + button3, + LauncherLogLevel.Debug); } else { @@ -496,7 +496,7 @@ public static int MyMsgBoxMarkdown(string caption, string? title = null, string? } } - ModBase.Log($"[Control] 普通弹框返回:{converter.Result ?? "null"}"); + LauncherLog.Log($"[Control] 普通弹框返回:{converter.Result ?? "null"}"); return (int)converter.Result; } @@ -541,7 +541,7 @@ public static string MyMsgBoxInput(string title, string text = "", string defaul ComponentDispatcher.PopModal(); } - ModBase.Log($"[Control] 输入弹框返回:{converter.Result}"); + LauncherLog.Log($"[Control] 输入弹框返回:{converter.Result}"); return converter.Result?.ToString(); } @@ -578,7 +578,7 @@ public static string MyMsgBoxInput(string title, string text = "", string defaul ComponentDispatcher.PopModal(); } - ModBase.Log($"[Control] 选择弹框返回:{converter.Result ?? "null"}"); + LauncherLog.Log($"[Control] 选择弹框返回:{converter.Result ?? "null"}"); return (int?)converter.Result; } @@ -637,10 +637,10 @@ public static void MyMsgBoxTick() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "处理等待中的弹窗失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } } @@ -773,10 +773,10 @@ private static void TimerFool() frmLaunchLeft.AprilPosTrans.Y += aprilSpeed.Y; // 大小改变 frmLaunchLeft.AprilScaleTrans.ScaleX = - ModBase.MathClamp(1d - (Math.Abs(direction.X) - Math.Abs(direction.Y)) * (speedValue / 160d), 0.2d, + LauncherMath.Clamp(1d - (Math.Abs(direction.X) - Math.Abs(direction.Y)) * (speedValue / 160d), 0.2d, 1.8d); frmLaunchLeft.AprilScaleTrans.ScaleY = - ModBase.MathClamp(1d - (Math.Abs(direction.Y) - Math.Abs(direction.X)) * (speedValue / 100d), 0.2d, + LauncherMath.Clamp(1d - (Math.Abs(direction.Y) - Math.Abs(direction.X)) * (speedValue / 100d), 0.2d, 1.8d); // 放弃提示 if (aprilDistance > 4000) @@ -810,10 +810,10 @@ private static void TimerFool() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "愚人节移动出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Main.Error.OperationFailed")); } } @@ -834,10 +834,10 @@ public static void ShowWindowToTop(nint handle) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "设置窗口置顶失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Main.Error.OperationFailed")); } } @@ -875,19 +875,19 @@ public static void SetGPUPreference(string executeable, bool wantHighPerformance else { // 创建父级键 - ModBase.Log("[System] 需要创建显卡设置的父级键"); + LauncherLog.Log("[System] 需要创建显卡设置的父级键"); Registry.CurrentUser.CreateSubKey(GPU_PERFERENCE_REG_KEY); } } - ModBase.Log($"[System] 当前程序 ({executeable}) 的显卡设置为高性能: {isCurrentHighPerformance}"); + LauncherLog.Log($"[System] 当前程序 ({executeable}) 的显卡设置为高性能: {isCurrentHighPerformance}"); if (isCurrentHighPerformance ^ wantHighPerformance) // 写入新设置 using (var writeKey = Registry.CurrentUser.OpenSubKey(GPU_PERFERENCE_REG_KEY, true)) { writeKey.SetValue(executeable, wantHighPerformance ? GPU_PERFERENCE_REG_VALUE_HIGH : GPU_PERFERENCE_REG_VALUE_DEFAULT); - ModBase.Log($"[System] 已调整程序 ({executeable}) 显卡设置: {wantHighPerformance}"); + LauncherLog.Log($"[System] 已调整程序 ({executeable}) 显卡设置: {wantHighPerformance}"); } } @@ -903,19 +903,19 @@ public static string ArgumentReplace(string text, Func escapeHan { if (s is null) return ""; if (escapeHandler is null) return s; - if (s.Contains(":\\")) s = ModBase.ShortenPath(s); + if (s.Contains(":\\")) s = LegacyFileFacade.ShortenPath(s); return escapeHandler(s); }; // 基础 - text = text.Replace("{pcl_version}", replacer(ModBase.VersionBaseName)); - text = text.Replace("{pcl_version_code}", replacer(ModBase.VersionCode.ToString())); - text = text.Replace("{pcl_version_branch}", replacer(ModBase.VersionBranchName)); - text = text.Replace("{pcl_branch}", replacer(ModBase.VersionBranchName)); + text = text.Replace("{pcl_version}", replacer(LauncherEnvironment.VersionBaseName)); + text = text.Replace("{pcl_version_code}", replacer(LauncherEnvironment.VersionCode.ToString())); + text = text.Replace("{pcl_version_branch}", replacer(LauncherEnvironment.VersionBranchName)); + text = text.Replace("{pcl_branch}", replacer(LauncherEnvironment.VersionBranchName)); text = text.Replace("{identify}", replacer(Identify.LauncherId)); text = text.Replace("{path}", replacer(Basics.ExecutableDirectory)); text = text.Replace("{path_with_name}", replacer(Basics.ExecutableName)); - text = text.Replace("{path_temp}", replacer(ModBase.pathTemp)); + text = text.Replace("{path_temp}", replacer(LauncherPaths.TempWithSlash)); // 时间 if (replaceTime) // 在窗口标题中,时间会被后续动态替换,所以此时不应该替换 @@ -956,7 +956,7 @@ public static string ArgumentReplace(string text, Func escapeHan } // 验证信息 - if (ModLaunch.mcLoginLoader.State == ModBase.LoadState.Finished) + if (ModLaunch.mcLoginLoader.State == LoadState.Finished) { text = text.Replace("{user}", replacer(ModLaunch.mcLoginLoader.output.Name)); text = text.Replace("{uuid}", replacer(ModLaunch.mcLoginLoader.output.Uuid.ToLower())); @@ -982,16 +982,16 @@ public static string ArgumentReplace(string text, Func escapeHan } // 高级 - text = ModBase.RegexReplaceEach(text, @"\{hint\}", m => replacer(PageToolsTest.GetRandomHint())); - text = ModBase.RegexReplaceEach(text, @"\{cave\}", m => replacer(PageToolsTest.GetRandomCave())); - text = ModBase.RegexReplaceEach(text, @"\{setup:([a-zA-Z0-9]+)\}", m => + text = LauncherText.RegexReplaceEach(text, @"\{hint\}", m => replacer(PageToolsTest.GetRandomHint())); + text = LauncherText.RegexReplaceEach(text, @"\{cave\}", m => replacer(PageToolsTest.GetRandomCave())); + text = LauncherText.RegexReplaceEach(text, @"\{setup:([a-zA-Z0-9]+)\}", m => { if (ConfigService.TryGetConfigItemNoType(m.Groups[1].Value, out var item) && item.Source != ConfigSource.SharedEncrypt) return replacer(item.GetValueNoType(ModInstanceList.McMcInstanceSelected?.PathInstance)?.ToString() ?? ""); return replacer(""); }); - text = ModBase.RegexReplaceEach(text, @"\{varible:([^:\}]+)(?::([^\}]+))?\}", m => replacer(CustomEvent.GetCustomVariable(m.Groups[1].Value, m.Groups[2].Value))); - text = ModBase.RegexReplaceEach(text, @"\{variable:([^:\}]+)(?::([^\}]+))?\}", m => replacer(CustomEvent.GetCustomVariable(m.Groups[1].Value, m.Groups[2].Value))); + text = LauncherText.RegexReplaceEach(text, @"\{varible:([^:\}]+)(?::([^\}]+))?\}", m => replacer(CustomEvent.GetCustomVariable(m.Groups[1].Value, m.Groups[2].Value))); + text = LauncherText.RegexReplaceEach(text, @"\{variable:([^:\}]+)(?::([^\}]+))?\}", m => replacer(CustomEvent.GetCustomVariable(m.Groups[1].Value, m.Groups[2].Value))); return text; } @@ -1014,14 +1014,14 @@ public static void TryClearTaskTemp() isTaskTempClearing = true; try { - ModBase.Log("[System] 开始清理任务缓存文件夹"); - ModBase.DeleteDirectory(Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL", "TaskTemp")); - ModBase.DeleteDirectory($@"{ModBase.pathTemp}TaskTemp\"); - ModBase.Log("[System] 已清理任务缓存文件夹"); + LauncherLog.Log("[System] 开始清理任务缓存文件夹"); + LegacyFileFacade.DeleteDirectory(Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL", "TaskTemp")); + LegacyFileFacade.DeleteDirectory($@"{LauncherPaths.TempWithSlash}TaskTemp\"); + LauncherLog.Log("[System] 已清理任务缓存文件夹"); } catch (Exception ex) { - ModBase.Log(ex, "清理任务缓存文件夹失败"); + LauncherLog.Log(ex, "清理任务缓存文件夹失败"); } finally { @@ -1049,11 +1049,11 @@ public static string RequestTaskTempFolder(bool requireNonSpace = false) { try { - resultFolder = $@"{ModBase.pathTemp}TaskTemp\{ModBase.GetUuid()}-{RandomUtils.NextInt(0, 1000000)}\"; + resultFolder = $@"{LauncherPaths.TempWithSlash}TaskTemp\{LauncherRuntime.GetUuid()}-{RandomUtils.NextInt(0, 1000000)}\"; if (requireNonSpace && resultFolder.Contains(" ")) break; // 带空格 Directory.CreateDirectory(resultFolder); - ModBase.CheckPermissionWithException(resultFolder); + LegacyFileFacade.CheckPermissionWithException(resultFolder); return resultFolder; } catch @@ -1063,9 +1063,9 @@ public static string RequestTaskTempFolder(bool requireNonSpace = false) // 使用备用路径 resultFolder = - Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL", "TaskTemp", $"{ModBase.GetUuid()}-{RandomUtils.NextInt(0, 1000000)}"); + Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL", "TaskTemp", $"{LauncherRuntime.GetUuid()}-{RandomUtils.NextInt(0, 1000000)}"); Directory.CreateDirectory(resultFolder); - ModBase.CheckPermission(resultFolder); + LegacyFileFacade.CheckPermission(resultFolder); return resultFolder; } @@ -1081,10 +1081,10 @@ public static void RaiseCustomEvent(DependencyObject control) if (!events.Any()) return; - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { foreach (var e in events) e.Raise(); - }, $"执行自定义事件 {ModBase.GetUuid()}"); + }, $"执行自定义事件 {LauncherRuntime.GetUuid()}"); } } diff --git a/Plain Craft Launcher 2/Modules/ModMusic.cs b/Plain Craft Launcher 2/Modules/ModMusic.cs index 2215369d7..3c289bd5b 100644 --- a/Plain Craft Launcher 2/Modules/ModMusic.cs +++ b/Plain Craft Launcher 2/Modules/ModMusic.cs @@ -58,7 +58,7 @@ private static void MusicLoop(bool isFirstLoad = false) if (reader.TotalTime.TotalMilliseconds > 0d) { var progress = reader.CurrentTime.TotalMilliseconds / reader.TotalTime.TotalMilliseconds; - ModBase.RunInUi(() => ModMain.frmMain.BtnExtraMusic.Progress = progress); + UiThread.Post(() => ModMain.frmMain.BtnExtraMusic.Progress = progress); } Thread.Sleep(100); @@ -72,10 +72,10 @@ private static void MusicLoop(bool isFirstLoad = false) catch (Exception ex) { - ModBase.Log(ex, $"播放音乐出现内部错误({musicCurrent})", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, $"播放音乐出现内部错误({musicCurrent})", LauncherLogLevel.Developer); // 错误处理:精准提示用户 - var fileName = ModBase.GetFileNameFromPath(musicCurrent); + var fileName = LegacyFileFacade.GetFileNameFromPath(musicCurrent); if (ex is MmException) { var msg = ex.Message; @@ -84,10 +84,10 @@ private static void MusicLoop(bool isFirstLoad = false) else if (msg.Contains("NoDriver") || msg.Contains("BadDeviceId")) HintService.Hint(Lang.Text("Music.Error.DeviceChanged"), HintType.Error); else - ModBase.Log( + LauncherLog.Log( ex, $"播放失败({fileName})", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Music.Error.PlaybackFailed", fileName)); } else if (ex.Message.Contains("Got a frame at sample rate") || @@ -106,10 +106,10 @@ private static void MusicLoop(bool isFirstLoad = false) } else { - ModBase.Log( + LauncherLog.Log( ex, $"播放失败({fileName})", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Music.Error.PlaybackFailed", fileName)); } @@ -161,9 +161,9 @@ private static void MusicListInit(bool forceReload, string preventFirst = null) if (musicAllList is null) { musicAllList = new List(); - var musicDir = Path.Combine(ModBase.exePath, "PCL", "Musics"); + var musicDir = Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Musics"); Directory.CreateDirectory(musicDir); - foreach (var file in ModBase.EnumerateFiles(musicDir)) + foreach (var file in LegacyFileFacade.EnumerateFiles(musicDir)) { var ext = file.Extension.ToLowerInvariant(); // 忽略非音频文件 @@ -190,10 +190,10 @@ private static void MusicListInit(bool forceReload, string preventFirst = null) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "初始化音乐列表失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Music.Error.OperationFailed")); } } @@ -226,7 +226,7 @@ private static string DequeueNextMusicAddress() /// private static void MusicRefreshUI() { - ModBase.RunInUi(() => + UiThread.Post(() => { try { @@ -237,7 +237,7 @@ private static void MusicRefreshUI() else { ModMain.frmMain.BtnExtraMusic.Show = true; - var fileName = ModBase.GetFileNameWithoutExtentionFromPath(musicCurrent); + var fileName = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(musicCurrent); var isSingle = musicAllList.Count == 1; string tipText; if (MusicState == MusicStates.Pause) @@ -270,10 +270,10 @@ private static void MusicRefreshUI() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "刷新背景音乐 UI 失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Music.Error.OperationFailed")); } }); @@ -302,7 +302,7 @@ public static void MusicControlPause() default: { - ModBase.Log("[Music] 音乐目前为停止状态,已强制尝试开始播放", ModBase.LogLevel.Debug); + LauncherLog.Log("[Music] 音乐目前为停止状态,已强制尝试开始播放", LauncherLogLevel.Debug); MusicRefreshPlay(false); break; } @@ -314,7 +314,7 @@ public static void MusicControlNext() if (musicAllList?.Count is { } arg2 && arg2 == 1) { MusicStartPlay(musicCurrent); - HintService.Hint(Lang.Text("Music.Hint.Replaying", ModBase.GetFileNameFromPath(musicCurrent)), + HintService.Hint(Lang.Text("Music.Hint.Replaying", LegacyFileFacade.GetFileNameFromPath(musicCurrent)), HintType.Success); } else @@ -327,7 +327,7 @@ public static void MusicControlNext() else { MusicStartPlay(addr); - HintService.Hint(Lang.Text("Music.Hint.Playing", ModBase.GetFileNameFromPath(addr)), + HintService.Hint(Lang.Text("Music.Hint.Playing", LegacyFileFacade.GetFileNameFromPath(addr)), HintType.Success); } } @@ -391,7 +391,7 @@ public static void MusicRefreshPlay(bool showHint, bool isFirstLoad = false) MusicStartPlay(addr, isFirstLoad); if (showHint) HintService.Hint( - Lang.Text("Music.Hint.Refreshed", ModBase.GetFileNameFromPath(addr)), + Lang.Text("Music.Hint.Refreshed", LegacyFileFacade.GetFileNameFromPath(addr)), HintType.Success, false); } @@ -407,10 +407,10 @@ public static void MusicRefreshPlay(bool showHint, bool isFirstLoad = false) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "刷新背景音乐播放失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Music.Error.OperationFailed")); } } @@ -419,22 +419,22 @@ private static void MusicStartPlay(string address, bool isFirstLoad = false) { if (string.IsNullOrEmpty(address)) return; - ModBase.Log("[Music] 播放开始:" + address); + LauncherLog.Log("[Music] 播放开始:" + address); musicCurrent = address; - ModBase.RunInNewThread(() => MusicLoop(isFirstLoad), "Music", ThreadPriority.BelowNormal); + PCL.Core.App.Basics.RunInNewThread(() => MusicLoop(isFirstLoad), "Music", ThreadPriority.BelowNormal); } public static bool MusicPause() { if (MusicState != MusicStates.Play) { - ModBase.Log($"[Music] 无需暂停播放,当前状态为 {MusicState}"); + LauncherLog.Log($"[Music] 无需暂停播放,当前状态为 {MusicState}"); return false; } - ModBase.RunInThread(() => + UiThread.RunInThread(() => { - ModBase.Log("[Music] 已暂停播放"); + LauncherLog.Log("[Music] 已暂停播放"); musicNAudio?.Pause(); MusicRefreshUI(); }); @@ -445,13 +445,13 @@ public static bool MusicResume() { if (MusicState == MusicStates.Play || musicAllList.Count == 0) { - ModBase.Log($"[Music] 无需继续播放,当前状态为 {MusicState}"); + LauncherLog.Log($"[Music] 无需继续播放,当前状态为 {MusicState}"); return false; } - ModBase.RunInThread(() => + UiThread.RunInThread(() => { - ModBase.Log("[Music] 已恢复播放"); + LauncherLog.Log("[Music] 已恢复播放"); try { musicNAudio?.Play(); diff --git a/Plain Craft Launcher 2/Modules/ModVideoBack.cs b/Plain Craft Launcher 2/Modules/ModVideoBack.cs index c7595e814..cd76a60b4 100644 --- a/Plain Craft Launcher 2/Modules/ModVideoBack.cs +++ b/Plain Craft Launcher 2/Modules/ModVideoBack.cs @@ -1,4 +1,4 @@ -namespace PCL; +namespace PCL; public static class ModVideoBack { @@ -35,7 +35,7 @@ public static bool ForcePlay // 判断是否强行播放 public static void OnGamingStateChanged(object sender, BooleanEventArgs e) // 用户是否在游戏中 事件 { - ModBase.RunInUi(() => + UiThread.Post(() => { if (IsGaming) { @@ -57,7 +57,7 @@ public static void OnGamingStateChanged(object sender, BooleanEventArgs e) // public static void OnForcePlayChanged(object sender, BooleanEventArgs e) // 是否强行播放 事件 { - ModBase.RunInUi(() => + UiThread.Post(() => { if (IsGaming) { @@ -82,18 +82,18 @@ public static void OnForcePlayChanged(object sender, BooleanEventArgs e) // 是 /// public static void VideoPlay() { - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.frmMain.VideoBack.Source is not null && !isMinimized) if (!IsGaming || ForcePlay) try { ModMain.frmMain.VideoBack.Play(); - ModBase.Log("[UI] 已开始视频背景播放"); + LauncherLog.Log("[UI] 已开始视频背景播放"); } catch (Exception ex) { - ModBase.Log(ex, "[UI] 开始视频背景播放失败"); + LauncherLog.Log(ex, "[UI] 开始视频背景播放失败"); } }); } @@ -103,18 +103,18 @@ public static void VideoPlay() /// public static void VideoStop() { - ModBase.RunInUi(() => + UiThread.Post(() => { try { ModMain.frmMain.VideoBack.Source = null; ModMain.frmMain.VideoBack.Stop(); ModMain.frmMain.VideoBack.Position = TimeSpan.Zero; - ModBase.Log("[UI] 已停止视频背景播放"); + LauncherLog.Log("[UI] 已停止视频背景播放"); } catch (Exception ex) { - ModBase.Log(ex, "[UI] 停止视频背景播放失败"); + LauncherLog.Log(ex, "[UI] 停止视频背景播放失败"); } }); } @@ -126,7 +126,7 @@ public static void VideoPause() { // 窗口最小化后暂停 // 游戏启动后暂停 - ModBase.RunInUi(() => + UiThread.Post(() => { if (isMinimized) { @@ -134,11 +134,11 @@ public static void VideoPause() try { ModMain.frmMain.VideoBack.Pause(); - ModBase.Log("[UI] 已暂停视频背景播放"); + LauncherLog.Log("[UI] 已暂停视频背景播放"); } catch (Exception ex) { - ModBase.Log(ex, "[UI] 暂停视频背景播放失败"); + LauncherLog.Log(ex, "[UI] 暂停视频背景播放失败"); } } else if (ForcePlay) @@ -150,11 +150,11 @@ public static void VideoPause() { if (ModMain.frmSetupUI is not null) ModMain.frmSetupUI.BtnBackgroundRefresh.IsEnabled = false; ModMain.frmMain.VideoBack.Pause(); - ModBase.Log("[UI] 已暂停视频背景播放"); + LauncherLog.Log("[UI] 已暂停视频背景播放"); } catch (Exception ex) { - ModBase.Log(ex, "[UI] 暂停视频背景播放失败"); + LauncherLog.Log(ex, "[UI] 暂停视频背景播放失败"); } } }); diff --git a/Plain Craft Launcher 2/Modules/ModWebServer.cs b/Plain Craft Launcher 2/Modules/ModWebServer.cs index cf95fc81e..82f444abd 100644 --- a/Plain Craft Launcher 2/Modules/ModWebServer.cs +++ b/Plain Craft Launcher 2/Modules/ModWebServer.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Net; using System.Net.Http; using PCL.Core.App; @@ -29,7 +29,7 @@ public static bool StartWebServer(string name, HttpServer server) Task.Run(() => { - ModBase.Log($"[WebServer] 服务端 '{name}' 已启动"); + LauncherLog.Log($"[WebServer] 服务端 '{name}' 已启动"); try { server.Start(); @@ -47,7 +47,7 @@ public static bool StartWebServer(string name, HttpServer server) } catch (Exception ex) { - ModBase.Log(ex, $"[WebServer] 服务端 '{name}' 运行出错"); + LauncherLog.Log(ex, $"[WebServer] 服务端 '{name}' 运行出错"); } finally { @@ -60,7 +60,7 @@ public static bool StartWebServer(string name, HttpServer server) // 忽略已释放的异常 } - ModBase.Log($"[WebServer] 服务端 '{name}' 已停止"); + LauncherLog.Log($"[WebServer] 服务端 '{name}' 已停止"); lock (_webServers) { _webServers.Remove(name); @@ -204,7 +204,7 @@ private Task HandleStatus(HttpListenerRequest request) } else if (!_status.success) { - ModBase.Log($"[OAuth] {_serviceName}: {_status.message}{"\r\n"}{_status.stacktrace}"); + LauncherLog.Log($"[OAuth] {_serviceName}: {_status.message}{"\r\n"}{_status.stacktrace}"); var pa = new Dictionary(); pa["Port"] = Port.ToString(); _completeCallback(false, pa, _status.message); @@ -229,12 +229,12 @@ private Task HandleBackground(HttpListenerRequest request) private Task HandleIcon(HttpListenerRequest request) { - return HttpRouteResponse.Input(ModBase.GetResourceStream("Images/icon.ico")).AsTask(); + return HttpRouteResponse.Input(PCL.Core.App.Basics.GetResourceStream("Images/icon.ico")).AsTask(); } private Task HandleComplete(HttpListenerRequest request) { - return HttpRouteResponse.Input(ModBase.GetResourceStream("Resources/oauth-complete.html"), "text/html") + return HttpRouteResponse.Input(PCL.Core.App.Basics.GetResourceStream("Resources/oauth-complete.html"), "text/html") .AsTask(); } } @@ -277,7 +277,7 @@ public static bool StartOAuthWaitingCallback(string serviceName, string url, OAu { if (IsWebServerRunning(serviceName)) return false; - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { var serverPort = 0; lock (_webServers) @@ -292,16 +292,16 @@ public static bool StartOAuthWaitingCallback(string serviceName, string url, OAu server = new NaidCallbackServer(serviceName, completeCallback, currentPicAddress); serverPort = server.Port; - ModBase.Log($"[OAuth] {serviceName}: 已开始监听 {server.Port} 端口,正在初始化路由"); + LauncherLog.Log($"[OAuth] {serviceName}: 已开始监听 {server.Port} 端口,正在初始化路由"); // 开始响应请求 var webServiceName = $"oauth/{serviceName}"; - if (DisposeWebServer(webServiceName)) ModBase.Log("[OAuth] 已关闭先前认证服务服务端"); + if (DisposeWebServer(webServiceName)) LauncherLog.Log("[OAuth] 已关闭先前认证服务服务端"); StartWebServer(webServiceName, server); - ModBase.Log($"[OAuth] {serviceName}: 初始化完成,开始响应 HTTP 请求"); + LauncherLog.Log($"[OAuth] {serviceName}: 初始化完成,开始响应 HTTP 请求"); } // 打开 OAuth URL - ModBase.OpenWebsite(url.Replace("%r", $"http://localhost:{serverPort}/callback")); + LauncherProcess.OpenWebsite(url.Replace("%r", $"http://localhost:{serverPort}/callback")); }, $"CallbackWebServerLoading/{serviceName}"); return true; } diff --git a/Plain Craft Launcher 2/Modules/Network/Downloader/FileDownloader.cs b/Plain Craft Launcher 2/Modules/Network/Downloader/FileDownloader.cs index 038587389..b039a1c7f 100644 --- a/Plain Craft Launcher 2/Modules/Network/Downloader/FileDownloader.cs +++ b/Plain Craft Launcher 2/Modules/Network/Downloader/FileDownloader.cs @@ -1,8 +1,7 @@ -using System.IO; +using System.IO; using Downloader; using PCL.Core.IO.Net; - namespace PCL.Network; public static class FileDownloader @@ -63,7 +62,7 @@ await DownloadSingleAsync(url, localPath, useBrowserUserAgent, customUserAgent, { lastException = ex; CleanupTempFiles(localPath); - ModBase.Log(ex, $"[Download] 下载失败,尝试下一个源:{url}", ModBase.LogLevel.Debug); + LauncherLog.Log(ex, $"[Download] 下载失败,尝试下一个源:{url}"); } } @@ -73,7 +72,7 @@ await DownloadSingleAsync(url, localPath, useBrowserUserAgent, customUserAgent, private static async Task DownloadSingleAsync(string url, string localPath, bool useBrowserUserAgent, string customUserAgent, CancellationToken cancellationToken, bool enableParallelChunks, DownloadFile? trackedFile) { - ModBase.Log($"[Download] 开始下载:{url} -> {localPath}"); + LauncherLog.Log($"[Download] 开始下载:{url} -> {localPath}"); CleanupTempFiles(localPath); var perFileThreadLimit = enableParallelChunks ? Math.Max(1, ModNet.NetTaskThreadLimit) : 1; @@ -103,7 +102,7 @@ void UpdateDownloadStat(DownloadProgressChangedEventArgs args) if (trackedFile is null) return; - trackedFile.State = PCL.Network.NetState.Downloading; + trackedFile.State = NetState.Downloading; trackedFile.TotalSize = Math.Max(trackedFile.TotalSize, args.TotalBytesToReceive); trackedFile.IsUnknownSize = trackedFile.TotalSize <= 0; trackedFile.DownloadedBytes = Math.Max(trackedFile.DownloadedBytes, args.ReceivedBytesSize); @@ -116,7 +115,7 @@ void UpdateDownloadStat(DownloadProgressChangedEventArgs args) if (trackedFile is null) return; - trackedFile.State = PCL.Network.NetState.Reading; + trackedFile.State = NetState.Reading; trackedFile.TotalSize = Math.Max(trackedFile.TotalSize, args.TotalBytesToReceive); trackedFile.IsUnknownSize = args.TotalBytesToReceive <= 0; trackedFile.DownloadedBytes = 0; @@ -163,7 +162,7 @@ void UpdateDownloadStat(DownloadProgressChangedEventArgs args) } if (!File.Exists(localPath)) throw new IOException($"下载未产生任何文件:{localPath}"); - ModBase.Log($"[Download] 下载成功:{localPath}"); + LauncherLog.Log($"[Download] 下载成功:{localPath}"); } catch (TaskCanceledException ex) when (cancellationToken.IsCancellationRequested) { diff --git a/Plain Craft Launcher 2/Modules/Network/Facade/ModNet.cs b/Plain Craft Launcher 2/Modules/Network/Facade/ModNet.cs index fe461a8af..592a65500 100644 --- a/Plain Craft Launcher 2/Modules/Network/Facade/ModNet.cs +++ b/Plain Craft Launcher 2/Modules/Network/Facade/ModNet.cs @@ -1,5 +1,5 @@ -using System.IO; -using System.Text; +using System.Text; +using PCL.Core.Utils; namespace PCL.Network; @@ -26,7 +26,7 @@ public static object NetGetCodeByRequestRetry(string url, Encoding? encode = nul Retries = 3 }; var result = Requester.FetchString(url, param); - return isJson ? (object)ModBase.GetJson(result) : result; + return isJson ? (object)JsonCompat.ParseNode(result) : result; } public static object NetGetCodeByRequestOnce(string url, Encoding? encode = null, int timeout = 30000, @@ -41,7 +41,7 @@ public static object NetGetCodeByRequestOnce(string url, Encoding? encode = null Retries = 1 }; var result = Requester.FetchString(url, param); - return isJson ? (object)ModBase.GetJson(result) : result; + return isJson ? (object)JsonCompat.ParseNode(result) : result; } public static string NetGetCodeByLoader(string url, int timeout = 45000, bool isJson = false, @@ -65,13 +65,13 @@ public static string NetGetCodeByLoader(IEnumerable urls, int timeout = Timeout = timeout, UseBrowserUserAgent = useBrowserUserAgent }); - - return isJson ? ModBase.GetJson(content).ToString() : content; + + return isJson ? JsonCompat.ParseNode(content).ToString() : content; } catch (Exception ex) { lastException = ex; - ModBase.Log(ex, $"[Fetch] 获取文件内容失败,尝试下一个源:{url}", ModBase.LogLevel.Debug); + LauncherLog.Log(ex, $"[Fetch] 获取文件内容失败,尝试下一个源:{url}"); } } @@ -105,13 +105,13 @@ public static Task NetDownloadByClient(string url, string localFile, bool useBro } public static void NetDownloadByLoader(string url, string localFile, ModLoader.LoaderBase? loaderToSyncProgress = null, - ModBase.FileChecker? check = null, bool useBrowserUserAgent = false) + FileChecker? check = null, bool useBrowserUserAgent = false) { FileDownloader.DownloadAsync(url, localFile, useBrowserUserAgent).GetAwaiter().GetResult(); } public static void NetDownloadByLoader(IEnumerable urls, string localFile, - ModLoader.LoaderBase? loaderToSyncProgress = null, ModBase.FileChecker? check = null, + ModLoader.LoaderBase? loaderToSyncProgress = null, FileChecker? check = null, bool useBrowserUserAgent = false) { FileDownloader.DownloadAsync(urls, localFile, useBrowserUserAgent).GetAwaiter().GetResult(); @@ -121,7 +121,7 @@ public static bool HasDownloadingTask(bool ignoreCustomDownload = false) { foreach (var task in ModLoader.loaderTaskbar.ToList()) { - if (task.show && task.State == ModBase.LoadState.Loading && + if (task.show && task.State == LoadState.Loading && (!ignoreCustomDownload || !task.name.Contains("自定义下载"))) return true; } diff --git a/Plain Craft Launcher 2/Modules/Network/Http/RequestSigning.cs b/Plain Craft Launcher 2/Modules/Network/Http/RequestSigning.cs index 171f41c03..2af47b815 100644 --- a/Plain Craft Launcher 2/Modules/Network/Http/RequestSigning.cs +++ b/Plain Craft Launcher 2/Modules/Network/Http/RequestSigning.cs @@ -1,4 +1,4 @@ -using System.Net; +using System.Net; using System.Net.Http; using PCL.Core.App; @@ -31,8 +31,8 @@ internal static void SecretHeadersSign(string url, ref HttpRequestMessage client var userAgent = !string.IsNullOrEmpty(customUserAgent) ? customUserAgent : useBrowserUserAgent - ? $"PCL2/{ModBase.UpstreamVersion}.{ModBase.VersionBranchCode} PCLCE/{ModBase.VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0" - : $"PCL2/{ModBase.UpstreamVersion}.{ModBase.VersionBranchCode} PCLCE/{ModBase.VersionStandardCode}"; + ? $"PCL2/{LauncherEnvironment.UpstreamVersion}.{LauncherEnvironment.VersionBranchCode} PCLCE/{LauncherEnvironment.VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0" + : $"PCL2/{LauncherEnvironment.UpstreamVersion}.{LauncherEnvironment.VersionBranchCode} PCLCE/{LauncherEnvironment.VersionStandardCode}"; client.Headers.Add("User-Agent", userAgent); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Network/Http/Requester.cs b/Plain Craft Launcher 2/Modules/Network/Http/Requester.cs index 100d9a433..b4a6769af 100644 --- a/Plain Craft Launcher 2/Modules/Network/Http/Requester.cs +++ b/Plain Craft Launcher 2/Modules/Network/Http/Requester.cs @@ -1,12 +1,11 @@ -using System.Net; -using System.Net.Http; +using System.Net.Http; using System.Net.Http.Headers; using System.Net.NetworkInformation; using System.Text; using Downloader; -using System.Text.Json.Nodes; using PCL.Core.IO.Net; using PCL.Core.IO.Net.Http; +using PCL.Core.Utils; namespace PCL.Network; @@ -39,7 +38,7 @@ public static string FetchString(string url, RequestParam param = default) public static async Task FetchJsonAsync(string url, RequestParam param = default) { - return ModBase.GetJson(await FetchStringAsync(url, param).ConfigureAwait(false)); + return JsonCompat.ParseNode(await FetchStringAsync(url, param).ConfigureAwait(false)); } public static async Task FetchJsonAsync(string url, RequestParam param = default) where T : JsonNode diff --git a/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownload.cs b/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownload.cs index 2492f3ff0..b2a16011f 100644 --- a/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownload.cs +++ b/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownload.cs @@ -1,14 +1,13 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.IO; -using System.Threading; -using System.Threading.Tasks; +using PCL.Core.App; using PCL.Core.Utils; namespace PCL.Network.Loaders; public class LoaderDownload : ModLoader.LoaderBase { - public ModBase.SafeList files; + public SafeList files; private int _fileRemain; private readonly object _fileRemainLock = new(); private CancellationTokenSource? _cancellationTokenSource; @@ -16,28 +15,28 @@ public class LoaderDownload : ModLoader.LoaderBase public override double Progress { - get => State >= ModBase.LoadState.Finished ? 1 : (files.Any() ? files.Average(file => file.Progress) : 0); + get => State >= LoadState.Finished ? 1 : files.Any() ? files.Average(file => file.Progress) : 0; set => throw new Exception("文件下载不允许指定进度"); } - public LoaderDownload(string name, List fileTasks) + public LoaderDownload(string name, List fileTasks) { base.name = name; - files = new ModBase.SafeList(fileTasks ?? new List()); + files = new SafeList(fileTasks ?? new List()); } public void RefreshStat() { } public override void Start(object input = null, bool isForceRestart = false) { - if (input is List inputFiles) - files = new ModBase.SafeList(inputFiles); + if (input is List inputFiles) + files = new SafeList(inputFiles); lock (lockState) { - if (State == ModBase.LoadState.Loading) + if (State == LoadState.Loading) return; - State = ModBase.LoadState.Loading; + State = LoadState.Loading; } _cancellationTokenSource = new CancellationTokenSource(); @@ -48,7 +47,7 @@ public override void Start(object input = null, bool isForceRestart = false) ModNet.NetManager.Start(this); - ModBase.RunInNewThread(() => Run(_cancellationTokenSource.Token), $"DL/{Uuid}"); + Basics.RunInNewThread(() => Run(_cancellationTokenSource.Token), $"DL/{Uuid}"); } private void Run(CancellationToken cancellationToken) @@ -78,7 +77,7 @@ private void Run(CancellationToken cancellationToken) catch (Exception ex) { file.Errors.Add(ex); - file.State = PCL.Network.NetState.Interrupted; + file.State = NetState.Interrupted; exceptions.Enqueue(ex); _cancellationTokenSource?.Cancel(); } @@ -108,19 +107,19 @@ private int GetMaxParallelFiles() return Math.Max(1, Math.Min(files.Count, Math.Clamp(ModNet.NetTaskThreadLimit, 1, 64))); } - private async Task ProcessFileAsync(PCL.Network.DownloadFile file, CancellationToken cancellationToken) + private async Task ProcessFileAsync(DownloadFile file, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (!file.Loaders.Contains(this)) file.Loaders.Add(this); - if (State >= ModBase.LoadState.Finished) + if (State >= LoadState.Finished) return; Directory.CreateDirectory(Path.GetDirectoryName(file.LocalPath) ?? throw new IOException("下载路径无效")); if (file.Check?.canUseExistsFile == true && file.Check.Check(file.LocalPath) is null) { file.IsCopy = true; - file.State = PCL.Network.NetState.Finished; + file.State = NetState.Finished; try { file.TotalSize = new FileInfo(file.LocalPath).Length; } catch (IOException) { file.TotalSize = -1; } file.DownloadedBytes = file.TotalSize; @@ -130,7 +129,7 @@ private async Task ProcessFileAsync(PCL.Network.DownloadFile file, CancellationT return; } - file.State = PCL.Network.NetState.Connecting; + file.State = NetState.Connecting; var enableParallelChunks = files.Count <= 1; for (var retry = 0; retry < 4; retry++) { @@ -147,7 +146,7 @@ await FileDownloader.DownloadAsync(file.Urls, file.LocalPath, file.UseBrowserUse } catch (Exception ex) when (retry < 3) { - ModBase.Log(ex, $"[Download] 重试 {retry + 1}/3:{file.LocalPath}", ModBase.LogLevel.Debug); + LauncherLog.Log(ex, $"[Download] 重试 {retry + 1}/3:{file.LocalPath}"); Thread.Sleep(RandomUtils.NextInt(300, 500 + retry * 300)); } } @@ -157,11 +156,11 @@ await FileDownloader.DownloadAsync(file.Urls, file.LocalPath, file.UseBrowserUse file.DownloadedBytes = Math.Max(0, file.TotalSize); file.Speed = 0; file.ActiveThreads = 0; - file.State = PCL.Network.NetState.Finished; + file.State = NetState.Finished; OnFileFinish(file); } - public void OnFileFinish(PCL.Network.DownloadFile file) + public void OnFileFinish(DownloadFile file) { lock (_fileRemainLock) { @@ -178,15 +177,15 @@ public void OnFinish() RaisePreviewFinish(); lock (lockState) { - if (State > ModBase.LoadState.Loading) + if (State > LoadState.Loading) return; - State = ModBase.LoadState.Finished; + State = LoadState.Finished; } ModNet.NetManager.Finish(this); } - public void OnFileFail(PCL.Network.DownloadFile file) + public void OnFileFail(DownloadFile file) { OnFail(file.Errors.Any() ? file.Errors : new List { new Exception($"文件下载失败:{file.LocalPath}") }); } @@ -195,16 +194,16 @@ public void OnFail(List exList) { lock (lockState) { - if (State > ModBase.LoadState.Loading) + if (State > LoadState.Loading) return; Error = exList.FirstOrDefault() ?? new Exception("未知下载错误"); - State = ModBase.LoadState.Failed; + State = LoadState.Failed; } FailCount += exList.Count; - foreach (var file in files.Where(file => file.State < PCL.Network.NetState.Finished)) + foreach (var file in files.Where(file => file.State < NetState.Finished)) { - file.State = PCL.Network.NetState.Interrupted; + file.State = NetState.Interrupted; file.Speed = 0; file.ActiveThreads = 0; file.Errors.AddRange(exList); @@ -217,15 +216,15 @@ public override void Abort() { lock (lockState) { - if (State >= ModBase.LoadState.Finished) + if (State >= LoadState.Finished) return; - State = ModBase.LoadState.Aborted; + State = LoadState.Aborted; } _cancellationTokenSource?.Cancel(); - foreach (var file in files.Where(file => file.State < PCL.Network.NetState.Finished)) + foreach (var file in files.Where(file => file.State < NetState.Finished)) { - file.State = PCL.Network.NetState.Interrupted; + file.State = NetState.Interrupted; file.Speed = 0; file.ActiveThreads = 0; } diff --git a/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownloadUnc.cs b/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownloadUnc.cs index 402d2b565..f03ea975b 100644 --- a/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownloadUnc.cs +++ b/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownloadUnc.cs @@ -1,5 +1,5 @@ -using System.IO; -using System.Threading; +using System.IO; +using PCL.Core.App; namespace PCL.Network.Loaders; @@ -26,13 +26,13 @@ public override void Start(object input = null, bool isForceRestart = false) lock (lockState) { - if (State == ModBase.LoadState.Loading) + if (State == LoadState.Loading) return; - State = ModBase.LoadState.Loading; + State = LoadState.Loading; } _cancellationTokenSource = new CancellationTokenSource(); - ModBase.RunInNewThread(() => Run(_cancellationTokenSource.Token), $"UNC/{Uuid}"); + Basics.RunInNewThread(() => Run(_cancellationTokenSource.Token), $"UNC/{Uuid}"); } private void Run(CancellationToken cancellationToken) @@ -41,8 +41,8 @@ private void Run(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Directory.CreateDirectory(Path.GetDirectoryName(savePath) ?? throw new IOException("下载路径无效")); - ModBase.CopyFile(unc, savePath); - State = ModBase.LoadState.Finished; + LegacyFileFacade.CopyFile(unc, savePath); + State = LoadState.Finished; } catch (OperationCanceledException) { @@ -51,15 +51,15 @@ private void Run(CancellationToken cancellationToken) catch (Exception ex) { Error = ex; - State = ModBase.LoadState.Failed; + State = LoadState.Failed; } } public override void Abort() { - if (State >= ModBase.LoadState.Finished) + if (State >= LoadState.Finished) return; - State = ModBase.LoadState.Aborted; + State = LoadState.Aborted; _cancellationTokenSource?.Cancel(); } } diff --git a/Plain Craft Launcher 2/Modules/Network/Management/NetManager.cs b/Plain Craft Launcher 2/Modules/Network/Management/NetManager.cs index f12ea9745..15d899564 100644 --- a/Plain Craft Launcher 2/Modules/Network/Management/NetManager.cs +++ b/Plain Craft Launcher 2/Modules/Network/Management/NetManager.cs @@ -1,3 +1,5 @@ +using PCL.Network.Loaders; + namespace PCL.Network; public sealed class NetManager @@ -7,7 +9,7 @@ public sealed class NetManager public Dictionary Files { get; } = new(); public object LockFiles { get; } = new(); - public ModBase.SafeList Tasks { get; } = new(); + public SafeList Tasks { get; } = new(); public object LockRemain { get; } = new(); public int FileRemain { @@ -50,7 +52,7 @@ public int ThreadCount } } - public void Start(PCL.Network.Loaders.LoaderDownload task) + public void Start(LoaderDownload task) { lock (LockFiles) { @@ -61,7 +63,7 @@ public void Start(PCL.Network.Loaders.LoaderDownload task) } } - public void Finish(PCL.Network.Loaders.LoaderDownload task) + public void Finish(LoaderDownload task) { lock (LockFiles) { diff --git a/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs b/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs index de69c9298..57c42e6b3 100644 --- a/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs +++ b/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs @@ -1,14 +1,14 @@ -using PCL.Core.Utils; +using PCL.Network.Loaders; namespace PCL.Network; public class DownloadFile { - public int Id { get; } = ModBase.GetUuid(); + public int Id { get; } = LauncherRuntime.GetUuid(); public string LocalPath { get; set; } public string LocalName { get; } public List Urls { get; } - public ModBase.FileChecker? Check { get; } + public FileChecker? Check { get; } public bool UseBrowserUserAgent { get; } public string CustomUserAgent { get; } public NetState State { get; set; } = NetState.WaitingToCheck; @@ -17,7 +17,7 @@ public class DownloadFile public long DownloadedBytes { get; set; } public bool IsCopy { get; set; } public List Errors { get; } = new(); - public List Loaders { get; } = new(); + public List Loaders { get; } = new(); public long Speed { get; set; } public int ActiveThreads { get; set; } public double Progress @@ -39,12 +39,12 @@ public double Progress } } - public DownloadFile(IEnumerable urls, string localPath, ModBase.FileChecker? checker = null, + public DownloadFile(IEnumerable urls, string localPath, FileChecker? checker = null, bool useBrowserUserAgent = false, string customUserAgent = "") { Urls = urls.Where(url => !string.IsNullOrWhiteSpace(url)).Distinct().ToList(); LocalPath = localPath; - LocalName = ModBase.GetFileNameFromPath(localPath); + LocalName = LegacyFileFacade.GetFileNameFromPath(localPath); Check = checker; UseBrowserUserAgent = useBrowserUserAgent; CustomUserAgent = customUserAgent; diff --git a/Plain Craft Launcher 2/Modules/UI/HintService.cs b/Plain Craft Launcher 2/Modules/UI/HintService.cs index e8e117d4f..bd5c86313 100644 --- a/Plain Craft Launcher 2/Modules/UI/HintService.cs +++ b/Plain Craft Launcher 2/Modules/UI/HintService.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using PCL.Core.UI; namespace PCL; @@ -12,9 +12,9 @@ private struct HintMessage public bool Log; } - private static ModBase.SafeList HintWaiting + private static SafeList HintWaiting { - get => field ??= new ModBase.SafeList(); + get => field ??= new SafeList(); set; } @@ -80,19 +80,19 @@ internal static void Tick() HintType.Warning => "lucide/triangle-alert", _ => "lucide/info" }, - DisplayDuration = (800d + ModBase.MathClamp(currentHint.Text.Length, 5d, 23d) * 180d) * ModAnimation.aniSpeed + DisplayDuration = (800d + LauncherMath.Clamp(currentHint.Text.Length, 5d, 23d) * 180d) * ModAnimation.aniSpeed }; ModMain.frmMain.PanHint.Children.Add(toast); toast.Show(); if (currentHint.Log) - ModBase.Log("[UI] 弹出提示:" + currentHint.Text); + LauncherLog.Log("[UI] 弹出提示:" + currentHint.Text); HintWaiting.RemoveAt(0); } catch (Exception ex) { - ModBase.Log(ex, "显示弹出提示失败", ModBase.LogLevel.Normal); + LauncherLog.Log(ex, "显示弹出提示失败", LauncherLogLevel.Normal); } } diff --git a/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs b/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs index c7a2d0cf0..0570c3ada 100644 --- a/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs +++ b/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Media; using PCL.Core.App; @@ -14,23 +14,23 @@ public static class ThemeManager public static ResourceDictionary AppResources => System.Windows.Application.Current.Resources; - public static ModBase.MyColor colorGray1 = new(AppResources["ColorObjectGray1"]); - public static ModBase.MyColor colorGray4 = new(AppResources["ColorObjectGray4"]); - public static ModBase.MyColor colorGray5 = new(AppResources["ColorObjectGray5"]); - public static ModBase.MyColor colorSemiTransparent = new(AppResources["ColorBrushSemiTransparent"]); + public static MyColor colorGray1 = new(AppResources["ColorObjectGray1"]); + public static MyColor colorGray4 = new(AppResources["ColorObjectGray4"]); + public static MyColor colorGray5 = new(AppResources["ColorObjectGray5"]); + public static MyColor colorSemiTransparent = new(AppResources["ColorBrushSemiTransparent"]); public static void ThemeRefresh(int newTheme = -1) { - colorGray1 = new ModBase.MyColor(AppResources["ColorObjectGray1"]); - colorGray4 = new ModBase.MyColor(AppResources["ColorObjectGray4"]); - colorGray5 = new ModBase.MyColor(AppResources["ColorObjectGray5"]); - colorSemiTransparent = new ModBase.MyColor(AppResources["ColorBrushSemiTransparent"]); + colorGray1 = new MyColor(AppResources["ColorObjectGray1"]); + colorGray4 = new MyColor(AppResources["ColorObjectGray4"]); + colorGray5 = new MyColor(AppResources["ColorObjectGray5"]); + colorSemiTransparent = new MyColor(AppResources["ColorBrushSemiTransparent"]); ThemeRefreshMain(); } public static void ThemeRefreshMain() { - ModBase.RunInUi(() => + UiThread.Post(() => { if (!ModMain.frmMain.IsLoaded) return; RefreshBackground(); @@ -87,7 +87,7 @@ private static void RefreshAllContextMenuThemes() } catch (Exception ex) { - ModBase.Log(ex, "刷新ContextMenu主题时出错"); + LauncherLog.Log(ex, "刷新ContextMenu主题时出错"); } } diff --git a/Plain Craft Launcher 2/Modules/Updates/AnnouncementService.cs b/Plain Craft Launcher 2/Modules/Updates/AnnouncementService.cs index b48e9d8fe..a7b38ba8b 100644 --- a/Plain Craft Launcher 2/Modules/Updates/AnnouncementService.cs +++ b/Plain Craft Launcher 2/Modules/Updates/AnnouncementService.cs @@ -1,4 +1,4 @@ -using PCL.Core.App; +using PCL.Core.App; using PCL.Core.App.Localization; namespace PCL; @@ -18,9 +18,9 @@ public static void Load() .Where(x => !showedAnnounced.Contains(x.Id)) .ToList(); - ModBase.Log("[System] 需要展示的公告数量:" + showAnnounce.Count); + LauncherLog.Log("[System] 需要展示的公告数量:" + showAnnounce.Count); - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { foreach (var item in showAnnounce) { diff --git a/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs b/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs index cce26cda9..c258b9a52 100644 --- a/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs +++ b/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs @@ -27,7 +27,7 @@ public static bool IsCurrentVersionBeta { get { - if (ModBase.VersionBaseName.Contains("beta")) + if (LauncherEnvironment.VersionBaseName.Contains("beta")) return true; return (int)Config.Update.UpdateChannel == 1; } @@ -40,11 +40,11 @@ public static UpdateEnums.VersionStatus GetVersionStatus() if (IsCurrentVersionBeta && (int)Config.Update.UpdateChannel != 1) { var isNewerThanStable = remoteServer.IsLatest(UpdateChannel.stable, - SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.VersionBaseName), - ModBase.VersionCode); + SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(LauncherEnvironment.VersionBaseName), + LauncherEnvironment.VersionCode); var isBetaLatest = remoteServer.IsLatest(UpdateChannel.beta, - SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.VersionBaseName), - ModBase.VersionCode); + SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(LauncherEnvironment.VersionBaseName), + LauncherEnvironment.VersionCode); return isNewerThanStable && isBetaLatest ? UpdateEnums.VersionStatus.Latest : UpdateEnums.VersionStatus.NotLatest; @@ -52,17 +52,17 @@ public static UpdateEnums.VersionStatus GetVersionStatus() return remoteServer.IsLatest( IsCurrentVersionBeta ? UpdateChannel.beta : UpdateChannel.stable, - SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(ModBase.VersionBaseName), - ModBase.VersionCode) + SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, SemVer.Parse(LauncherEnvironment.VersionBaseName), + LauncherEnvironment.VersionCode) ? UpdateEnums.VersionStatus.Latest : UpdateEnums.VersionStatus.NotLatest; } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Update.Check.Failed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Update.Check.Failed")); return UpdateEnums.VersionStatus.Unknown; } @@ -72,8 +72,8 @@ public static UpdateEnums.VersionStatus GetVersionStatus() public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = null, bool forceValidated = false) { - var dlTargetPath = ModBase.exePath + @"PCL\Plain Craft Launcher Community Edition.exe"; - ModBase.RunInNewThread(() => + var dlTargetPath = LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Plain Craft Launcher Community Edition.exe"; + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -82,16 +82,16 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64 ); - ModBase.WriteFile($"{ModBase.pathTemp}CEUpdateLog.md", version.Changelog); - ModBase.Log($"[Update] 远程最新版本: {version.VersionName}, 当前版本: {ModBase.VersionBaseName}"); - if (!(SemVer.Parse(version.VersionName) > SemVer.Parse(ModBase.VersionBaseName))) + LegacyFileFacade.WriteFile($"{LauncherPaths.TempWithSlash}CEUpdateLog.md", version.Changelog); + LauncherLog.Log($"[Update] 远程最新版本: {version.VersionName}, 当前版本: {LauncherEnvironment.VersionBaseName}"); + if (!(SemVer.Parse(version.VersionName) > SemVer.Parse(LauncherEnvironment.VersionBaseName))) return; if (type == UpdateEnums.UpdateType.PromptOnly) { - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.MyMsgBox( - Lang.Text("Update.Available", ModBase.VersionBaseName, version.VersionName), + Lang.Text("Update.Available", LauncherEnvironment.VersionBaseName, version.VersionName), Lang.Text("Update.Title"), Lang.Text("Update.Action"), Lang.Text("Common.Action.Cancel") @@ -109,7 +109,7 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, dlTargetPath)); loaders.Add(new ModLoader.LoaderTask(Lang.Text("Update.Task.Check"), _ => { - var curHash = ModBase.GetFileSHA256(dlTargetPath); + var curHash = LegacyFileFacade.GetFileSha256(dlTargetPath); if ((curHash ?? "") != (version.Sha256 ?? "")) throw new Exception(Lang.Text("Update.Error.Sha256Mismatch", version.Sha256, curHash)); })); @@ -121,10 +121,10 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = loaders.Add(new ModLoader.LoaderTask(Lang.Text("Update.Task.ShowButton"), _ => { isUpdateWaitingRestart = true; - ModBase.RunInUi(() => + UiThread.Post(() => { ModMain.frmMain.BtnExtraUpdateRestart.ToolTip = - Lang.Text("Main.Extra.UpdateRestart.ToolTipWithVersion", ModBase.VersionBaseName, version.VersionName); + Lang.Text("Main.Extra.UpdateRestart.ToolTipWithVersion", LauncherEnvironment.VersionBaseName, version.VersionName); ModMain.frmMain.BtnExtraUpdateRestart.ShowRefresh(); ModMain.frmMain.BtnExtraUpdateRestart.Ribble(); }); @@ -135,7 +135,7 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = loaders.Add(new ModLoader.LoaderTask(Lang.Text("Update.Task.RefreshSettings"), _ => { if (ModMain.frmSetupUpdate is not null) - ModBase.RunInUi(() => + UiThread.Post(() => { ModMain.frmSetupUpdate.BtnUpdate.Text = Lang.Text("Update.Task.RestartInstall"); ModMain.frmSetupUpdate.BtnUpdate.IsEnabled = true; @@ -156,7 +156,7 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = } catch (Exception ex) { - ModBase.Log(ex, "[Update] 获取启动器更新失败"); + LauncherLog.Log(ex, "[Update] 获取启动器更新失败"); if (type != UpdateEnums.UpdateType.Silent) HintService.Hint(Lang.Text("Update.Error.FetchFailed"), HintType.Error); } @@ -167,30 +167,30 @@ public static void UpdateRestart(bool triggerRestartAndByEnd, bool triggerRestar { try { - var fileName = ModBase.exePath + @"PCL\Plain Craft Launcher Community Edition.exe"; + var fileName = LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Plain Craft Launcher Community Edition.exe"; if (!File.Exists(fileName)) { - ModBase.Log("[System] 更新失败:未找到更新文件"); + LauncherLog.Log("[System] 更新失败:未找到更新文件"); return; } // id old new restart var text = $"update {Process.GetCurrentProcess().Id} \"{Basics.ExecutablePath}\" \"{fileName}\" {(triggerRestart ? "true" : "false")}"; - ModBase.Log("[System] 更新程序启动,参数:" + text); + LauncherLog.Log("[System] 更新程序启动,参数:" + text); Process.Start(new ProcessStartInfo(fileName) { WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, Arguments = text }); if (triggerRestartAndByEnd) { ModMain.frmMain.EndProgram(false, true); - ModBase.Log("[System] 已由于更新强制结束程序"); + LauncherLog.Log("[System] 已由于更新强制结束程序"); } } catch (Win32Exception ex) { - ModBase.Log(ex, "自动更新时触发 Win32 错误,疑似被拦截"); + LauncherLog.Log(ex, "自动更新时触发 Win32 错误,疑似被拦截"); ModMain.MyMsgBox( - Lang.Text("Update.Error.UpdateBlockedMessage", ModBase.exePath), + Lang.Text("Update.Error.UpdateBlockedMessage", LauncherPaths.ExecutableDirectoryWithSlash), Lang.Text("Update.Error.UpdateBlocked"), Lang.Text("Common.Action.Confirm"), "", @@ -206,20 +206,20 @@ public static void UpdateRestart(bool triggerRestartAndByEnd, bool triggerRestar internal static void DownloadLatestPCL(ModLoader.LoaderBase loaderToSyncProgress = null) { // 注意:如果要自行实现这个功能,请换用另一个文件路径,以免与官方版本冲突 - var latestPCLPath = Path.Combine(ModBase.pathTemp, "CE-Latest.exe"); + var latestPCLPath = Path.Combine(LauncherPaths.TempWithSlash, "CE-Latest.exe"); var target = remoteServer.GetLatestVersion(UpdateChannel.stable, SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64); if (target is null) throw new Exception(Lang.Text("Update.Error.UnableToGetUpdate")); - if (File.Exists(latestPCLPath) && (ModBase.GetFileSHA256(latestPCLPath) ?? "") == (target.Sha256 ?? "")) + if (File.Exists(latestPCLPath) && (LegacyFileFacade.GetFileSha256(latestPCLPath) ?? "") == (target.Sha256 ?? "")) { - ModBase.Log("[System] 最新版 PCL 已存在,跳过下载"); + LauncherLog.Log("[System] 最新版 PCL 已存在,跳过下载"); return; } - if ((ModBase.GetFileSHA256(Basics.ExecutablePath) ?? "") == (target.Sha256 ?? "")) // 正在使用的版本符合要求,直接拿来用 + if ((LegacyFileFacade.GetFileSha256(Basics.ExecutablePath) ?? "") == (target.Sha256 ?? "")) // 正在使用的版本符合要求,直接拿来用 { - ModBase.CopyFile(Basics.ExecutablePath, latestPCLPath); + LegacyFileFacade.CopyFile(Basics.ExecutablePath, latestPCLPath); return; } @@ -246,20 +246,20 @@ private static void ScheduleBasedOnConfig() switch (Config.Update.UpdateMode) { case LauncherAutoUpdateBehavior.DownloadAndInstall: - ModBase.Log("[Update] 更新设置: 自动下载并安装更新"); + LauncherLog.Log("[Update] 更新设置: 自动下载并安装更新"); if (GetVersionStatus() != UpdateEnums.VersionStatus.Latest) UpdateStart(UpdateEnums.UpdateType.Silent); break; case LauncherAutoUpdateBehavior.DownloadAndAnnounce: - ModBase.Log("[Update] 更新设置: 自动下载并提示更新"); + LauncherLog.Log("[Update] 更新设置: 自动下载并提示更新"); UpdateStart(UpdateEnums.UpdateType.DownloadAndPrompt); break; case LauncherAutoUpdateBehavior.AnnounceOnly: - ModBase.Log("[Update] 更新设置: 提示更新"); + LauncherLog.Log("[Update] 更新设置: 提示更新"); UpdateStart(UpdateEnums.UpdateType.PromptOnly); break; default: - ModBase.Log("[Update] 更新设置: 不自动检查更新"); + LauncherLog.Log("[Update] 更新设置: 不自动检查更新"); return; } } diff --git a/Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs b/Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs index 2848dd741..a94bf554e 100644 --- a/Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs +++ b/Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.IO.Compression; using System.Net.Http; using System.Text.Json.Serialization; @@ -35,7 +35,7 @@ public bool RefreshCache() { // 先检查缓存 var remoteCache = - ModBase.GetJson(Requester.FetchString($"{_baseUrl}apiv2/cache.json", RequestParam.WithRetry)); + PCL.Core.Utils.JsonCompat.ParseNode(Requester.FetchString($"{_baseUrl}apiv2/cache.json", RequestParam.WithRetry)); _remoteCache = remoteCache.ToObject>(); return true; } @@ -72,7 +72,7 @@ public VersionAnnouncementDataModel GetAnnouncementList() RefreshCache(); var loaders = new List(); var patchUpdate = true; - var tempPath = $@"{ModBase.pathTemp}Cache\Update\Download\"; + var tempPath = $@"{LauncherPaths.TempWithSlash}Cache\Update\Download\"; loaders.Add(new ModLoader.LoaderTask>(Lang.Text("Update.Task.GetVersionInfo"), load => { var channelName = GetChannelName(channel, arch); @@ -82,7 +82,7 @@ public VersionAnnouncementDataModel GetAnnouncementList() ?.FirstOrDefault(); if (deJsonData is null) throw new Exception("No assets can download!"); - var selfSha256 = ModBase.GetFileSHA256(Basics.ExecutablePath); + var selfSha256 = LegacyFileFacade.GetFileSha256(Basics.ExecutablePath); var remoteUpdSha256 = deJsonData.Sha256; var patchFileName = $"{selfSha256}_{remoteUpdSha256}.patch"; if (deJsonData.Patches.Contains(patchFileName)) @@ -107,9 +107,9 @@ public VersionAnnouncementDataModel GetAnnouncementList() { var diff = new BsDiff(); var newFile = diff - .ApplyAsync(ModBase.ReadFileBytes(Basics.ExecutablePath), ModBase.ReadFileBytes(tempPath)) + .ApplyAsync(LegacyFileFacade.ReadBytes(Basics.ExecutablePath), LegacyFileFacade.ReadBytes(tempPath)) .GetAwaiter().GetResult(); - ModBase.WriteFile(output, newFile); + LegacyFileFacade.WriteFile(output, newFile); } else { @@ -158,11 +158,11 @@ private VersionDataModel GetChannelInfo(UpdateChannel channel, UpdateArch arch) private JsonNode GetRemoteInfoByName(string name, string path = "") { - var localInfoFile = Path.Combine(ModBase.pathTemp, "Cache", "Update", $"{name}.json"); + var localInfoFile = Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Update", $"{name}.json"); JsonNode jsonData; if (IsCacheValid($"{name}.json", _remoteCache[name])) { - jsonData = ModBase.GetJson(ModBase.ReadFile(localInfoFile)); + jsonData = PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(localInfoFile)); } else { @@ -172,8 +172,8 @@ private JsonNode GetRemoteInfoByName(string name, string path = "") .GetResult(); var content = response.AsString(); - jsonData = ModBase.GetJson(content); - ModBase.WriteFile(localInfoFile, content); + jsonData = PCL.Core.Utils.JsonCompat.ParseNode(content); + LegacyFileFacade.WriteFile(localInfoFile, content); } return jsonData; @@ -187,10 +187,10 @@ private JsonNode GetRemoteInfoByName(string name, string path = "") /// private bool IsCacheValid(string path, string hash) { - var cacheFile = Path.Combine(ModBase.pathTemp, "Cache", "Update", path); + var cacheFile = Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Update", path); var fileInfo = new FileInfo(cacheFile); return fileInfo.Exists && (DateTime.Now - fileInfo.LastWriteTime).TotalHours < 1 && - (ModBase.GetFileMD5(cacheFile) ?? "") == (hash ?? ""); + (LegacyFileFacade.GetFileMd5(cacheFile) ?? "") == (hash ?? ""); } private string GetChannelName(UpdateChannel channel, UpdateArch arch) diff --git a/Plain Craft Launcher 2/Modules/Updates/UpdatesMirrorChyanModel.cs b/Plain Craft Launcher 2/Modules/Updates/UpdatesMirrorChyanModel.cs index 335f4eb1e..a46b1e89f 100644 --- a/Plain Craft Launcher 2/Modules/Updates/UpdatesMirrorChyanModel.cs +++ b/Plain Craft Launcher 2/Modules/Updates/UpdatesMirrorChyanModel.cs @@ -1,4 +1,4 @@ -using System.Net.Http; +using System.Net.Http; using PCL.Core.App; using PCL.Core.App.Localization; using PCL.Core.Utils; @@ -28,7 +28,7 @@ public VersionDataModel GetLatestVersion(UpdateChannel channel, UpdateArch arch) .GetAwaiter() .GetResult()) { - var ret = (JsonObject)ModBase.GetJson(response.AsString()); + var ret = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(response.AsString()); if ((int)ret["code"] != 0) throw new Exception("Mirror 酱获取数据不成功"); var data = ret["data"]; diff --git a/Plain Craft Launcher 2/Modules/Updates/UpdatesWrapperModel.cs b/Plain Craft Launcher 2/Modules/Updates/UpdatesWrapperModel.cs index 644ec66ce..bfb7cb30c 100644 --- a/Plain Craft Launcher 2/Modules/Updates/UpdatesWrapperModel.cs +++ b/Plain Craft Launcher 2/Modules/Updates/UpdatesWrapperModel.cs @@ -1,4 +1,4 @@ -using PCL.Core.App.Localization; +using PCL.Core.App.Localization; using PCL.Core.Utils; namespace PCL; @@ -41,7 +41,7 @@ public bool RefreshCache() } catch (Exception ex) { - ModBase.Log(ex, $"[Update] {item.SourceName} 暂不可用"); + LauncherLog.Log(ex, $"[Update] {item.SourceName} 暂不可用"); } return _versionSource is not null; @@ -59,7 +59,7 @@ public VersionDataModel GetLatestVersion(UpdateChannel channel, UpdateArch arch) } catch (Exception ex) { - ModBase.Log(ex, $"[Update] 缓存的版本源 {_versionSource.SourceName} 不可用"); + LauncherLog.Log(ex, $"[Update] 缓存的版本源 {_versionSource.SourceName} 不可用"); } var ret = item.GetLatestVersion(channel, arch); @@ -68,10 +68,10 @@ public VersionDataModel GetLatestVersion(UpdateChannel channel, UpdateArch arch) } catch (Exception ex) { - ModBase.Log(ex, $"[Update] {item.SourceName} 无法获取最新版本信息"); + LauncherLog.Log(ex, $"[Update] {item.SourceName} 无法获取最新版本信息"); } - ModBase.Log("[Update] 错误!所有的版本源都无法使用!"); + LauncherLog.Log("[Update] 错误!所有的版本源都无法使用!"); throw new Exception(Lang.Text("Update.Task.GetVersionInfoFailed")); } @@ -87,7 +87,7 @@ public bool IsLatest(UpdateChannel channel, UpdateArch arch, SemVer currentVersi } catch (Exception ex) { - ModBase.Log(ex, $"[Update] 缓存的版本源 {_versionSource.SourceName} 不可用"); + LauncherLog.Log(ex, $"[Update] 缓存的版本源 {_versionSource.SourceName} 不可用"); } var ret = item.IsLatest(channel, arch, currentVersion, currentVersionCode); @@ -96,10 +96,10 @@ public bool IsLatest(UpdateChannel channel, UpdateArch arch, SemVer currentVersi } catch (Exception ex) { - ModBase.Log(ex, $"[Update] {item.SourceName} 无法获取最新版本信息"); + LauncherLog.Log(ex, $"[Update] {item.SourceName} 无法获取最新版本信息"); } - ModBase.Log("[Update] 错误!所有的版本源都无法使用!"); + LauncherLog.Log("[Update] 错误!所有的版本源都无法使用!"); throw new Exception(Lang.Text("Update.Task.GetVersionInfoFailed")); } @@ -115,7 +115,7 @@ public VersionAnnouncementDataModel GetAnnouncementList() } catch (Exception ex) { - ModBase.Log(ex, $"[Update] 缓存的公告源 {_announcementSource.SourceName} 不可用"); + LauncherLog.Log(ex, $"[Update] 缓存的公告源 {_announcementSource.SourceName} 不可用"); } var ret = item.GetAnnouncementList(); @@ -124,10 +124,10 @@ public VersionAnnouncementDataModel GetAnnouncementList() } catch (Exception ex) { - ModBase.Log(ex, $"[Update] {item.SourceName} 无法获取最新公告信息"); + LauncherLog.Log(ex, $"[Update] {item.SourceName} 无法获取最新公告信息"); } - ModBase.Log("[Update] 错误!所有的公告源都无法使用!"); + LauncherLog.Log("[Update] 错误!所有的公告源都无法使用!"); throw new Exception(Lang.Text("Update.Task.GetAnnouncementFailed")); } @@ -143,7 +143,7 @@ public VersionAnnouncementDataModel GetAnnouncementList() } catch (Exception ex) { - ModBase.Log(ex, $"[Update] 缓存的版本源 {_versionSource.SourceName} 不可用"); + LauncherLog.Log(ex, $"[Update] 缓存的版本源 {_versionSource.SourceName} 不可用"); } var ret = item.GetDownloadLoader(channel, arch, output); @@ -152,10 +152,10 @@ public VersionAnnouncementDataModel GetAnnouncementList() } catch (Exception ex) { - ModBase.Log(ex, $"[Update] {item.SourceName} 无法获取最新版本信息"); + LauncherLog.Log(ex, $"[Update] {item.SourceName} 无法获取最新版本信息"); } - ModBase.Log("[Update] 错误!所有的版本源都无法使用!"); + LauncherLog.Log("[Update] 错误!所有的版本源都无法使用!"); throw new Exception(Lang.Text("Update.Task.GetVersionInfoFailed")); } diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.cs index 2cebfa044..a0c805cfe 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; @@ -99,7 +99,7 @@ public void RefreshColor(object sender, EventArgs e) #region 基础属性 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); // Logo public string Logo @@ -183,7 +183,7 @@ private bool IsTextTrimmed(TextBlock textBlock) var typeface = new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch); var formattedText = new FormattedText(textBlock.Text, Thread.CurrentThread.CurrentCulture, - textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground, ModBase.dpi); + textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground, DpiUtils.Dpi); return formattedText.Width > textBlock.ActualWidth; } @@ -292,7 +292,7 @@ private void MyCompItem_Click(MyCompItem sender, EventArgs e) foreach (MyCard Card in ModMain.frmDownloadCompDetail.PanResults.Children) if (!string.IsNullOrEmpty(Card.Title) && !Card.IsSwapped) titles.Add(Card.Title); - ModBase.Log("[Comp] 记录当前已展开的卡片:" + string.Join("、", titles)); + LauncherLog.Log("[Comp] 记录当前已展开的卡片:" + string.Join("、", titles)); var additional = ModMain.frmMain.pageCurrent.additional.Value; ModMain.frmMain.pageCurrent.additional = additional with { ExpandedTitles = titles }; } @@ -443,7 +443,7 @@ public Border RectBack CornerRadius = new CornerRadius(3d), RenderTransform = new ScaleTransform(0.8d, 0.8d), RenderTransformOrigin = new Point(0.5d, 0.5d), - BorderThickness = new Thickness(ModBase.GetWPFSize(1d)), + BorderThickness = new Thickness(DpiUtils.GetWpfSize(1d)), SnapsToDevicePixels = true, IsHitTestVisible = false, Opacity = 0d diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.cs index e7a913cff..e44d5e25e 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.cs @@ -23,7 +23,7 @@ private void Load_OnFinish() { try { - ModBase.Log($"[Comp] 开始可视化{TypeNameSpaced}列表,已储藏 {storage.results.Count} 个结果,当前在第 {page + 1} 页"); + LauncherLog.Log($"[Comp] 开始可视化{TypeNameSpaced}列表,已储藏 {storage.results.Count} 个结果,当前在第 {page + 1} 页"); // 列表项 PanProjects.Children.Clear(); var index = Math.Min(page * pageSize, storage.results.Count - 1); @@ -69,10 +69,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"可视化{TypeNameSpaced}列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Comp.Error.OperationFailed")); } } @@ -82,14 +82,14 @@ private void Load_State(object sender, MyLoading.MyLoadingState state, MyLoading { switch (loader.State) { - case ModBase.LoadState.Failed: + case LoadState.Failed: { var errorMessage = ""; if (loader.Error is not null) errorMessage = loader.Error.Message; if (errorMessage.Contains(Lang.Text("Common.Error.InvalidJson"))) { - ModBase.Log($"[Download] 下载的{TypeNameSpaced}列表 json 文件损坏,已自动重试", ModBase.LogLevel.Debug); + LauncherLog.Log($"[Download] 下载的{TypeNameSpaced}列表 json 文件损坏,已自动重试", LauncherLogLevel.Debug); ((MyPageRight)Parent).PageLoaderRestart(); } @@ -119,11 +119,11 @@ private void ChangePage(int newPage) CardPages.IsEnabled = false; page = newPage; ModMain.frmMain.BackToTop(); - ModBase.Log($"[Download] {TypeName}:切换到第 {page + 1} 页"); - ModBase.RunInThread(() => + LauncherLog.Log($"[Download] {TypeName}:切换到第 {page + 1} 页"); + UiThread.RunInThread(() => { Thread.Sleep(100); // 等待向上滚的动画结束 - ModBase.RunInUi(() => CardPages.IsEnabled = true); + UiThread.Post(() => CardPages.IsEnabled = true); loader.Start(); }); } @@ -147,7 +147,7 @@ public void RefreshAllFavoriteStatus() } catch (Exception ex) { - ModBase.Log(ex, "刷新收藏状态时出错"); + LauncherLog.Log(ex, "刷新收藏状态时出错"); } } @@ -320,8 +320,8 @@ private ModComp.CompProjectRequest LoaderInput() var modLoader = ModComp.CompLoaderType.Any; if (PageType == ModComp.CompType.Mod || PageType == ModComp.CompType.ModPack) // 只有 Mod 考虑加载器 { - modLoader = (ModComp.CompLoaderType)ModBase.Val(((MyComboBoxItem)ComboSearchLoader.SelectedItem).Tag); - if (gameVersion is not null && gameVersion.Contains(".") && ModBase.Val(gameVersion.Split(".")[1]) < 14d && + modLoader = (ModComp.CompLoaderType)LauncherText.Val(((MyComboBoxItem)ComboSearchLoader.SelectedItem).Tag); + if (gameVersion is not null && gameVersion.Contains(".") && LauncherText.Val(gameVersion.Split(".")[1]) < 14d && modLoader == ModComp.CompLoaderType.Forge) // 1.14- // 选择了 Forge modLoader = ModComp.CompLoaderType.Any; // 此时,视作没有筛选 Mod Loader(因为部分老 Mod 没有设置自己支持的加载器) @@ -339,10 +339,10 @@ private ModComp.CompProjectRequest LoaderInput() : selectedTag; request.modLoader = (ModComp.CompLoaderType)(PageType == ModComp.CompType.Mod || PageType == ModComp.CompType.ModPack - ? ModBase.Val(((MyComboBoxItem)ComboSearchLoader.SelectedItem).Tag) + ? LauncherText.Val(((MyComboBoxItem)ComboSearchLoader.SelectedItem).Tag) : (double)ModComp.CompLoaderType.Any); - request.source = (ModComp.CompSourceType)ModBase.Val(((MyComboBoxItem)ComboSearchSource.SelectedItem).Tag); - request.sort = (ModComp.CompSortType)ModBase.Val(((MyComboBoxItem)ComboSearchSort.SelectedItem).Tag); + request.source = (ModComp.CompSourceType)LauncherText.Val(((MyComboBoxItem)ComboSearchSource.SelectedItem).Tag); + request.sort = (ModComp.CompSortType)LauncherText.Val(((MyComboBoxItem)ComboSearchSort.SelectedItem).Tag); return request; } diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.cs index df2ee66d9..02c882f5a 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.cs @@ -99,19 +99,19 @@ public void Install_Click(MyListItem sender, EventArgs e) { switch (myLoader.State) { - case ModBase.LoadState.Failed: + case LoadState.Failed: { HintService.Hint( Lang.Text("Download.Comp.Detail.Task.Failed", myLoader.name, myLoader.Error.ToString()), HintType.Error); break; } - case ModBase.LoadState.Aborted: + case LoadState.Aborted: { HintService.Hint(Lang.Text("Download.Comp.Detail.Task.Cancelled", myLoader.name)); break; } - case ModBase.LoadState.Loading: + case LoadState.Loading: { return; // 不重新加载版本列表 } @@ -128,10 +128,10 @@ public void Install_Click(MyListItem sender, EventArgs e) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "下载资源整合包失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Comp.Error.OperationFailed")); } } @@ -154,7 +154,7 @@ public void InstallWorld_Click(MyListItem sender, EventArgs e) if (file.ModLoaders.Any()) allowedLoaders = file.ModLoaders; else if (_project.ModLoaders.Any()) allowedLoaders = _project.ModLoaders; - ModBase.Log("[Comp] 世界要求的加载器种类:" + (allowedLoaders.Any() ? allowedLoaders.Join(" / ") : "无要求")); + LauncherLog.Log("[Comp] 世界要求的加载器种类:" + (allowedLoaders.Any() ? allowedLoaders.Join(" / ") : "无要求")); // 判断某个版本是否符合资源要求 isVersionSuitable = version => { @@ -174,19 +174,19 @@ public void InstallWorld_Click(MyListItem sender, EventArgs e) if (cachedFolder.ContainsKey(file.Type) && !string.IsNullOrEmpty(cachedFolder[file.Type])) { defaultFolder = cachedFolder.GetOrDefault(file.Type, - ModInstanceList.McMcInstanceSelected?.PathIndie ?? ModBase.exePath); - ModBase.Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{defaultFolder}"); + ModInstanceList.McMcInstanceSelected?.PathIndie ?? LauncherPaths.ExecutableDirectoryWithSlash); + LauncherLog.Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{defaultFolder}"); } else if (ModInstanceList.McMcInstanceSelected is not null && isVersionSuitable(ModInstanceList.McMcInstanceSelected)) { defaultFolder = $"{ModInstanceList.McMcInstanceSelected.PathIndie}{subFolder}"; Directory.CreateDirectory(defaultFolder); - ModBase.Log($"[Comp] 使用当前实例作为默认下载位置:{defaultFolder}"); + LauncherLog.Log($"[Comp] 使用当前实例作为默认下载位置:{defaultFolder}"); } else { // 查找所有可能的实例 - var needLoad = ModInstanceList.mcInstanceListLoader.State != ModBase.LoadState.Finished; + var needLoad = ModInstanceList.mcInstanceListLoader.State != LoadState.Finished; if (needLoad) { HintService.Hint(Lang.Text("Download.Comp.Detail.FindingApplicableInstance")); @@ -204,7 +204,7 @@ public void InstallWorld_Click(MyListItem sender, EventArgs e) // 再按文件夹中的文件数量降序 defaultFolder = selectedVersion.FullName; Directory.CreateDirectory(defaultFolder); - ModBase.Log($"[Comp] 使用适合的游戏实例作为默认下载位置:{defaultFolder}"); + LauncherLog.Log($"[Comp] 使用适合的游戏实例作为默认下载位置:{defaultFolder}"); } else { @@ -212,7 +212,7 @@ public void InstallWorld_Click(MyListItem sender, EventArgs e) if (needLoad) HintService.Hint(Lang.Text("Download.Comp.Detail.NoApplicableInstance")); else - ModBase.Log("[Comp] 由于当前实例不兼容,使用当前的 MC 文件夹作为默认下载位置"); + LauncherLog.Log("[Comp] 由于当前实例不兼容,使用当前的 MC 文件夹作为默认下载位置"); } } @@ -228,7 +228,7 @@ public void InstallWorld_Click(MyListItem sender, EventArgs e) loaders.Add(new LoaderDownload(Lang.Text("Download.Comp.Detail.DownloadWorldFile"), new List { file.ToNetFile(target) }) { ProgressWeight = 10d, block = true }); loaders.Add(new ModLoader.LoaderTask(Lang.Text("Download.Comp.Detail.InstallWorld"), - _ => ModBase.ExtractFile(target, targetPath, Encoding.UTF8)) { ProgressWeight = 0.1d, block = true }); + _ => LegacyFileFacade.ExtractFile(target, targetPath, Encoding.UTF8)) { ProgressWeight = 0.1d, block = true }); loaders.Add(new ModLoader.LoaderTask(Lang.Text("Download.Comp.Detail.CleanCache"), _ => System.IO.File.Delete(target))); @@ -243,10 +243,10 @@ public void InstallWorld_Click(MyListItem sender, EventArgs e) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "下载世界资源失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Comp.Error.OperationFailed")); } } @@ -262,7 +262,7 @@ public void Save_Click(object sender, EventArgs e) _ => null }; - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -296,7 +296,7 @@ public void Save_Click(object sender, EventArgs e) if (file.ModLoaders.Any()) allowedLoaders = file.ModLoaders; else if (_project.ModLoaders.Any()) allowedLoaders = _project.ModLoaders; - ModBase.Log( + LauncherLog.Log( $"[Comp] {desc}要求的加载器种类:{(allowedLoaders.Any() ? string.Join(" / ", allowedLoaders) : "无要求")}"); // 判断某个版本是否符合资源要求 (局部函数) @@ -327,20 +327,20 @@ public void Save_Click(object sender, EventArgs e) if (cachedFolder.ContainsKey(file.Type) && !string.IsNullOrEmpty(cachedFolder[file.Type])) { defaultFolder = cachedFolder.GetOrDefault(file.Type, - ModInstanceList.McMcInstanceSelected?.PathIndie ?? ModBase.exePath); - ModBase.Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{defaultFolder}"); + ModInstanceList.McMcInstanceSelected?.PathIndie ?? LauncherPaths.ExecutableDirectoryWithSlash); + LauncherLog.Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{defaultFolder}"); } else if (ModInstanceList.McMcInstanceSelected is not null && isVersionSuitable(ModInstanceList.McMcInstanceSelected)) { defaultFolder = $"{ModInstanceList.McMcInstanceSelected.PathIndie}{subFolder}"; Directory.CreateDirectory(defaultFolder); - ModBase.Log($"[Comp] 使用当前实例作为默认下载位置:{defaultFolder}"); + LauncherLog.Log($"[Comp] 使用当前实例作为默认下载位置:{defaultFolder}"); } else { // 查找所有可能的实例 - var needLoad = ModInstanceList.mcInstanceListLoader.State != ModBase.LoadState.Finished; + var needLoad = ModInstanceList.mcInstanceListLoader.State != LoadState.Finished; if (needLoad) { HintService.Hint(Lang.Text("Download.Comp.Detail.FindingApplicableInstance")); @@ -360,7 +360,7 @@ public void Save_Click(object sender, EventArgs e) .First(); defaultFolder = selectedVersion.FullName; Directory.CreateDirectory(defaultFolder); - ModBase.Log($"[Comp] 使用适合的游戏实例作为默认下载位置:{defaultFolder}"); + LauncherLog.Log($"[Comp] 使用适合的游戏实例作为默认下载位置:{defaultFolder}"); } else { @@ -368,14 +368,14 @@ public void Save_Click(object sender, EventArgs e) if (needLoad) HintService.Hint(Lang.Text("Download.Comp.Detail.NoApplicableInstance")); else - ModBase.Log("[Comp] 由于当前实例不兼容,使用当前的 MC 文件夹作为默认下载位置"); + LauncherLog.Log("[Comp] 由于当前实例不兼容,使用当前的 MC 文件夹作为默认下载位置"); } } } // 获取文件名并弹窗 var fileName = ModComp.CompFileNameGet(_project, file); - ModBase.RunInUi(() => + UiThread.Post(() => { var target = SystemDialogs.SelectSaveFile(Lang.Text("Download.Comp.Detail.SelectSaveLocation"), fileName, Lang.Text("Download.Comp.Detail.ResourceFile.Filter", desc) + "|" + @@ -389,7 +389,7 @@ public void Save_Click(object sender, EventArgs e) if (!target.Contains("\\")) return; // 记录缓存路径 - var targetDir = ModBase.GetPathFromFullPath(target); + var targetDir = LegacyFileFacade.GetPathFromFullPath(target); if (target != defaultFolder) { if (cachedFolder.ContainsKey(file.Type)) @@ -444,7 +444,7 @@ public void Save_Click(object sender, EventArgs e) targetLoaders = allowedLoaders.ToList(); } - ModBase.Log($"[CompDeps] 开始解析必需前置: {file.Dependencies.Count} 个依赖"); + LauncherLog.Log($"[CompDeps] 开始解析必需前置: {file.Dependencies.Count} 个依赖"); var request = ModCompDependency.BuildRequest(file, _project, mcVersion, targetLoaders, targetDir); var resolver = new ModDependencyResolver(); @@ -454,16 +454,16 @@ void DownloadDependencies() { if (!result.ToInstall.Any()) { - ModBase.Log("[CompDeps] 所有前置均无法解析,仅下载 Mod 本体"); + LauncherLog.Log("[CompDeps] 所有前置均无法解析,仅下载 Mod 本体"); return; } - ModBase.Log($"[CompDeps] 准备下载: {result.ToInstall.Count} 个前置"); + LauncherLog.Log($"[CompDeps] 准备下载: {result.ToInstall.Count} 个前置"); var depDownloads = ModCompDependency.BuildDependencyDownloads(result, targetDir); foreach (var (depFilename, downloadFile) in depDownloads) { var depLoaderName = Lang.Text("Download.Comp.Detail.DownloadResource", desc, - ModBase.GetFileNameWithoutExtentionFromPath(depFilename)); + LegacyFileFacade.GetFileNameWithoutExtensionFromPath(depFilename)); var depLoaders = new List { new LoaderDownload(Lang.Text("Download.Comp.Detail.DownloadFile"), @@ -489,7 +489,7 @@ void DownloadDependencies() switch (installChoice) { case ModComp.CompDepsInstallTypes.Unresolved: - ModBase.Log("[CompDeps] 发现无法解析的前置"); + LauncherLog.Log("[CompDeps] 发现无法解析的前置"); DownloadDependencies(); break; @@ -498,26 +498,26 @@ void DownloadDependencies() break; case ModComp.CompDepsInstallTypes.WithoutDeps: - ModBase.Log("[CompDeps] 用户选择仅下载 Mod 本体,跳过前置下载"); + LauncherLog.Log("[CompDeps] 用户选择仅下载 Mod 本体,跳过前置下载"); break; case ModComp.CompDepsInstallTypes.Cancel: - ModBase.Log("[CompDeps] 用户取消安装"); + LauncherLog.Log("[CompDeps] 用户取消安装"); return; default: - ModBase.Log($"[CompDeps] 未知返回值: {installChoice} ,终止下载"); + LauncherLog.Log($"[CompDeps] 未知返回值: {installChoice} ,终止下载"); return; } } else { - ModBase.Log("[CompDeps] 已满足: 所有必需前置已安装"); + LauncherLog.Log("[CompDeps] 已满足: 所有必需前置已安装"); } } catch (Exception depEx) { - ModBase.Log(depEx, "[CompDeps] 依赖解析失败,跳过前置安装"); + LauncherLog.Log(depEx, "[CompDeps] 依赖解析失败,跳过前置安装"); var message = ExceptionDetails.Compose( Lang.Text("Download.Comp.Dependency.ResolveFailed.Message"), depEx); @@ -532,7 +532,7 @@ void DownloadDependencies() // 构造下载任务 var loaderName = Lang.Text("Download.Comp.Detail.DownloadResource", desc, - ModBase.GetFileNameWithoutExtentionFromPath(target)); + LegacyFileFacade.GetFileNameWithoutExtensionFromPath(target)); var loaders = new List { new LoaderDownload(Lang.Text("Download.Comp.Detail.DownloadFile"), @@ -555,10 +555,10 @@ void DownloadDependencies() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "保存资源文件失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Comp.Error.OperationFailed")); } }, "Download CompDetail Save"); @@ -566,17 +566,17 @@ void DownloadDependencies() private void BtnIntroWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite(_project.Website); + LauncherProcess.OpenWebsite(_project.Website); } private void BtnIntroWiki_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://www.mcmod.cn/class/" + _project.WikiId + ".html"); + LauncherProcess.OpenWebsite("https://www.mcmod.cn/class/" + _project.WikiId + ".html"); } private void BtnIntroCopy_Click(object sender, EventArgs e) { - ModBase.ClipboardSet(_compItem.LabTitle.Text + _compItem.LabTitleRaw.Text); + LauncherProcess.ClipboardSet(_compItem.LabTitle.Text + _compItem.LabTitleRaw.Text); } private void BtnFavorites_Click(object sender, EventArgs e) @@ -587,7 +587,7 @@ private void BtnFavorites_Click(object sender, EventArgs e) private void BtnIntroLinkCopy_Click(object sender, EventArgs e) { ModComp.CompClipboard.currentText = _project.Website; - ModBase.ClipboardSet(_project.Website); + LauncherProcess.ClipboardSet(_project.Website); } // 翻译简介 @@ -619,7 +619,7 @@ public void RefreshFavoriteButton() } catch (Exception ex) { - ModBase.Log(ex, "刷新收藏按钮状态时出错"); + LauncherLog.Log(ex, "刷新收藏按钮状态时出错"); } } @@ -680,14 +680,14 @@ private void Load_State(object sender, MyLoading.MyLoadingState state, MyLoading { switch (_compFileLoader.State) { - case ModBase.LoadState.Failed: + case LoadState.Failed: { var errorMessage = ""; if (_compFileLoader.Error is not null) errorMessage = _compFileLoader.Error.Message; if (errorMessage.Contains(Lang.Text("Common.Error.InvalidJson"))) { - ModBase.Log("[Comp] 下载的文件 Json 列表损坏,已自动重试", ModBase.LogLevel.Debug); + LauncherLog.Log("[Comp] 下载的文件 Json 列表损坏,已自动重试", LauncherLogLevel.Debug); PageLoaderRestart(); } @@ -1124,10 +1124,10 @@ private void UpdateFilterResult() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化工程下载列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Comp.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs index beb8d3b41..ea69d2efe 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs @@ -54,9 +54,9 @@ private static string CombineCacheSubfolder(string parentFolder, string childFol private static void CancelUnsafeCacheSubfolder(string childFolderName, string reason) { var message = "远程版本名" + reason + ":" + childFolderName; - ModBase.Log("[Download] " + message); + LauncherLog.Log("[Download] " + message); HintService.Hint(message, HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } #region Minecraft 下载 @@ -120,10 +120,10 @@ public static ModLoader.LoaderCombo McDownloadClient(NetPreDownloadBehav catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 Minecraft 下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); return null; } @@ -160,7 +160,7 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa new List { new(ModDownload.DlSourceLauncherOrMetaGet(jsonUrl), Path.Combine(versionFolder, id + ".json"), - new ModBase.FileChecker(canUseExistsFile: false, isJson: true)) + new FileChecker(canUseExistsFile: false, isJson: true)) }) { ProgressWeight = 2d }); // 获取支持库文件地址 loaders.Add(new ModLoader.LoaderTask>( @@ -185,10 +185,10 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 Minecraft 下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -224,7 +224,7 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa new List { new(ModDownload.DlSourceLauncherOrMetaGet(jsonUrl ?? ""), Path.Combine(instanceFolder, instanceName + ".json"), - new ModBase.FileChecker(canUseExistsFile: false, isJson: true)) + new FileChecker(canUseExistsFile: false, isJson: true)) }) { ProgressWeight = 3d }); // 下载支持库文件 @@ -233,21 +233,21 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa Lang.Text("Minecraft.Download.Stage.AnalyzeVanillaLibraries.Side"), task => { var jsonPath = Path.Combine(instanceFolder, instanceName + ".json"); - ModBase.WaitForFileReady(jsonPath); - ModBase.Log("[Download] 开始分析原版支持库文件:" + instanceFolder); + LegacyFileFacade.WaitForFileReady(jsonPath); + LauncherLog.Log("[Download] 开始分析原版支持库文件:" + instanceFolder); if (id == "1.16.5" && Config.Download.FixAuthLib) // 1.16.5 Authlib 修复 try { - var json = ModBase.ReadFile(jsonPath); + var json = LegacyFileFacade.ReadText(jsonPath); json = json.Replace("2.1.28/authlib-2.1.28.jar", "2.3.31/authlib-2.3.31.jar") .Replace("com.mojang:authlib:2.1.28", "com.mojang:authlib:2.3.31") .Replace("ad54da276bf59983d02d5ed16fc14541354c71fd", "bbd00ca33b052f73a6312254780fc580d2da3535") .Replace("76328", "87662"); - ModBase.WriteFile(jsonPath, json); + LegacyFileFacade.WriteFile(jsonPath, json); } catch (Exception ex) { - ModBase.Log("[Download] 替换 Authlib 版本失败: " + ex.Message); + LauncherLog.Log("[Download] 替换 Authlib 版本失败: " + ex.Message); } task.output = ModLibrary.McLibNetFilesFromInstance(new McInstance(instanceFolder)); @@ -267,7 +267,7 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa loadersAssets.Add(new ModLoader.LoaderTask>( Lang.Text("Minecraft.Download.Stage.AnalyzeAssetsIndex.Side"), task => { - ModBase.WaitForFileReady(Path.Combine(instanceFolder, instanceName + ".json")); + LegacyFileFacade.WaitForFileReady(Path.Combine(instanceFolder, instanceName + ".json")); try { var assetIndex = new McInstance(instanceFolder); @@ -281,9 +281,9 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa // 顺手添加 Json 项目 try { - var versionJson = (JsonObject)ModBase.GetJson(ModBase.ReadFile(Path.Combine(instanceFolder, instanceName + ".json"))); + var versionJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(Path.Combine(instanceFolder, instanceName + ".json"))); versionJson.Add("clientVersion", id); - ModBase.WriteFile(Path.Combine(instanceFolder, instanceName + ".json"), versionJson.ToString()); + LegacyFileFacade.WriteFile(Path.Combine(instanceFolder, instanceName + ".json"), versionJson.ToString()); } catch (Exception ex) { @@ -331,11 +331,11 @@ public static MyListItem McDownloadListItem(JsonObject entry, MyListItem.ClickEv // 确定图标 string logo = entry["type"].ToString() switch { - "release" => ModBase.pathImage + "Blocks/Grass.png", - "snapshot" => ModBase.pathImage + "Blocks/CommandBlock.png", - "pending" => ModBase.pathImage + "Blocks/CommandBlock.png", - "special" => ModBase.pathImage + "Blocks/GoldBlock.png", - _ => ModBase.pathImage + "Blocks/CobbleStone.png" + "release" => LauncherPaths.ImageBaseUri + "Blocks/Grass.png", + "snapshot" => LauncherPaths.ImageBaseUri + "Blocks/CommandBlock.png", + "pending" => LauncherPaths.ImageBaseUri + "Blocks/CommandBlock.png", + "special" => LauncherPaths.ImageBaseUri + "Blocks/GoldBlock.png", + _ => LauncherPaths.ImageBaseUri + "Blocks/CobbleStone.png" }; // 建立控件 @@ -455,7 +455,7 @@ private static void McDownloadMenuSaveServer(object sender, RoutedEventArgs e) new List { new(ModDownload.DlSourceLauncherOrMetaGet(jsonUrl), Path.Combine(versionFolder, id + ".json"), - new ModBase.FileChecker(canUseExistsFile: false, isJson: true)) + new FileChecker(canUseExistsFile: false, isJson: true)) }) { ProgressWeight = 2d }); // 构建服务端 loaders.Add(new ModLoader.LoaderTask>( @@ -479,7 +479,7 @@ private static void McDownloadMenuSaveServer(object sender, RoutedEventArgs e) } var jarUrl = (string)mcInstance.JsonObject["downloads"]["server"]["url"]; - var checker = new ModBase.FileChecker(1024L, + var checker = new FileChecker(1024L, (long)(mcInstance.JsonObject["downloads"]["server"]["size"] ?? -1), (string)mcInstance.JsonObject["downloads"]["server"]["sha1"]); task.output = new List @@ -498,7 +498,7 @@ @echo off echo {Lang.Text("Minecraft.Download.ServerBatch.ServerStopped")} pause """; - ModBase.WriteFile(Path.Combine(versionFolder, "Launch Server.bat"), bat.Replace("\n", "\r\n"), + LegacyFileFacade.WriteFile(Path.Combine(versionFolder, "Launch Server.bat"), bat.Replace("\n", "\r\n"), encoding: Encoding.Default.Equals(Encoding.UTF8) ? Encoding.UTF8 : Encoding.GetEncoding("GB18030")); // 删除实例 JSON File.Delete(Path.Combine(versionFolder, id + ".json")); @@ -523,10 +523,10 @@ @echo off } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 Minecraft 服务端下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -562,7 +562,7 @@ public static void McDownloadMenuSave(object sender, RoutedEventArgs e) new List { new(ModDownload.DlSourceLauncherOrMetaGet(jsonUrl), Path.Combine(versionFolder, id + ".json"), - new ModBase.FileChecker(canUseExistsFile: false, isJson: true)) + new FileChecker(canUseExistsFile: false, isJson: true)) }) { ProgressWeight = 2d }); // 获取支持库文件地址 loaders.Add(new ModLoader.LoaderTask>( @@ -586,10 +586,10 @@ public static void McDownloadMenuSave(object sender, RoutedEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 Minecraft 下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -602,7 +602,7 @@ public static void McUpdateLogShow(JsonNode versionJson) { var wikiName = McFormatter.GetWikiUrlSuffix(versionJson["id"].ToString()); var wikiUrl = $"{McFormatter.GetWikiBaseUrl()}/{wikiName.TrimStart('/')}"; - ModBase.OpenWebsite(wikiUrl); + LauncherProcess.OpenWebsite(wikiUrl); } #endregion @@ -615,9 +615,9 @@ public static void McDownloadOptiFine(ModDownload.DlOptiFineListEntry downloadIn { var id = downloadInfo.NameVersion; var versionFolder = Path.Combine(ModFolder.mcFolderSelected, "versions", id); - var isNewVersion = ModBase.Val(downloadInfo.Inherit.Split(".")[1]) >= 14d; + var isNewVersion = LauncherText.Val(downloadInfo.Inherit.Split(".")[1]) >= 14d; var target = isNewVersion - ? Path.Combine(ModBase.pathTemp, "Cache", "Code", downloadInfo.NameVersion + "_" + ModBase.GetUuid()) + ? Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Code", downloadInfo.NameVersion + "_" + LauncherRuntime.GetUuid()) : Path.Combine(ModFolder.mcFolderSelected, "libraries", "optifine", "OptiFine", downloadInfo.NameFile.Replace("OptiFine_", "").Replace(".jar", "").Replace("preview_", ""), downloadInfo.NameFile.Replace("OptiFine_", "OptiFine-").Replace("preview_", "")); @@ -663,10 +663,10 @@ public static void McDownloadOptiFine(ModDownload.DlOptiFineListEntry downloadIn catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 OptiFine 下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -703,10 +703,10 @@ private static void McDownloadOptiFineSave(ModDownload.DlOptiFineListEntry downl catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 OptiFine 下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -728,7 +728,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta try { javaLoader.Start(17, true); - while (javaLoader.State == ModBase.LoadState.Loading && !task.IsAborted) + while (javaLoader.State == LoadState.Loading && !task.IsAborted) Thread.Sleep(10); } finally @@ -751,7 +751,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta if (useJavaWrapper && !(dynamic)Config.Launch.DisableJlw) // dynamic! arguments = - $"-Doolloo.jlw.tmpdir=\"{ModBase.pathPure.TrimEnd('\\')}\" -Duser.home=\"{baseMcFolderHome.TrimEnd('\\')}\" -cp \"{target}\" -jar \"{ModLaunch.ExtractJavaWrapper()}\" optifine.Installer"; + $"-Doolloo.jlw.tmpdir=\"{LauncherPaths.PureAsciiDirectory.TrimEnd('\\')}\" -Duser.home=\"{baseMcFolderHome.TrimEnd('\\')}\" -cp \"{target}\" -jar \"{ModLaunch.ExtractJavaWrapper()}\" optifine.Installer"; else arguments = $"-Duser.home=\"{baseMcFolderHome.TrimEnd('\\')}\" -cp \"{target}\" optifine.Installer"; if (java.Installation.MajorVersion >= 9) @@ -767,13 +767,13 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta CreateNoWindow = true, RedirectStandardError = true, RedirectStandardOutput = true, - WorkingDirectory = ModBase.ShortenPath(baseMcFolderHome) + WorkingDirectory = LegacyFileFacade.ShortenPath(baseMcFolderHome) }; if (info.EnvironmentVariables.ContainsKey("appdata")) info.EnvironmentVariables["appdata"] = baseMcFolderHome; else info.EnvironmentVariables.Add("appdata", baseMcFolderHome); - ModBase.Log("[Download] 开始安装 OptiFine:" + target); + LauncherLog.Log("[Download] 开始安装 OptiFine:" + target); var totalLength = 0; var process = new Process { StartInfo = info }; var lastResult = ""; @@ -792,8 +792,8 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta else { lastResult = e.Data; - if (ModBase.ModeDebug) - ModBase.Log("[Installer] " + lastResult); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Installer] " + lastResult); totalLength += 1; task.Progress += 0.9d / 7000d; } @@ -803,14 +803,14 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta } catch (Exception ex) { - ModBase.Log(ex, "读取 OptiFine 安装器信息失败"); + LauncherLog.Log(ex, "读取 OptiFine 安装器信息失败"); } try { - if (task.State == ModBase.LoadState.Aborted && !process.HasExited) + if (task.State == LoadState.Aborted && !process.HasExited) { - ModBase.Log("[Installer] 由于任务取消,已中止 OptiFine 安装"); + LauncherLog.Log("[Installer] 由于任务取消,已中止 OptiFine 安装"); process.Kill(); } } @@ -829,8 +829,8 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta else { lastResult = e.Data; - if (ModBase.ModeDebug) - ModBase.Log("[Installer] " + lastResult); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[Installer] " + lastResult); totalLength += 1; task.Progress += 0.9d / 7000d; } @@ -840,14 +840,14 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta } catch (Exception ex) { - ModBase.Log(ex, "读取 OptiFine 安装器错误信息失败"); + LauncherLog.Log(ex, "读取 OptiFine 安装器错误信息失败"); } try { - if (task.State == ModBase.LoadState.Aborted && !process.HasExited) + if (task.State == LoadState.Aborted && !process.HasExited) { - ModBase.Log("[Installer] 由于任务取消,已中止 OptiFine 安装"); + LauncherLog.Log("[Installer] 由于任务取消,已中止 OptiFine 安装"); process.Kill(); } } @@ -884,7 +884,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta var isCustomFolder = (mcFolder ?? "") != (ModFolder.mcFolderSelected ?? ""); var id = downloadInfo.NameVersion; var versionFolder = Path.Combine(mcFolder, "versions", id); - var isNewVersion = downloadInfo.Inherit.Contains("w") || ModBase.Val(downloadInfo.Inherit.Split(".")[1]) >= 14d; + var isNewVersion = downloadInfo.Inherit.Contains("w") || LauncherText.Val(downloadInfo.Inherit.Split(".")[1]) >= 14d; var target = isNewVersion ? $"{ModMain.RequestTaskTempFolder()}OptiFine.jar" : $@"{mcFolder}libraries\optifine\OptiFine\{downloadInfo.NameFile.Replace("OptiFine_", "").Replace(".jar", "").Replace("preview_", "")}\{downloadInfo.NameFile.Replace("OptiFine_", "OptiFine-").Replace("preview_", "")}"; @@ -933,16 +933,16 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta } task.Progress = 0.8d; sources.Add("https://optifine.net/" + pageData.RegexSearch(@"downloadx\?f=[^""']+")[0]); - ModBase.Log("[Download] OptiFine " + downloadInfo.DisplayName + " 官方下载地址:" + sources.Last()); + LauncherLog.Log("[Download] OptiFine " + downloadInfo.DisplayName + " 官方下载地址:" + sources.Last()); } catch (Exception ex) { - ModBase.Log(ex, "获取 OptiFine " + downloadInfo.DisplayName + " 官方下载地址失败"); + LauncherLog.Log(ex, "获取 OptiFine " + downloadInfo.DisplayName + " 官方下载地址失败"); } // 构造文件请求 task.output = new List - { new(sources.ToArray(), target, new ModBase.FileChecker(300 * 1024)) }; + { new(sources.ToArray(), target, new FileChecker(300 * 1024)) }; }) { ProgressWeight = 8d @@ -957,12 +957,12 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta return; var targetLoaders = clientDownloadLoader.GetLoaderList() .Where(l => (l.name ?? "") == mcDownloadClientLibName || (l.name ?? "") == mcDownloadClientJsonName) - .Where(l => l.State != ModBase.LoadState.Finished).ToList(); + .Where(l => l.State != LoadState.Finished).ToList(); if (targetLoaders.Any()) - ModBase.Log("[Download] OptiFine 安装正在等待原版文件下载完成"); + LauncherLog.Log("[Download] OptiFine 安装正在等待原版文件下载完成"); while (targetLoaders.Any() && !task.IsAborted) { - targetLoaders = targetLoaders.Where(l => l.State != ModBase.LoadState.Finished).ToList(); + targetLoaders = targetLoaders.Where(l => l.State != LoadState.Finished).ToList(); Thread.Sleep(50); } @@ -973,13 +973,13 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta return; lock (vanillaSyncLock) { - var clientName = ModBase.GetFolderNameFromPath(clientFolder); + var clientName = LegacyFileFacade.GetFolderNameFromPath(clientFolder); Directory.CreateDirectory(Path.Combine(mcFolder, "versions", downloadInfo.Inherit)); if (!File.Exists(Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".json"))) - ModBase.CopyFile($"{clientFolder}{clientName}.json", + LegacyFileFacade.CopyFile($"{clientFolder}{clientName}.json", $@"{mcFolder}versions\{downloadInfo.Inherit}\{downloadInfo.Inherit}.json"); if (!File.Exists(Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar"))) - ModBase.CopyFile($"{clientFolder}{clientName}.jar", + LegacyFileFacade.CopyFile($"{clientFolder}{clientName}.jar", $@"{mcFolder}versions\{downloadInfo.Inherit}\{downloadInfo.Inherit}.jar"); } }) @@ -991,7 +991,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta // 安装(新旧方式均需要原版 Jar 和 Json) if (isNewVersion) { - ModBase.Log("[Download] 检测为新版 OptiFine:" + downloadInfo.Inherit); + LauncherLog.Log("[Download] 检测为新版 OptiFine:" + downloadInfo.Inherit); loaders.Add(new ModLoader.LoaderTask, bool>( Lang.Text("Minecraft.Download.Stage.InstallOptiFine.MethodA"), task => { @@ -1001,18 +1001,18 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta { // 准备安装环境 if (Directory.Exists(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit))) - ModBase.DeleteDirectory(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit)); + LegacyFileFacade.DeleteDirectory(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit)); Directory.CreateDirectory(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit)); ModFolder.McFolderLauncherProfilesJsonCreate(baseMcFolder); - ModBase.CopyFile( + LegacyFileFacade.CopyFile( Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".json"), Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".json")); - ModBase.CopyFile( + LegacyFileFacade.CopyFile( Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar"), Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar")); task.Progress = 0.06d; // 进行安装 - var useJavaWrapper = ModBase.IsUtf8CodePage(); + var useJavaWrapper = PCL.Core.Utils.Codecs.EncodingUtils.IsDefaultEncodingUtf8(); Retry: ; try @@ -1023,7 +1023,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta { if (!useJavaWrapper) { - ModBase.Log(ex, "不使用 JavaWrapper 安装 OptiFine 失败,将使用 JavaWrapper 并重试"); + LauncherLog.Log(ex, "不使用 JavaWrapper 安装 OptiFine 失败,将使用 JavaWrapper 并重试"); useJavaWrapper = true; goto Retry; } @@ -1034,11 +1034,11 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta task.Progress = 0.96d; // 复制文件 File.Delete(Path.Combine(baseMcFolder, "launcher_profiles.json")); - ModBase.CopyDirectory(baseMcFolder, mcFolder); + LegacyFileFacade.CopyDirectory(baseMcFolder, mcFolder); task.Progress = 0.98d; // 清理文件 File.Delete(target); - ModBase.DeleteDirectory(baseMcFolderHome); + LegacyFileFacade.DeleteDirectory(baseMcFolderHome); } catch (Exception ex) { @@ -1051,7 +1051,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta } else { - ModBase.Log("[Download] 检测为旧版 OptiFine:" + downloadInfo.Inherit); + LauncherLog.Log("[Download] 检测为旧版 OptiFine:" + downloadInfo.Inherit); // 新建实例文件夹 // 复制 Jar 文件 // 建立 Json 文件 @@ -1063,7 +1063,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta Directory.CreateDirectory(versionFolder); task.Progress = 0.1d; if (File.Exists(Path.Combine(versionFolder, id + ".jar"))) File.Delete(Path.Combine(versionFolder, id + ".jar")); - ModBase.CopyFile( + LegacyFileFacade.CopyFile( Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar"), Path.Combine(versionFolder, id + ".jar")); task.Progress = 0.7d; @@ -1106,7 +1106,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta ] } }"; - ModBase.WriteFile(Path.Combine(versionFolder, id + ".json"), json); + LegacyFileFacade.WriteFile(Path.Combine(versionFolder, id + ".json"), json); } catch (Exception ex) { @@ -1171,17 +1171,17 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta } task.Progress = 0.8d; sources.Add("https://optifine.net/" + pageData.RegexSearch(@"downloadx\?f=[^""']+")[0]); - ModBase.Log("[Download] OptiFine " + downloadInfo.DisplayName + " 官方下载地址:" + sources.Last()); + LauncherLog.Log("[Download] OptiFine " + downloadInfo.DisplayName + " 官方下载地址:" + sources.Last()); } catch (Exception ex) { - ModBase.Log(ex, "获取 OptiFine " + downloadInfo.DisplayName + " 官方下载地址失败"); + LauncherLog.Log(ex, "获取 OptiFine " + downloadInfo.DisplayName + " 官方下载地址失败"); } task.Progress = 0.9d; // 构造文件请求 task.output = new List - { new(sources.ToArray(), targetFolder, new ModBase.FileChecker(64 * 1024)) }; + { new(sources.ToArray(), targetFolder, new FileChecker(64 * 1024)) }; }) { ProgressWeight = 6d @@ -1223,7 +1223,7 @@ public static MyListItem OptiFineDownloadListItem(ModDownload.DlOptiFineListEntr Type = MyListItem.CheckType.Clickable, Tag = entry, Info = string.Join(" | ", infoParts), - Logo = ModBase.pathImage + "Blocks/GrassPath.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/GrassPath.png" }; newItem.Click += onClick; @@ -1269,7 +1269,7 @@ private static void OptiFineLog_Click(object sender, RoutedEventArgs e) version = (ModDownload.DlOptiFineListEntry)((dynamic)sender).Parent.Tag; else version = (ModDownload.DlOptiFineListEntry)((dynamic)sender).Parent.Parent.Tag; - ModBase.OpenWebsite("https://optifine.net/changelog?f=" + version.NameFile); + LauncherProcess.OpenWebsite("https://optifine.net/changelog?f=" + version.NameFile); } public static void OptiFineSave_Click(object sender, RoutedEventArgs e) @@ -1293,7 +1293,7 @@ public static void McDownloadLiteLoader(ModDownload.DlLiteLoaderListEntry downlo try { var id = downloadInfo.Inherit; - var target = Path.Combine(ModBase.pathTemp, "Download", id + "-Liteloader.jar"); + var target = Path.Combine(LauncherPaths.TempWithSlash, "Download", id + "-Liteloader.jar"); var versionName = downloadInfo.Inherit + "-LiteLoader"; var versionFolder = Path.Combine(ModFolder.mcFolderSelected, "versions", versionName); @@ -1337,10 +1337,10 @@ public static void McDownloadLiteLoader(ModDownload.DlLiteLoaderListEntry downlo catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 LiteLoader 下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -1411,7 +1411,7 @@ private static void McDownloadLiteLoaderSave(ModDownload.DlLiteLoaderListEntry d (downloadInfo.Inherit == "1.8" ? "ant/dist/" : "build/libs/") + downloadInfo.FileName); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new ModBase.FileChecker(1024 * 1024)) }) + new List { new(address.ToArray(), target, new FileChecker(1024 * 1024)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -1426,10 +1426,10 @@ private static void McDownloadLiteLoaderSave(ModDownload.DlLiteLoaderListEntry d catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 LiteLoader 安装器下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -1444,7 +1444,7 @@ private static void McDownloadLiteLoaderSave(ModDownload.DlLiteLoaderListEntry d mcFolder = mcFolder ?? ModFolder.mcFolderSelected; var isCustomFolder = (mcFolder ?? "") != (ModFolder.mcFolderSelected ?? ""); var id = downloadInfo.Inherit; - var target = Path.Combine(ModBase.pathTemp, "Download", id + "-Liteloader.jar"); + var target = Path.Combine(LauncherPaths.TempWithSlash, "Download", id + "-Liteloader.jar"); var versionName = downloadInfo.Inherit + "-LiteLoader"; var versionFolder = Path.Combine(mcFolder, "versions", versionName); var loaders = new List(); @@ -1482,17 +1482,17 @@ private static void McDownloadLiteLoaderSave(ModDownload.DlLiteLoaderListEntry d DateTime.ParseExact(downloadInfo.ReleaseTime, "yyyy/MM/dd HH:mm", CultureInfo.InvariantCulture)); versionJson.Add("type", "release"); versionJson.Add("arguments", - (JsonNode)ModBase.GetJson("{\"game\":[\"--tweakClass\",\"" + downloadInfo.jsonToken["tweakClass"] + + (JsonNode)PCL.Core.Utils.JsonCompat.ParseNode("{\"game\":[\"--tweakClass\",\"" + downloadInfo.jsonToken["tweakClass"] + "\"]}")); versionJson.Add("libraries", downloadInfo.jsonToken["libraries"]?.DeepClone()); - versionJson["libraries"].AsArray().Add(ModBase.GetJson("{\"name\": \"com.mumfrey:liteloader:" + + versionJson["libraries"].AsArray().Add(PCL.Core.Utils.JsonCompat.ParseNode("{\"name\": \"com.mumfrey:liteloader:" + downloadInfo.jsonToken["version"] + "\",\"url\": \"https://dl.liteloader.com/versions/\"}")); versionJson.Add("mainClass", "net.minecraft.launchwrapper.Launch"); versionJson.Add("minimumLauncherVersion", 18); versionJson.Add("inheritsFrom", downloadInfo.Inherit); versionJson.Add("jar", downloadInfo.Inherit); - ModBase.WriteFile(Path.Combine(versionFolder, versionName + ".json"), versionJson.ToString()); + LegacyFileFacade.WriteFile(Path.Combine(versionFolder, versionName + ".json"), versionJson.ToString()); } catch (Exception ex) { @@ -1541,7 +1541,7 @@ public static MyListItem LiteLoaderDownloadListItem(ModDownload.DlLiteLoaderList Type = MyListItem.CheckType.Clickable, Tag = entry, Info = string.Join(" | ", infoParts), - Logo = ModBase.pathImage + "Blocks/Egg.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/Egg.png" }; newItem.Click += onClick; @@ -1599,7 +1599,7 @@ private static void LiteLoaderAll_Click(object sender, RoutedEventArgs e) version = (ModDownload.DlLiteLoaderListEntry)((dynamic)sender).Tag; else version = (ModDownload.DlLiteLoaderListEntry)((dynamic)sender).Tag.Tag; - ModBase.OpenWebsite("https://jenkins.liteloader.com/view/" + version.Inherit); + LauncherProcess.OpenWebsite("https://jenkins.liteloader.com/view/" + version.Inherit); } public static void LiteLoaderSave_Click(object sender, RoutedEventArgs e) @@ -1647,14 +1647,14 @@ public static void McDownloadForgelikeSave(ModDownload.DlForgelikeEntry info) var url = neo.UrlBase + "-installer.jar"; files.Add(new DownloadFile( new[] { url.Replace("maven.neoforged.net/releases", "bmclapi2.bangbang93.com/maven"), url }, target, - new ModBase.FileChecker(64 * 1024))); + new FileChecker(64 * 1024))); } else if (info.forgeType == ModDownload.DlForgelikeEntry.ForgelikeType.Cleanroom) { // Cleanroom var clr = (ModDownload.DlCleanroomListEntry)info; var url = clr.UrlBase + "-installer.jar"; - files.Add(new DownloadFile(new[] { url }, target, new ModBase.FileChecker(64 * 1024))); + files.Add(new DownloadFile(new[] { url }, target, new FileChecker(64 * 1024))); } else { @@ -1665,7 +1665,7 @@ public static void McDownloadForgelikeSave(ModDownload.DlForgelikeEntry info) { $"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/{forge.Inherit}-{forge.FileVersion}/forge-{forge.Inherit}-{forge.FileVersion}-{forge.Category}.{forge.FileExtension}", $"https://files.minecraftforge.net/maven/net/minecraftforge/forge/{forge.Inherit}-{forge.FileVersion}/forge-{forge.Inherit}-{forge.FileVersion}-{forge.Category}.{forge.FileExtension}" - }, target, new ModBase.FileChecker(64 * 1024, hash: forge.Hash))); + }, target, new FileChecker(64 * 1024, hash: forge.Hash))); } // 构造加载器 @@ -1686,10 +1686,10 @@ public static void McDownloadForgelikeSave(ModDownload.DlForgelikeEntry info) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"开始 {info.LoaderName} 安装器下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -1712,7 +1712,7 @@ private static void ForgelikeInjector(string target, ModLoader.LoaderTask= 9) arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " + arguments; // 开始启动 @@ -1752,8 +1752,8 @@ private static void ForgelikeInjector(string target, ModLoader.LoaderTask(); using (var outputWaitHandle = new AutoResetEvent(false)) @@ -1781,14 +1781,14 @@ private static void ForgelikeInjector(string target, ModLoader.LoaderTask l == "true")) return; - ModBase.Log(lastResults.Join("\r\n")); + LauncherLog.Log(lastResults.Join("\r\n")); var lastLines = ""; for (int i = Math.Max(0, lastResults.Count - 5), loopTo = lastResults.Count - 1; i <= loopTo; @@ -1864,20 +1864,20 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask @@ -1978,7 +1978,7 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask= 20d) { - ModBase.Log($"[Download] 检测为{(forgeType == ModDownload.DlForgelikeEntry.ForgelikeType.Forge ? "新版 Forge" : " " + forgeType)}:" + loaderVersion); + LauncherLog.Log($"[Download] 检测为{(forgeType == ModDownload.DlForgelikeEntry.ForgelikeType.Forge ? "新版 Forge" : " " + forgeType)}:" + loaderVersion); List libs = null; loaders.Add(new ModLoader.LoaderTask>( Lang.Text("Minecraft.Download.Stage.AnalyzeLoaderLibraries", loaderName), task => @@ -2079,16 +2079,16 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask (l.name ?? "") == mcDownloadClientLibName || (l.name ?? "") == mcDownloadClientJsonName) - .Where(l => l.State != ModBase.LoadState.Finished).ToList(); + .Where(l => l.State != LoadState.Finished).ToList(); if (targetLoaders.Any()) - ModBase.Log($"[Download] {loaderName} 安装正在等待原版文件下载完成"); + LauncherLog.Log($"[Download] {loaderName} 安装正在等待原版文件下载完成"); while (targetLoaders.Any() && !task.IsAborted) { - targetLoaders = targetLoaders.Where(l => l.State != ModBase.LoadState.Finished).ToList(); + targetLoaders = targetLoaders.Where(l => l.State != LoadState.Finished).ToList(); Thread.Sleep(50); } @@ -2202,13 +2202,13 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask { - ModBase.WaitForFileReady(installerAddress); + LegacyFileFacade.WaitForFileReady(installerAddress); var installer = new ZipArchive(new FileStream(installerAddress, FileMode.Open)); try { // 记录当前文件夹列表(在新建目标文件夹之前) - ModBase.Log("[Download] 开始进行 Forgelike 安装:" + installerAddress); + LauncherLog.Log("[Download] 开始进行 Forgelike 安装:" + installerAddress); // 解压并获取信息 var oldList = new DirectoryInfo(mcFolder + "versions/") .EnumerateDirectories().Select(i => i.FullName).ToList(); // 新建目标实例文件夹 - var json = ModBase.GetJson(ModBase.ReadFile(installer.GetEntry("install_profile.json").Open())); + var json = PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(installer.GetEntry("install_profile.json").Open())); Directory.CreateDirectory(versionFolder); task.Progress = 0.04d; // 释放 launcher_installer.json ModFolder.McFolderLauncherProfilesJsonCreate(mcFolder); task.Progress = 0.05d; // 运行 Forge 安装器 - var useJavaWrapper = ModBase.IsUtf8CodePage(); + var useJavaWrapper = PCL.Core.Utils.Codecs.EncodingUtils.IsDefaultEncodingUtf8(); Retry: try { // 释放 Forge 注入器 - ModBase.WriteFile(Path.Combine(ModBase.pathTemp, "Cache", "forge_installer.jar"), - ModBase.GetResourceStream("Resources/forge-installer.jar")); + LegacyFileFacade.WriteFile(Path.Combine(LauncherPaths.TempWithSlash, "Cache", "forge_installer.jar"), + PCL.Core.App.Basics.GetResourceStream("Resources/forge-installer.jar")); task.Progress = 0.06d; // 运行注入器 ForgelikeInjector(installerAddress, task, mcFolder, useJavaWrapper, forgeType); @@ -2259,7 +2259,7 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask {versionFolder}{targetVersion}.json"); } else if (deltaList.Count > 1) { // 新增了多个文件夹 //Enumerable.Select((IEnumerable)DeltaList, d => d.Name).Join(";") - ModBase.Log( + LauncherLog.Log( $"[Download] 有多个疑似的新增实例,无法确定:{string.Join(";", deltaList.Select(d => d.Name))}"); } else { // 没有新增文件夹 - ModBase.Log("[Download] 未找到新增的实例文件夹"); + LauncherLog.Log("[Download] 未找到新增的实例文件夹"); } } catch (Exception ex) @@ -2317,7 +2317,7 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask, bool>( $"{(forgeType == ModDownload.DlForgelikeEntry.ForgelikeType.Forge ? Lang.Text("Minecraft.Download.Stage.InstallForge.MethodB") : Lang.Text("Minecraft.Download.Stage.InstallForgeType", forgeType))}", task => @@ -2336,11 +2336,11 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask + PCL.Core.App.Basics.RunInNewThread(() => { try { - ModBase.Log("[Download] 刷新 Forge 推荐版本缓存开始"); + LauncherLog.Log("[Download] 刷新 Forge 推荐版本缓存开始"); var result = ModNet.NetGetCodeByLoader("https://bmclapi2.bangbang93.com/forge/promos"); if (result.Length < 1000) throw new Exception(Lang.Text("Minecraft.Download.Error.ForgePromosResultTooShort", result)); - var resultJson = (JsonNode)ModBase.GetJson(result); + var resultJson = (JsonNode)PCL.Core.Utils.JsonCompat.ParseNode(result); var recommendedList = new List(); foreach (JsonObject Version in resultJson.AsArray()) { @@ -2577,12 +2577,12 @@ public static void McDownloadForgeRecommendedRefresh() if (recommendedList.Count < 5) throw new Exception(Lang.Text("Minecraft.Download.Error.ForgeRecommendedTooFew", result)); var cacheJson = "{" + recommendedList.Join(",") + "}"; - ModBase.WriteFile(Path.Combine(ModBase.pathTemp, "Cache", "ForgeRecommendedList.json"), cacheJson); - ModBase.Log("[Download] 刷新 Forge 推荐版本缓存成功"); + LegacyFileFacade.WriteFile(Path.Combine(LauncherPaths.TempWithSlash, "Cache", "ForgeRecommendedList.json"), cacheJson); + LauncherLog.Log("[Download] 刷新 Forge 推荐版本缓存成功"); } catch (Exception ex) { - ModBase.Log(ex, "刷新 Forge 推荐版本缓存失败"); + LauncherLog.Log(ex, "刷新 Forge 推荐版本缓存失败"); } }, "ForgeRecommendedRefresh"); } @@ -2598,24 +2598,24 @@ public static string McDownloadForgeRecommendedGet(string mcInstance) { if (mcInstance is null) return null; - var list = ModBase.ReadFile(Path.Combine(ModBase.pathTemp, "Cache", "ForgeRecommendedList.json")); + var list = LegacyFileFacade.ReadText(Path.Combine(LauncherPaths.TempWithSlash, "Cache", "ForgeRecommendedList.json")); if (list is null || string.IsNullOrEmpty(list)) { - ModBase.Log("[Download] 没有 Forge 推荐版本缓存文件"); + LauncherLog.Log("[Download] 没有 Forge 推荐版本缓存文件"); return null; } - var json = (JsonObject)ModBase.GetJson(list); + var json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(list); if (json is null || !(mcInstance ?? "null").Contains(".") || !json.ContainsKey(mcInstance)) return null; return (json[mcInstance] ?? "").ToString(); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "获取 Forge 推荐版本失败(" + (mcInstance ?? "null") + ")", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); return null; } @@ -2647,7 +2647,7 @@ public static void NeoForgeDownloadListItemPreload(StackPanel stack, List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new ModBase.FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -2898,10 +2898,10 @@ public static void McDownloadFabricLoaderSave(JsonObject downloadInfo) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 Fabric 安装器下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -2943,7 +2943,7 @@ public static void McDownloadFabricLoaderSave(JsonObject downloadInfo) } catch (Exception ex) { - ModBase.Log(ex, $"[Download] 从 {url} 下载 Fabric meta 失败"); + LauncherLog.Log(ex, $"[Download] 从 {url} 下载 Fabric meta 失败"); } } @@ -2986,8 +2986,8 @@ public static void McDownloadLegacyFabricLoaderSave(JsonObject downloadInfo) try { var url = downloadInfo["url"].ToString(); - var fileName = ModBase.GetFileNameFromPath(url); - var version = ModBase.GetFileNameFromPath(downloadInfo["version"].ToString()); + var fileName = LegacyFileFacade.GetFileNameFromPath(url); + var version = LegacyFileFacade.GetFileNameFromPath(downloadInfo["version"].ToString()); var target = SystemDialogs.SelectSaveFile(Lang.Text("Download.Version.SelectSaveLocation"), fileName, Lang.Text("Download.Version.Installer.LegacyFabric.Filter")); if (!target.Contains(@"\")) return; @@ -3008,7 +3008,7 @@ public static void McDownloadLegacyFabricLoaderSave(JsonObject downloadInfo) var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new ModBase.FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3023,10 +3023,10 @@ public static void McDownloadLegacyFabricLoaderSave(JsonObject downloadInfo) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 Legacy Fabric 安装器下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -3060,7 +3060,7 @@ public static void McDownloadLegacyFabricLoaderSave(JsonObject downloadInfo) { "https://meta.legacyfabric.net/v2/versions/loader/" + minecraftName + "/" + legacyFabricVersion + "/profile/json" - }, Path.Combine(versionFolder, id + ".json"), new ModBase.FileChecker(isJson: true)) + }, Path.Combine(versionFolder, id + ".json"), new FileChecker(isJson: true)) }; }) { @@ -3102,7 +3102,7 @@ public static MyListItem FabricDownloadListItem(JsonObject entry, MyListItem.Cli Type = MyListItem.CheckType.Clickable, Tag = entry, Info = entry["stable"].ToObject() ? Lang.Text("Download.Version.Type.Stable") : Lang.Text("Download.Version.Type.Preview"), - Logo = ModBase.pathImage + "Blocks/Fabric.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/Fabric.png" }; newItem.Click += onClick; newItem.ContentHandler = FabricContMenuBuild; @@ -3122,7 +3122,7 @@ private static void FabricContMenuBuild(object sender, EventArgs e) private static void FabricLog_Click(object sender, RoutedEventArgs e) { - ModBase.OpenWebsite("https://fabricmc.net/blog"); + LauncherProcess.OpenWebsite("https://fabricmc.net/blog"); } public static MyListItem FabricApiDownloadListItem(ModComp.CompFile entry, MyListItem.ClickEventHandler onClick) @@ -3136,7 +3136,7 @@ public static MyListItem FabricApiDownloadListItem(ModComp.CompFile entry, MyLis Type = MyListItem.CheckType.Clickable, Tag = entry, Info = entry.StatusDescription + Lang.Text("Download.Version.ReleaseDate", Lang.Date(entry.ReleaseDate, "g")), - Logo = ModBase.pathImage + "Blocks/Fabric.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/Fabric.png" }; newItem.Click += onClick; // 结束 @@ -3154,7 +3154,7 @@ public static MyListItem OptiFabricDownloadListItem(ModComp.CompFile entry, MyLi Type = MyListItem.CheckType.Clickable, Tag = entry, Info = entry.StatusDescription + Lang.Text("Download.Version.ReleaseDate", Lang.Date(entry.ReleaseDate, "g")), - Logo = ModBase.pathImage + "Blocks/OptiFabric.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/OptiFabric.png" }; newItem.Click += onClick; // 结束 @@ -3176,7 +3176,7 @@ public static MyListItem LegacyFabricDownloadListItem(JsonObject entry, MyListIt Type = MyListItem.CheckType.Clickable, Tag = entry, Info = entry["stable"].ToObject() ? Lang.Text("Download.Version.Type.Stable") : Lang.Text("Download.Version.Type.Preview"), - Logo = ModBase.pathImage + "Blocks/Fabric.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/Fabric.png" }; newItem.Click += onClick; // 结束 @@ -3195,7 +3195,7 @@ public static MyListItem LegacyFabricApiDownloadListItem(ModComp.CompFile entry, Type = MyListItem.CheckType.Clickable, Tag = entry, Info = entry.StatusDescription + Lang.Text("Download.Version.ReleaseDate", Lang.Date(entry.ReleaseDate, "g")), - Logo = ModBase.pathImage + "Blocks/Fabric.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/Fabric.png" }; newItem.Click += onClick; // 结束 @@ -3211,8 +3211,8 @@ public static void McDownloadQuiltLoaderSave(JsonObject downloadInfo) try { var url = downloadInfo["url"].ToString(); - var fileName = ModBase.GetFileNameFromPath(url); - var version = ModBase.GetFileNameFromPath(downloadInfo["version"].ToString()); + var fileName = LegacyFileFacade.GetFileNameFromPath(url); + var version = LegacyFileFacade.GetFileNameFromPath(downloadInfo["version"].ToString()); var target = SystemDialogs.SelectSaveFile(Lang.Text("Download.Version.SelectSaveLocation"), fileName, Lang.Text("Download.Version.Installer.Quilt.Filter")); if (!target.Contains(@"\")) return; @@ -3234,7 +3234,7 @@ public static void McDownloadQuiltLoaderSave(JsonObject downloadInfo) var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new ModBase.FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3249,10 +3249,10 @@ public static void McDownloadQuiltLoaderSave(JsonObject downloadInfo) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 Quilt 安装器下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -3287,7 +3287,7 @@ public static void McDownloadQuiltLoaderSave(JsonObject downloadInfo) { "https://meta.quiltmc.org/v3/versions/loader/" + minecraftName + "/" + quiltVersion + "/profile/json" - }, Path.Combine(versionFolder, id + ".json"), new ModBase.FileChecker(isJson: true)) + }, Path.Combine(versionFolder, id + ".json"), new FileChecker(isJson: true)) }; // 新建 mods 文件夹 Directory.CreateDirectory($@"{mcFolder ?? ModFolder.mcFolderSelected}mods\"); @@ -3331,7 +3331,7 @@ public static MyListItem QuiltDownloadListItem(JsonObject entry, MyListItem.Clic Info = entry["maven"].ToString().Contains("installer") ? Lang.Text("Download.Version.Type.Installer") : entry["version"].ToString().Contains("beta") || entry["version"].ToString().Contains("pre") ? Lang.Text("Download.Version.Type.Preview") : Lang.Text("Download.Version.Type.Stable"), - Logo = ModBase.pathImage + "Blocks/Quilt.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/Quilt.png" }; newItem.Click += onClick; newItem.ContentHandler = QuiltContMenuBuild; @@ -3351,7 +3351,7 @@ private static void QuiltContMenuBuild(object sender, EventArgs e) private static void QuiltLog_Click(object sender, RoutedEventArgs e) { - ModBase.OpenWebsite("https://quiltmc.org/en/blog/1/"); + LauncherProcess.OpenWebsite("https://quiltmc.org/en/blog/1/"); } public static MyListItem QSLDownloadListItem(ModComp.CompFile entry, MyListItem.ClickEventHandler onClick) @@ -3365,7 +3365,7 @@ public static MyListItem QSLDownloadListItem(ModComp.CompFile entry, MyListItem. Type = MyListItem.CheckType.Clickable, Tag = entry, Info = entry.StatusDescription + Lang.Text("Download.Version.ReleaseDate", Lang.Date(entry.ReleaseDate, "g")), - Logo = ModBase.pathImage + "Blocks/Quilt.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/Quilt.png" }; newItem.Click += onClick; // 结束 @@ -3402,7 +3402,7 @@ public static void McDownloadLabyModProductionLoaderSave() var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new ModBase.FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3416,10 +3416,10 @@ public static void McDownloadLabyModProductionLoaderSave() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 LabyMod 安装器下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -3450,7 +3450,7 @@ public static void McDownloadLabyModSnapshotLoaderSave() var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new ModBase.FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3464,10 +3464,10 @@ public static void McDownloadLabyModSnapshotLoaderSave() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始 LabyMod 安装器下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); } } @@ -3502,7 +3502,7 @@ public static void McDownloadLabyModSnapshotLoaderSave() new[] { $"https://releases.r2.labymod.net/api/v1/download/manifest/labymod4/{labyModChannel}/{minecraftName}/{labyModCommitRef}.json" - }, Path.Combine(versionFolder, id + ".json"), new ModBase.FileChecker(isJson: true)) + }, Path.Combine(versionFolder, id + ".json"), new FileChecker(isJson: true)) }; task.Progress = 1d; }) @@ -3545,8 +3545,8 @@ public static void McDownloadLabyModSnapshotLoaderSave() loadersLib.Add(new ModLoader.LoaderTask>( Lang.Text("Minecraft.Download.Stage.AnalyzeVanillaAndLabyModLibrariesSide"), task => { - ModBase.WaitForFileReady(Path.Combine(versionFolder, versionName + ".json")); - ModBase.Log("[Download] 开始分析原版与 LabyMod 支持库文件:" + versionFolder); + LegacyFileFacade.WaitForFileReady(Path.Combine(versionFolder, versionName + ".json")); + LauncherLog.Log("[Download] 开始分析原版与 LabyMod 支持库文件:" + versionFolder); task.output = ModLibrary.McLibNetFilesFromInstance(new McInstance(versionFolder)); }) { @@ -3577,9 +3577,9 @@ public static void McDownloadLabyModSnapshotLoaderSave() // 顺手添加 Json 项目 try { - var versionJson = (JsonObject)ModBase.GetJson(ModBase.ReadFile(Path.Combine(versionFolder, versionName + ".json"))); + var versionJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(Path.Combine(versionFolder, versionName + ".json"))); versionJson.Add("clientVersion", id); - ModBase.WriteFile(Path.Combine(versionFolder, versionName + ".json"), versionJson.ToString()); + LegacyFileFacade.WriteFile(Path.Combine(versionFolder, versionName + ".json"), versionJson.ToString()); } catch (Exception ex) { @@ -3630,7 +3630,7 @@ public static MyListItem LabyModDownloadListItem(JsonObject entry, MyListItem.Cl Type = MyListItem.CheckType.Clickable, Tag = entry, Info = entry["channel"].ToString().Contains("snapshot") ? Lang.Text("Download.Version.Type.Snapshot") : Lang.Text("Download.Version.Type.Stable"), - Logo = ModBase.pathImage + "Blocks/LabyMod.png" + Logo = LauncherPaths.ImageBaseUri + "Blocks/LabyMod.png" }; newItem.Click += onClick; newItem.ContentHandler = LabyModContMenuBuild; @@ -3655,7 +3655,7 @@ private static void LabyModContMenuBuild(object sender, EventArgs e) private static void LabyModLog_Click(object sender, RoutedEventArgs e) { - ModBase.OpenWebsite("https://www.labymod.net/zh_Hans/download"); + LauncherProcess.OpenWebsite("https://www.labymod.net/zh_Hans/download"); } private static void LabyModSave_Click(object sender, RoutedEventArgs e) @@ -3811,13 +3811,13 @@ public static void LoaderStateChangedHintOnly(object loaderObj) var loader = (ModLoader.LoaderBase)loaderObj; switch (loader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: HintService.Hint($"{loader.name}{Lang.Text("Common.Status.Success")}", HintType.Success); break; - case ModBase.LoadState.Failed: + case LoadState.Failed: HintService.Hint($"{loader.name}{Lang.Text("Common.Status.Failure")}{loader.Error.Message}", HintType.Error); break; - case ModBase.LoadState.Aborted: + case LoadState.Aborted: HintService.Hint($"{loader.name}{Lang.Text("Common.Status.Cancelled")}"); break; } @@ -3832,49 +3832,49 @@ public static void McInstallState(object loaderObj) var combo = (ModLoader.LoaderCombo)loader; switch (loader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: { if (Config.Download.AutoSelectInstance) { var versionName = loader.name; - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "Version", + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", versionName.Remove(versionName.Length - 3, 3)); } - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 清空缓存(合并安装会先生成文件夹,这会在刷新时误判为可以使用缓存) - ModBase.DeleteDirectory($"{combo.input}PCLInstallBackups\\"); + LegacyFileFacade.DeleteDirectory($"{combo.input}PCLInstallBackups\\"); HintService.Hint($"{loader.name}{Lang.Text("Common.Status.Success")}", HintType.Success); break; } - case ModBase.LoadState.Failed: + case LoadState.Failed: { HintService.Hint( $"{loader.name}{Lang.Text("Common.Status.Failure")}{loader.Error.Message}", HintType.Error); break; } - case ModBase.LoadState.Aborted: + case LoadState.Aborted: { HintService.Hint($"{loader.name}{Lang.Text("Common.Status.Cancelled")}"); break; } - case ModBase.LoadState.Loading: + case LoadState.Loading: { return; // 不重新加载实例列表 } } - if (loader.State != ModBase.LoadState.Finished && + if (loader.State != LoadState.Finished && Directory.Exists( $"{combo.input}PCLInstallBackups\\")) // 实例修改失败回滚 { - ModBase.CopyDirectory( + LegacyFileFacade.CopyDirectory( $"{combo.input}PCLInstallBackups\\", (string)combo.input); File.Delete($"{combo.input}.pclignore"); - ModBase.DeleteDirectory( + LegacyFileFacade.DeleteDirectory( $"{combo.input}PCLInstallBackups\\"); } else @@ -3891,19 +3891,19 @@ public static void McInstallFailedClearFolder(object loader) try { Thread.Sleep(1000); // 防止存在尚未完全释放的文件,导致清理失败(例如整合包安装) - if (((ModLoader.LoaderBase)loader).State == ModBase.LoadState.Failed || - ((ModLoader.LoaderBase)loader).State == ModBase.LoadState.Aborted) + if (((ModLoader.LoaderBase)loader).State == LoadState.Failed || + ((ModLoader.LoaderBase)loader).State == LoadState.Aborted) { // 删除实例文件夹 - ModBase.Log($"[Download] 由于下载失败或取消,清理实例文件夹:{((ModLoader.LoaderCombo)loader).input}", ModBase.LogLevel.Developer); + LauncherLog.Log($"[Download] 由于下载失败或取消,清理实例文件夹:{((ModLoader.LoaderCombo)loader).input}", LauncherLogLevel.Developer); var instancePath = (string)((ModLoader.LoaderCombo)loader).input; ((DynamicCacheConfigStorage)ConfigService.GetProvider(ConfigSource.GameInstance)).InvalidateCache(instancePath); - ModBase.DeleteDirectory(instancePath); + LegacyFileFacade.DeleteDirectory(instancePath); } } catch (Exception ex) { - ModBase.Log(ex, "下载失败或取消后清理实例文件夹失败"); + LauncherLog.Log(ex, "下载失败或取消后清理实例文件夹失败"); } } @@ -3930,16 +3930,16 @@ public static bool McInstall(McInstallRequest request, string type = mcInstallDe return true; } - catch (ModBase.CancelledException ex) + catch (CancelledException ex) { return false; } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始合并安装失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Download.Error.OperationFailed")); try { @@ -3951,13 +3951,13 @@ public static bool McInstall(McInstallRequest request, string type = mcInstallDe { ((DynamicCacheConfigStorage)ConfigService.GetProvider(ConfigSource.GameInstance)) .InvalidateCache(request.targetInstanceFolder); - ModBase.DeleteDirectory(request.targetInstanceFolder); + LegacyFileFacade.DeleteDirectory(request.targetInstanceFolder); } } } catch (Exception innerEx) { - ModBase.Log(innerEx, "清理未完成的实例文件夹失败"); + LauncherLog.Log(innerEx, "清理未完成的实例文件夹失败"); } return false; } @@ -3966,7 +3966,7 @@ public static bool McInstall(McInstallRequest request, string type = mcInstallDe /// /// 获取合并安装加载器列表,并进行前期的缓存清理与 Java 检查工作。 /// - /// + /// public static List McInstallLoader(McInstallRequest request, bool dontFixLibraries = false, bool ignoreDump = false) { @@ -3978,7 +3978,7 @@ request.forgeEntry is not null || // 获取参数 var instanceFolder = Path.Combine(ModFolder.mcFolderSelected, "versions", request.targetInstanceName); if (Directory.Exists(tempMcFolder)) - ModBase.DeleteDirectory(tempMcFolder); + LegacyFileFacade.DeleteDirectory(tempMcFolder); string optiFineFolder = null; if (request.optiFineVersion is not null) { @@ -4040,7 +4040,7 @@ request.forgeEntry is not null || request.neoForgeEntry is not null || var optiFineAsMod = request.optiFineEntry is not null && modable; // 选择了 OptiFine 与任意 Mod 加载器 if (optiFineAsMod) { - ModBase.Log("[Download] OptiFine 将作为 Mod 进行下载"); + LauncherLog.Log("[Download] OptiFine 将作为 Mod 进行下载"); if (request.liteLoaderEntry is not null) optiFineFolder = CombineCacheSubfolder(modsTempFolder, request.minecraftName); else @@ -4049,37 +4049,37 @@ request.forgeEntry is not null || request.neoForgeEntry is not null || // 记录日志 if (optiFineFolder is not null) - ModBase.Log("[Download] OptiFine 缓存:" + optiFineFolder); + LauncherLog.Log("[Download] OptiFine 缓存:" + optiFineFolder); if (forgeFolder is not null) - ModBase.Log("[Download] Forge 缓存:" + forgeFolder); + LauncherLog.Log("[Download] Forge 缓存:" + forgeFolder); if (neoForgeFolder is not null) - ModBase.Log("[Download] NeoForge 缓存:" + neoForgeFolder); + LauncherLog.Log("[Download] NeoForge 缓存:" + neoForgeFolder); if (cleanroomFolder is not null) - ModBase.Log("[Download] Cleanroom 缓存:" + cleanroomFolder); + LauncherLog.Log("[Download] Cleanroom 缓存:" + cleanroomFolder); if (fabricFolder is not null) - ModBase.Log("[Download] Fabric 缓存:" + fabricFolder); + LauncherLog.Log("[Download] Fabric 缓存:" + fabricFolder); if (legacyFabricFolder is not null) - ModBase.Log("[Download] LegacyFabric 缓存:" + legacyFabricFolder); + LauncherLog.Log("[Download] LegacyFabric 缓存:" + legacyFabricFolder); if (quiltFolder is not null) - ModBase.Log("[Download] Quilt 缓存:" + quiltFolder); + LauncherLog.Log("[Download] Quilt 缓存:" + quiltFolder); if (labyModFolder is not null) - ModBase.Log("[Download] LabyMod 缓存:" + labyModFolder); + LauncherLog.Log("[Download] LabyMod 缓存:" + labyModFolder); if (liteLoaderFolder is not null) - ModBase.Log("[Download] LiteLoader 缓存:" + liteLoaderFolder); - ModBase.Log("[Download] 对应的原版版本:" + request.minecraftName); + LauncherLog.Log("[Download] LiteLoader 缓存:" + liteLoaderFolder); + LauncherLog.Log("[Download] 对应的原版版本:" + request.minecraftName); // 重复实例检查 if (File.Exists(Path.Combine(instanceFolder, request.targetInstanceName + ".json")) && !ignoreDump) { HintService.Hint(Lang.Text("Minecraft.Download.Error.InstanceAlreadyExists", request.targetInstanceName, ""), HintType.Error); - throw new ModBase.CancelledException(); + throw new CancelledException(); } var loaderList = new List(); // 添加忽略标识 loaderList.Add(new ModLoader.LoaderTask(Lang.Text("Minecraft.Download.Stage.AddIgnoreFlag"), - _ => ModBase.WriteFile(Path.Combine(instanceFolder, ".pclignore"), "用于临时地在 PCL 的实例列表中屏蔽此实例。")) + _ => LegacyFileFacade.WriteFile(Path.Combine(instanceFolder, ".pclignore"), "用于临时地在 PCL 的实例列表中屏蔽此实例。")) { show = false, block = false }); // Fabric API if (request.fabricApi is not null) @@ -4245,23 +4245,23 @@ request.neoForgeEntry is null task.Progress = 0.2d; // 迁移文件 if (Directory.Exists(Path.Combine(tempMcFolder, "libraries"))) - ModBase.CopyDirectory(Path.Combine(tempMcFolder, "libraries"), Path.Combine(ModFolder.mcFolderSelected, "libraries")); + LegacyFileFacade.CopyDirectory(Path.Combine(tempMcFolder, "libraries"), Path.Combine(ModFolder.mcFolderSelected, "libraries")); task.Progress = 0.8d; // 创建 Mod 和资源包文件夹 var modsFolder = Path.Combine(new McInstance(instanceFolder).PathIndie, "mods"); // 版本隔离信息在此时被决定 if (Directory.Exists(modsTempFolder)) { - ModBase.CopyDirectory(modsTempFolder, modsFolder); + LegacyFileFacade.CopyDirectory(modsTempFolder, modsFolder); } else if (modable) { Directory.CreateDirectory(modsFolder); - ModBase.Log("[Download] 自动创建 Mod 文件夹:" + modsFolder); + LauncherLog.Log("[Download] 自动创建 Mod 文件夹:" + modsFolder); } var resourcepacksFolder = Path.Combine(new McInstance(instanceFolder).PathIndie, "resourcepacks"); Directory.CreateDirectory(resourcepacksFolder); - ModBase.Log("[Download] 自动创建资源包文件夹:" + resourcepacksFolder); + LauncherLog.Log("[Download] 自动创建资源包文件夹:" + resourcepacksFolder); }) { ProgressWeight = 2d, @@ -4327,7 +4327,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin string labyModChannel = null, string liteLoaderFolder = null, ModModpack.MMCPackInfo mMCPackInfo = null, string legacyFabricFolder = null) { - ModBase.Log("[Download] 开始进行实例合并,输出:" + outputFolder + ",Minecraft:" + minecraftFolder + + LauncherLog.Log("[Download] 开始进行实例合并,输出:" + outputFolder + ",Minecraft:" + minecraftFolder + (optiFineFolder is not null ? ",OptiFine:" + optiFineFolder : "") + (forgeFolder is not null ? ",Forge:" + forgeFolder : "") + (neoForgeFolder is not null ? ",NeoForge:" + neoForgeFolder : "") + @@ -4377,13 +4377,13 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!outputFolder.EndsWithF(@"\")) outputFolder += @"\"; - outputName = ModBase.GetFolderNameFromPath(outputFolder); + outputName = LegacyFileFacade.GetFolderNameFromPath(outputFolder); outputJsonPath = Path.Combine(outputFolder, outputName + ".json"); outputJar = Path.Combine(outputFolder, outputName + ".jar"); if (!minecraftFolder.EndsWithF(@"\")) minecraftFolder += @"\"; - minecraftName = ModBase.GetFolderNameFromPath(minecraftFolder); + minecraftName = LegacyFileFacade.GetFolderNameFromPath(minecraftFolder); minecraftJsonPath = Path.Combine(minecraftFolder, minecraftName + ".json"); minecraftJar = Path.Combine(minecraftFolder, minecraftName + ".jar"); @@ -4391,7 +4391,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!optiFineFolder.EndsWithF(@"\")) optiFineFolder += @"\"; - optiFineName = ModBase.GetFolderNameFromPath(optiFineFolder); + optiFineName = LegacyFileFacade.GetFolderNameFromPath(optiFineFolder); optiFineJsonPath = Path.Combine(optiFineFolder, optiFineName + ".json"); } @@ -4399,7 +4399,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!forgeFolder.EndsWithF(@"\")) forgeFolder += @"\"; - forgeName = ModBase.GetFolderNameFromPath(forgeFolder); + forgeName = LegacyFileFacade.GetFolderNameFromPath(forgeFolder); forgeJsonPath = Path.Combine(forgeFolder, forgeName + ".json"); } @@ -4407,7 +4407,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!neoForgeFolder.EndsWithF(@"\")) neoForgeFolder += @"\"; - neoForgeName = ModBase.GetFolderNameFromPath(neoForgeFolder); + neoForgeName = LegacyFileFacade.GetFolderNameFromPath(neoForgeFolder); neoForgeJsonPath = Path.Combine(neoForgeFolder, neoForgeName + ".json"); } @@ -4415,7 +4415,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!cleanroomFolder.EndsWithF(@"\")) cleanroomFolder += @"\"; - cleanroomName = ModBase.GetFolderNameFromPath(cleanroomFolder); + cleanroomName = LegacyFileFacade.GetFolderNameFromPath(cleanroomFolder); cleanroomJsonPath = Path.Combine(cleanroomFolder, cleanroomName + ".json"); } @@ -4423,7 +4423,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!liteLoaderFolder.EndsWithF(@"\")) liteLoaderFolder += @"\"; - liteLoaderName = ModBase.GetFolderNameFromPath(liteLoaderFolder); + liteLoaderName = LegacyFileFacade.GetFolderNameFromPath(liteLoaderFolder); liteLoaderJsonPath = Path.Combine(liteLoaderFolder, liteLoaderName + ".json"); } @@ -4431,7 +4431,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!fabricFolder.EndsWithF(@"\")) fabricFolder += @"\"; - fabricName = ModBase.GetFolderNameFromPath(fabricFolder); + fabricName = LegacyFileFacade.GetFolderNameFromPath(fabricFolder); fabricJsonPath = Path.Combine(fabricFolder, fabricName + ".json"); } @@ -4439,7 +4439,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!legacyFabricFolder.EndsWithF(@"\")) legacyFabricFolder += @"\"; - legacyFabricName = ModBase.GetFolderNameFromPath(legacyFabricFolder); + legacyFabricName = LegacyFileFacade.GetFolderNameFromPath(legacyFabricFolder); legacyFabricJsonPath = Path.Combine(legacyFabricFolder, legacyFabricName + ".json"); } @@ -4447,7 +4447,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!quiltFolder.EndsWithF(@"\")) quiltFolder += @"\"; - quiltName = ModBase.GetFolderNameFromPath(quiltFolder); + quiltName = LegacyFileFacade.GetFolderNameFromPath(quiltFolder); quiltJsonPath = Path.Combine(quiltFolder, quiltName + ".json"); } @@ -4455,7 +4455,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!labyModFolder.EndsWithF(@"\")) labyModFolder += @"\"; - labyModName = ModBase.GetFolderNameFromPath(labyModFolder); + labyModName = LegacyFileFacade.GetFolderNameFromPath(labyModFolder); labyModJsonPath = Path.Combine(labyModFolder, labyModName + ".json"); } @@ -4475,94 +4475,94 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin #region 读取文件并检查文件是否合规 - var minecraftJsonText = ModBase.ReadFile(minecraftJsonPath); + var minecraftJsonText = LegacyFileFacade.ReadText(minecraftJsonPath); if (!hasLabyMod) { if (!minecraftJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Minecraft", minecraftJsonPath, minecraftJsonText.Substring(0, Math.Min(minecraftJsonText.Length, 1000)))); - minecraftJson = (JsonObject)ModBase.GetJson(minecraftJsonText); + minecraftJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(minecraftJsonText); } if (hasOptiFine) { - var optiFineJsonText = ModBase.ReadFile(optiFineJsonPath); + var optiFineJsonText = LegacyFileFacade.ReadText(optiFineJsonPath); if (!optiFineJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "OptiFine", optiFineJsonPath, optiFineJsonText.Substring(0, Math.Min(optiFineJsonText.Length, 1000)))); - optiFineJson = (JsonObject)ModBase.GetJson(optiFineJsonText); + optiFineJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(optiFineJsonText); } if (hasForge) { - var forgeJsonText = ModBase.ReadFile(forgeJsonPath); + var forgeJsonText = LegacyFileFacade.ReadText(forgeJsonPath); if (!forgeJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Forge", forgeJsonPath, forgeJsonText.Substring(0, Math.Min(forgeJsonText.Length, 1000)))); - forgeJson = (JsonObject)ModBase.GetJson(forgeJsonText); + forgeJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(forgeJsonText); } if (hasNeoForge) { - var neoForgeJsonText = ModBase.ReadFile(neoForgeJsonPath); + var neoForgeJsonText = LegacyFileFacade.ReadText(neoForgeJsonPath); if (!neoForgeJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "NeoForge", neoForgeJsonPath, neoForgeJsonText.Substring(0, Math.Min(neoForgeJsonText.Length, 1000)))); - neoForgeJson = (JsonObject)ModBase.GetJson(neoForgeJsonText); + neoForgeJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(neoForgeJsonText); } if (hasCleanroom) { - var cleanroomJsonText = ModBase.ReadFile(cleanroomJsonPath); + var cleanroomJsonText = LegacyFileFacade.ReadText(cleanroomJsonPath); if (!cleanroomJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Cleanroom", cleanroomJsonPath, cleanroomJsonText.Substring(0, Math.Min(cleanroomJsonText.Length, 1000)))); - cleanroomJson = (JsonObject)ModBase.GetJson(cleanroomJsonText); + cleanroomJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(cleanroomJsonText); } if (hasLiteLoader) { - var liteLoaderJsonText = ModBase.ReadFile(liteLoaderJsonPath); + var liteLoaderJsonText = LegacyFileFacade.ReadText(liteLoaderJsonPath); if (!liteLoaderJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "LiteLoader", liteLoaderJsonPath, liteLoaderJsonText.Substring(0, Math.Min(liteLoaderJsonText.Length, 1000)))); - liteLoaderJson = (JsonObject)ModBase.GetJson(liteLoaderJsonText); + liteLoaderJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(liteLoaderJsonText); } if (hasFabric) { - var fabricJsonText = ModBase.ReadFile(fabricJsonPath); + var fabricJsonText = LegacyFileFacade.ReadText(fabricJsonPath); if (!fabricJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Fabric", fabricJsonPath, fabricJsonText.Substring(0, Math.Min(fabricJsonText.Length, 1000)))); - fabricJson = (JsonObject)ModBase.GetJson(fabricJsonText); + fabricJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(fabricJsonText); } if (hasLegacyFabric) { - var legacyFabricJsonText = ModBase.ReadFile(legacyFabricJsonPath); + var legacyFabricJsonText = LegacyFileFacade.ReadText(legacyFabricJsonPath); if (!legacyFabricJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Legacy Fabric", fabricJsonPath, legacyFabricJsonText.Substring(0, Math.Min(legacyFabricJsonText.Length, 1000)))); - legacyFabricJson = (JsonObject)ModBase.GetJson(legacyFabricJsonText); + legacyFabricJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(legacyFabricJsonText); } if (hasQuilt) { - var quiltJsonText = ModBase.ReadFile(quiltJsonPath); + var quiltJsonText = LegacyFileFacade.ReadText(quiltJsonPath); if (!quiltJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Quilt", quiltJsonPath, quiltJsonText.Substring(0, Math.Min(quiltJsonText.Length, 1000)))); - quiltJson = (JsonObject)ModBase.GetJson(quiltJsonText); + quiltJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(quiltJsonText); } if (hasLabyMod) { - var labyModJsonText = ModBase.ReadFile(labyModJsonPath); + var labyModJsonText = LegacyFileFacade.ReadText(labyModJsonPath); if (!labyModJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "LabyMod", labyModJsonPath, labyModJsonText.Substring(0, Math.Min(labyModJsonText.Length, 1000)))); - labyModJson = (JsonObject)ModBase.GetJson(labyModJsonText); + labyModJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(labyModJsonText); } #endregion @@ -4602,12 +4602,12 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (mMCPackInfo.isMinecraftOverrided) { - ModBase.Log("[Download] 当前实例的 MC 核心已被修改,使用对应的 MMC 整合包参数"); + LauncherLog.Log("[Download] 当前实例的 MC 核心已被修改,使用对应的 MMC 整合包参数"); outputJson = mMCPackInfo.overridedJson; } else { - ModBase.Log("[Download] 存在无修改 MC 核心文件的 MMC 整合包信息,应用相关参数"); + LauncherLog.Log("[Download] 存在无修改 MC 核心文件的 MMC 整合包信息,应用相关参数"); outputJson = minecraftJson; // 合并来自 MultiMC 的 JSON outputJson.Merge(mMCPackInfo.overridedJson); @@ -4776,15 +4776,15 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin #region 保存 - ModBase.WriteFile(outputJsonPath, outputJson.ToString()); + LegacyFileFacade.WriteFile(outputJsonPath, outputJson.ToString()); if ((minecraftJar ?? "") != (outputJar ?? "")) // 可能是同一个文件 { if (File.Exists(outputJar)) File.Delete(outputJar); - ModBase.CopyFile(minecraftJar, outputJar); + LegacyFileFacade.CopyFile(minecraftJar, outputJar); } - ModBase.Log("[Download] 实例合并 " + outputName + " 完成"); + LauncherLog.Log("[Download] 实例合并 " + outputName + " 完成"); #endregion } diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCleanroom.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCleanroom.xaml.cs index 84dc4e5a7..9062577be 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCleanroom.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCleanroom.xaml.cs @@ -64,10 +64,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Cleanroom 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } @@ -75,6 +75,6 @@ private void Load_OnFinish() // 介绍栏 private void BtnWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://cleanroommc.com/zh/"); + LauncherProcess.OpenWebsite("https://cleanroommc.com/zh/"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadClient.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadClient.xaml.cs index d2057ea0d..03a6a04a1 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadClient.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadClient.xaml.cs @@ -111,10 +111,10 @@ void PutMethod(StackPanel stack) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 MC 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs index c6a54fb5e..ab7089bf7 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs @@ -51,7 +51,7 @@ private ModComp.CompFavorites.FavData CurrentFavTarget var selectedItem = (MyComboBoxItem)ComboTargetFav.SelectedItem; if (selectedItem is null) { - ModBase.Log("[Favorites] 异常:未选择收藏夹"); + LauncherLog.Log("[Favorites] 异常:未选择收藏夹"); selectedItem = (MyComboBoxItem)ComboTargetFav.Items.GetItemAt(0); } @@ -87,7 +87,7 @@ private List LoaderInput() } catch (Exception ex) { - ModBase.Log(ex, "[Favorites] 加载收藏夹列表时出错"); + LauncherLog.Log(ex, "[Favorites] 加载收藏夹列表时出错"); } return (List)targetList.Clone(); // 复制而不是直接引用! @@ -282,10 +282,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化收藏夹列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Comp.Favorites.Error.OperationFailed")); } } @@ -432,7 +432,7 @@ private void RefreshBar() #region 事件 // 选中状态改变 - private void ItemCheckStatusChanged(object sender, ModBase.RouteEventArgs e) + private void ItemCheckStatusChanged(object sender, RouteEventArgs e) { var senderItem = (MyListItem)sender; if (selectedItemList.Contains(senderItem)) @@ -447,14 +447,14 @@ private void Load_State(object sender, MyLoading.MyLoadingState state, MyLoading { switch (loader.State) { - case ModBase.LoadState.Failed: + case LoadState.Failed: { var errorMessage = ""; if (loader.Error is not null) errorMessage = loader.Error.Message; if (errorMessage.Contains(Lang.Text("Common.Error.InvalidJson"))) { - ModBase.Log("[Download] 下载的工程列表 JSON 文件损坏,已自动重试", ModBase.LogLevel.Debug); + LauncherLog.Log("[Download] 下载的工程列表 JSON 文件损坏,已自动重试", LauncherLogLevel.Debug); PageLoaderRestart(); } @@ -463,7 +463,7 @@ private void Load_State(object sender, MyLoading.MyLoadingState state, MyLoading } } - private void Btn_FavoritesCancel_Clicked(object sender, ModBase.RouteEventArgs e) + private void Btn_FavoritesCancel_Clicked(object sender, RouteEventArgs e) { foreach (var Items in selectedItemList.Clone()) Items_CancelFavorites(Items); @@ -480,31 +480,31 @@ private void Btn_FavoritesCancel_Clicked(object sender, ModBase.RouteEventArgs e RefreshBar(); } - private void Btn_SelectCancel_Clicked(object sender, ModBase.RouteEventArgs e) + private void Btn_SelectCancel_Clicked(object sender, RouteEventArgs e) { Items_SetSelectAll(false); } - private void Btn_FavoritesShare_Clicked(object sender, ModBase.RouteEventArgs e) + private void Btn_FavoritesShare_Clicked(object sender, RouteEventArgs e) { try { - ModBase.ClipboardSet( + LauncherProcess.ClipboardSet( ModComp.CompFavorites.GetShareCode(selectedItemList.Select(i => ((ModComp.CompProject)i.Tag).Id) .ToHashSet())); Items_SetSelectAll(false); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "[CompFavourites] 分享收藏时发生错误", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Download.Comp.Favorites.Error.OperationFailed")); } } - private void Btn_FavoritesDownload_Clicked(object sender, ModBase.RouteEventArgs e) + private void Btn_FavoritesDownload_Clicked(object sender, RouteEventArgs e) { try { @@ -576,7 +576,7 @@ private void Btn_FavoritesDownload_Clicked(object sender, ModBase.RouteEventArgs // 获取多个工程之间支持的版本的交集 var finishedTasks = 0; foreach (var Item in ts.input) - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -586,10 +586,10 @@ private void Btn_FavoritesDownload_Clicked(object sender, ModBase.RouteEventArgs } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"获取 {Item} 的下载信息失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Download.Comp.Favorites.Error.OperationFailed")); } finally @@ -624,7 +624,7 @@ private void Btn_FavoritesDownload_Clicked(object sender, ModBase.RouteEventArgs } int? selectedVersion = 0; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { List selection = []; foreach (var i in suitVersion) @@ -672,7 +672,7 @@ private void Btn_FavoritesDownload_Clicked(object sender, ModBase.RouteEventArgs } ); var checkLoader = new ModLoader.LoaderCombo>( - Lang.Text("Download.Comp.Favorites.LoaderName.BatchDownload", ModBase.GetUuid()), + Lang.Text("Download.Comp.Favorites.LoaderName.BatchDownload", LauncherRuntime.GetUuid()), getInfoAndDownloadLoader ) { @@ -687,10 +687,10 @@ private void Btn_FavoritesDownload_Clicked(object sender, ModBase.RouteEventArgs } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "批量下载收藏时发生错误", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Download.Comp.Favorites.Error.OperationFailed")); } } @@ -722,7 +722,7 @@ private void Items_CancelFavorites(MyListItem item) } catch (Exception ex) { - ModBase.Log(ex, "[CompFavourites] 移除收藏时发生错误"); + LauncherLog.Log(ex, "[CompFavourites] 移除收藏时发生错误"); } } @@ -750,14 +750,14 @@ private void Manage_Click(object sender, EventArgs _) return; } - ModBase.ClipboardSet(ModComp.CompFavorites.GetShareCode(CurrentFavTarget.Favs)); + LauncherProcess.ClipboardSet(ModComp.CompFavorites.GetShareCode(CurrentFavTarget.Favs)); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "[Favourites] 分享收藏时发生错误", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Download.Comp.Favorites.Error.OperationFailed")); } }; @@ -804,10 +804,10 @@ private void Manage_Click(object sender, EventArgs _) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "解析分享数据失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Download.Comp.Favorites.Error.OperationFailed")); } }; @@ -888,7 +888,7 @@ private void HintGetFail_MouseLeftButtonDown(object sender, MouseButtonEventArgs foreach (var Id in failIds) content += $" - {Id}" + "\r\n"; ModMain.MyMsgBox(content, Lang.Text("Download.Comp.Favorites.Dialog.GetFailed.Title"), button2: Lang.Text("Download.Comp.Favorites.Dialog.GetFailed.CopyIds"), button3: Lang.Text("Download.Comp.Favorites.Dialog.GetFailed.Remove"), - button2Action: () => ModBase.ClipboardSet(failIds.Join("\r\n")), button3Action: () => + button2Action: () => LauncherProcess.ClipboardSet(failIds.Join("\r\n")), button3Action: () => { foreach (var Id in failIds) CurrentFavTarget.Favs.Remove(Id); @@ -913,24 +913,24 @@ public void SearchRun(object sender, EventArgs e) if (IsSearching) { // 构造请求 - var queryList = new List>(); + var queryList = new List>(); foreach (var Item in compItemList) { if (Item.Tag is not ModComp.CompProject) continue; var entry = (ModComp.CompProject)Item.Tag; - var searchSource = new List(); - searchSource.Add(new ModBase.SearchSource(entry.RawName, 1d)); + var searchSource = new List(); + searchSource.Add(new SearchSource(entry.RawName, 1d)); if (entry.Description is not null && !string.IsNullOrEmpty(entry.Description)) - searchSource.Add(new ModBase.SearchSource(entry.Description, 0.4d)); + searchSource.Add(new SearchSource(entry.Description, 0.4d)); if ((entry.TranslatedName ?? "") != (entry.RawName ?? "")) - searchSource.Add(new ModBase.SearchSource(entry.TranslatedName, 1d)); - searchSource.Add(new ModBase.SearchSource(string.Join("", entry.Tags), 0.2d)); - queryList.Add(new ModBase.SearchEntry { item = Item, searchSource = searchSource }); + searchSource.Add(new SearchSource(entry.TranslatedName, 1d)); + searchSource.Add(new SearchSource(string.Join("", entry.Tags), 0.2d)); + queryList.Add(new SearchEntry { item = Item, searchSource = searchSource }); } // 进行搜索 - searchResult = ModBase.Search(queryList, PanSearchBox.Text, ModBase.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); + searchResult = LauncherSearch.Search(queryList, PanSearchBox.Text, LauncherSearch.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); } RefreshContent(); diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadFabric.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadFabric.xaml.cs index 9a3ea26f3..e1e3cb355 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadFabric.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadFabric.xaml.cs @@ -37,10 +37,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Fabric 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } @@ -52,6 +52,6 @@ private void Fabric_Selected(MyListItem sender, EventArgs e) private void BtnWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://www.fabricmc.net"); + LauncherProcess.OpenWebsite("https://www.fabricmc.net"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadForge.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadForge.xaml.cs index 7587a18c5..05178615c 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadForge.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadForge.xaml.cs @@ -67,10 +67,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Forge 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } @@ -109,6 +109,6 @@ public void Forge_StateChanged(MyLoading sender, MyLoading.MyLoadingState newSta // 介绍栏 private void BtnWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://files.minecraftforge.net"); + LauncherProcess.OpenWebsite("https://files.minecraftforge.net"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.cs index 3d2fd4177..6e5c0d400 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.cs @@ -1026,7 +1026,7 @@ private void LoadMinecraft_OnFinish() if (mcVersionWaitingForSelect is null) return; - ModBase.Log("[Download] 自动选择 MC 版本:" + mcVersionWaitingForSelect); + LauncherLog.Log("[Download] 自动选择 MC 版本:" + mcVersionWaitingForSelect); foreach (JsonObject version1 in versions) { @@ -1040,10 +1040,10 @@ private void LoadMinecraft_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1218,7 +1218,7 @@ private object IsOptiFineSuitForForge(ModDownload.DlOptiFineListEntry optiFine, } // 限制展开 - private void CardOptiFine_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardOptiFine_PreviewSwap(object sender, RouteEventArgs e) { if (LoadOptiFineGetError() is not null) e.handled = true; @@ -1231,7 +1231,7 @@ private void OptiFine_Loaded() { try { - if (ModDownload.dlOptiFineListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlOptiFineListLoader.State != LoadState.Finished) return; // 获取版本列表 @@ -1265,10 +1265,10 @@ private void OptiFine_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 OptiFine 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1318,7 +1318,7 @@ private string LoadLiteLoaderGetError() } // 限制展开 - private void CardLiteLoader_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardLiteLoader_PreviewSwap(object sender, RouteEventArgs e) { if (LoadLiteLoaderGetError() is not null) e.handled = true; @@ -1331,7 +1331,7 @@ private void LiteLoader_Loaded() { try { - if (ModDownload.dlLiteLoaderListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlLiteLoaderListLoader.State != LoadState.Finished) return; // 获取版本列表 var versions = new List(); @@ -1348,10 +1348,10 @@ private void LiteLoader_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LiteLoader 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1412,7 +1412,7 @@ private string LoadForgeGetError() } // 限制展开 - private void CardForge_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardForge_PreviewSwap(object sender, RouteEventArgs e) { if (LoadForgeGetError() is not null) e.handled = true; @@ -1430,7 +1430,7 @@ private void Forge_Loaded() var loader = (ModLoader.LoaderTask>)LoadForge.State; if ((_vanillaName ?? "") != (loader.input ?? "")) return; - if (loader.State != ModBase.LoadState.Finished) + if (loader.State != LoadState.Finished) return; // 获取要显示的版本 var versions = loader.output.ToList(); // 复制数组,以免 Output 在实例化后变空 @@ -1454,10 +1454,10 @@ private void Forge_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Forge 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1508,7 +1508,7 @@ private string LoadNeoForgeGetError() } // 限制展开 - private void CardNeoForge_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardNeoForge_PreviewSwap(object sender, RouteEventArgs e) { if (LoadNeoForgeGetError() is not null) e.handled = true; @@ -1522,7 +1522,7 @@ private void NeoForge_Loaded() try { // 获取版本列表 - if (ModDownload.dlNeoForgeListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlNeoForgeListLoader.State != LoadState.Finished) return; var versions = ModDownload.dlNeoForgeListLoader.output.Value .Where(v => (v.Inherit ?? "") == (_vanillaName ?? "")).ToList(); @@ -1540,10 +1540,10 @@ private void NeoForge_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 NeoForge 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1593,7 +1593,7 @@ private void NeoForge_Clear(object sender, MouseButtonEventArgs e) } // 限制展开 - private void CardCleanroom_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardCleanroom_PreviewSwap(object sender, RouteEventArgs e) { if (LoadCleanroomGetError() is not null) e.handled = true; @@ -1607,7 +1607,7 @@ private void Cleanroom_Loaded() try { // 获取版本列表 - if (ModDownload.dlCleanroomListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlCleanroomListLoader.State != LoadState.Finished) return; var versions = ModDownload.dlCleanroomListLoader.output.Value .Where(v => (v.Inherit ?? "") == (_vanillaName ?? "")).ToList(); @@ -1624,10 +1624,10 @@ private void Cleanroom_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Cleanroom 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1681,7 +1681,7 @@ private string LoadFabricGetError() } // 限制展开 - private void CardFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardFabric_PreviewSwap(object sender, RouteEventArgs e) { if (LoadFabricGetError() is not null) e.handled = true; @@ -1694,7 +1694,7 @@ private void Fabric_Loaded() { try { - if (ModDownload.dlFabricListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlFabricListLoader.State != LoadState.Finished) return; // 获取版本列表 var versions = (JsonArray)ModDownload.dlFabricListLoader.output.Value["loader"]; @@ -1714,10 +1714,10 @@ private void Fabric_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Fabric 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1725,7 +1725,7 @@ private void Fabric_Loaded() // 选择与清除 public void Fabric_Selected(MyListItem sender, EventArgs e) { - ModBase.Log(((dynamic)sender.Tag).ToString()); + LauncherLog.Log(((dynamic)sender.Tag).ToString()); selectedFabric = ((dynamic)sender.Tag)["version"].ToString(); selectedLoaderName = "Fabric"; FabricApi_Loaded(); @@ -1767,7 +1767,7 @@ public bool IsFabricApiCompatible(ModComp.CompFile fabricApi) } catch (Exception ex) { - ModBase.Log(ex, "判断 Fabric API 版本适配性出错(" + fabricApiName + ", " + _vanillaName + ")"); + LauncherLog.Log(ex, "判断 Fabric API 版本适配性出错(" + fabricApiName + ", " + _vanillaName + ")"); return false; } } @@ -1790,7 +1790,7 @@ private string LoadFabricApiGetError() } // 限制展开 - private void CardFabricApi_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardFabricApi_PreviewSwap(object sender, RouteEventArgs e) { if (LoadFabricApiGetError() is not null) e.handled = true; @@ -1805,7 +1805,7 @@ private void FabricApi_Loaded() { try { - if (ModDownload.dlFabricApiLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlFabricApiLoader.State != LoadState.Finished) return; if (_vanillaName is null || (selectedFabric is null && selectedQuilt is null)) return; @@ -1816,7 +1816,7 @@ private void FabricApi_Loaded() { if (!version.DisplayName.StartsWith("[")) { - ModBase.Log("[Download] 已特判修改 Fabric API 显示名:" + version.DisplayName, ModBase.LogLevel.Debug); + LauncherLog.Log("[Download] 已特判修改 Fabric API 显示名:" + version.DisplayName, LauncherLogLevel.Debug); version.DisplayName = "[" + _vanillaName + "] " + version.DisplayName; } @@ -1841,16 +1841,16 @@ private void FabricApi_Loaded() (selectedQuilt is not null && LoadQSLGetError() == Lang.Text("Download.Install.State.NoAvailableVersion"))) { autoSelectedFabricApi = true; - ModBase.Log($"[Download] 已自动选择 Fabric API:{((MyListItem)PanFabricApi.Children[0]).Title}"); + LauncherLog.Log($"[Download] 已自动选择 Fabric API:{((MyListItem)PanFabricApi.Children[0]).Title}"); FabricApi_Selected((MyListItem)PanFabricApi.Children[0], null); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Fabric API 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1900,7 +1900,7 @@ private string LoadLegacyFabricGetError() } // 限制展开 - private void CardLegacyFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardLegacyFabric_PreviewSwap(object sender, RouteEventArgs e) { if (LoadLegacyFabricGetError() is not null) e.handled = true; @@ -1913,7 +1913,7 @@ private void LegacyFabric_Loaded() { try { - if (ModDownload.dlLegacyFabricListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlLegacyFabricListLoader.State != LoadState.Finished) return; // 获取版本列表 var versions = (JsonArray)ModDownload.dlLegacyFabricListLoader.output.Value["loader"]; @@ -1932,10 +1932,10 @@ private void LegacyFabric_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LegacyFabric 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -1979,7 +1979,7 @@ public static bool IsSuitableLegacyFabricApi(List supportVersions, strin } catch (Exception ex) { - ModBase.Log(ex, "判断 Legacy Fabric API 版本适配性出错(" + supportVersions + ", " + minecraftVersion + ")"); + LauncherLog.Log(ex, "判断 Legacy Fabric API 版本适配性出错(" + supportVersions + ", " + minecraftVersion + ")"); return false; } } @@ -2015,7 +2015,7 @@ private string LoadLegacyFabricApiGetError() } // 限制展开 - private void CardLegacyFabricApi_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardLegacyFabricApi_PreviewSwap(object sender, RouteEventArgs e) { if (LoadLegacyFabricApiGetError() is not null) e.handled = true; @@ -2030,7 +2030,7 @@ private void LegacyFabricApi_Loaded() { try { - if (ModDownload.dlLegacyFabricApiLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlLegacyFabricApiLoader.State != LoadState.Finished) return; if (_vanillaName is null || (selectedLegacyFabric is null && selectedQuilt is null)) return; @@ -2059,16 +2059,16 @@ private void LegacyFabricApi_Loaded() (selectedQuilt is not null && LoadQSLGetError() == Lang.Text("Download.Install.State.NoAvailableVersion"))) { autoSelectedLegacyFabricApi = true; - ModBase.Log($"[Download] 已自动选择 Legacy Fabric API:{((MyListItem)PanLegacyFabricApi.Children[0]).Title}"); + LauncherLog.Log($"[Download] 已自动选择 Legacy Fabric API:{((MyListItem)PanLegacyFabricApi.Children[0]).Title}"); LegacyFabricApi_Selected((MyListItem)PanLegacyFabricApi.Children[0], null); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Legacy Fabric API 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -2121,7 +2121,7 @@ private string LoadQuiltGetError() } // 限制展开 - private void CardQuilt_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardQuilt_PreviewSwap(object sender, RouteEventArgs e) { if (LoadQuiltGetError() is not null) e.handled = true; @@ -2134,7 +2134,7 @@ private void Quilt_Loaded() { try { - if (ModDownload.dlQuiltListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlQuiltListLoader.State != LoadState.Finished) return; // 获取版本列表 var versions = (JsonArray)ModDownload.dlQuiltListLoader.output.Value["loader"]; @@ -2154,10 +2154,10 @@ private void Quilt_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Quilt 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -2202,7 +2202,7 @@ public static bool IsSuitableQSL(List supportVersions, string minecraftV } catch (Exception ex) { - ModBase.Log(ex, "判断 QSL 版本适配性出错(" + supportVersions + ", " + minecraftVersion + ")"); + LauncherLog.Log(ex, "判断 QSL 版本适配性出错(" + supportVersions + ", " + minecraftVersion + ")"); return false; } } @@ -2238,7 +2238,7 @@ private string LoadQSLGetError() } // 限制展开 - private void CardQSL_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardQSL_PreviewSwap(object sender, RouteEventArgs e) { if (LoadQSLGetError() is not null) e.handled = true; @@ -2253,7 +2253,7 @@ private void QSL_Loaded() { try { - if (ModDownload.dlQSLLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlQSLLoader.State != LoadState.Finished) return; if (_vanillaName is null || selectedQuilt is null) return; @@ -2264,7 +2264,7 @@ private void QSL_Loaded() { if (!Version.DisplayName.StartsWith("[")) { - ModBase.Log("[Download] 已特判修改 QSL 显示名:" + Version.DisplayName, ModBase.LogLevel.Debug); + LauncherLog.Log("[Download] 已特判修改 QSL 显示名:" + Version.DisplayName, LauncherLogLevel.Debug); Version.DisplayName = "[" + _vanillaName + "] " + Version.DisplayName; } @@ -2288,16 +2288,16 @@ private void QSL_Loaded() if (!autoSelectedQSL) { autoSelectedQSL = true; - ModBase.Log($"[Download] 已自动选择 QSL:{((MyListItem)PanQSL.Children[0]).Title}"); + LauncherLog.Log($"[Download] 已自动选择 QSL:{((MyListItem)PanQSL.Children[0]).Title}"); QSL_Selected((MyListItem)PanQSL.Children[0], null); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 QSL 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -2337,7 +2337,7 @@ private bool IsOptiFabricCompatible(ModComp.CompFile modFile) } catch (Exception ex) { - ModBase.Log(ex, "判断 OptiFabric 版本适配性出错(" + _vanillaName + ")"); + LauncherLog.Log(ex, "判断 OptiFabric 版本适配性出错(" + _vanillaName + ")"); return false; } } @@ -2383,7 +2383,7 @@ private string LoadOptiFabricGetError() } // 限制展开 - private void CardOptiFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardOptiFabric_PreviewSwap(object sender, RouteEventArgs e) { if (LoadOptiFabricGetError() is not null) e.handled = true; @@ -2396,7 +2396,7 @@ private void OptiFabric_Loaded() { try { - if (ModDownload.dlOptiFabricLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlOptiFabricLoader.State != LoadState.Finished) return; if (_vanillaName is null || selectedFabric is null || selectedOptiFine is null) return; @@ -2424,15 +2424,15 @@ private void OptiFabric_Loaded() if (autoSelectedOptiFabric || (VanillaDrop >= 140 && VanillaDrop <= 150)) return; // 1.14~15 不自动选择 autoSelectedOptiFabric = true; - ModBase.Log($"[Download] 已自动选择 OptiFabric:{((MyListItem)PanOptiFabric.Children[0]).Title}"); + LauncherLog.Log($"[Download] 已自动选择 OptiFabric:{((MyListItem)PanOptiFabric.Children[0]).Title}"); OptiFabric_Selected((MyListItem)PanOptiFabric.Children[0], null); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 OptiFabric 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } @@ -2483,7 +2483,7 @@ private string LoadLabyModGetError() } // 限制展开 - private void CardLabyMod_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardLabyMod_PreviewSwap(object sender, RouteEventArgs e) { if (LoadLabyModGetError() is not null) e.handled = true; @@ -2537,10 +2537,10 @@ private void LabyMod_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LabyMod 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Install.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLabyMod.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLabyMod.xaml.cs index 7834ac6ba..fbc52ec3c 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLabyMod.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLabyMod.xaml.cs @@ -45,10 +45,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LabyMod 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } @@ -65,6 +65,6 @@ private void LabyMod_Snapshot_Selected(MyListItem sender, EventArgs e) private void BtnWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://labymod.net"); + LauncherProcess.OpenWebsite("https://labymod.net"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.cs index 0bf401951..209041cf8 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.cs @@ -14,7 +14,7 @@ public void Refresh() // 强制刷新 public void RefreshButton_Click(object sender, EventArgs e) // 由边栏按钮匿名调用 { - Refresh((FormMain.PageSubType)ModBase.Val(((MyIconButton)sender).Tag)); + Refresh((FormMain.PageSubType)LauncherText.Val(((MyIconButton)sender).Tag)); } public void Refresh(FormMain.PageSubType subType) @@ -237,10 +237,10 @@ public PageDownloadLeft() /// /// 勾选事件改变页面。 /// - private void PageCheck(object sender, ModBase.RouteEventArgs e) + private void PageCheck(object sender, RouteEventArgs e) { if (sender is MyListItem { Tag: { } tag }) - PageChange((FormMain.PageSubType)ModBase.Val(tag)); + PageChange((FormMain.PageSubType)LauncherText.Val(tag)); } public object PageGet(FormMain.PageSubType id) @@ -380,10 +380,10 @@ public void PageChange(FormMain.PageSubType id) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "切换分页面失败(ID " + (int)id + ")", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } finally diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLegacyFabric.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLegacyFabric.xaml.cs index 430e80b31..35073a4a9 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLegacyFabric.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLegacyFabric.xaml.cs @@ -37,10 +37,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LegacyFabric 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } @@ -52,6 +52,6 @@ private void LegacyFabric_Selected(MyListItem sender, EventArgs e) private void BtnWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://legacyfabric.net/"); + LauncherProcess.OpenWebsite("https://legacyfabric.net/"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLiteLoader.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLiteLoader.xaml.cs index ce527d2a8..453fdb7e5 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLiteLoader.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLiteLoader.xaml.cs @@ -82,10 +82,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LiteLoader 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } @@ -97,6 +97,6 @@ public void DownloadStart(MyListItem sender, object e) private void BtnWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://www.liteloader.com"); + LauncherProcess.OpenWebsite("https://www.liteloader.com"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml.cs index c66f3bfd3..8272caebe 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml.cs @@ -63,10 +63,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 NeoForge 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.cs index 18e11aec8..84e666436 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.cs @@ -86,16 +86,16 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 OptiFine 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } private void BtnWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://www.optifine.net/"); + LauncherProcess.OpenWebsite("https://www.optifine.net/"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadQuilt.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadQuilt.xaml.cs index 793f35f53..1952e51d7 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadQuilt.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadQuilt.xaml.cs @@ -37,10 +37,10 @@ private void Load_OnFinish() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Quilt 版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Download.Error.OperationFailed")); } } @@ -52,6 +52,6 @@ private void Quilt_Selected(MyListItem sender, EventArgs e) private void BtnWeb_Click(object sender, EventArgs e) { - ModBase.OpenWebsite("https://quiltmc.org"); + LauncherProcess.OpenWebsite("https://quiltmc.org"); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs index 39c2ed84b..bca13218b 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs @@ -65,20 +65,20 @@ public void Refresh() { case ModLocalComp.LocalCompFile.LocalFileStatus.Fine: { - descFileName = ModBase.GetFileNameWithoutExtentionFromPath(Entry.path); + descFileName = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(Entry.path); break; } case ModLocalComp.LocalCompFile.LocalFileStatus.Disabled: { descFileName = - ModBase.GetFileNameWithoutExtentionFromPath(Entry.path.Replace(".disabled", "") + LegacyFileFacade.GetFileNameWithoutExtensionFromPath(Entry.path.Replace(".disabled", "") .Replace(".old", "")); // McMod.McModState.Unavailable break; } default: { - descFileName = ModBase.GetFileNameFromPath(Entry.path); + descFileName = LegacyFileFacade.GetFileNameFromPath(Entry.path); break; } } @@ -180,7 +180,7 @@ public void Refresh() // Source="/Images/Icons/Unavailable.png" /> } - imgState.Source = new MyBitmap(ModBase.pathImage + $"Icons/{Entry.State}.png"); + imgState.Source = new MyBitmap(LauncherPaths.ImageBaseUri + $"Icons/{Entry.State}.png"); } // 标签 @@ -277,7 +277,7 @@ private void ShowUpdateLog() var modrinthUrl = Entry.changelogUrls.FirstOrDefault(x => x.Contains("modrinth.com")); if (modrinthUrl is not null) { - ModBase.OpenWebsite(modrinthUrl); + LauncherProcess.OpenWebsite(modrinthUrl); return; } } @@ -286,15 +286,15 @@ private void ShowUpdateLog() var curseForgeUrl = Entry.changelogUrls.FirstOrDefault(x => x.Contains("curseforge.com")); if (curseForgeUrl is not null) { - ModBase.OpenWebsite(curseForgeUrl); + LauncherProcess.OpenWebsite(curseForgeUrl); return; } } } - ModBase.Log( + LauncherLog.Log( Lang.Text("Instance.Resource.Item.OpenChangelogFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Resource.Item.OpenChangelogFailed")); } @@ -423,7 +423,7 @@ private void PanTitle_SizeChanged(object sender, SizeChangedEventArgs sizeChange #region 基础属性 - public int Uuid = ModBase.GetUuid(); + public int Uuid = LauncherRuntime.GetUuid(); // Logo public string Logo @@ -569,7 +569,7 @@ private void Button_MouseUp(object sender, MouseButtonEventArgs e) Click?.Invoke(sender, e); if (e.Handled) return; - ModBase.Log("[Control] 按下本地 Mod 列表项:" + LabTitle.Text); + LauncherLog.Log("[Control] 按下本地 Mod 列表项:" + LabTitle.Text); } } @@ -649,9 +649,9 @@ private void Button_MouseSwipe(object sender, object e) var elements = ((StackPanel)Parent).Children; var index = elements.IndexOf(this); CurrentSwipe.Start = - (int)Math.Round(ModBase.MathClamp(Math.Min(CurrentSwipe.Start, index), 0d, elements.Count - 1)); + (int)Math.Round(LauncherMath.Clamp(Math.Min(CurrentSwipe.Start, index), 0d, elements.Count - 1)); CurrentSwipe.End = - (int)Math.Round(ModBase.MathClamp(Math.Max(CurrentSwipe.End, index), 0d, elements.Count - 1)); + (int)Math.Round(LauncherMath.Clamp(Math.Max(CurrentSwipe.End, index), 0d, elements.Count - 1)); // 勾选所有范围中的项 if (CurrentSwipe.Start == CurrentSwipe.End) return; @@ -666,11 +666,11 @@ private void Button_MouseSwipe(object sender, object e) // 勾选状态 public event CheckEventHandler? Check; - public delegate void CheckEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void CheckEventHandler(object sender, RouteEventArgs e); public event ChangedEventHandler? Changed; - public delegate void ChangedEventHandler(object sender, ModBase.RouteEventArgs e); + public delegate void ChangedEventHandler(object sender, RouteEventArgs e); public bool Checked { @@ -684,7 +684,7 @@ public bool Checked if (value == field) return; field = value; - var ChangedEventArgs = new ModBase.RouteEventArgs(); + var ChangedEventArgs = new RouteEventArgs(); if (IsInitialized) { Changed?.Invoke(this, ChangedEventArgs); @@ -697,7 +697,7 @@ public bool Checked if (value) { - var checkEventArgs = new ModBase.RouteEventArgs(); + var checkEventArgs = new RouteEventArgs(); Check?.Invoke(this, checkEventArgs); if (checkEventArgs.handled) return; @@ -765,7 +765,7 @@ public bool Checked } catch (Exception ex) { - ModBase.Log(ex, "设置 Checked 失败"); + LauncherLog.Log(ex, "设置 Checked 失败"); } } } @@ -790,7 +790,7 @@ public Border RectBack CornerRadius = new CornerRadius(3d), RenderTransform = new ScaleTransform(0.8d, 0.8d), RenderTransformOrigin = new Point(0.5d, 0.5d), - BorderThickness = new Thickness(ModBase.GetWPFSize(1d)), + BorderThickness = new Thickness(DpiUtils.GetWpfSize(1d)), SnapsToDevicePixels = true, IsHitTestVisible = false, Opacity = 0d diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs index 6718d2c65..9226128dd 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs @@ -80,7 +80,7 @@ public PageInstanceCompResource() } catch (Exception ex) { - ModBase.Log(ex, "获取模组信息失败: " + path); + LauncherLog.Log(ex, "获取模组信息失败: " + path); return (DateTime.MinValue, 0L); } } @@ -226,7 +226,7 @@ public void PageOther_Loaded() // 检查是否为原理图管理界面且首次打开 if (currentCompType == ModComp.CompType.Schematic && !States.Hint.SchematicFirstTime) // 显示首次打开提示 - ModBase.RunInUi(() => + UiThread.Post(() => { ModMain.MyMsgBox(Lang.Text("Instance.Saves.Folder.DoubleClickHint.Message"), Lang.Text("Instance.Saves.Folder.DoubleClickHint.Title"), Lang.Text("Common.Action.GotIt")); States.Hint.SchematicFirstTime = true; @@ -247,10 +247,10 @@ public void ReloadCompFileList(bool forceReload = false) ? ModLoader.LoaderFolderRunType.ForceRun : ModLoader.LoaderFolderRunType.RunOnUpdated)) { - ModBase.Log($"[System] 已刷新 {currentCompType} 列表"); + LauncherLog.Log($"[System] 已刷新 {currentCompType} 列表"); modFileInfoCache.Clear(); - ModBase.RunInUi(() => + UiThread.Post(() => { Filter = FilterType.All; PanBack.ScrollToHome(); @@ -277,12 +277,12 @@ public static void Refresh(ModComp.CompType whichPage) { ModComp.compProjectCache.Clear(); ModComp.compFilesCache.Clear(); - File.Delete(ModBase.pathTemp + @"Cache\LocalComp.json"); - ModBase.Log("[CompResource] 由于点击刷新按钮,清理本地工程信息缓存"); + File.Delete(LauncherPaths.TempWithSlash + @"Cache\LocalComp.json"); + LauncherLog.Log("[CompResource] 由于点击刷新按钮,清理本地工程信息缓存"); } catch (Exception ex) { - ModBase.Log(ex, "强制刷新时清理本地工程信息缓存失败"); + LauncherLog.Log(ex, "强制刷新时清理本地工程信息缓存失败"); } switch (whichPage) @@ -328,7 +328,7 @@ private void LoaderInit() private void Load_Click(object sender, MouseButtonEventArgs e) { - if (ModLocalComp.compResourceListLoader.State == ModBase.LoadState.Failed) + if (ModLocalComp.compResourceListLoader.State == LoadState.Failed) LoaderRun(ModLoader.LoaderFolderRunType.ForceRun); } @@ -371,17 +371,17 @@ private void EnterFolder(string folderPath) } CurrentFolderPath = folderPath; - ModBase.Log($"[原理图] 进入文件夹:{folderPath}"); + LauncherLog.Log($"[原理图] 进入文件夹:{folderPath}"); ModLoader.LoaderFolderRun(ModLocalComp.compResourceListLoader, folderPath, ModLoader.LoaderFolderRunType.ForceRun, loaderInput: GetRequireLoaderData()); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "进入文件夹失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -397,10 +397,10 @@ private void EnterFolderWithCheck(string folderPath) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "进入文件夹失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -434,12 +434,12 @@ private void GoBackToParentFolder() } catch (Exception ex) { - ModBase.Log(ex, "路径处理失败"); + LauncherLog.Log(ex, "路径处理失败"); // 发生错误时直接返回根目录 CurrentFolderPath = ""; } - ModBase.Log($"[原理图] 返回上级文件夹:{(string.IsNullOrEmpty(CurrentFolderPath) ? "根目录" : CurrentFolderPath)}"); + LauncherLog.Log($"[原理图] 返回上级文件夹:{(string.IsNullOrEmpty(CurrentFolderPath) ? "根目录" : CurrentFolderPath)}"); // 重新加载当前文件夹的内容 string loadPath; @@ -455,12 +455,12 @@ private void GoBackToParentFolder() // 强制刷新UI状态 // 确保按钮状态正确 - ModBase.RunInUi(() => + UiThread.Post(() => BtnManageBack.Visibility = !string.IsNullOrEmpty(CurrentFolderPath) ? Visibility.Visible : Visibility.Collapsed); // 延迟一帧后再加载,确保UI状态已更新 - ModBase.RunInUi( + UiThread.Post( () => ModLoader.LoaderFolderRun(ModLocalComp.compResourceListLoader, loadPath, ModLoader.LoaderFolderRunType.ForceRun, loaderInput: GetRequireLoaderData()), true); } @@ -559,7 +559,7 @@ private void LoadUIFromLoaderOutput() foreach (var ModEntity in itemsToShow) modItems[ModEntity.RawPath] = BuildLocalCompItem(ModEntity); // 显示结果 - ModBase.RunInUi(() => + UiThread.Post(() => { Filter = FilterType.All; SearchBox.Text = ""; // 这会触发结果刷新,所以需要在 ModItems 更新之后,详见 #3124 的视频 @@ -569,10 +569,10 @@ private void LoadUIFromLoaderOutput() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"加载 {currentCompType} 列表 UI 失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -600,7 +600,7 @@ private MyLocalCompItem BuildLocalCompItem(ModLocalComp.LocalCompFile entry) catch (Exception ex) { ModAnimation.AniControlEnabled -= 1; - ModBase.Log(ex, $"创建 UI 项失败:{entry.RawPath}"); + LauncherLog.Log(ex, $"创建 UI 项失败:{entry.RawPath}"); throw; } } @@ -957,14 +957,14 @@ private void BtnManageOpen_Click(object sender, EventArgs e) // 打开当前子文件夹 compFilePath = CurrentFolderPath.EndsWith(@"\") ? CurrentFolderPath : CurrentFolderPath + @"\"; Directory.CreateDirectory(compFilePath); - ModBase.OpenExplorer(compFilePath); + LauncherProcess.OpenExplorer(compFilePath); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "打开 Mods 文件夹失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -1086,19 +1086,19 @@ private static void ExecuteModInstallation(McInstance targetMcInstance, IEnumera { foreach (var modFile in filePathList) { - var fileName = ModBase.GetFileNameFromPath(modFile) + var fileName = LegacyFileFacade.GetFileNameFromPath(modFile) .Replace(".disabled", "") .Replace(".old", ""); if (!fileName.Contains(".")) fileName += ".jar"; // Ensure extension (#4227) - ModBase.CopyFile(modFile, Path.Combine(modFolder, fileName)); + LegacyFileFacade.CopyFile(modFile, Path.Combine(modFolder, fileName)); } // Success hint if (filePathList.Count() == 1) { - var installedName = ModBase.GetFileNameFromPath(filePathList.First()).Replace(".disabled", "") + var installedName = LegacyFileFacade.GetFileNameFromPath(filePathList.First()).Replace(".disabled", "") .Replace(".old", ""); HintWrapper.Show(Lang.Text("Instance.Resource.Install.SuccessSingle", installedName), HintTheme.Success); } @@ -1207,7 +1207,7 @@ public static void InstallCompFiles(IEnumerable filePathList, ModComp.Co return; } - ModBase.Log($"[System] 文件为 {extension} 格式,尝试作为{compTypeName}安装"); + LauncherLog.Log($"[System] 文件为 {extension} 格式,尝试作为{compTypeName}安装"); // 检查实例兼容性 if (compType == ModComp.CompType.Mod && (ModMain.frmMain.pageCurrent == FormMain.PageType.InstanceSelect || @@ -1256,7 +1256,7 @@ public static void InstallCompFiles(IEnumerable filePathList, ModComp.Co Directory.CreateDirectory(compFolder); foreach (var FilePath in filePathList) { - var newFileName = ModBase.GetFileNameFromPath(FilePath); + var newFileName = LegacyFileFacade.GetFileNameFromPath(FilePath); if (compType == ModComp.CompType.Mod) { newFileName = newFileName.Replace(".disabled", "").Replace(".old", ""); @@ -1269,11 +1269,11 @@ public static void InstallCompFiles(IEnumerable filePathList, ModComp.Co if (ModMain.MyMsgBox(Lang.Text("Instance.Resource.Install.OverwriteConfirm.Message", newFileName), Lang.Text("Instance.Resource.Install.OverwriteConfirm.Title"), Lang.Text("Common.Action.Overwrite"), Lang.Text("Common.Action.Cancel")) != 1) continue; - ModBase.CopyFile(FilePath, destFile); + LegacyFileFacade.CopyFile(FilePath, destFile); } if (filePathList.Count() == 1) - HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessSingle", ModBase.GetFileNameFromPath(filePathList.First())), HintType.Success); + HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessSingle", LegacyFileFacade.GetFileNameFromPath(filePathList.First())), HintType.Success); else HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessMultiple", filePathList.Count(), compTypeName), HintType.Success); @@ -1296,7 +1296,7 @@ public static void InstallCompFiles(IEnumerable filePathList, ModComp.Co case ModComp.CompType.Schematic: { var currentForm = GetCurrentCompResourceForm(); - if (currentForm is not null) ModBase.RunInUi(() => currentForm.ReloadCompFileList(true)); + if (currentForm is not null) UiThread.Post(() => currentForm.ReloadCompFileList(true)); break; } @@ -1305,10 +1305,10 @@ public static void InstallCompFiles(IEnumerable filePathList, ModComp.Co catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"复制{compTypeName}文件失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -1358,14 +1358,14 @@ void ExportText(string content, string fileName) SystemDialogs.SelectSaveFile(Lang.Text("Instance.Resource.Export.SelectSaveLocation"), fileName, Lang.Text("Instance.Resource.Export.FilesFilter")); if (string.IsNullOrWhiteSpace(savePath)) return; File.WriteAllText(savePath, content, Encoding.UTF8); - ModBase.OpenExplorer(savePath); + LauncherProcess.OpenExplorer(savePath); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "导出资源信息失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -1450,7 +1450,7 @@ private void BtnSchematicVersionSelect_Click(object sender, MouseButtonEventArgs public HashSet selectedMods = new(); // 单项切换选择状态 - public void CheckChanged(MyLocalCompItem sender, ModBase.RouteEventArgs e) + public void CheckChanged(MyLocalCompItem sender, RouteEventArgs e) { if (ModAnimation.AniControlEnabled != 0) return; @@ -1676,7 +1676,7 @@ private string GetSortName(SortMethod method) return ""; } - private void BtnSortClick(object sender, ModBase.RouteEventArgs e) + private void BtnSortClick(object sender, RouteEventArgs e) { var body = new ContextMenu(); foreach (SortMethod i in Enum.GetValues(typeof(SortMethod))) @@ -1724,10 +1724,10 @@ private void DoSort() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "执行排序时出错", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -1869,7 +1869,7 @@ int folderFirstCompare(ModLocalComp.LocalCompFile a, ModLocalComp.LocalCompFile #region 下边栏 // 启用 / 禁用 - private void BtnSelectED_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectED_Click(object sender, RouteEventArgs e) { EDMods(ModLocalComp.compResourceListLoader.output.Where(m => selectedMods.Contains(m.RawPath)).ToList(), !sender.Equals(BtnSelectDisable)); @@ -1899,7 +1899,7 @@ private void EDMods(IEnumerable modList, bool isEnab if (File.Exists(modEntity.path)) { // 同时存在两个名称的 Mod - if ((ModBase.GetFileMD5(modEntity.path) ?? "") != (ModBase.GetFileMD5(newPath) ?? "")) + if ((LegacyFileFacade.GetFileMd5(modEntity.path) ?? "") != (LegacyFileFacade.GetFileMd5(newPath) ?? "")) { ModMain.MyMsgBox( Lang.Text("Instance.Resource.Ed.FileConflict.Message", newPath, modEntity.path), @@ -1910,7 +1910,7 @@ private void EDMods(IEnumerable modList, bool isEnab else { // 已经重命名过了 - ModBase.Log("[Mod] Mod 的状态已被切换", ModBase.LogLevel.Debug); + LauncherLog.Log("[Mod] Mod 的状态已被切换", LauncherLogLevel.Debug); continue; } } @@ -1920,17 +1920,17 @@ private void EDMods(IEnumerable modList, bool isEnab } catch (FileNotFoundException ex) { - ModBase.Log( + LauncherLog.Log( ex, $"未找到需要重命名的 Mod({modEntity.path ?? "null"})", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); ReloadCompFileList(true); return; } catch (Exception ex) { - ModBase.Log(ex, $"重命名 Mod 失败({modEntity.path ?? "null"})"); + LauncherLog.Log(ex, $"重命名 Mod 失败({modEntity.path ?? "null"})"); isSuccessful = false; } @@ -1965,10 +1965,10 @@ private void EDMods(IEnumerable modList, bool isEnab } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"更新 UI 列表项失败:{modEntity.FileName}", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -1988,7 +1988,7 @@ private void EDMods(IEnumerable modList, bool isEnab } // 更新 - private void BtnSelectUpdate_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectUpdate_Click(object sender, RouteEventArgs e) { var updateList = ModLocalComp.compResourceListLoader.output .Where(m => selectedMods.Contains(m.RawPath) && m.CanUpdate).ToList(); @@ -2064,9 +2064,9 @@ public void UpdateResource(IEnumerable modList) } // 添加到下载列表 - var tempAddress = ModBase.pathTemp + @"DownloadedComp\" + + var tempAddress = LauncherPaths.TempWithSlash + @"DownloadedComp\" + Entry.FileName.Replace(currentReplaceName, newestReplaceName); - var realAddress = ModBase.GetPathFromFullPath(Entry.path) + + var realAddress = LegacyFileFacade.GetPathFromFullPath(Entry.path) + Entry.FileName.Replace(currentReplaceName, newestReplaceName); fileList.Add(file.ToNetFile(tempAddress)); fileCopyList[tempAddress] = realAddress; @@ -2087,7 +2087,7 @@ public void UpdateResource(IEnumerable modList) Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile(Entry.path, UIOption.AllDialogs, RecycleOption.SendToRecycleBin); else - ModBase.Log($"[CompUpdate] 未找到更新前的资源文件,跳过对它的删除:{Entry.path}", ModBase.LogLevel.Debug); + LauncherLog.Log($"[CompUpdate] 未找到更新前的资源文件,跳过对它的删除:{Entry.path}", LauncherLogLevel.Debug); foreach (var Entry in fileCopyList) { @@ -2095,23 +2095,23 @@ public void UpdateResource(IEnumerable modList) { Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile(Entry.Value, UIOption.AllDialogs, RecycleOption.SendToRecycleBin); - ModBase.Log($"[Mod] 更新后的资源文件已存在,将会把它放入回收站:{Entry.Value}", ModBase.LogLevel.Debug); + LauncherLog.Log($"[Mod] 更新后的资源文件已存在,将会把它放入回收站:{Entry.Value}", LauncherLogLevel.Debug); } - if (Directory.Exists(ModBase.GetPathFromFullPath(Entry.Value))) + if (Directory.Exists(LegacyFileFacade.GetPathFromFullPath(Entry.Value))) { File.Move(Entry.Key, Entry.Value); - finishedFileNames.Add(ModBase.GetFileNameFromPath(Entry.Value)); + finishedFileNames.Add(LegacyFileFacade.GetFileNameFromPath(Entry.Value)); } else { - ModBase.Log($"[Mod] 更新后的目标文件夹已被删除:{Entry.Value}", ModBase.LogLevel.Debug); + LauncherLog.Log($"[Mod] 更新后的目标文件夹已被删除:{Entry.Value}", LauncherLogLevel.Debug); } } } catch (OperationCanceledException ex) { - ModBase.Log(ex, "替换旧版资源文件时被主动取消"); + LauncherLog.Log(ex, "替换旧版资源文件时被主动取消"); } })); // 结束处理 @@ -2127,13 +2127,13 @@ public void UpdateResource(IEnumerable modList) // 结果提示 switch (loader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: { switch (finishedFileNames.Count) { case 0: // 一般是由于 Mod 文件被占用,然后玩家主动取消 { - ModBase.Log("[CompUpdate] 没有资源被成功更新"); + LauncherLog.Log("[CompUpdate] 没有资源被成功更新"); break; } case 1: @@ -2151,12 +2151,12 @@ public void UpdateResource(IEnumerable modList) break; } - case ModBase.LoadState.Failed: + case LoadState.Failed: { HintService.Hint(Lang.Text("Instance.Resource.Update.Failed", loader.Error.Message), HintType.Error); break; } - case ModBase.LoadState.Aborted: + case LoadState.Aborted: { HintService.Hint(Lang.Text("Instance.Resource.Update.Aborted")); break; @@ -2168,10 +2168,10 @@ public void UpdateResource(IEnumerable modList) } } - ModBase.Log($"[CompUpdate] 已从正在进行资源更新的文件夹列表移除:{pathMods}"); + LauncherLog.Log($"[CompUpdate] 已从正在进行资源更新的文件夹列表移除:{pathMods}"); updatingVersions.Remove(pathMods); // 清理缓存 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -2181,12 +2181,12 @@ public void UpdateResource(IEnumerable modList) } catch (Exception ex) { - ModBase.Log(ex, "清理资源更新缓存失败"); + LauncherLog.Log(ex, "清理资源更新缓存失败"); } }, "Clean Comp Update Cache", ThreadPriority.BelowNormal); }; // 启动加载器 - ModBase.Log($"[CompUpdate] 开始更新 {modList.Count()} 个资源:{pathMods}"); + LauncherLog.Log($"[CompUpdate] 开始更新 {modList.Count()} 个资源:{pathMods}"); updatingVersions.Add(pathMods); loader.Start(); ModLoader.LoaderTaskbarAdd(loader); @@ -2196,12 +2196,12 @@ public void UpdateResource(IEnumerable modList) } catch (Exception ex) { - ModBase.Log(ex, "初始化资源更新失败"); + LauncherLog.Log(ex, "初始化资源更新失败"); } } // 删除 - private void BtnSelectDelete_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectDelete_Click(object sender, RouteEventArgs e) { DeleteMods(ModLocalComp.compResourceListLoader.output.Where(m => selectedMods.Contains(m.RawPath))); ChangeAllSelected(false); @@ -2256,16 +2256,16 @@ private void DeleteMods(IEnumerable modList) } catch (OperationCanceledException ex) { - ModBase.Log(ex, "删除资源被主动取消"); + LauncherLog.Log(ex, "删除资源被主动取消"); ReloadCompFileList(true); return; } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"删除资源失败({ModEntity.path})", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); isSuccessful = false; } @@ -2318,15 +2318,15 @@ private void DeleteMods(IEnumerable modList) } catch (OperationCanceledException ex) { - ModBase.Log(ex, "删除资源被主动取消"); + LauncherLog.Log(ex, "删除资源被主动取消"); ReloadCompFileList(true); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "删除资源出现未知错误", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); ReloadCompFileList(true); } @@ -2335,13 +2335,13 @@ private void DeleteMods(IEnumerable modList) } // 取消选择 - private void BtnSelectCancel_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectCancel_Click(object sender, RouteEventArgs e) { ChangeAllSelected(false); } // 收藏 - private void BtnSelectFavorites_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectFavorites_Click(object sender, RouteEventArgs e) { var selected = ModLocalComp.compResourceListLoader.output .Where(m => selectedMods.Contains(m.RawPath) && m.Comp is not null).Select(i => i.Comp).ToList(); @@ -2349,11 +2349,11 @@ private void BtnSelectFavorites_Click(object sender, ModBase.RouteEventArgs e) } // 分享 - private void BtnSelectShare_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectShare_Click(object sender, RouteEventArgs e) { var shareList = ModLocalComp.compResourceListLoader.output .Where(m => selectedMods.Contains(m.RawPath) && m.Comp is not null).Select(i => i.Comp.Id).ToHashSet(); - ModBase.ClipboardSet(ModComp.CompFavorites.GetShareCode(shareList)); + LauncherProcess.ClipboardSet(ModComp.CompFavorites.GetShareCode(shareList)); ChangeAllSelected(false); } @@ -2480,7 +2480,7 @@ public void Info_Click(object sender, EventArgs e) contentLines.Add(modEntry.Description + "\r\n"); if (modEntry.Authors is not null) contentLines.Add(Lang.Text("Instance.Resource.Item.Info.Author", modEntry.Authors)); - contentLines.Add(Lang.Text("Instance.Resource.Item.Info.File", modEntry.FileName, ModBase.GetString(GetModFileInfo(modEntry.path).Length))); + contentLines.Add(Lang.Text("Instance.Resource.Item.Info.File", modEntry.FileName, LauncherText.GetReadableFileSize(GetModFileInfo(modEntry.path).Length))); if (modEntry.Version is not null) contentLines.Add(Lang.Text("Instance.Resource.Item.Info.Version", modEntry.Version)); @@ -2539,13 +2539,13 @@ public void Info_Click(object sender, EventArgs e) if (modEntry.Url is null) ModMain.MyMsgBox(contentLines.Join("\r\n"), modEntry.Name, Lang.Text("Instance.Resource.Item.Info.Return")); else if (ModMain.MyMsgBox(contentLines.Join("\r\n"), modEntry.Name, Lang.Text("Instance.Resource.Item.Info.OpenWebsite"), Lang.Text("Instance.Resource.Item.Info.Return")) == - 1) ModBase.OpenWebsite(modEntry.Url); + 1) LauncherProcess.OpenWebsite(modEntry.Url); } // 其他资源类型保留百科搜索功能 else if (modEntry.Url is null) { if (ModMain.MyMsgBox(contentLines.Join("\r\n"), modEntry.Name, Lang.Text("Instance.Resource.Item.Info.McMod"), Lang.Text("Instance.Resource.Item.Info.Return")) == 1) - ModBase.OpenWebsite("https://www.mcmod.cn/s?key=" + modSearchName + "&site=all&filter=0"); + LauncherProcess.OpenWebsite("https://www.mcmod.cn/s?key=" + modSearchName + "&site=all&filter=0"); } else { @@ -2554,12 +2554,12 @@ public void Info_Click(object sender, EventArgs e) { case 1: { - ModBase.OpenWebsite(modEntry.Url); + LauncherProcess.OpenWebsite(modEntry.Url); break; } case 2: { - ModBase.OpenWebsite( + LauncherProcess.OpenWebsite( "https://www.mcmod.cn/s?key=" + modSearchName + "&site=all&filter=0"); break; } @@ -2570,10 +2570,10 @@ public void Info_Click(object sender, EventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "获取资源详情失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -2586,14 +2586,14 @@ public void Open_Click(MyIconButton sender, EventArgs e) var listItem = (MyLocalCompItem)sender.Tag; // 对于文件夹使用实际路径,对于文件使用原路径 var targetPath = listItem.Entry.IsFolder ? listItem.Entry.ActualPath : listItem.Entry.path; - ModBase.OpenExplorer(targetPath); + LauncherProcess.OpenExplorer(targetPath); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "打开资源文件位置失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } } @@ -2635,19 +2635,19 @@ private void ShowSchematicInfoAsync(ModLocalComp.LocalCompFile modEntry) // 记录错误日志但不显示错误提示,因为通用的文件状态检查已经处理了 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { modEntry.LoadNbtDataIfNeeded(); - ModBase.RunInUi(() => + UiThread.Post(() => { try { var contentLines = new List(); if (modEntry.Description is not null) contentLines.Add(modEntry.Description + "\r\n"); if (modEntry.Authors is not null) contentLines.Add(Lang.Text("Instance.Resource.Item.Info.Author", modEntry.Authors)); - contentLines.Add(Lang.Text("Instance.Resource.Item.Info.File", modEntry.FileName, ModBase.GetString(GetModFileInfo(modEntry.path).Length))); + contentLines.Add(Lang.Text("Instance.Resource.Item.Info.File", modEntry.FileName, LauncherText.GetReadableFileSize(GetModFileInfo(modEntry.path).Length))); if (modEntry.Version is not null) contentLines.Add(Lang.Text("Instance.Resource.Item.Info.Version", modEntry.Version)); if (modEntry.path.EndsWithF(".litematic", true)) ShowLitematicDetails(contentLines, modEntry); @@ -2661,20 +2661,20 @@ private void ShowSchematicInfoAsync(ModLocalComp.LocalCompFile modEntry) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "显示原理图详情失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } }); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "加载原理图 NBT 数据失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Resource.Error.OperationFailed")); } }); @@ -2853,7 +2853,7 @@ private void ShowSchematicDialog(List contentLines, ModLocalComp.LocalCo if (modEntry.Url is null) ModMain.MyMsgBox(contentLines.Join("\r\n"), modEntry.Name, Lang.Text("Instance.Resource.Item.Info.Return")); else if (ModMain.MyMsgBox(contentLines.Join("\r\n"), modEntry.Name, Lang.Text("Instance.Resource.Item.Info.OpenWebsite"), Lang.Text("Instance.Resource.Item.Info.Return")) == 1) - ModBase.OpenWebsite(modEntry.Url); + LauncherProcess.OpenWebsite(modEntry.Url); } #endregion @@ -2893,7 +2893,7 @@ public void SearchRun(object sender, EventArgs e) } catch (Exception ex) { - ModBase.Log(ex, "搜索过程中发生异常"); + LauncherLog.Log(ex, "搜索过程中发生异常"); } })); } @@ -2901,32 +2901,32 @@ public void SearchRun(object sender, EventArgs e) private List GetSearchResult(string query) { // 构造请求 - var queryList = new List>(); + var queryList = new List>(); foreach (var Entry in ModLocalComp.compResourceListLoader.output.AsReadOnly()) { - var searchSource = new List(); - searchSource.Add(new ModBase.SearchSource(Entry.Name, 1d)); - searchSource.Add(new ModBase.SearchSource(Entry.FileName, 1d)); - if (Entry.Version is not null) searchSource.Add(new ModBase.SearchSource(Entry.Version, 0.2d)); + var searchSource = new List(); + searchSource.Add(new SearchSource(Entry.Name, 1d)); + searchSource.Add(new SearchSource(Entry.FileName, 1d)); + if (Entry.Version is not null) searchSource.Add(new SearchSource(Entry.Version, 0.2d)); if (Entry.Description is not null && !string.IsNullOrEmpty(Entry.Description)) - searchSource.Add(new ModBase.SearchSource(Entry.Description, 0.4d)); + searchSource.Add(new SearchSource(Entry.Description, 0.4d)); if (Entry.Comp is not null) { if ((Entry.Comp.RawName ?? "") != (Entry.Name ?? "")) - searchSource.Add(new ModBase.SearchSource(Entry.Comp.RawName, 1d)); + searchSource.Add(new SearchSource(Entry.Comp.RawName, 1d)); if ((Entry.Comp.TranslatedName ?? "") != (Entry.Comp.RawName ?? "")) - searchSource.Add(new ModBase.SearchSource(Entry.Comp.TranslatedName, 1d)); + searchSource.Add(new SearchSource(Entry.Comp.TranslatedName, 1d)); if ((Entry.Comp.Description ?? "") != (Entry.Description ?? "")) - searchSource.Add(new ModBase.SearchSource(Entry.Comp.Description, 0.4d)); - searchSource.Add(new ModBase.SearchSource(string.Join("", Entry.Comp.Tags), 0.2d)); + searchSource.Add(new SearchSource(Entry.Comp.Description, 0.4d)); + searchSource.Add(new SearchSource(string.Join("", Entry.Comp.Tags), 0.2d)); } - queryList.Add(new ModBase.SearchEntry + queryList.Add(new SearchEntry { item = Entry, searchSource = searchSource }); } // 进行搜索 - return ModBase.Search(queryList, query, ModBase.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); + return LauncherSearch.Search(queryList, query, LauncherSearch.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); } #endregion diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs index 653009577..a09c02746 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs @@ -80,7 +80,7 @@ private void PageInstanceExport_Loaded() public void RefreshAll() { - ModBase.Log("[Export] 刷新导出页面"); + LauncherLog.Log("[Export] 刷新导出页面"); HintOptiFine.Visibility = PageInstanceLeft.McInstance.Info.HasOptiFine ? Visibility.Visible : Visibility.Collapsed; currentVersion = PageInstanceLeft.McInstance.PathInstance; @@ -157,7 +157,7 @@ private void ReloadSubOptions(StackPanel panel, bool acceptCompressedFile, bool Tag = new ExportOption { Title = File.Name, DefaultChecked = true, - Rules = ModBase.EscapeLikePattern($"{Folder}/{File.Name}") + Rules = LauncherText.EscapeLikePattern($"{Folder}/{File.Name}") } }); if (Folder == "shaderpacks") // 处理光影包的配置文件 @@ -172,7 +172,7 @@ private void ReloadSubOptions(StackPanel panel, bool acceptCompressedFile, bool { Title = $"{shaderConfig.Name}", DefaultChecked = true, Description = Lang.Text("Instance.Export.Config.ShaderConfigSuffix"), - Rules = ModBase.EscapeLikePattern($"{Folder}/{shaderConfig.Name}") + Rules = LauncherText.EscapeLikePattern($"{Folder}/{shaderConfig.Name}") } }); } @@ -190,7 +190,7 @@ private void ReloadSubOptions(StackPanel panel, bool acceptCompressedFile, bool Tag = new ExportOption { Title = SubFolder.Name, DefaultChecked = true, - Rules = ModBase.EscapeLikePattern($"{Folder}/{SubFolder.Name}/") + Rules = LauncherText.EscapeLikePattern($"{Folder}/{SubFolder.Name}/") } }; if (ReferenceEquals(panel, PanOptionsSaves)) @@ -209,7 +209,7 @@ private void ReloadSubOptions(StackPanel panel, bool acceptCompressedFile, bool { Title = $"{shaderConfig.Name}", DefaultChecked = true, Description = Lang.Text("Instance.Export.Config.ShaderConfigSuffix"), - Rules = ModBase.EscapeLikePattern($"{Folder}/{shaderConfig.Name}") + Rules = LauncherText.EscapeLikePattern($"{Folder}/{shaderConfig.Name}") } }); } @@ -254,7 +254,7 @@ bool IsValidDirectory(DirectoryInfo folder) .Select(d => $@"{SubFolder.Name}\{d.Name}\")); } - ModBase.Log($"[Export] 共发现 {allEntries.Count} 个可行的二级文件/文件夹"); + LauncherLog.Log($"[Export] 共发现 {allEntries.Count} 个可行的二级文件/文件夹"); // 确认选项是否应该被显示 bool IsVisible(ExportOption targetOption) @@ -280,10 +280,10 @@ bool IsVisible(ExportOption targetOption) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"错误的规则:{rule}", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Export.Error.OperationFailed")); return false; } @@ -542,16 +542,16 @@ private void ExportConfig(object sender, MouseButtonEventArgs e) configLines.Add(sperator); configLines.AddRange(GetExtraFileLines()); // 结束 - ModBase.WriteFile(configPath, configLines.Join("\r\n")); + LegacyFileFacade.WriteFile(configPath, configLines.Join("\r\n")); HintService.Hint(Lang.Text("Instance.Export.SaveSuccess", configPath), HintType.Success); - ModBase.OpenExplorer(configPath); + LauncherProcess.OpenExplorer(configPath); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "保存配置失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Export.Error.OperationFailed")); } } @@ -569,7 +569,7 @@ private void ReadConfigFile(string configPath) // 保存配置文件路径到缓存 States.System.ExportConfigPath = configPath; - var fileContent = ModBase.ReadFile(configPath); + var fileContent = LegacyFileFacade.ReadText(configPath); var segments = fileContent.Split(sperator); if (segments.Length == 0) @@ -620,10 +620,10 @@ private void ReadConfigFile(string configPath) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"读取配置文件失败:{configPath}", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Export.Error.OperationFailed")); } } @@ -646,10 +646,10 @@ private void ImportConfig(object sender, MouseButtonEventArgs e) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "选择配置文件失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Export.Error.OperationFailed")); } } @@ -735,13 +735,13 @@ private void StartExport(object sender, MouseButtonEventArgs e) !configPackPath.EndsWithF("/")) try { - Directory.CreateDirectory(ModBase.GetPathFromFullPath(configPackPath)); + Directory.CreateDirectory(LegacyFileFacade.GetPathFromFullPath(configPackPath)); packPath = configPackPath; - ModBase.Log($"[Export] 使用配置文件中指定的导出路径:{configPackPath}"); + LauncherLog.Log($"[Export] 使用配置文件中指定的导出路径:{configPackPath}"); } catch (Exception ex) { - ModBase.Log(ex, $"无法使用配置文件中指定的导出路径({configPackPath})"); + LauncherLog.Log(ex, $"无法使用配置文件中指定的导出路径({configPackPath})"); if (ModMain.MyMsgBox( Lang.Text("Instance.Export.PackPathInvalid.WithDetail", configPackPath, ex.ToString()), Lang.Text("Instance.Export.PackPathInvalid.Title"), Lang.Text("Common.Action.Confirm"), @@ -759,7 +759,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) packPath = SystemDialogs.SelectSaveFile(Lang.Text("Instance.Export.SelectSaveLocation"), packName + (string.IsNullOrEmpty(TextExportVersion.Text) ? "" : " " + TextExportVersion.Text), extensions.Join("|")); - ModBase.Log($"[Export] 手动指定的导出路径:{packPath}"); + LauncherLog.Log($"[Export] 手动指定的导出路径:{packPath}"); } if (string.IsNullOrEmpty(packPath)) @@ -776,7 +776,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) var includePCLCustom = (bool)(includePCL ? CheckOptionsPclCustom.Checked : (bool?)false); var allRules = StandardizeLines(GetAllRules(), true).ToList(); var allExtraFiles = StandardizeLines(GetExtraFileLines(), false).ToList(); - ModBase.Log($"[Export] 准备导出整合包,共有 {allRules.Count} 条规则,{allExtraFiles.Count} 条追加内容行"); + LauncherLog.Log($"[Export] 准备导出整合包,共有 {allRules.Count} 条规则,{allExtraFiles.Count} 条追加内容行"); // 构造步骤加载器 var loaders = new List(); @@ -789,7 +789,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) loader => { UpdateManager.DownloadLatestPCL(loader); - ModBase.CopyFile(Path.Combine(ModBase.pathTemp, "CE-Latest.exe"), + LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.TempWithSlash, "CE-Latest.exe"), Path.Combine(cacheFolder, "Plain Craft Launcher.exe")); }) { @@ -840,7 +840,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) if (!shouldKeep) continue; var targetPath = Path.Combine(overridesFolder, relativePath); - ModBase.CopyFile(Entry.FullName, targetPath); + LegacyFileFacade.CopyFile(Entry.FullName, targetPath); // 若为压缩包,考虑联网获取路径 if (checkHostedAssets && new[] { ".zip", ".rar", ".jar", ".disabled", ".old" }.Contains(Entry.Extension.ToLower()) && @@ -862,7 +862,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) } }; searchFolder(new DirectoryInfo(pathIndie)); - ModBase.Log($"[Export] 复制 overrides 文件完成,有 {loader.output.Count} 个文件需要联网检查"); + LauncherLog.Log($"[Export] 复制 overrides 文件完成,有 {loader.output.Count} 个文件需要联网检查"); loader.Progress = 0.95d; // 复制追加内容到根目录 var baseFolder = includePCL ? cacheFolder : Path.Combine(cacheFolder, "modpack"); @@ -870,13 +870,13 @@ private void StartExport(object sender, MouseButtonEventArgs e) if (Line.EndsWithF(@"\") || Line.EndsWithF("/")) { if (Directory.Exists(Line)) - ModBase.CopyDirectory(Line, Path.Combine(baseFolder, ModBase.GetFolderNameFromPath(Line)) + @"\"); + LegacyFileFacade.CopyDirectory(Line, Path.Combine(baseFolder, LegacyFileFacade.GetFolderNameFromPath(Line)) + @"\"); else HintService.Hint(Lang.Text("Instance.Export.Config.FolderNotFound", Line), HintType.Error); } else if (File.Exists(Line)) { - ModBase.CopyFile(Line, Path.Combine(baseFolder, ModBase.GetFileNameFromPath(Line))); + LegacyFileFacade.CopyFile(Line, Path.Combine(baseFolder, LegacyFileFacade.GetFileNameFromPath(Line))); } else { @@ -885,26 +885,26 @@ private void StartExport(object sender, MouseButtonEventArgs e) loader.Progress = 0.97d; // 复制 PCL 实例设置 - ModBase.CopyDirectory(Path.Combine(mcInstance.PathInstance, "PCL"), Path.Combine(overridesFolder, "PCL")); + LegacyFileFacade.CopyDirectory(Path.Combine(mcInstance.PathInstance, "PCL"), Path.Combine(overridesFolder, "PCL")); #if RELEASE // 复制 PCL 本体 - if (includePCL) ModBase.CopyFile(Basics.ExecutablePath, Path.Combine(cacheFolder, Basics.ExecutableName)); + if (includePCL) LegacyFileFacade.CopyFile(Basics.ExecutablePath, Path.Combine(cacheFolder, Basics.ExecutableName)); #endif // 复制 PCL 个性化内容 if (includePCLCustom) { - if (Directory.Exists(Path.Combine(ModBase.exePath, "PCL", "Pictures"))) - ModBase.CopyDirectory(Path.Combine(ModBase.exePath, "PCL", "Pictures"), Path.Combine(cacheFolder, "PCL", "Pictures")); - if (Directory.Exists(Path.Combine(ModBase.exePath, "PCL", "Musics"))) - ModBase.CopyDirectory(Path.Combine(ModBase.exePath, "PCL", "Musics"), Path.Combine(cacheFolder, "PCL", "Musics")); - if (File.Exists(Path.Combine(ModBase.exePath, "PCL", "Custom.xaml"))) - ModBase.CopyFile(Path.Combine(ModBase.exePath, "PCL", "Custom.xaml"), Path.Combine(cacheFolder, "PCL", "Custom.xaml")); - if (File.Exists(Path.Combine(ModBase.exePath, "PCL", "Setup.ini"))) - ModBase.CopyFile(Path.Combine(ModBase.exePath, "PCL", "Setup.ini"), Path.Combine(cacheFolder, "PCL", "Setup.ini")); - if (File.Exists(Path.Combine(ModBase.exePath, "PCL", "hints.txt"))) - ModBase.CopyFile(Path.Combine(ModBase.exePath, "PCL", "hints.txt"), Path.Combine(cacheFolder, "PCL", "hints.txt")); - if (File.Exists(Path.Combine(ModBase.exePath, "PCL", "Logo.png"))) - ModBase.CopyFile(Path.Combine(ModBase.exePath, "PCL", "Logo.png"), Path.Combine(cacheFolder, "PCL", "Logo.png")); + if (Directory.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Pictures"))) + LegacyFileFacade.CopyDirectory(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Pictures"), Path.Combine(cacheFolder, "PCL", "Pictures")); + if (Directory.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Musics"))) + LegacyFileFacade.CopyDirectory(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Musics"), Path.Combine(cacheFolder, "PCL", "Musics")); + if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Custom.xaml"))) + LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Custom.xaml"), Path.Combine(cacheFolder, "PCL", "Custom.xaml")); + if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Setup.ini"))) + LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Setup.ini"), Path.Combine(cacheFolder, "PCL", "Setup.ini")); + if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "hints.txt"))) + LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "hints.txt"), Path.Combine(cacheFolder, "PCL", "hints.txt")); + if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Logo.png"))) + LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Logo.png"), Path.Combine(cacheFolder, "PCL", "Logo.png")); } }) { @@ -923,13 +923,13 @@ private void StartExport(object sender, MouseButtonEventArgs e) loader.output = new Dictionary>(); if (!checkHostedAssets) { - ModBase.Log("[Export] 要求跳过联网获取步骤"); + LauncherLog.Log("[Export] 要求跳过联网获取步骤"); return; } if (!loader.input.Any()) { - ModBase.Log("[Export] 没有需要联网检查的文件,跳过联网获取步骤"); + LauncherLog.Log("[Export] 没有需要联网检查的文件,跳过联网获取步骤"); return; } @@ -940,12 +940,12 @@ private void StartExport(object sender, MouseButtonEventArgs e) // 从 Modrinth 获取信息 // 查找对应的文件 // 写入下载地址 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { var modrinthHashes = loader.input.Select(m => m.ModrinthHash); - var modrinthRaw = (JsonObject)ModBase.GetJson(ModDownload.DlModRequest( + var modrinthRaw = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ModDownload.DlModRequest( "https://api.modrinth.com/v2/version_files", "POST", $"{{\"hashes\": [\"{modrinthHashes.Join("\",\"")}\"], \"algorithm\": \"sha1\"}}", "application/json")); @@ -958,11 +958,11 @@ private void StartExport(object sender, MouseButtonEventArgs e) (string)modrinthRaw[ModFile.ModrinthHash]["files"][0]["url"]); } - ModBase.Log($"[Export] 从 Modrinth 获取到 {modrinthRaw.Count} 个本地资源项的对应信息"); + LauncherLog.Log($"[Export] 从 Modrinth 获取到 {modrinthRaw.Count} 个本地资源项的对应信息"); } catch (Exception ex) { - ModBase.Log(ex, "从 Modrinth 获取本地 Mod 信息失败"); + LauncherLog.Log(ex, "从 Modrinth 获取本地 Mod 信息失败"); failedExceptions.Add(ex); } finally @@ -975,13 +975,13 @@ private void StartExport(object sender, MouseButtonEventArgs e) // 从 CurseForge 获取信息 // 查找对应的文件 // 写入下载地址 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { if (modrinthUploadMode) return; var curseForgeHashes = loader.input.Select(m => m.CurseForgeHash); - var curseForgeRaw = (JsonNode)((JsonObject)ModBase.GetJson( + var curseForgeRaw = (JsonNode)((JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( ModDownload.DlModRequest("https://api.curseforge.com/v1/fingerprints/432/", "POST", $"{{\"fingerprints\": [{curseForgeHashes.Join(",")}]}}", "application/json")))["data"][ @@ -998,11 +998,11 @@ private void StartExport(object sender, MouseButtonEventArgs e) ModComp.CompFile.HandleCurseForgeDownloadUrls(file["downloadUrl"].ToString())); } - ModBase.Log($"[Export] 从 CurseForge 获取到 {curseForgeRaw.AsArray().Count} 个本地资源项的对应信息"); + LauncherLog.Log($"[Export] 从 CurseForge 获取到 {curseForgeRaw.AsArray().Count} 个本地资源项的对应信息"); } catch (Exception ex) { - ModBase.Log(ex, "从 CurseForge 获取本地 Mod 信息失败"); + LauncherLog.Log(ex, "从 CurseForge 获取本地 Mod 信息失败"); failedExceptions.Add(ex); } finally @@ -1063,7 +1063,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) "hashes", new JsonObject { - { "sha1", modFile.ModrinthHash }, { "sha512", ModBase.GetFileSHA512(modFile.path) } + { "sha1", modFile.ModrinthHash }, { "sha512", LegacyFileFacade.GetFileSha512(modFile.path) } } }, { "downloads", new JsonArray(Pair.Value.OrderByDescending(u => u.Contains("modrinth.com")).Select(s => (JsonNode)s).ToArray()) }, @@ -1089,7 +1089,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) File.WriteAllText(Path.Combine(cacheFolder, "modpack", "modrinth.index.json"), resultJson.ToJsonString(new JsonSerializerOptions(JsonCompat.SerializerOptions) { WriteIndented = true })); // 打包 - Directory.CreateDirectory(ModBase.GetPathFromFullPath(packPath)); + Directory.CreateDirectory(LegacyFileFacade.GetPathFromFullPath(packPath)); if (File.Exists(packPath)) File.Delete(packPath); if (includePCL) @@ -1111,7 +1111,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) } Directory.Delete(cacheFolder, true); - ModBase.OpenExplorer(packPath); + LauncherProcess.OpenExplorer(packPath); }) { ProgressWeight = 6d diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs index 257815ac7..4eed53f45 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs @@ -126,10 +126,10 @@ private void BtnSelectStart_Click(object sender, MouseButtonEventArgs mouseButto PageInstanceLeft.McInstance.Info.HasLabyMod) Directory.Delete(System.IO.Path.Combine(PageInstanceLeft.McInstance.PathIndie, "labymod-neo"), true); // 备份实例核心文件 - ModBase.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json", + LegacyFileFacade.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json", PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + ".json"); if (File.Exists(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar")) - ModBase.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar", + LegacyFileFacade.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar", PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + ".jar"); // 确认独立 API (如 Fabric API 等) 是否需要被修改 @@ -378,7 +378,7 @@ public void MinecraftSelected(MyListItem sender, MouseButtonEventArgs e) EnterSelectPage(); } - private void CardMinecraft_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardMinecraft_PreviewSwap(object sender, RouteEventArgs e) { ExitSelectPage(); e.handled = true; @@ -1404,7 +1404,7 @@ void StackInstall(StackPanel stack) // 自动选择版本 if (mcVersionWaitingForSelect is null) break; - ModBase.Log("[Download] 自动选择 MC 版本:" + mcVersionWaitingForSelect); + LauncherLog.Log("[Download] 自动选择 MC 版本:" + mcVersionWaitingForSelect); foreach (JsonObject Version in versions) { if ((Version["id"].ToString() ?? "") != (mcVersionWaitingForSelect ?? "")) @@ -1415,10 +1415,10 @@ void StackInstall(StackPanel stack) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } while (false); @@ -1497,7 +1497,7 @@ private object IsOptiFineSuitForForge(ModDownload.DlOptiFineListEntry optiFine, } // 限制展开 - private void CardOptiFine_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardOptiFine_PreviewSwap(object sender, RouteEventArgs e) { if (LoadOptiFineGetError() is not null) e.handled = true; @@ -1510,7 +1510,7 @@ private void OptiFine_Loaded() { try { - if (ModDownload.dlOptiFineListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlOptiFineListLoader.State != LoadState.Finished) return; // 获取版本列表 @@ -1544,10 +1544,10 @@ private void OptiFine_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 OptiFine 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -1597,7 +1597,7 @@ private string LoadLiteLoaderGetError() } // 限制展开 - private void CardLiteLoader_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardLiteLoader_PreviewSwap(object sender, RouteEventArgs e) { if (LoadLiteLoaderGetError() is not null) e.handled = true; @@ -1610,7 +1610,7 @@ private void LiteLoader_Loaded() { try { - if (ModDownload.dlLiteLoaderListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlLiteLoaderListLoader.State != LoadState.Finished) return; // 获取版本列表 var versions = new List(); @@ -1627,10 +1627,10 @@ private void LiteLoader_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LiteLoader 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -1693,7 +1693,7 @@ private string LoadForgeGetError() } // 限制展开 - private void CardForge_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardForge_PreviewSwap(object sender, RouteEventArgs e) { if (LoadForgeGetError() is not null) e.handled = true; @@ -1711,7 +1711,7 @@ private void Forge_Loaded() var loader = (ModLoader.LoaderTask>)LoadForge.State; if ((_vanillaName ?? "") != (loader.input ?? "")) return; - if (loader.State != ModBase.LoadState.Finished) + if (loader.State != LoadState.Finished) return; // 获取要显示的版本 var versions = loader.output.ToList(); // 复制数组,以免 Output 在实例化后变空 @@ -1735,10 +1735,10 @@ private void Forge_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Forge 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -1789,7 +1789,7 @@ private string LoadNeoForgeGetError() } // 限制展开 - private void CardNeoForge_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardNeoForge_PreviewSwap(object sender, RouteEventArgs e) { if (LoadNeoForgeGetError() is not null) e.handled = true; @@ -1803,7 +1803,7 @@ private void NeoForge_Loaded() try { // 获取版本列表 - if (ModDownload.dlNeoForgeListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlNeoForgeListLoader.State != LoadState.Finished) return; var versions = ModDownload.dlNeoForgeListLoader.output.Value .Where(v => (v.Inherit ?? "") == (_vanillaName ?? "")).ToList(); @@ -1821,10 +1821,10 @@ private void NeoForge_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 NeoForge 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -1874,7 +1874,7 @@ private string LoadCleanroomGetError() } // 限制展开 - private void CardCleanroom_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardCleanroom_PreviewSwap(object sender, RouteEventArgs e) { if (LoadCleanroomGetError() is not null) e.handled = true; @@ -1888,7 +1888,7 @@ private void Cleanroom_Loaded() try { // 获取版本列表 - if (ModDownload.dlCleanroomListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlCleanroomListLoader.State != LoadState.Finished) return; var versions = ModDownload.dlCleanroomListLoader.output.Value .Where(v => (v.Inherit ?? "") == (_vanillaName ?? "")).ToList(); @@ -1905,10 +1905,10 @@ private void Cleanroom_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Cleanroom 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -1964,7 +1964,7 @@ private string LoadFabricGetError() } // 限制展开 - private void CardFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardFabric_PreviewSwap(object sender, RouteEventArgs e) { if (LoadFabricGetError() is not null) e.handled = true; @@ -1977,7 +1977,7 @@ private void Fabric_Loaded() { try { - if (ModDownload.dlFabricListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlFabricListLoader.State != LoadState.Finished) return; // 获取版本列表 var versions = (JsonArray)ModDownload.dlFabricListLoader.output.Value["loader"]; @@ -1997,10 +1997,10 @@ private void Fabric_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Fabric 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -2085,7 +2085,7 @@ public bool IsFabricApiCompatible(ModComp.CompFile fabricApi) } catch (Exception ex) { - ModBase.Log(ex, "判断 Fabric API 版本适配性出错(" + fabricApiName + ", " + _vanillaName + ")"); + LauncherLog.Log(ex, "判断 Fabric API 版本适配性出错(" + fabricApiName + ", " + _vanillaName + ")"); return false; } } @@ -2108,7 +2108,7 @@ private string LoadFabricApiGetError() } // 限制展开 - private void CardFabricApi_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardFabricApi_PreviewSwap(object sender, RouteEventArgs e) { if (LoadFabricApiGetError() is not null) e.handled = true; @@ -2123,7 +2123,7 @@ private void FabricApi_Loaded() { try { - if (ModDownload.dlFabricApiLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlFabricApiLoader.State != LoadState.Finished) return; if (_vanillaName is null || (selectedFabric is null && selectedQuilt is null)) return; @@ -2134,7 +2134,7 @@ private void FabricApi_Loaded() { if (!version.DisplayName.StartsWith("[")) { - ModBase.Log("[Download] 已特判修改 Fabric API 显示名:" + version.DisplayName, ModBase.LogLevel.Debug); + LauncherLog.Log("[Download] 已特判修改 Fabric API 显示名:" + version.DisplayName, LauncherLogLevel.Debug); version.DisplayName = "[" + _vanillaName + "] " + version.DisplayName; } @@ -2160,16 +2160,16 @@ private void FabricApi_Loaded() (selectedQuilt is not null && ReferenceEquals(LoadQSLGetError(), Lang.Text("Download.Install.State.NoAvailableVersion")))) { autoSelectedFabricApi = true; - ModBase.Log($"[Download] 已自动选择 Fabric API:{((MyListItem)PanFabricApi.Children[0]).Title}"); + LauncherLog.Log($"[Download] 已自动选择 Fabric API:{((MyListItem)PanFabricApi.Children[0]).Title}"); FabricApi_Selected((MyListItem)PanFabricApi.Children[0], null); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Fabric API 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -2219,7 +2219,7 @@ private string LoadLegacyFabricGetError() } // 限制展开 - private void CardLegacyFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardLegacyFabric_PreviewSwap(object sender, RouteEventArgs e) { if (LoadLegacyFabricGetError() is not null) e.handled = true; @@ -2232,7 +2232,7 @@ private void LegacyFabric_Loaded() { try { - if (ModDownload.dlLegacyFabricListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlLegacyFabricListLoader.State != LoadState.Finished) return; // 获取版本列表 var versions = (JsonArray)ModDownload.dlLegacyFabricListLoader.output.Value["loader"]; @@ -2251,10 +2251,10 @@ private void LegacyFabric_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LegacyFabric 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -2298,7 +2298,7 @@ public static bool IsSuitableLegacyFabricApi(List supportVersions, strin } catch (Exception ex) { - ModBase.Log(ex, "判断 Legacy Fabric API 版本适配性出错(" + supportVersions + ", " + minecraftVersion + ")"); + LauncherLog.Log(ex, "判断 Legacy Fabric API 版本适配性出错(" + supportVersions + ", " + minecraftVersion + ")"); return false; } } @@ -2334,7 +2334,7 @@ private string LoadLegacyFabricApiGetError() } // 限制展开 - private void CardLegacyFabricApi_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardLegacyFabricApi_PreviewSwap(object sender, RouteEventArgs e) { if (LoadLegacyFabricApiGetError() is not null) e.handled = true; @@ -2349,7 +2349,7 @@ private void LegacyFabricApi_Loaded() { try { - if (ModDownload.dlLegacyFabricApiLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlLegacyFabricApiLoader.State != LoadState.Finished) return; if (_vanillaName is null || (selectedLegacyFabric is null && selectedQuilt is null)) return; @@ -2378,16 +2378,16 @@ private void LegacyFabricApi_Loaded() (selectedQuilt is not null && ReferenceEquals(LoadQSLGetError(), Lang.Text("Download.Install.State.NoAvailableVersion")))) { autoSelectedLegacyFabricApi = true; - ModBase.Log($"[Download] 已自动选择 Legacy Fabric API:{((MyListItem)PanLegacyFabricApi.Children[0]).Title}"); + LauncherLog.Log($"[Download] 已自动选择 Legacy Fabric API:{((MyListItem)PanLegacyFabricApi.Children[0]).Title}"); LegacyFabricApi_Selected((MyListItem)PanLegacyFabricApi.Children[0], null); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Legacy Fabric API 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -2440,7 +2440,7 @@ private string LoadQuiltGetError() } // 限制展开 - private void CardQuilt_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardQuilt_PreviewSwap(object sender, RouteEventArgs e) { if (LoadQuiltGetError() is not null) e.handled = true; @@ -2453,7 +2453,7 @@ private void Quilt_Loaded() { try { - if (ModDownload.dlQuiltListLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlQuiltListLoader.State != LoadState.Finished) return; // 获取版本列表 var versions = (JsonArray)ModDownload.dlQuiltListLoader.output.Value["loader"]; @@ -2473,10 +2473,10 @@ private void Quilt_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 Quilt 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -2521,7 +2521,7 @@ public static bool IsSuitableQSL(List supportVersions, string minecraftV } catch (Exception ex) { - ModBase.Log(ex, "判断 QSL 版本适配性出错(" + supportVersions + ", " + minecraftVersion + ")"); + LauncherLog.Log(ex, "判断 QSL 版本适配性出错(" + supportVersions + ", " + minecraftVersion + ")"); return false; } } @@ -2557,7 +2557,7 @@ private string LoadQSLGetError() } // 限制展开 - private void CardQSL_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardQSL_PreviewSwap(object sender, RouteEventArgs e) { if (LoadQSLGetError() is not null) e.handled = true; @@ -2572,7 +2572,7 @@ private void QSL_Loaded() { try { - if (ModDownload.dlQSLLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlQSLLoader.State != LoadState.Finished) return; if (_vanillaName is null || selectedQuilt is null) return; @@ -2583,7 +2583,7 @@ private void QSL_Loaded() { if (!Version.DisplayName.StartsWith("[")) { - ModBase.Log("[Download] 已特判修改 QSL 显示名:" + Version.DisplayName, ModBase.LogLevel.Debug); + LauncherLog.Log("[Download] 已特判修改 QSL 显示名:" + Version.DisplayName, LauncherLogLevel.Debug); Version.DisplayName = "[" + _vanillaName + "] " + Version.DisplayName; } @@ -2607,16 +2607,16 @@ private void QSL_Loaded() if (!autoSelectedQSL) { autoSelectedQSL = true; - ModBase.Log($"[Download] 已自动选择 QSL:{((MyListItem)PanQSL.Children[0]).Title}"); + LauncherLog.Log($"[Download] 已自动选择 QSL:{((MyListItem)PanQSL.Children[0]).Title}"); QSL_Selected((MyListItem)PanQSL.Children[0], null); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 QSL 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -2656,7 +2656,7 @@ private bool IsOptiFabricCompatible(ModComp.CompFile modFile) } catch (Exception ex) { - ModBase.Log(ex, "判断 OptiFabric 版本适配性出错(" + _vanillaName + ")"); + LauncherLog.Log(ex, "判断 OptiFabric 版本适配性出错(" + _vanillaName + ")"); return false; } } @@ -2702,7 +2702,7 @@ private string LoadOptiFabricGetError() } // 限制展开 - private void CardOptiFabric_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardOptiFabric_PreviewSwap(object sender, RouteEventArgs e) { if (LoadOptiFabricGetError() is not null) e.handled = true; @@ -2715,7 +2715,7 @@ private void OptiFabric_Loaded() { try { - if (ModDownload.dlOptiFabricLoader.State != ModBase.LoadState.Finished) + if (ModDownload.dlOptiFabricLoader.State != LoadState.Finished) return; if (_vanillaName is null || selectedFabric is null || selectedOptiFine is null) return; @@ -2743,15 +2743,15 @@ private void OptiFabric_Loaded() if (autoSelectedOptiFabric || (VanillaDrop >= 140 && VanillaDrop <= 150)) return; // 1.14~15 不自动选择 autoSelectedOptiFabric = true; - ModBase.Log($"[Download] 已自动选择 OptiFabric:{((MyListItem)PanOptiFabric.Children[0]).Title}"); + LauncherLog.Log($"[Download] 已自动选择 OptiFabric:{((MyListItem)PanOptiFabric.Children[0]).Title}"); OptiFabric_Selected((MyListItem)PanOptiFabric.Children[0], null); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 OptiFabric 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } @@ -2802,7 +2802,7 @@ private string LoadLabyModGetError() } // 限制展开 - private void CardLabyMod_PreviewSwap(object sender, ModBase.RouteEventArgs e) + private void CardLabyMod_PreviewSwap(object sender, RouteEventArgs e) { if (LoadLabyModGetError() is not null) e.handled = true; @@ -2856,10 +2856,10 @@ private void LabyMod_Loaded() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "可视化 LabyMod 安装版本列表出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Install.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.cs index 341345bca..1d01455f5 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.cs @@ -98,7 +98,7 @@ public void RefreshModDisabled() private void RefreshButton_Click(object sender, EventArgs e) // 由边栏按钮匿名调用 { - Refresh((FormMain.PageSubType)ModBase.Val(((MyIconButton)sender).Tag)); + Refresh((FormMain.PageSubType)LauncherText.Val(((MyIconButton)sender).Tag)); } public void Refresh(FormMain.PageSubType subType) @@ -194,10 +194,10 @@ public void Reset(object sender, EventArgs e) /// /// 勾选事件改变页面。 /// - private void PageCheck(object sender, ModBase.RouteEventArgs e) + private void PageCheck(object sender, RouteEventArgs e) { if (sender is MyListItem item && item.Tag is not null) - PageChange((FormMain.PageSubType)ModBase.Val(item.Tag)); + PageChange((FormMain.PageSubType)LauncherText.Val(item.Tag)); } public object PageGet(FormMain.PageSubType id) @@ -301,10 +301,10 @@ public void PageChange(FormMain.PageSubType id) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "切换分页面失败(ID " + (int)id + ")", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Error.OperationFailed")); } finally diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.cs index 0e1d56228..e02e0d25b 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.cs @@ -103,7 +103,7 @@ private void Reload() private void GetInstanceInfo() { modpackCompItem = null; - ModBase.RunInUi(() => + UiThread.Post(() => { PanInfo.Children.Clear(); PanInfo.Children.Add(new MyLoading { Text = Lang.Text("Instance.Overall.Info.Loading"), Margin = new Thickness(0d, 0d, 0d, 10d) }); @@ -116,7 +116,7 @@ private void GetInstanceInfo() { var compProjects = ModComp.CompRequest.GetCompProjectsByIds(new List { modpackId }); if (compProjects.Count > 0) - ModBase.RunInUi(() => + UiThread.Post(() => { modpackCompItem = compProjects.First().ToCompItem(false, false); modpackCompItem.Tag = compProjects.First(); @@ -126,7 +126,7 @@ private void GetInstanceInfo() { block = true }); - loaders.Add(new ModLoader.LoaderTask(Lang.Text("Instance.Overall.Info.LoadInstanceInfoTask"), _ => ModBase.RunInUi(() => + loaders.Add(new ModLoader.LoaderTask(Lang.Text("Instance.Overall.Info.LoadInstanceInfoTask"), _ => UiThread.Post(() => { var instance = PageInstanceLeft.McInstance; var instanceInfo = instance.Info; @@ -241,16 +241,16 @@ private void ComboDisplayType_SelectionChanged(object sender, SelectionChangedEv PageInstanceLeft.McInstance.displayType = (McInstanceCardType)States.Instance.CardType[PageInstanceLeft.McInstance.PathInstance]; ModMain.frmInstanceLeft.RefreshModDisabled(); - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"修改实例分类失败({PageInstanceLeft.McInstance.Name})", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } @@ -275,16 +275,16 @@ private void ComboDisplayType_SelectionChanged(object sender, SelectionChangedEv States.Instance.CardType[PageInstanceLeft.McInstance.PathInstance] = (int)McInstanceCardType.Hidden; - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"隐藏实例 {PageInstanceLeft.McInstance.Name} 失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -307,10 +307,10 @@ private void BtnDisplayDesc_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"实例 {PageInstanceLeft.McInstance.Name} 描述更改失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -337,12 +337,12 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) JsonObject jsonObject; try { - jsonObject = (JsonObject)ModBase.GetJson(ModBase.ReadFile(PageInstanceLeft.McInstance.PathInstance + + jsonObject = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json")); } catch (Exception ex) { - ModBase.Log(ex, "重命名读取 Json 时失败"); + LauncherLog.Log(ex, "重命名读取 Json 时失败"); jsonObject = PageInstanceLeft.McInstance.JsonObject; } @@ -350,7 +350,7 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) FileSystem.RenameDirectory(oldPath, tempName); FileSystem.RenameDirectory(tempPath, newName); // 清理 ini 缓存 - ModBase.IniClearCache(Path.Combine(PageInstanceLeft.McInstance.PathIndie, "options.txt")); + LegacyIniStore.Shared.ClearCache(Path.Combine(PageInstanceLeft.McInstance.PathIndie, "options.txt")); // 重命名 Jar 文件与 natives 文件夹 // 不能进行遍历重命名,否则在实例名很短的时候容易误伤其他文件(Meloong-Git/#6443) if (Directory.Exists(Path.Combine(newPath, $"{oldName}-natives"))) @@ -362,7 +362,7 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) } else { - ModBase.DeleteDirectory(Path.Combine(newPath, $"{newName}-natives")); + LegacyFileFacade.DeleteDirectory(Path.Combine(newPath, $"{newName}-natives")); FileSystem.RenameDirectory(Path.Combine(newPath, $"{oldName}-natives"), $"{newName}-natives"); } } @@ -383,22 +383,22 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) // 替换实例设置文件中的路径 if (File.Exists(Path.Combine(newPath, "PCL", "Setup.ini"))) - ModBase.WriteFile(Path.Combine(newPath, "PCL", "Setup.ini"), - ModBase.ReadFile(Path.Combine(newPath, "PCL", "Setup.ini")).Replace(oldPath, newPath)); + LegacyFileFacade.WriteFile(Path.Combine(newPath, "PCL", "Setup.ini"), + LegacyFileFacade.ReadText(Path.Combine(newPath, "PCL", "Setup.ini")).Replace(oldPath, newPath)); // 更改已选中的实例 - if ((ModBase.ReadIni(ModFolder.mcFolderSelected + "PCL.ini", "Version") ?? "") == (oldName ?? "")) - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "Version", newName); + if ((LegacyIniStore.Shared.Read(ModFolder.mcFolderSelected + "PCL.ini", "Version") ?? "") == (oldName ?? "")) + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", newName); // 写入实例 Json,并删除旧的 Json try { jsonObject["id"] = newName; - ModBase.WriteFile(Path.Combine(newPath, $"{newName}.json"), jsonObject.ToString()); + LegacyFileFacade.WriteFile(Path.Combine(newPath, $"{newName}.json"), jsonObject.ToString()); if (!isCaseChangedOnly) File.Delete(Path.Combine(newPath, $"{oldName}.json")); } catch (Exception ex) { - ModBase.Log(ex, "重命名实例 Json 失败"); + LauncherLog.Log(ex, "重命名实例 Json 失败"); } // 刷新与提示 @@ -406,17 +406,17 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) PageInstanceLeft.McInstance = new McInstance(newName).Load(); if (ModInstanceList.McMcInstanceSelected is not null && ModInstanceList.McMcInstanceSelected.Equals(PageInstanceLeft.McInstance)) - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "Version", newName); + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", newName); Reload(); ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "重命名实例失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -438,7 +438,7 @@ private void ComboDisplayLogo_SelectionChanged(object sender, SelectionChangedEv return; } - ModBase.CopyFile(fileName, PageInstanceLeft.McInstance.PathInstance + @"PCL\Logo.png"); + LegacyFileFacade.CopyFile(fileName, PageInstanceLeft.McInstance.PathInstance + @"PCL\Logo.png"); } else { @@ -447,10 +447,10 @@ private void ComboDisplayLogo_SelectionChanged(object sender, SelectionChangedEv } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"更改自定义实例图标失败({PageInstanceLeft.McInstance.Name})", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } @@ -461,7 +461,7 @@ private void ComboDisplayLogo_SelectionChanged(object sender, SelectionChangedEv States.Instance.LogoPath[PageInstanceLeft.McInstance.PathInstance] = newLogo; States.Instance.IsLogoCustom[PageInstanceLeft.McInstance.PathInstance] = !string.IsNullOrEmpty(newLogo); // 刷新显示 - ModBase.WriteIni(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 + LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 PageInstanceLeft.McInstance = new McInstance(PageInstanceLeft.McInstance.Name).Load(); Reload(); ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, @@ -469,10 +469,10 @@ private void ComboDisplayLogo_SelectionChanged(object sender, SelectionChangedEv } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"更改实例图标失败({PageInstanceLeft.McInstance.Name})", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -491,10 +491,10 @@ private void BtnDisplayStar_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"实例 {PageInstanceLeft.McInstance.Name} 收藏状态更改失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -511,7 +511,7 @@ private void BtnFolderVersion_Click(object sender, MouseButtonEventArgs mouseBut public static void OpenVersionFolder(McInstance version) { - ModBase.OpenExplorer(version.PathInstance); + LauncherProcess.OpenExplorer(version.PathInstance); } // 存档文件夹 @@ -519,7 +519,7 @@ private void BtnFolderSaves_Click(object sender, MouseButtonEventArgs mouseButto { var folderPath = PageInstanceLeft.McInstance.PathIndie + @"saves\"; Directory.CreateDirectory(folderPath); - ModBase.OpenExplorer(folderPath); + LauncherProcess.OpenExplorer(folderPath); } // Mod 文件夹 @@ -527,7 +527,7 @@ private void BtnFolderMods_Click(object sender, MouseButtonEventArgs mouseButton { var folderPath = PageInstanceLeft.McInstance.PathIndie + @"mods\"; Directory.CreateDirectory(folderPath); - ModBase.OpenExplorer(folderPath); + LauncherProcess.OpenExplorer(folderPath); } #endregion @@ -545,7 +545,7 @@ private void BtnManageScript_Click(object sender, MouseButtonEventArgs mouseButt if (string.IsNullOrEmpty(savePath)) return; // 检查中断(等玩家选完弹窗指不定任务就结束了呢……) - if (ModLaunch.mcLaunchLoader.State == ModBase.LoadState.Loading) + if (ModLaunch.mcLaunchLoader.State == LoadState.Loading) { HintService.Hint(Lang.Text("Instance.Overall.Script.WaitForLaunchTask"), HintType.Error); return; @@ -563,10 +563,10 @@ private void BtnManageScript_Click(object sender, MouseButtonEventArgs mouseButt } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"导出启动脚本失败({PageInstanceLeft.McInstance.Name})", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -601,20 +601,20 @@ private void BtnManageCheck_Click(object sender, MouseButtonEventArgs e) { switch (loader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: { HintService.Hint( Lang.Text("Instance.Overall.Repair.Success.WithTaskName", taskName), HintType.Success); break; } - case ModBase.LoadState.Failed: + case LoadState.Failed: { HintService.Hint( Lang.Text("Instance.Overall.Repair.Failed.WithDetail", taskName, loader.Error.ToString()), HintType.Error); break; } - case ModBase.LoadState.Aborted: + case LoadState.Aborted: { HintService.Hint( Lang.Text("Instance.Overall.Repair.Cancelled.WithTaskName", taskName)); @@ -629,10 +629,10 @@ private void BtnManageCheck_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"尝试补全文件失败({PageInstanceLeft.McInstance.Name})", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -656,10 +656,10 @@ private void BtnManageRestore_Click(object sender, MouseButtonEventArgs e) return; // 备份实例核心文件 - ModBase.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json", + LegacyFileFacade.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json", PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + ".json"); - ModBase.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar", + LegacyFileFacade.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar", PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + ".jar"); // 提交安装申请 @@ -696,10 +696,10 @@ private void BtnManageRestore_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"重置实例 {PageInstanceLeft.McInstance.Name} 失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -715,10 +715,10 @@ private void BtnManageTest_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "测试游戏失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -760,12 +760,12 @@ private void BtnManageDelete_Click(object sender, MouseButtonEventArgs e) { var instancePath = PageInstanceLeft.McInstance.PathInstance; var instanceName = PageInstanceLeft.McInstance.Name; - ModBase.IniClearCache(Path.Combine(PageInstanceLeft.McInstance.PathIndie, "options.txt")); + LegacyIniStore.Shared.ClearCache(Path.Combine(PageInstanceLeft.McInstance.PathIndie, "options.txt")); ((DynamicCacheConfigStorage)ConfigService.GetProvider(ConfigSource.GameInstance)).InvalidateCache( instancePath); if (isShiftPressed) { - ModBase.DeleteDirectory(instancePath); + LegacyFileFacade.DeleteDirectory(instancePath); HintService.Hint(Lang.Text("Instance.Overall.Delete.PermanentSuccess", instanceName), HintType.Success); } @@ -791,14 +791,14 @@ private void BtnManageDelete_Click(object sender, MouseButtonEventArgs e) } catch (OperationCanceledException ex) { - ModBase.Log(ex, "删除实例 " + PageInstanceLeft.McInstance.Name + " 被主动取消"); + LauncherLog.Log(ex, "删除实例 " + PageInstanceLeft.McInstance.Name + " 被主动取消"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"删除实例 {PageInstanceLeft.McInstance.Name} 失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Overall.Error.OperationFailed")); } } @@ -816,7 +816,7 @@ private void BtnManagePatch_Click(object sender, MouseButtonEventArgs e) if (userInput is null || string.IsNullOrWhiteSpace(userInput)) return; HintService.Hint(Lang.Text("Instance.Overall.Patch.Patching")); - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { var core = new GameCore(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar"); diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs index 4523518b2..d98fa9cea 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs @@ -115,7 +115,7 @@ private void OnFileSystemChanged(object sender, FileSystemEventArgs e) private void FileSystemRefreshTimer_Tick(object sender, EventArgs e) { fileSystemRefreshTimer.Stop(); - ModBase.RunInUi(() => Reload(), true); + UiThread.Post(() => Reload(), true); } private void Page_Unloaded(object sender, RoutedEventArgs e) @@ -191,13 +191,13 @@ private void RefreshUI() if (File.Exists(saveLogo)) { var target = - $@"{PageInstanceLeft.McInstance.PathInstance}PCL\ImgCache\{ModBase.GetStringMD5(saveLogo)}.png"; - ModBase.CopyFile(saveLogo, target); + $@"{PageInstanceLeft.McInstance.PathInstance}PCL\ImgCache\{LauncherText.GetStringMD5(saveLogo)}.png"; + LegacyFileFacade.CopyFile(saveLogo, target); saveLogo = target; } else { - saveLogo = ModBase.pathImage + "Icons/NoIcon.png"; + saveLogo = LauncherPaths.ImageBaseUri + "Icons/NoIcon.png"; } var worldItem = new MyListItem @@ -216,7 +216,7 @@ private void RefreshUI() SvgIcon = "lucide/folder-open", ToolTip = Lang.Text("Common.Action.Open") }; - btnOpen.Click += (_, _) => ModBase.OpenExplorer(tmpCurFolder); + btnOpen.Click += (_, _) => LauncherProcess.OpenExplorer(tmpCurFolder); var btnDelete = new MyIconButton { SvgIcon = "lucide/trash-2", @@ -226,23 +226,23 @@ private void RefreshUI() { worldItem.IsEnabled = false; worldItem.Info = Lang.Text("Instance.Saves.Deleting"); - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { FileSystem.DeleteDirectory(tmpCurFolder, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin); HintService.Hint(Lang.Text("Instance.Saves.DeletedToRecycleBin")); - ModBase.RunInUiWait(() => RemoveItem(worldItem)); + UiThread.Invoke(() => RemoveItem(worldItem)); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.DeleteFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.DeleteFailed")); - ModBase.RunInUiWait(() => Reload()); + UiThread.Invoke(() => Reload()); } }); }; @@ -268,10 +268,10 @@ private void RefreshUI() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.CopyFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.CopyFailed")); } }; @@ -312,10 +312,10 @@ private void RefreshUI() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.RefreshUiFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.RefreshUiFailed")); } } @@ -329,10 +329,10 @@ private void CheckQuickPlay() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "检查存档快捷启动失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -341,34 +341,34 @@ private void LoadFileList() { try { - ModBase.Log("[World] 刷新存档文件"); + LauncherLog.Log("[World] 刷新存档文件"); saveFolders.Clear(); if (Directory.Exists(worldPath)) saveFolders = Directory.EnumerateDirectories(worldPath).ToList(); else saveFolders = new List(); - if (ModBase.ModeDebug) - ModBase.Log("[World] 共发现 " + saveFolders.Count + " 个存档文件夹", ModBase.LogLevel.Debug); + if (LauncherRuntime.ModeDebug) + LauncherLog.Log("[World] 共发现 " + saveFolders.Count + " 个存档文件夹", LauncherLogLevel.Debug); PanList.Children.Clear(); CheckQuickPlay(); - if (ModBase.ModeDebug) + if (LauncherRuntime.ModeDebug) { if ((bool)quickPlayFeature) - ModBase.Log("[World] 该实例支持存档快捷启动", ModBase.LogLevel.Debug); + LauncherLog.Log("[World] 该实例支持存档快捷启动", LauncherLogLevel.Debug); else - ModBase.Log("[World] 该实例不支持存档快捷启动", ModBase.LogLevel.Debug); + LauncherLog.Log("[World] 该实例不支持存档快捷启动", LauncherLogLevel.Debug); } RefreshUI(); // 确保UI刷新 } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.LoadListFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.LoadListFailed")); } } @@ -383,7 +383,7 @@ private void RemoveItem(MyListItem item) private void BtnOpenFolder_Click(object sender, MouseButtonEventArgs e) { - ModBase.OpenExplorer(worldPath); + LauncherProcess.OpenExplorer(worldPath); } private void BtnPaste_Click(object sender, MouseButtonEventArgs e) @@ -404,7 +404,7 @@ private void BtnPaste_Click(object sender, MouseButtonEventArgs e) } else { - ModBase.CopyDirectory(i, worldPath + GetFolderNameFromPath(i)); + LegacyFileFacade.CopyDirectory(i, worldPath + GetFolderNameFromPath(i)); copied += 1; } } @@ -415,16 +415,16 @@ private void BtnPaste_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.PasteFolderFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.PasteFolderFailed")); } if (copied > 0) HintService.Hint(Lang.Text("Instance.Saves.PastedCount", copied.ToString()), HintType.Success); - ModBase.RunInUi(() => Reload()); + UiThread.Post(() => Reload()); })); var loader = new ModLoader.LoaderCombo($"{PageInstanceLeft.McInstance.Name} - {Lang.Text("Instance.Saves.CopySave")}", loaders) { OnStateChanged = ModDownloadLib.LoaderStateChangedHintOnly }; @@ -519,16 +519,16 @@ private void PerformSearch() { if (IsSearching) { - var queryList = new List>(); + var queryList = new List>(); foreach (var saveFolder in saveFolders) { var folderName = GetFolderNameFromPath(saveFolder); - var searchSource = new List(); - searchSource.Add(new ModBase.SearchSource(folderName, 1d)); - queryList.Add(new ModBase.SearchEntry { item = saveFolder, searchSource = searchSource }); + var searchSource = new List(); + searchSource.Add(new SearchSource(folderName, 1d)); + queryList.Add(new SearchEntry { item = saveFolder, searchSource = searchSource }); } - _searchResult = ModBase.Search(queryList, SearchBox.Text, ModBase.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); + _searchResult = LauncherSearch.Search(queryList, SearchBox.Text, LauncherSearch.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); } else { @@ -539,7 +539,7 @@ private void PerformSearch() } catch (Exception ex) { - ModBase.Log(ex, Lang.Text("Instance.Saves.SearchError")); + LauncherLog.Log(ex, Lang.Text("Instance.Saves.SearchError")); } } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs index 9671e7c10..03896bfd8 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs @@ -37,7 +37,7 @@ public partial class PageInstanceSavesDatapack : IRefreshable } catch (Exception ex) { - ModBase.Log(ex, "获取数据包信息失败: " + path); + LauncherLog.Log(ex, "获取数据包信息失败: " + path); return (DateTime.MinValue, 0L); } } @@ -134,10 +134,10 @@ public void ReloadDatapackFileList(bool forceReload = false) ? ModLoader.LoaderFolderRunType.ForceRun : ModLoader.LoaderFolderRunType.RunOnUpdated)) { - ModBase.Log("[System] 已刷新数据包列表"); + LauncherLog.Log("[System] 已刷新数据包列表"); datapackFileInfoCache.Clear(); - ModBase.RunInUi(() => + UiThread.Post(() => { Filter = FilterType.All; PanBack.ScrollToHome(); @@ -160,7 +160,7 @@ void IRefreshable.Refresh() public void Refresh() { ModMain.frmInstanceSavesDatapack.ReloadDatapackFileList(true); - ModBase.Log("[Datapack] 刷新数据包列表"); + LauncherLog.Log("[Datapack] 刷新数据包列表"); } private void LoaderInit() @@ -171,7 +171,7 @@ private void LoaderInit() private void Load_Click(object sender, MouseButtonEventArgs e) { - if (ModLocalComp.compResourceListLoader.State == ModBase.LoadState.Failed) + if (ModLocalComp.compResourceListLoader.State == LoadState.Failed) LoaderRun(ModLoader.LoaderFolderRunType.ForceRun); } @@ -223,7 +223,7 @@ private void LoadUIFromLoaderOutput() datapackItems[DatapackEntity.RawPath] = BuildLocalCompItem(DatapackEntity); // 显示结果 - ModBase.RunInUi(() => + UiThread.Post(() => { Filter = FilterType.All; SearchBox.Text = ""; // 这会触发结果刷新,所以需要在 DatapackItems 更新之后 @@ -233,10 +233,10 @@ private void LoadUIFromLoaderOutput() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "加载数据包列表 UI 失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -263,7 +263,7 @@ private MyLocalCompItem BuildLocalCompItem(ModLocalComp.LocalCompFile entry) catch (Exception ex) { ModAnimation.AniControlEnabled -= 1; - ModBase.Log(ex, $"创建 UI 项失败:{entry.RawPath}"); + LauncherLog.Log(ex, $"创建 UI 项失败:{entry.RawPath}"); throw; } } @@ -551,14 +551,14 @@ private void BtnManageOpen_Click(object sender, EventArgs e) { var datapackPath = Path.Combine(PageInstanceSavesLeft.currentSave, "datapacks"); Directory.CreateDirectory(datapackPath); - ModBase.OpenExplorer(datapackPath); + LauncherProcess.OpenExplorer(datapackPath); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "打开 datapacks 文件夹失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -609,7 +609,7 @@ public static void InstallDatapackFiles(IEnumerable filePathList) return; } - ModBase.Log($"[System] 文件为 {extension} 格式,尝试作为数据包安装"); + LauncherLog.Log($"[System] 文件为 {extension} 格式,尝试作为数据包安装"); // 确认安装 if (!(ModMain.frmMain.pageCurrent == FormMain.PageType.InstanceSetup && @@ -627,18 +627,18 @@ public static void InstallDatapackFiles(IEnumerable filePathList) foreach (var FilePath in filePathList) { - var newFileName = ModBase.GetFileNameFromPath(FilePath); + var newFileName = LegacyFileFacade.GetFileNameFromPath(FilePath); var destFile = datapackFolder + newFileName; if (File.Exists(destFile)) if (ModMain.MyMsgBox(Lang.Text("Instance.Resource.Install.OverwriteConfirm.Message", newFileName), Lang.Text("Instance.Resource.Install.OverwriteConfirm.Title"), Lang.Text("Common.Action.Overwrite"), Lang.Text("Common.Action.Cancel")) != 1) continue; - ModBase.CopyFile(FilePath, destFile); + LegacyFileFacade.CopyFile(FilePath, destFile); } if (filePathList.Count() == 1) - HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessSingle", ModBase.GetFileNameFromPath(filePathList.First())), HintType.Success); + HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessSingle", LegacyFileFacade.GetFileNameFromPath(filePathList.First())), HintType.Success); else HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessMultiple", filePathList.Count(), Lang.Text("Download.Comp.Type.DataPack")), HintType.Success); @@ -651,10 +651,10 @@ public static void InstallDatapackFiles(IEnumerable filePathList) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "复制数据包文件失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -686,14 +686,14 @@ void ExportText(string content, string fileName) SystemDialogs.SelectSaveFile(Lang.Text("Instance.Resource.Export.SelectSaveLocation"), fileName, Lang.Text("Instance.Resource.Export.FilesFilter")); if (string.IsNullOrWhiteSpace(savePath)) return; File.WriteAllText(savePath, content, Encoding.UTF8); - ModBase.OpenExplorer(savePath); + LauncherProcess.OpenExplorer(savePath); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "导出数据包信息失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -707,7 +707,7 @@ void ExportText(string content, string fileName) foreach (var DatapackEntity in ModLocalComp.compResourceListLoader.output) exportContent.Add(DatapackEntity.FileName); ExportText(exportContent.Join("\r\n"), - ModBase.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave) + "的数据包信息.txt"); + LegacyFileFacade.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave) + "的数据包信息.txt"); break; } @@ -719,7 +719,7 @@ void ExportText(string content, string fileName) exportContent.Add( $"{DatapackEntity.FileName},{DatapackEntity.Comp?.TranslatedName},{DatapackEntity.Version},{DatapackEntity.compFile?.ReleaseDate},{DatapackEntity.Comp?.Id},{GetDatapackFileInfo(DatapackEntity.path).Length},{DatapackEntity.path}"); ExportText(exportContent.Join("\r\n"), - ModBase.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave) + "的数据包信息.csv"); + LegacyFileFacade.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave) + "的数据包信息.csv"); break; } } @@ -735,7 +735,7 @@ void ExportText(string content, string fileName) public HashSet selectedDatapacks = new(); // 单项切换选择状态 - public void CheckChanged(MyLocalCompItem sender, ModBase.RouteEventArgs e) + public void CheckChanged(MyLocalCompItem sender, RouteEventArgs e) { if (ModAnimation.AniControlEnabled != 0) return; @@ -939,7 +939,7 @@ private string GetSortName(SortMethod method) return ""; } - private void BtnSortClick(object sender, ModBase.RouteEventArgs e) + private void BtnSortClick(object sender, RouteEventArgs e) { var body = new ContextMenu(); foreach (SortMethod i in Enum.GetValues(typeof(SortMethod))) @@ -985,10 +985,10 @@ private void DoSort() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "执行排序时出错", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -1049,7 +1049,7 @@ private void DoSort() #region 下边栏 // 启用 - private void BtnSelectEnable_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectEnable_Click(object sender, RouteEventArgs e) { ToggleDatapacks( ModLocalComp.compResourceListLoader.output.Where(m => selectedDatapacks.Contains(m.RawPath)).ToList(), @@ -1058,7 +1058,7 @@ private void BtnSelectEnable_Click(object sender, ModBase.RouteEventArgs e) } // 禁用 - private void BtnSelectDisable_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectDisable_Click(object sender, RouteEventArgs e) { ToggleDatapacks( ModLocalComp.compResourceListLoader.output.Where(m => selectedDatapacks.Contains(m.RawPath)).ToList(), @@ -1091,7 +1091,7 @@ private void ToggleDatapacks(IEnumerable datapackLis { if (File.Exists(newPath)) { - ModMain.MyMsgBox(Lang.Text("Instance.Saves.Datapack.Replace.FileNameConflict", ModBase.GetFileNameFromPath(newPath))); + ModMain.MyMsgBox(Lang.Text("Instance.Saves.Datapack.Replace.FileNameConflict", LegacyFileFacade.GetFileNameFromPath(newPath))); continue; } @@ -1099,17 +1099,17 @@ private void ToggleDatapacks(IEnumerable datapackLis } catch (FileNotFoundException ex) { - ModBase.Log( + LauncherLog.Log( ex, $"未找到需要重命名的数据包({datapackEntity.path ?? "null"})", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); ReloadDatapackFileList(true); return; } catch (Exception ex) { - ModBase.Log(ex, $"重命名数据包失败({datapackEntity.path ?? "null"})"); + LauncherLog.Log(ex, $"重命名数据包失败({datapackEntity.path ?? "null"})"); isSuccessful = false; } @@ -1144,10 +1144,10 @@ private void ToggleDatapacks(IEnumerable datapackLis } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"更新 UI 列表项失败:{datapackEntity.FileName}", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -1168,7 +1168,7 @@ private void ToggleDatapacks(IEnumerable datapackLis } // 更新 - private void BtnSelectUpdate_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectUpdate_Click(object sender, RouteEventArgs e) { var updateList = ModLocalComp.compResourceListLoader.output .Where(m => selectedDatapacks.Contains(m.RawPath) && m.CanUpdate).ToList(); @@ -1232,7 +1232,7 @@ public void UpdateResource(IEnumerable datapackList) var fileList = new List(); var fileCopyList = new Dictionary(); var updateEntryList = new List(); - var tempRoot = Path.Combine(ModBase.pathTemp, "DownloadedComp"); + var tempRoot = Path.Combine(LauncherPaths.TempWithSlash, "DownloadedComp"); var datapackRoot = Path.Combine(PageInstanceSavesLeft.currentSave, "datapacks"); var skippedUnsafeFileCount = 0; foreach (var Entry in datapackList) @@ -1245,7 +1245,7 @@ public void UpdateResource(IEnumerable datapackList) !TryBuildDatapackUpdatePath(datapackRoot, safeFileName, out var realAddress)) { skippedUnsafeFileCount++; - ModBase.Log($"[DatapackUpdate] 已跳过不安全的数据包更新文件名:{file.FileName}", ModBase.LogLevel.Debug); + LauncherLog.Log($"[DatapackUpdate] 已跳过不安全的数据包更新文件名:{file.FileName}", LauncherLogLevel.Debug); continue; } @@ -1279,8 +1279,8 @@ public void UpdateResource(IEnumerable datapackList) Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile(Entry.path, UIOption.AllDialogs, RecycleOption.SendToRecycleBin); else - ModBase.Log($"[DatapackUpdate] 未找到更新前的数据包文件,跳过对它的删除:{Entry.path}", - ModBase.LogLevel.Debug); + LauncherLog.Log($"[DatapackUpdate] 未找到更新前的数据包文件,跳过对它的删除:{Entry.path}", + LauncherLogLevel.Debug); foreach (var Entry in fileCopyList) { @@ -1288,43 +1288,43 @@ public void UpdateResource(IEnumerable datapackList) { Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile(Entry.Value, UIOption.AllDialogs, RecycleOption.SendToRecycleBin); - ModBase.Log($"[Datapack] 更新后的数据包文件已存在,将会把它放入回收站:{Entry.Value}", ModBase.LogLevel.Debug); + LauncherLog.Log($"[Datapack] 更新后的数据包文件已存在,将会把它放入回收站:{Entry.Value}", LauncherLogLevel.Debug); } - if (Directory.Exists(ModBase.GetPathFromFullPath(Entry.Value))) + if (Directory.Exists(LegacyFileFacade.GetPathFromFullPath(Entry.Value))) { File.Move(Entry.Key, Entry.Value); - finishedFileNames.Add(ModBase.GetFileNameFromPath(Entry.Value)); + finishedFileNames.Add(LegacyFileFacade.GetFileNameFromPath(Entry.Value)); } else { - ModBase.Log($"[Datapack] 更新后的目标文件夹已被删除:{Entry.Value}", ModBase.LogLevel.Debug); + LauncherLog.Log($"[Datapack] 更新后的目标文件夹已被删除:{Entry.Value}", LauncherLogLevel.Debug); } } } catch (OperationCanceledException ex) { - ModBase.Log(ex, "替换旧版数据包文件时被主动取消"); + LauncherLog.Log(ex, "替换旧版数据包文件时被主动取消"); } })); // 结束处理 var loader = new ModLoader.LoaderCombo>( Lang.Text("Instance.Saves.Datapack.Update.Task.Title", - ModBase.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave)), installLoaders); + LegacyFileFacade.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave)), installLoaders); var pathDatapacks = Path.Combine(PageInstanceSavesLeft.currentSave, "datapacks"); loader.OnStateChanged = _ => { switch (loader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: { switch (finishedFileNames.Count) { case 0: { - ModBase.Log("[DatapackUpdate] 没有数据包被成功更新"); + LauncherLog.Log("[DatapackUpdate] 没有数据包被成功更新"); break; } case 1: @@ -1342,12 +1342,12 @@ public void UpdateResource(IEnumerable datapackList) break; } - case ModBase.LoadState.Failed: + case LoadState.Failed: { HintService.Hint(Lang.Text("Instance.Resource.Update.Failed", loader.Error.Message), HintType.Error); break; } - case ModBase.LoadState.Aborted: + case LoadState.Aborted: { HintService.Hint(Lang.Text("Instance.Resource.Update.Aborted")); break; @@ -1359,11 +1359,11 @@ public void UpdateResource(IEnumerable datapackList) } } - ModBase.Log($"[DatapackUpdate] 已从正在进行数据包更新的文件夹列表移除:{pathDatapacks}"); + LauncherLog.Log($"[DatapackUpdate] 已从正在进行数据包更新的文件夹列表移除:{pathDatapacks}"); updatingVersions.Remove(pathDatapacks); // 清理缓存 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -1373,13 +1373,13 @@ public void UpdateResource(IEnumerable datapackList) } catch (Exception ex) { - ModBase.Log(ex, "清理数据包更新缓存失败"); + LauncherLog.Log(ex, "清理数据包更新缓存失败"); } }, "Clean Datapack Update Cache", ThreadPriority.BelowNormal); }; // 启动加载器 - ModBase.Log($"[DatapackUpdate] 开始更新 {datapackList.Count()} 个数据包:{pathDatapacks}"); + LauncherLog.Log($"[DatapackUpdate] 开始更新 {datapackList.Count()} 个数据包:{pathDatapacks}"); updatingVersions.Add(pathDatapacks); loader.Start(); ModLoader.LoaderTaskbarAdd(loader); @@ -1389,12 +1389,12 @@ public void UpdateResource(IEnumerable datapackList) } catch (Exception ex) { - ModBase.Log(ex, "初始化数据包更新失败"); + LauncherLog.Log(ex, "初始化数据包更新失败"); } } // 删除 - private void BtnSelectDelete_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectDelete_Click(object sender, RouteEventArgs e) { DeleteDatapacks(ModLocalComp.compResourceListLoader.output.Where(m => selectedDatapacks.Contains(m.RawPath))); ChangeAllSelected(false); @@ -1429,16 +1429,16 @@ private void DeleteDatapacks(IEnumerable datapackLis } catch (OperationCanceledException ex) { - ModBase.Log(ex, "删除数据包被主动取消"); + LauncherLog.Log(ex, "删除数据包被主动取消"); ReloadDatapackFileList(true); return; } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"删除数据包失败({DatapackEntity.path})", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); isSuccessful = false; } @@ -1490,15 +1490,15 @@ private void DeleteDatapacks(IEnumerable datapackLis } catch (OperationCanceledException ex) { - ModBase.Log(ex, "删除数据包被主动取消"); + LauncherLog.Log(ex, "删除数据包被主动取消"); ReloadDatapackFileList(true); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "删除数据包出现未知错误", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); ReloadDatapackFileList(true); } @@ -1507,13 +1507,13 @@ private void DeleteDatapacks(IEnumerable datapackLis } // 取消选择 - private void BtnSelectCancel_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectCancel_Click(object sender, RouteEventArgs e) { ChangeAllSelected(false); } // 收藏 - private void BtnSelectFavorites_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectFavorites_Click(object sender, RouteEventArgs e) { var selected = ModLocalComp.compResourceListLoader.output .Where(m => selectedDatapacks.Contains(m.RawPath) && m.Comp is not null).Select(i => i.Comp).ToList(); @@ -1521,11 +1521,11 @@ private void BtnSelectFavorites_Click(object sender, ModBase.RouteEventArgs e) } // 分享 - private void BtnSelectShare_Click(object sender, ModBase.RouteEventArgs e) + private void BtnSelectShare_Click(object sender, RouteEventArgs e) { var shareList = ModLocalComp.compResourceListLoader.output .Where(m => selectedDatapacks.Contains(m.RawPath) && m.Comp is not null).Select(i => i.Comp.Id).ToHashSet(); - ModBase.ClipboardSet(ModComp.CompFavorites.GetShareCode(shareList)); + LauncherProcess.ClipboardSet(ModComp.CompFavorites.GetShareCode(shareList)); ChangeAllSelected(false); } @@ -1571,7 +1571,7 @@ public void Info_Click(object sender, EventArgs e) if (datapackEntry.Authors is not null) contentLines.Add(Lang.Text("Instance.Saves.Datapack.Info.Author") + datapackEntry.Authors); contentLines.Add(Lang.Text("Instance.Saves.Datapack.Info.File") + datapackEntry.FileName + "(" + - ModBase.GetString(GetDatapackFileInfo(datapackEntry.path).Length) + ")"); + LauncherText.GetReadableFileSize(GetDatapackFileInfo(datapackEntry.path).Length) + ")"); if (datapackEntry.Version is not null) contentLines.Add(Lang.Text("Instance.Saves.Datapack.Info.Version") + datapackEntry.Version); @@ -1587,15 +1587,15 @@ public void Info_Click(object sender, EventArgs e) if (datapackEntry.Url is null) ModMain.MyMsgBox(contentLines.Join("\r\n"), datapackEntry.Name, Lang.Text("Instance.Resource.Item.Info.Return")); else if (ModMain.MyMsgBox(contentLines.Join("\r\n"), datapackEntry.Name, Lang.Text("Instance.Resource.Item.Info.OpenWebsite"), Lang.Text("Instance.Resource.Item.Info.Return")) == 1) - ModBase.OpenWebsite(datapackEntry.Url); + LauncherProcess.OpenWebsite(datapackEntry.Url); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "获取数据包详情失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -1606,14 +1606,14 @@ public void Open_Click(MyIconButton sender, EventArgs e) try { var listItem = (MyLocalCompItem)sender.Tag; - ModBase.OpenExplorer(listItem.Entry.path); + LauncherProcess.OpenExplorer(listItem.Entry.path); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "打开数据包文件位置失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Saves.Error.OperationFailed")); } } @@ -1653,40 +1653,40 @@ public void SearchRun(object sender, EventArgs e) if (IsSearching) { // 构造请求 - var queryList = new List>(); + var queryList = new List>(); foreach (var Entry in ModLocalComp.compResourceListLoader.output) { - var searchSource = new List(); - searchSource.Add(new ModBase.SearchSource(Entry.Name, 1d)); - searchSource.Add(new ModBase.SearchSource(Entry.FileName, 1d)); + var searchSource = new List(); + searchSource.Add(new SearchSource(Entry.Name, 1d)); + searchSource.Add(new SearchSource(Entry.FileName, 1d)); if (Entry.Version is not null) - searchSource.Add(new ModBase.SearchSource(Entry.Version, 0.2d)); + searchSource.Add(new SearchSource(Entry.Version, 0.2d)); if (Entry.Description is not null && !string.IsNullOrEmpty(Entry.Description)) - searchSource.Add(new ModBase.SearchSource(Entry.Description, 0.4d)); + searchSource.Add(new SearchSource(Entry.Description, 0.4d)); if (Entry.Comp is not null) { if ((Entry.Comp.RawName ?? "") != (Entry.Name ?? "")) - searchSource.Add(new ModBase.SearchSource(Entry.Comp.RawName, 1d)); + searchSource.Add(new SearchSource(Entry.Comp.RawName, 1d)); if ((Entry.Comp.TranslatedName ?? "") != (Entry.Comp.RawName ?? "")) - searchSource.Add(new ModBase.SearchSource(Entry.Comp.TranslatedName, 1d)); + searchSource.Add(new SearchSource(Entry.Comp.TranslatedName, 1d)); if ((Entry.Comp.Description ?? "") != (Entry.Description ?? "")) - searchSource.Add(new ModBase.SearchSource(Entry.Comp.Description, 0.4d)); - searchSource.Add(new ModBase.SearchSource(string.Join("", Entry.Comp.Tags), 0.2d)); + searchSource.Add(new SearchSource(Entry.Comp.Description, 0.4d)); + searchSource.Add(new SearchSource(string.Join("", Entry.Comp.Tags), 0.2d)); } - queryList.Add(new ModBase.SearchEntry + queryList.Add(new SearchEntry { item = Entry, searchSource = searchSource }); } // 进行搜索 - searchResult = ModBase.Search(queryList, SearchBox.Text, ModBase.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); + searchResult = LauncherSearch.Search(queryList, SearchBox.Text, LauncherSearch.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); } RefreshUI(); } catch (Exception ex) { - ModBase.Log(ex, "搜索过程中发生异常"); + LauncherLog.Log(ex, "搜索过程中发生异常"); } } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesInfo.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesInfo.xaml.cs index 0aca8470b..e19e02dbb 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesInfo.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesInfo.xaml.cs @@ -97,10 +97,10 @@ private async Task RefreshInfoAsync() catch (OperationCanceledException) { } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.Info.Error.LoadFailed"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Saves.Info.Error.LoadFailed")); PanContent.Visibility = Visibility.Collapsed; PanSettings.Visibility = Visibility.Collapsed; @@ -149,10 +149,10 @@ private void BuildAllowCommandsSetting(bool allowCommands) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.Info.Modify.CheatFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Info.Modify.CheatFailed")); } }; @@ -213,10 +213,10 @@ async Task ApplyAsync() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.Info.Modify.DifficultyFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Info.Modify.DifficultyFailed")); } } @@ -260,14 +260,14 @@ private void AddInfoRow(string head, string content, bool isSeed = false, string { try { - ModBase.ClipboardSet(content); + LauncherProcess.ClipboardSet(content); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.Info.Error.ClipboardFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Info.Error.ClipboardFailed")); } }; @@ -320,18 +320,18 @@ private static void OpenChunkbase(string seed, string? versionName) { if (versionName is null) { - ModBase.Log( + LauncherLog.Log( Lang.Text("Instance.Saves.Info.Chunkbase.UnknownVersion"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Info.Chunkbase.UnknownVersion")); return; } if (versionName.Any(char.IsLetter)) { - ModBase.Log( + LauncherLog.Log( Lang.Text("Instance.Saves.Info.Chunkbase.PreviewVersion", versionName), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Info.Chunkbase.PreviewVersion", versionName)); return; } @@ -341,15 +341,15 @@ private static void OpenChunkbase(string seed, string? versionName) : versionName.Contains('.') ? string.Join("_", versionName.Split('.').Take(2)) : versionName.Replace(".", "_"); - ModBase.OpenWebsite( + LauncherProcess.OpenWebsite( $"https://www.chunkbase.com/apps/seed-map#seed={seed}&platform=java_{usedVersion}&dimension=overworld"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.Info.Error.ChunkbaseFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Saves.Info.Error.ChunkbaseFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesLeft.xaml.cs index aeae00416..9c10cad22 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesLeft.xaml.cs @@ -22,7 +22,7 @@ private void Page_Loaded(object sender, RoutedEventArgs e) private void BtnOpenFolder_Click(object sender, MouseButtonEventArgs e) { e.Handled = true; - ModBase.OpenExplorer($@"{currentSave}\"); + LauncherProcess.OpenExplorer($@"{currentSave}\"); } #region 龙猫牌 页面管理 @@ -44,10 +44,10 @@ public PageInstanceSavesLeft() /// /// 勾选事件改变页面。 /// - private void PageCheck(object sender, ModBase.RouteEventArgs e) + private void PageCheck(object sender, RouteEventArgs e) { if (sender is MyListItem item && item.Tag is not null) - PageChange((FormMain.PageSubType)ModBase.Val(item.Tag)); + PageChange((FormMain.PageSubType)LauncherText.Val(item.Tag)); } public object PageGet(FormMain.PageSubType id = FormMain.PageSubType.Default) @@ -91,10 +91,10 @@ public void PageChange(FormMain.PageSubType id) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Saves.Left.SwitchFailed", (int)id), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Saves.Left.SwitchFailed", (int)id)); } finally @@ -129,7 +129,7 @@ private static void PageChangeRun(MyPageRight target) public void RefreshButton_Click(object sender, EventArgs e) // 由边栏按钮匿名调用 { - Refresh((FormMain.PageSubType)ModBase.Val(((MyIconButton)sender).Tag)); + Refresh((FormMain.PageSubType)LauncherText.Val(((MyIconButton)sender).Tag)); } public void Refresh() diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceScreenshot.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceScreenshot.xaml.cs index 1bef17205..d2e5dcce8 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceScreenshot.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceScreenshot.xaml.cs @@ -93,7 +93,7 @@ private void RefreshTip() private async Task LoadFileListAsync() { - ModBase.Log("[Screenshot] 刷新截图文件"); + LauncherLog.Log("[Screenshot] 刷新截图文件"); fileList.Clear(); if (Directory.Exists(screenshotPath)) { @@ -106,7 +106,7 @@ private async Task LoadFileListAsync() RefreshTip(); //FileList = FileList.Where(e => !e.ContainsF(@"\debug\")).ToList(); // 排除资源包调试输出 //FileList.Sort((a, b) => new FileInfo(a).CreationTime > new FileInfo(b).CreationTime); - ModBase.Log("[Screenshot] 共发现 " + fileList.Count + " 个截图文件"); + LauncherLog.Log("[Screenshot] 共发现 " + fileList.Count + " 个截图文件"); if (fileList.Count == 0) return; await ListAppendAsync(20, 0); @@ -192,10 +192,10 @@ private async Task ListAppendAsync(int count = 20, int offset = -1) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Screenshot.OpenFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Screenshot.OpenFailed")); } }; // 使用系统默认程序打开 @@ -246,7 +246,7 @@ private async Task ListAppendAsync(int count = 20, int offset = -1) } catch (Exception ex) { - ModBase.Log(ex, $"[Screenshot] 创建 {i} 截图预览失败,图像可能损坏"); + LauncherLog.Log(ex, $"[Screenshot] 创建 {i} 截图预览失败,图像可能损坏"); } } @@ -268,7 +268,7 @@ private void RemoveItem(string path) } catch (Exception ex) { - ModBase.Log(ex, "未能找到对应 UI"); + LauncherLog.Log(ex, "未能找到对应 UI"); } } @@ -279,7 +279,7 @@ private string GetPathFromSender(MyIconTextButton sender) private void BtnOpen_Click(MyIconTextButton sender, EventArgs e) { - ModBase.OpenExplorer(GetPathFromSender(sender)); + LauncherProcess.OpenExplorer(GetPathFromSender(sender)); } private void BtnDelete_Click(MyIconTextButton sender, EventArgs e) @@ -294,10 +294,10 @@ private void BtnDelete_Click(MyIconTextButton sender, EventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Screenshot.DeleteFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Instance.Screenshot.DeleteFailed")); } } @@ -311,7 +311,7 @@ private void BtnCopy_Click(MyIconTextButton sender, EventArgs e) while (tryTime <= 5) try { - ModBase.Log("[Screenshot] 尝试复制" + imagePath + "到剪贴板"); + LauncherLog.Log("[Screenshot] 尝试复制" + imagePath + "到剪贴板"); Clipboard.SetImage(new BitmapImage(new Uri(imagePath))); HintService.Hint(Lang.Text("Instance.Screenshot.CopiedToClipboard")); tryTime = 6; @@ -320,7 +320,7 @@ private void BtnCopy_Click(MyIconTextButton sender, EventArgs e) catch (Exception ex) { tryTime += 1; - ModBase.Log(ex, $"[Screenshot]第 {tryTime} 次复制尝试失败"); + LauncherLog.Log(ex, $"[Screenshot]第 {tryTime} 次复制尝试失败"); } HintService.Hint(Lang.Text("Instance.Screenshot.CopyFailed"), HintType.Error); @@ -335,6 +335,6 @@ private void BtnOpenFolder_Click(object sender, MouseButtonEventArgs e) { if (!Directory.Exists(screenshotPath)) Directory.CreateDirectory(screenshotPath); - ModBase.OpenExplorer(screenshotPath); + LauncherProcess.OpenExplorer(screenshotPath); } } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceServer.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceServer.xaml.cs index 988676b20..c9c3e1af1 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceServer.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceServer.xaml.cs @@ -159,26 +159,26 @@ await NbtFileHandler.ReadTagInNbtFileAsync(Path.Combine(PageInstanceLef /// public async void RefreshServers() { - ModBase.Log("刷新服务器列表"); + LauncherLog.Log("刷新服务器列表"); try { // 读取服务器信息 await LoadServersFromFileAsync(); // 在UI线程中更新界面 - ModBase.RunInUi(() => UpdateServerUi()); + UiThread.Post(() => UpdateServerUi()); // 异步ping所有服务器 PingAllServers(); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Server.RefreshFailed"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Server.RefreshFailed")); - ModBase.RunInUi(() => HintService.Hint( + UiThread.Post(() => HintService.Hint( Lang.Text("Instance.Server.RefreshFailed.WithDetail", ex.ToString()), HintType.Error)); } @@ -200,10 +200,10 @@ private void BtnRefresh_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Server.RefreshFailed"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Server.RefreshFailed")); HintService.Hint( Lang.Text("Instance.Server.RefreshFailed.WithDetail", ex.ToString()), @@ -293,7 +293,7 @@ private async Task LoadServersFromFileAsync() } catch (Exception ex) { - ModBase.Log(ex, Lang.Text("Instance.Server.ReadFileFailed")); + LauncherLog.Log(ex, Lang.Text("Instance.Server.ReadFileFailed")); } } @@ -304,7 +304,7 @@ private void ParseServersFromNBT(NbtList serversList) { if (serversList is not null) { - ModBase.Log($"Found {serversList.Count} servers:"); + LauncherLog.Log($"Found {serversList.Count} servers:"); // 遍历 servers 列表中的每个服务器 for (int i = 0, loopTo = serversList.Count - 1; i <= loopTo; i++) @@ -318,9 +318,9 @@ private void ParseServersFromNBT(NbtList serversList) var name = server.Get("name")?.Value ?? "Unknown"; var iconBase64 = server.Get("icon")?.Value; - ModBase.Log($"服务器 {i + 1}:"); - ModBase.Log($" 名字: {name}"); - ModBase.Log($" IP: {ip}"); + LauncherLog.Log($"服务器 {i + 1}:"); + LauncherLog.Log($" 名字: {name}"); + LauncherLog.Log($" IP: {ip}"); // Log($" Hidden: {If(hidden = 1, "Yes", "No")}") serverList.Add(new MinecraftServerInfo { @@ -334,7 +334,7 @@ private void ParseServersFromNBT(NbtList serversList) } else { - ModBase.Log("No 'servers' list found in servers.dat."); + LauncherLog.Log("No 'servers' list found in servers.dat."); } } @@ -362,14 +362,14 @@ private void RefreshTip() { if (serverList.Count == 0) { - ModBase.Log(Lang.Text("Instance.Server.NoServersFound")); + LauncherLog.Log(Lang.Text("Instance.Server.NoServersFound")); PanNoServer.Visibility = Visibility.Visible; PanContent.Visibility = Visibility.Collapsed; PanServers.Visibility = Visibility.Collapsed; return; } - ModBase.Log(Lang.Text("Instance.Server.FoundServers")); + LauncherLog.Log(Lang.Text("Instance.Server.FoundServers")); PanNoServer.Visibility = Visibility.Collapsed; PanContent.Visibility = Visibility.Visible; PanServers.Visibility = Visibility.Visible; @@ -403,7 +403,7 @@ private async void PingAllServers() } catch (Exception ex) { - ModBase.Log(ex, $"Ping 服务器失败: {currentServer}"); + LauncherLog.Log(ex, $"Ping 服务器失败: {currentServer}"); } finally { @@ -416,11 +416,11 @@ private async void PingAllServers() } catch (OperationCanceledException ex) { - ModBase.Log("PingAllServers 被取消", ModBase.LogLevel.Debug); + LauncherLog.Log("PingAllServers 被取消", LauncherLogLevel.Debug); } catch (Exception ex) { - ModBase.Log(ex, "PingAllServers 失败"); + LauncherLog.Log(ex, "PingAllServers 失败"); } } @@ -435,9 +435,9 @@ public static async Task PingServerAsync(MinecraftServerInf using (var query = McPingServiceFactory.CreateService(addr.Host, addr.Ip, addr.Port)) { McPingResult? result; - ModBase.Log("Pinging server: " + server.Address + ":" + addr.Port); + LauncherLog.Log("Pinging server: " + server.Address + ":" + addr.Port); result = await query.PingAsync(token); // 传递 token - ModBase.Log("Ping result: " + (result is not null ? "Success" : "Failed")); + LauncherLog.Log("Ping result: " + (result is not null ? "Success" : "Failed")); if (result is not null) { server.Status = ServerStatus.Online; @@ -457,12 +457,12 @@ public static async Task PingServerAsync(MinecraftServerInf catch (OperationCanceledException ex) { server.Status = ServerStatus.Offline; - ModBase.Log("Ping 服务器被取消: " + server.Address, ModBase.LogLevel.Debug); + LauncherLog.Log("Ping 服务器被取消: " + server.Address, LauncherLogLevel.Debug); } catch (Exception ex) { server.Status = ServerStatus.Offline; - ModBase.Log(ex, $"Ping 服务器失败: {server.Address}:{server.Port}"); + LauncherLog.Log(ex, $"Ping 服务器失败: {server.Address}:{server.Port}"); } return server; diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs index 9cb90acc7..529dcc205 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs @@ -128,7 +128,7 @@ public void Reload() CheckAdvanceDisableLwjglUnsafeAgent.Checked = Config.Instance.DisableLwjglUnsafeAgent[PageInstanceLeft.McInstance.PathInstance]; if (Config.Instance.AssetVerifySolutionV1[PageInstanceLeft.McInstance.PathInstance] == 2) { - ModBase.Log("[Setup] 已迁移老版本的关闭文件校验设置"); + LauncherLog.Log("[Setup] 已迁移老版本的关闭文件校验设置"); Config.Instance.AssetVerifySolutionV1Config.Reset(PageInstanceLeft.McInstance.PathInstance); Config.Instance.DisableAssetVerifyV2[PageInstanceLeft.McInstance.PathInstance] = true; } @@ -152,10 +152,10 @@ public void Reload() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "重载实例独立设置时出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Setup.Error.OperationFailed")); } } @@ -170,15 +170,15 @@ public void Reset() Config.Instance.Reset(PageInstanceLeft.McInstance.PathInstance); - ModBase.Log("[Setup] 已初始化实例独立设置"); + LauncherLog.Log("[Setup] 已初始化实例独立设置"); HintService.Hint(Lang.Text("Instance.Setup.Initialize.Success"), HintType.Success, false); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "初始化实例独立设置失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Instance.Setup.Error.OperationFailed")); } @@ -189,7 +189,7 @@ public void Reset() private static void SetByTag(string tag, object value) => ConfigService.TrySetValue(tag, value, PageInstanceLeft.McInstance.PathInstance); - private void RadioBoxChange(object o, ModBase.RouteEventArgs routeEventArgs) + private void RadioBoxChange(object o, RouteEventArgs routeEventArgs) { if (ModAnimation.AniControlEnabled != 0) return; @@ -266,7 +266,7 @@ public void RefreshRam(bool showAnim) var ramAvailable = Math.Round((double)(phyRam.Available / 1024 / 1024 / 1024), 1); var ramGameActual = Math.Round(Math.Min(ramGame, ramAvailable), 5); var ramUsed = Math.Round(ramTotal - ramAvailable, 5); - var ramEmpty = Math.Round(ModBase.MathClamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); + var ramEmpty = Math.Round(LauncherMath.Clamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); // 设置最大可用内存 if (ramTotal <= 1.5d) SliderRamCustom.MaxValue = (int)Math.Round(Math.Max(Math.Floor((ramTotal - 0.3d) / 0.1d), 1d)); @@ -686,10 +686,10 @@ private void BtnServerNewProfile_Click(object sender, MouseButtonEventArgs e) { ModMain.frmMain.PageChange(new FormMain.PageStackData { page = FormMain.PageType.Launch }); PageLoginAuth.draggedAuthServer = TextServerAuthServer.Text; - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { Thread.Sleep(150); - ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Auth)); + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(true, ModLaunch.McLoginType.Auth)); }); } @@ -788,10 +788,10 @@ public void RefreshJavaComboBox() catch (Exception ex) { Config.Instance.SelectedJava[PageInstanceLeft.McInstance.PathInstance] = "使用全局设置"; - ModBase.Log( + LauncherLog.Log( ex, "更新实例设置 Java 下拉框失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Setup.Error.OperationFailed")); ComboArgumentJava.Items.Clear(); ComboArgumentJava.Items.Add(new MyComboBoxItem @@ -940,7 +940,7 @@ private void JavaSelectionUpdate(object sender, SelectionChangedEventArgs e) Config.Instance.SelectedJava[PageInstanceLeft.McInstance.PathInstance] = json; - ModBase.Log(logMessage); + LauncherLog.Log(logMessage); RefreshRam(true); } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/ServerCard.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/ServerCard.xaml.cs index e68b24a2b..8e8ce6511 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/ServerCard.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/ServerCard.xaml.cs @@ -50,7 +50,7 @@ private void BtnSkin_Click(object sender, EventArgs eventArgs) public void UpdateServerInfo(MinecraftServerInfo serverInfo) { server = serverInfo; - ModBase.RunInUi(() => UpdateServerUi()); + UiThread.Post(() => UpdateServerUi()); } /// @@ -157,10 +157,10 @@ private void BtnConnect_Click(object sender, EventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Instance.Server.Card.LaunchFailed"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Instance.Server.Card.LaunchFailed")); HintService.Hint(Lang.Text("Instance.Server.Card.LaunchFailedMsg", ex.Message), HintType.Error); } @@ -178,7 +178,7 @@ private void BtnCopy_Click(object sender, RoutedEventArgs e) } catch (Exception ex) { - ModBase.Log(ex, Lang.Text("Instance.Server.Card.CopyAddressFailed")); + LauncherLog.Log(ex, Lang.Text("Instance.Server.Card.CopyAddressFailed")); HintService.Hint(Lang.Text("Instance.Server.Card.CopyAddressFailed"), HintType.Error); } } diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs index 6d7e327fa..ebed3be9b 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs @@ -35,7 +35,7 @@ private void Finished(object result) return; myConverter.IsExited = true; myConverter.Result = result; - ModBase.RunInUi(Close); + UiThread.Post(Close); Thread.Sleep(200); ModMain.frmMain.ShowWindowToTop(); } @@ -44,7 +44,7 @@ private void Init() { userCode = (string)data["user_code"]; deviceCode = (string)data["device_code"]; - ModBase.ClipboardSet(deviceCode); + LauncherProcess.ClipboardSet(deviceCode); if (data["verification_uri_complete"] is not null) { website = (string)data["verification_uri_complete"]; @@ -73,8 +73,8 @@ private async Task WorkThreadAsync() await Task.Delay(2000).ConfigureAwait(false); if (myConverter.IsExited) return; - ModBase.OpenWebsite(website); - ModBase.ClipboardSet(userCode); + LauncherProcess.OpenWebsite(website); + LauncherProcess.ClipboardSet(userCode); var delayTime = (data["interval"].ToObject() - 1) * 1000; // 轮询 var unknownFailureCount = 0; @@ -108,7 +108,7 @@ await Task.Delay(delayTime) } // 获取结果 var ctx = await result.AsStringAsync().ConfigureAwait(false); - var resultJson = (JsonObject)ModBase.GetJson(ctx); + var resultJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ctx); ModProfile.ProfileLog($"令牌过期时间:{resultJson["expires_in"]} 秒"); HintService.Hint(Lang.Text("Launch.Account.LoginDialog.Success"), HintType.Success); Finished(new[] { resultJson["access_token"].ToString(), resultJson["refresh_token"].ToString() }); @@ -119,8 +119,8 @@ await Task.Delay(delayTime) if (unknownFailureCount <= 2) { unknownFailureCount += 1; - ModBase.Log(ex, $"正版验证轮询第 {unknownFailureCount} 次失败"); - ModBase.Log(ex.Message); + LauncherLog.Log(ex, $"正版验证轮询第 {unknownFailureCount} 次失败"); + LauncherLog.Log(ex.Message); await Task.Delay(2000).ConfigureAwait(false); } else @@ -136,28 +136,28 @@ await Task.Delay(delayTime) #region 弹窗 private readonly ModMain.MyMsgBoxConverter myConverter; - private readonly int uuid = ModBase.GetUuid(); + private readonly int uuid = LauncherRuntime.GetUuid(); public MyMsgLogin(ModMain.MyMsgBoxConverter converter) { try { InitializeComponent(); - Btn1.Name += ModBase.GetUuid(); - Btn2.Name += ModBase.GetUuid(); - Btn3.Name += ModBase.GetUuid(); + Btn1.Name += LauncherRuntime.GetUuid(); + Btn2.Name += LauncherRuntime.GetUuid(); + Btn3.Name += LauncherRuntime.GetUuid(); myConverter = converter; - ShapeLine.StrokeThickness = ModBase.GetWPFSize(1d); + ShapeLine.StrokeThickness = DpiUtils.GetWpfSize(1d); data = (JsonObject)converter.Content; oAuthUrl = converter.AuthUrl?.ToString() ?? ""; Init(); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.LoginDialog.Error.Init"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Account.LoginDialog.Error.Init")); } @@ -173,8 +173,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new ModBase.MyColor(140d, 80d, 0d, 0d) - : new ModBase.MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -187,14 +187,14 @@ private void Load(object sender, EventArgs e) new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak)) }, "MyMsgBox " + uuid); // 记录日志 - ModBase.Log($"[Control] 正版验证弹窗:{LabTitle.Text}\r\n{LabCaption.Text}"); + LauncherLog.Log($"[Control] 正版验证弹窗:{LabTitle.Text}\r\n{LabCaption.Text}"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.LoginDialog.Error.Load"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Account.LoginDialog.Error.Load")); } } @@ -209,7 +209,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new ModBase.MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs index 40d69ea79..4420f96d6 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs @@ -20,7 +20,7 @@ public partial class MySkin // 点击 private bool isSkinMouseDown; - public ModLoader.LoaderTask, string> loader; + public ModLoader.LoaderTask, string> loader; public MySkin() { @@ -97,13 +97,13 @@ public void BtnSkinSave_Click(object sender, RoutedEventArgs e) Save(loader); } - public static void Save(ModLoader.LoaderTask, string> loader) + public static void Save(ModLoader.LoaderTask, string> loader) { var address = loader.output; - if (loader.State != ModBase.LoadState.Finished) + if (loader.State != LoadState.Finished) { HintService.Hint(Lang.Text("Launch.Skin.Fetching"), HintType.Error); - if (loader.State != ModBase.LoadState.Loading) + if (loader.State != LoadState.Loading) loader.Start(); return; } @@ -111,28 +111,28 @@ public static void Save(ModLoader.LoaderTask, stri try { var fileAddress = SystemDialogs.SelectSaveFile(Lang.Text("Launch.Skin.SaveDialog.Title"), - ModBase.GetFileNameFromPath(address), + LegacyFileFacade.GetFileNameFromPath(address), Lang.Text("Launch.Skin.SaveDialog.Filter")); if (!fileAddress.Contains(@"\")) return; File.Delete(fileAddress); - if (address.StartsWith(ModBase.pathImage)) + if (address.StartsWith(LauncherPaths.ImageBaseUri)) { var image = new MyBitmap(address); image.Save(fileAddress); } else { - ModBase.CopyFile(address, fileAddress); + LegacyFileFacade.CopyFile(address, fileAddress); } HintService.Hint(Lang.Text("Launch.Skin.SaveSuccess"), HintType.Success); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Skin.Save.Error"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Skin.Save.Error")); } } @@ -153,7 +153,7 @@ public void Load() Address = loader.output; if (string.IsNullOrEmpty(Address)) throw new Exception("皮肤加载器 " + loader.name + " 没有输出"); - if (!Address.StartsWith(ModBase.pathImage) && !File.Exists(Address)) + if (!Address.StartsWith(LauncherPaths.ImageBaseUri) && !File.Exists(Address)) throw new FileNotFoundException("皮肤文件未找到", Address); // 加载 MyBitmap image; @@ -163,10 +163,10 @@ public void Load() } catch (Exception ex) // #2272 { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Skin.Load.Error.Corrupted", Address), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Skin.Load.Error.Corrupted", Address)); File.Delete(Address); return; @@ -214,7 +214,7 @@ public void Load() // 用于显示档案列表头像的图片 var skinHeadId = Address.Between(new[] { Address.Contains("Images/Skins/") ? "Skins/" : @"Skin\" }[0], ".png"); - var cachePath = ModBase.pathTemp + $@"Cache\Skin\Head\{skinHeadId}.png"; + var cachePath = LauncherPaths.TempWithSlash + $@"Cache\Skin\Head\{skinHeadId}.png"; ModProfile.selectedProfile.SkinHeadId = skinHeadId; ModProfile.SaveProfile(); var completeHead = new Bitmap(56, 56); @@ -234,17 +234,17 @@ public void Load() } } - if (!Directory.Exists(ModBase.pathTemp + @"Cache\Skin\Head")) - Directory.CreateDirectory(ModBase.pathTemp + @"Cache\Skin\Head"); + if (!Directory.Exists(LauncherPaths.TempWithSlash + @"Cache\Skin\Head")) + Directory.CreateDirectory(LauncherPaths.TempWithSlash + @"Cache\Skin\Head"); completeHead.Save(cachePath, ImageFormat.Png); - ModBase.Log("[Skin] 载入头像成功:" + loader.name); + LauncherLog.Log("[Skin] 载入头像成功:" + loader.name); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Skin.Load.Error.Avatar", $"{(Address ?? "null")},{loader.name}"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Skin.Load.Error.Avatar", $"{(Address ?? "null")},{loader.name}")); } } @@ -279,10 +279,10 @@ public void RefreshClick(object sender, RoutedEventArgs e) /// /// 刷新皮肤缓存。 /// - public static void RefreshCache(ModLoader.LoaderTask, string> sender = null) + public static void RefreshCache(ModLoader.LoaderTask, string> sender = null) { var hasLoaderRunning = - PageLaunchLeft.skinLoaders.Any(skinLoader => skinLoader.State == ModBase.LoadState.Loading); + PageLaunchLeft.skinLoaders.Any(skinLoader => skinLoader.State == LoadState.Loading); if (ModMain.frmLaunchLeft is not null && hasLoaderRunning) // 由于 Abort 不是实时的,暂时不会释放文件,会导致删除报错,故只能取消执行 @@ -290,19 +290,19 @@ public static void RefreshCache(ModLoader.LoaderTask + UiThread.RunInThread(() => { try { HintService.Hint(Lang.Text("Launch.Skin.Refreshing")); - ModBase.Log("[Skin] 正在清空皮肤缓存"); - if (Directory.Exists(ModBase.pathTemp + @"Cache\Skin")) - ModBase.DeleteDirectory(ModBase.pathTemp + @"Cache\Skin"); - if (Directory.Exists(ModBase.pathTemp + @"Cache\Uuid")) - ModBase.DeleteDirectory(ModBase.pathTemp + @"Cache\Uuid"); - ModBase.IniClearCache(ModBase.pathTemp + @"Cache\Skin\IndexMs.ini"); - ModBase.IniClearCache(ModBase.pathTemp + @"Cache\Skin\IndexAuth.ini"); - ModBase.IniClearCache(ModBase.pathTemp + @"Cache\Uuid\Mojang.ini"); + LauncherLog.Log("[Skin] 正在清空皮肤缓存"); + if (Directory.Exists(LauncherPaths.TempWithSlash + @"Cache\Skin")) + LegacyFileFacade.DeleteDirectory(LauncherPaths.TempWithSlash + @"Cache\Skin"); + if (Directory.Exists(LauncherPaths.TempWithSlash + @"Cache\Uuid")) + LegacyFileFacade.DeleteDirectory(LauncherPaths.TempWithSlash + @"Cache\Uuid"); + LegacyIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexMs.ini"); + LegacyIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexAuth.ini"); + LegacyIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini"); foreach (var SkinLoader in sender is not null ? new[] { sender } : new[] { PageLaunchLeft.skinLegacy, PageLaunchLeft.skinMs }) @@ -311,10 +311,10 @@ public static void RefreshCache(ModLoader.LoaderTask + UiThread.RunInThread(() => { try { - ModBase.WriteIni(ModBase.pathTemp + @"Cache\Skin\IndexMs.ini", ModProfile.selectedProfile.Uuid, + LegacyIniStore.Shared.Write(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexMs.ini", ModProfile.selectedProfile.Uuid, skinAddress); - ModBase.Log($"[Skin] 已写入皮肤地址缓存 {ModProfile.selectedProfile.Uuid} -> {skinAddress}"); + LauncherLog.Log($"[Skin] 已写入皮肤地址缓存 {ModProfile.selectedProfile.Uuid} -> {skinAddress}"); foreach (var SkinLoader in new[] { PageLaunchLeft.skinMs, PageLaunchLeft.skinLegacy }) SkinLoader.WaitForExit(isForceRestart: true); HintService.Hint(Lang.Text("Launch.Skin.ChangeSuccess"), HintType.Success); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Skin.Change.Error.MsRefresh"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Launch.Skin.Change.Error.MsRefresh")); } }); @@ -360,7 +360,7 @@ public void BtnSkinCape_Click(object sender, RoutedEventArgs e) return; } - if (ModLaunch.mcLoginMsLoader.State == ModBase.LoadState.Failed) + if (ModLaunch.mcLoginMsLoader.State == LoadState.Failed) { HintService.Hint(Lang.Text("Launch.Skin.Cape.LoginFailed"), HintType.Error); return; @@ -369,14 +369,14 @@ public void BtnSkinCape_Click(object sender, RoutedEventArgs e) HintService.Hint(Lang.Text("Launch.Skin.Cape.FetchingList")); isChanging = true; // 开始实际获取 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { // 获取登录信息 - if (ModLaunch.mcLoginMsLoader.State != ModBase.LoadState.Finished) + if (ModLaunch.mcLoginMsLoader.State != LoadState.Finished) ModLaunch.mcLoginMsLoader.WaitForExit(ModProfile.GetLoginData()); - if (ModLaunch.mcLoginMsLoader.State != ModBase.LoadState.Finished) + if (ModLaunch.mcLoginMsLoader.State != LoadState.Finished) { HintService.Hint(Lang.Text("Launch.Skin.Cape.LoginFailed"), HintType.Error); return; @@ -384,13 +384,13 @@ public void BtnSkinCape_Click(object sender, RoutedEventArgs e) var accessToken = ModLaunch.mcLoginMsLoader.output.AccessToken; var uuid = ModLaunch.mcLoginMsLoader.output.Uuid; - var skinData = (JsonObject)ModBase.GetJson(ModLaunch.mcLoginMsLoader.output.ProfileJson); + var skinData = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ModLaunch.mcLoginMsLoader.output.ProfileJson); foreach (var itemSkin in skinData["capes"].AsArray()) { if (itemSkin["url"] is null) continue; - var localFile = $@"{ModBase.pathTemp}Cache\Capes\{itemSkin["alias"]}.png"; - var capeFrontFile = $@"{ModBase.pathTemp}Cache\Capes\{itemSkin["alias"]}-front.png"; + var localFile = $@"{LauncherPaths.TempWithSlash}Cache\Capes\{itemSkin["alias"]}.png"; + var capeFrontFile = $@"{LauncherPaths.TempWithSlash}Cache\Capes\{itemSkin["alias"]}-front.png"; if (File.Exists(localFile) && File.Exists(capeFrontFile)) { itemSkin["url"] = capeFrontFile; @@ -409,7 +409,7 @@ public void BtnSkinCape_Click(object sender, RoutedEventArgs e) // 获取玩家的所有披风 int? selId = null; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { try { @@ -441,10 +441,10 @@ public void BtnSkinCape_Click(object sender, RoutedEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Skin.Cape.Error.List"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Launch.Skin.Cape.Error.List")); } }); @@ -465,16 +465,16 @@ public void BtnSkinCape_Click(object sender, RoutedEventArgs e) if (result.Contains("\"errorMessage\"")) HintService.Hint( Lang.Text("Launch.Skin.Cape.ChangeFailedWithReason", - ((JsonObject)ModBase.GetJson(result))["errorMessage"]), HintType.Error); + ((JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(result))["errorMessage"]), HintType.Error); else HintService.Hint(Lang.Text("Launch.Skin.Cape.ChangeSuccess"), HintType.Success); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Skin.Cape.ChangeFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Skin.Cape.ChangeFailed")); } finally diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs index eb206c0ee..ff733a795 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs @@ -82,46 +82,46 @@ public void PageLaunchLeft_Loaded(object sender, RoutedEventArgs e) ModProfile.selectedProfile = ModProfile.profileList[ModProfile.lastUsedProfile]; // 加载实例 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { // 自动整合包安装:准备 string packInstallPath = null; - if (File.Exists(Path.Combine(ModBase.exePath, "modpack.zip"))) - packInstallPath = Path.Combine(ModBase.exePath, "modpack.zip"); - if (File.Exists(Path.Combine(ModBase.exePath, "modpack.mrpack"))) - packInstallPath = Path.Combine(ModBase.exePath, "modpack.mrpack"); + if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "modpack.zip"))) + packInstallPath = Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "modpack.zip"); + if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "modpack.mrpack"))) + packInstallPath = Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "modpack.mrpack"); if (packInstallPath is not null) { - ModBase.Log("[Launch] 需自动安装整合包:" + packInstallPath, ModBase.LogLevel.Debug); + LauncherLog.Log("[Launch] 需自动安装整合包:" + packInstallPath, LauncherLogLevel.Debug); States.Game.SelectedFolder = @"$.minecraft\"; - if (!Directory.Exists(ModBase.exePath + @".minecraft\")) + if (!Directory.Exists(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\")) { - Directory.CreateDirectory(ModBase.exePath + @".minecraft\"); - Directory.CreateDirectory(ModBase.exePath + @".minecraft\versions\"); - ModFolder.McFolderLauncherProfilesJsonCreate(ModBase.exePath + @".minecraft\"); + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\"); + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\versions\"); + ModFolder.McFolderLauncherProfilesJsonCreate(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\"); } - PageSelectLeft.AddFolder(ModBase.exePath + @".minecraft\", - ModBase.GetFolderNameFromPath(ModBase.exePath), false); + PageSelectLeft.AddFolder(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\", + LegacyFileFacade.GetFolderNameFromPath(LauncherPaths.ExecutableDirectoryWithSlash), false); ModFolder.mcFolderListLoader.WaitForExit(); } // 确认 Minecraft 文件夹存在 ModFolder.mcFolderSelected = - States.Game.SelectedFolder.ToString().Replace("$", ModBase.exePath); + States.Game.SelectedFolder.ToString().Replace("$", LauncherPaths.ExecutableDirectoryWithSlash); if (string.IsNullOrEmpty(ModFolder.mcFolderSelected) || !Directory.Exists(ModFolder.mcFolderSelected)) { // 无效的文件夹 if (string.IsNullOrEmpty(ModFolder.mcFolderSelected)) - ModBase.Log("[Launch] 没有已储存的 Minecraft 文件夹"); + LauncherLog.Log("[Launch] 没有已储存的 Minecraft 文件夹"); else - ModBase.Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" + ModFolder.mcFolderSelected, - ModBase.LogLevel.Debug); + LauncherLog.Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" + ModFolder.mcFolderSelected, + LauncherLogLevel.Debug); ModFolder.mcFolderListLoader.WaitForExit(isForceRestart: true); - States.Game.SelectedFolder = ModFolder.mcFolderList[0].Location.Replace(ModBase.exePath, "$"); + States.Game.SelectedFolder = ModFolder.mcFolderList[0].Location.Replace(LauncherPaths.ExecutableDirectoryWithSlash, "$"); } - ModBase.Log("[Launch] Minecraft 文件夹:" + ModFolder.mcFolderSelected); + LauncherLog.Log("[Launch] Minecraft 文件夹:" + ModFolder.mcFolderSelected); if (Config.Debug.AddRandomDelay) Thread.Sleep(RandomUtils.NextInt(500, 3000)); // 自动整合包安装 @@ -129,25 +129,25 @@ public void PageLaunchLeft_Loaded(object sender, RoutedEventArgs e) try { var installLoader = ModModpack.ModpackInstall(packInstallPath); - ModBase.Log("[Launch] 自动安装整合包已开始:" + packInstallPath); + LauncherLog.Log("[Launch] 自动安装整合包已开始:" + packInstallPath); installLoader.WaitForExit(); - if (installLoader.State == ModBase.LoadState.Finished) + if (installLoader.State == LoadState.Finished) { - ModBase.Log("[Launch] 自动安装整合包成功,清理安装包:" + packInstallPath); + LauncherLog.Log("[Launch] 自动安装整合包成功,清理安装包:" + packInstallPath); if (File.Exists(packInstallPath)) File.Delete(packInstallPath); } } - catch (ModBase.CancelledException ex) + catch (CancelledException ex) { - ModBase.Log(ex, "自动安装整合包被用户取消:" + packInstallPath); + LauncherLog.Log(ex, "自动安装整合包被用户取消:" + packInstallPath); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.InstallPack", packInstallPath), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Select.Folder.Error.InstallPack", packInstallPath)); } @@ -158,9 +158,9 @@ public void PageLaunchLeft_Loaded(object sender, RoutedEventArgs e) !instance.Check()) { // 无效的实例 - ModBase.Log("[Launch] 当前选择的 Minecraft 实例无效:" + (instance is null ? "null" : instance.PathInstance), - instance is null ? ModBase.LogLevel.Normal : ModBase.LogLevel.Debug); - if (ModInstanceList.mcInstanceListLoader.State != ModBase.LoadState.Finished) + LauncherLog.Log("[Launch] 当前选择的 Minecraft 实例无效:" + (instance is null ? "null" : instance.PathInstance), + instance is null ? LauncherLogLevel.Normal : LauncherLogLevel.Debug); + if (ModInstanceList.mcInstanceListLoader.State != LoadState.Finished) ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\", true); if (ModInstanceList.mcInstanceList.Count == 0 || @@ -168,17 +168,17 @@ public void PageLaunchLeft_Loaded(object sender, RoutedEventArgs e) { instance = null; States.Game.SelectedInstance = ""; - ModBase.Log("[Launch] 无可用 Minecraft 实例"); + LauncherLog.Log("[Launch] 无可用 Minecraft 实例"); } else { instance = ModInstanceList.mcInstanceList.First().Value[0]; States.Game.SelectedInstance = instance.Name; - ModBase.Log("[Launch] 自动选择 Minecraft 实例:" + instance.PathInstance); + LauncherLog.Log("[Launch] 自动选择 Minecraft 实例:" + instance.PathInstance); } } - ModBase.RunInUi(() => + UiThread.Post(() => { ModInstanceList.McMcInstanceSelected = instance; // 绕这一圈是为了避免 McInstanceCheck 触发第二次实例改变 isLoadFinished = true; @@ -197,7 +197,7 @@ public void PageLaunchLeft_Loaded(object sender, RoutedEventArgs e) // 实例选择按钮 private void BtnInstance_Click(object sender, MouseButtonEventArgs e) { - if (ModLaunch.mcLaunchLoader.State == ModBase.LoadState.Loading) + if (ModLaunch.mcLaunchLoader.State == LoadState.Loading) return; ModMain.frmMain.PageChange(FormMain.PageType.InstanceSelect); } @@ -205,7 +205,7 @@ private void BtnInstance_Click(object sender, MouseButtonEventArgs e) // 启动按钮 public void LaunchButtonClick() { - if (ModLaunch.mcLaunchLoader.State == ModBase.LoadState.Loading || !BtnLaunch.IsEnabled || + if (ModLaunch.mcLaunchLoader.State == LoadState.Loading || !BtnLaunch.IsEnabled || (ModMain.frmMain.pageRight is not null && ModMain.frmMain.pageRight.PageState != MyPageRight.PageStates.ContentStay && ModMain.frmMain.pageRight.PageState != MyPageRight.PageStates.ContentEnter)) @@ -249,8 +249,8 @@ public void RefreshButtonsUI() return; // 获取当前状态 int currentState; - if (!isLoadFinished || ModInstanceList.mcInstanceListLoader.State == ModBase.LoadState.Loading || - ModFolder.mcFolderListLoader.State == ModBase.LoadState.Loading) + if (!isLoadFinished || ModInstanceList.mcInstanceListLoader.State == LoadState.Loading || + ModFolder.mcFolderListLoader.State == LoadState.Loading) { currentState = 0; } @@ -278,7 +278,7 @@ public void RefreshButtonsUI() case 0: { _launchButtonAction = LaunchButtonAction.Loading; - ModBase.Log("[Minecraft] 启动按钮:正在加载 Minecraft 实例"); + LauncherLog.Log("[Minecraft] 启动按钮:正在加载 Minecraft 实例"); ModMain.frmLaunchLeft.BtnLaunch.Text = Lang.Text("Launch.Home.Button.Loading"); ModMain.frmLaunchLeft.BtnLaunch.IsEnabled = false; ModMain.frmLaunchLeft.LabVersion.Text = Lang.Text("Launch.Home.Instance.Loading"); @@ -289,7 +289,7 @@ public void RefreshButtonsUI() case 1: { _launchButtonAction = LaunchButtonAction.Disabled; - ModBase.Log("[Minecraft] 启动按钮:无 Minecraft 实例,下载已禁用"); + LauncherLog.Log("[Minecraft] 启动按钮:无 Minecraft 实例,下载已禁用"); ModMain.frmLaunchLeft.BtnLaunch.Text = Lang.Text("Launch.Home.Button.Launch"); ModMain.frmLaunchLeft.BtnLaunch.IsEnabled = false; ModMain.frmLaunchLeft.LabVersion.Text = Lang.Text("Launch.Home.Instance.NotFound"); @@ -300,7 +300,7 @@ public void RefreshButtonsUI() case 2: { _launchButtonAction = LaunchButtonAction.Download; - ModBase.Log("[Minecraft] 启动按钮:无 Minecraft 实例,要求下载"); + LauncherLog.Log("[Minecraft] 启动按钮:无 Minecraft 实例,要求下载"); ModMain.frmLaunchLeft.BtnLaunch.Text = Lang.Text("Launch.Home.Button.Download"); ModMain.frmLaunchLeft.BtnLaunch.IsEnabled = true; ModMain.frmLaunchLeft.LabVersion.Text = Lang.Text("Launch.Home.Instance.NotFound"); @@ -311,7 +311,7 @@ public void RefreshButtonsUI() case 3: { _launchButtonAction = LaunchButtonAction.Launch; - ModBase.Log("[Minecraft] 启动按钮:Minecraft 实例:" + ModInstanceList.McMcInstanceSelected.PathInstance); + LauncherLog.Log("[Minecraft] 启动按钮:Minecraft 实例:" + ModInstanceList.McMcInstanceSelected.PathInstance); ModMain.frmLaunchLeft.BtnLaunch.Text = Lang.Text("Launch.Home.Button.Launch"); ModMain.frmLaunchLeft.BtnInstance.IsEnabled = true; if (ModProfile.selectedProfile is not null) @@ -351,10 +351,10 @@ private void BtnCancel_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Launch.Error.CancelProcess"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Minecraft.Launch.Error.CancelProcess")); } } @@ -363,7 +363,7 @@ private void BtnCancel_Click(object sender, MouseButtonEventArgs e) // 实例设置按钮 private void BtnMore_Click(object sender, MouseButtonEventArgs e) { - if (ModLaunch.mcLaunchLoader.State == ModBase.LoadState.Loading) + if (ModLaunch.mcLaunchLoader.State == LoadState.Loading) return; ModInstanceList.McMcInstanceSelected.Load(); PageInstanceLeft.McInstance = ModInstanceList.McMcInstanceSelected; @@ -383,7 +383,7 @@ public void LaunchingRefresh() { try { - if (ModLaunch.mcLaunchLoaderReal.State == ModBase.LoadState.Aborted) + if (ModLaunch.mcLaunchLoaderReal.State == LoadState.Aborted) return; // 阶段状态获取 var isLaunched = false; // 是否已经启动游戏,只是在等待窗口 @@ -393,7 +393,7 @@ public void LaunchingRefresh() { var exitTry = false; foreach (var Loader in ModLaunch.mcLaunchLoaderReal.GetLoaderList(false)) - if (Loader.State == ModBase.LoadState.Loading || Loader.State == ModBase.LoadState.Waiting) + if (Loader.State == LoadState.Loading || Loader.State == LoadState.Waiting) { LabLaunchingStage.Text = Loader.name; isLaunched = Loader.name == StageWaitWindow || Loader.name == StageEnd; @@ -406,7 +406,7 @@ public void LaunchingRefresh() } catch (Exception ex) { - ModBase.Log(ex, "获取是否启动完成失败,可能是由于启动状态改变导致集合已修改"); + LauncherLog.Log(ex, "获取是否启动完成失败,可能是由于启动状态改变导致集合已修改"); return; } } while (false); @@ -430,16 +430,16 @@ public void LaunchingRefresh() { foreach (var Loader in ModNet.NetManager.Tasks) if (Loader.RealParent is not null && Loader.RealParent.name == StageRoot && - Loader.State == ModBase.LoadState.Loading) + Loader.State == LoadState.Loading) hasLaunchDownloader = true; } catch (Exception ex) { - ModBase.Log(ex, "获取 Minecraft 启动下载器失败,可能是因为启动被取消"); + LauncherLog.Log(ex, "获取 Minecraft 启动下载器失败,可能是因为启动被取消"); hasLaunchDownloader = false; } - LabLaunchingDownload.Text = ModBase.GetString(ModNet.NetManager.Speed) + "/s"; + LabLaunchingDownload.Text = LauncherText.GetReadableFileSize(ModNet.NetManager.Speed) + "/s"; var shouldShowHint = Config.Preference.ShowLaunchingHint; // 进度改变动画 var animList = new List @@ -495,10 +495,10 @@ public void LaunchingRefresh() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Minecraft.Launch.Error.RefreshInfo"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Minecraft.Launch.Error.RefreshInfo")); } } @@ -589,7 +589,7 @@ public void PageChangeToLaunching() LabLaunchingDownload.Visibility = Visibility.Visible; LabLaunchingProgressLeft.Opacity = 0.6d; LabLaunchingDownload.Visibility = Visibility.Visible; - LabLaunchingDownload.Text = ModBase.GetString(0) + "/s"; + LabLaunchingDownload.Text = LauncherText.GetReadableFileSize(0) + "/s"; LabLaunchingDownload.Opacity = 0d; LabLaunchingDownload.Visibility = Visibility.Collapsed; LabLaunchingDownloadLeft.Opacity = 0d; @@ -771,11 +771,11 @@ private object PageChange(PageType type, bool anim) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, - Lang.Text("Launch.Account.Error.SwitchPage", ModBase.GetStringFromEnum(type)), - ModBase.LogLevel.Feedback, - userSummary: Lang.Text("Launch.Account.Error.SwitchPage", ModBase.GetStringFromEnum(type))); + Lang.Text("Launch.Account.Error.SwitchPage", LauncherText.GetStringFromEnum(type)), + LauncherLogLevel.Feedback, + userSummary: Lang.Text("Launch.Account.Error.SwitchPage", LauncherText.GetStringFromEnum(type))); return pageNew; } } @@ -820,21 +820,21 @@ public void RefreshPage(bool anim, ModLaunch.McLoginType targetLoginType = defau #region 皮肤 // 正版皮肤 - public static ModLoader.LoaderTask, string> skinMs = new("Loader Skin Ms", SkinMsLoad, + public static ModLoader.LoaderTask, string> skinMs = new("Loader Skin Ms", SkinMsLoad, SkinMsInput, ThreadPriority.AboveNormal); - private static ModBase.EqualableList SkinMsInput() + private static EqualableList SkinMsInput() { // 获取名称 - return new ModBase.EqualableList + return new EqualableList { ModProfile.selectedProfile.Username, ModProfile.selectedProfile.Uuid }; } - private static void SkinMsLoad(ModLoader.LoaderTask, string> data) + private static void SkinMsLoad(ModLoader.LoaderTask, string> data) { // 清空已有皮肤 // 如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载 - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.frmLoginProfileSkin is not null && ModMain.frmLoginProfileSkin.Skin is not null) ModMain.frmLoginProfileSkin.Skin.Clear(); @@ -850,9 +850,9 @@ private static void SkinMsLoad(ModLoader.LoaderTask, string> skinLegacy = new("Loader Skin Legacy", + public static ModLoader.LoaderTask, string> skinLegacy = new("Loader Skin Legacy", SkinLegacyLoad, SkinLegacyInput, ThreadPriority.AboveNormal); - private static ModBase.EqualableList SkinLegacyInput() + private static EqualableList SkinLegacyInput() { - return new ModBase.EqualableList + return new EqualableList { ModProfile.selectedProfile.Username, ModProfile.selectedProfile.Uuid }; } - private static void SkinLegacyLoad(ModLoader.LoaderTask, string> data) + private static void SkinLegacyLoad(ModLoader.LoaderTask, string> data) { // 清空已有皮肤 - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.frmLoginProfileSkin is not null && ModMain.frmLoginProfileSkin.Skin is not null) ModMain.frmLoginProfileSkin.Skin.Clear(); }); - data.output = ModBase.pathImage + "Skins/" + ModSkin.McSkinSex(data.input[1]) + ".png"; + data.output = LauncherPaths.ImageBaseUri + "Skins/" + ModSkin.McSkinSex(data.input[1]) + ".png"; // 刷新显示 if (ModMain.frmLoginProfileSkin is not null && ReferenceEquals(ModMain.frmLoginProfileSkin.Skin.loader, data)) - ModBase.RunInUi(() => ModMain.frmLoginProfileSkin.Skin.Load()); + UiThread.Post(() => ModMain.frmLoginProfileSkin.Skin.Load()); else if (!data.IsAborted) // 如果已经中断,Input 也被清空,就不会再次刷新 data.input = null; // 清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染 } // Authlib-Injector 皮肤 - public static ModLoader.LoaderTask, string> skinAuth = new("Loader Skin Auth", + public static ModLoader.LoaderTask, string> skinAuth = new("Loader Skin Auth", SkinAuthLoad, SkinAuthInput, ThreadPriority.AboveNormal); - private static ModBase.EqualableList SkinAuthInput() + private static EqualableList SkinAuthInput() { // 获取名称 - return new ModBase.EqualableList + return new EqualableList { ModProfile.selectedProfile.Username, ModProfile.selectedProfile.Uuid }; } - private static void SkinAuthLoad(ModLoader.LoaderTask, string> data) + private static void SkinAuthLoad(ModLoader.LoaderTask, string> data) { // 清空已有皮肤 // 如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载 - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.frmLoginProfileSkin is not null && ModMain.frmLoginProfileSkin.Skin is not null) ModMain.frmLoginProfileSkin.Skin.Clear(); @@ -962,8 +962,8 @@ private static void SkinAuthLoad(ModLoader.LoaderTask, string>> skinLoaders = new() + public static List, string>> skinLoaders = new() { skinMs, skinLegacy, skinAuth }; #endregion diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs index 78ecfc571..a2a0df753 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs @@ -33,7 +33,7 @@ private void Init() { PanBack.ScrollToHome(); PanScroll = PanBack; // 不知道为啥不能在 XAML 设置 - PanLog.Visibility = ModBase.ModeDebug ? Visibility.Visible : Visibility.Collapsed; + PanLog.Visibility = LauncherRuntime.ModeDebug ? Visibility.Visible : Visibility.Collapsed; // 社区版提示 PanHint.Visibility = States.Hint.CEMessage ? Visibility.Visible @@ -68,7 +68,7 @@ private void BtnHintClose_Click(object sender, EventArgs e) /// private void Refresh() { - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -79,15 +79,15 @@ private void Refresh() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "加载 PCL 主页自定义信息失败", - ModBase.ModeDebug - ? ModBase.LogLevel.Msgbox - : ModBase.LogLevel.Hint, + LauncherRuntime.ModeDebug + ? LauncherLogLevel.Msgbox + : LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Error.OperationFailed")); } - }, $"刷新主页 #{ModBase.GetUuid()}"); + }, $"刷新主页 #{LauncherRuntime.GetUuid()}"); } private void RefreshReal() @@ -101,7 +101,7 @@ private void RefreshReal() { // 本地文件 LogWrapper.Info("[Page] 主页自定义数据来源:本地文件"); - content = ModBase.ReadFile(Path.Combine(ModBase.exePath, "PCL", "Custom.xaml")); + content = LegacyFileFacade.ReadText(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Custom.xaml")); } else if (uiCustomType == 2) { @@ -222,7 +222,7 @@ private void RefreshReal() } } - ModBase.RunInUi(() => LoadContent(content)); + UiThread.Post(() => LoadContent(content)); } /// @@ -232,7 +232,7 @@ private string LoadFromNetwork(string url) { if (string.IsNullOrWhiteSpace(url)) return ""; - var cachePath = Path.Combine(ModBase.pathTemp, "Cache", "Custom.xaml"); + var cachePath = Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Custom.xaml"); var cachedUrl = (string)States.UI.SavedHomepageUrl; if (url == cachedUrl && File.Exists(cachePath)) @@ -240,12 +240,12 @@ private string LoadFromNetwork(string url) LogWrapper.Info("[Page] 主页自定义数据来源:联网缓存文件"); // 后台更新缓存 onlineLoader.Start(url); - return ModBase.ReadFile(cachePath); + return LegacyFileFacade.ReadText(cachePath); } LogWrapper.Info("[Page] 主页自定义数据来源:联网全新下载"); HintWrapper.Show(Lang.Text("Launch.Homepage.Loading")); - ModBase.RunInUiWait(() => LoadContent("")); // 先清空页面 + UiThread.Invoke(() => LoadContent("")); // 先清空页面 States.UI.SavedHomepageVersion = ""; onlineLoader.Start(url); // 下载完成后将会再次触发更新 return ""; @@ -270,9 +270,9 @@ public static string GetRandomHint(bool enableLengthLimit = false, bool raw = fa } catch { - ModBase.Log( + LauncherLog.Log( Lang.Text("Launch.Homepage.Error.ExternalFile", externalPath), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Homepage.Error.ExternalFile", externalPath)); } } @@ -353,41 +353,41 @@ private void OnlineLoaderSub(ModLoader.LoaderTask task) if (!string.IsNullOrEmpty(version) && !string.IsNullOrEmpty(currentVersion) && (version ?? "") == (currentVersion ?? "")) { - ModBase.Log($"[Page] 当前缓存的主页已为最新,当前版本:{version},检查源:{versionAddress}"); + LauncherLog.Log($"[Page] 当前缓存的主页已为最新,当前版本:{version},检查源:{versionAddress}"); needDownload = false; } else { - ModBase.Log($"[Page] 需要下载联网主页,当前版本:{version},检查源:{versionAddress}"); + LauncherLog.Log($"[Page] 需要下载联网主页,当前版本:{version},检查源:{versionAddress}"); } } catch (Exception exx) { - ModBase.Log(exx, "联网获取主页版本失败", ModBase.LogLevel.Developer); - ModBase.Log($"[Page] 无法检查联网主页版本,将直接下载,检查源:{versionAddress}"); + LauncherLog.Log(exx, "联网获取主页版本失败", LauncherLogLevel.Developer); + LauncherLog.Log($"[Page] 无法检查联网主页版本,将直接下载,检查源:{versionAddress}"); } // 实际下载 if (needDownload) { var fileContent = Requester.FetchString(address); - ModBase.Log($"[Page] 已联网下载主页,内容长度:{fileContent.Length},来源:{address}"); + LauncherLog.Log($"[Page] 已联网下载主页,内容长度:{fileContent.Length},来源:{address}"); States.UI.SavedHomepageUrl = address; States.UI.SavedHomepageVersion = version; - ModBase.WriteFile(ModBase.pathTemp + @"Cache\Custom.xaml", fileContent); + LegacyFileFacade.WriteFile(LauncherPaths.TempWithSlash + @"Cache\Custom.xaml", fileContent); } // 要求刷新 - ModBase.RunInUi(Refresh); // 不直接调用 Refresh,以防止死循环(#6245) + UiThread.Post(Refresh); // 不直接调用 Refresh,以防止死循环(#6245) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Homepage.Error.Download", address), - ModBase.ModeDebug - ? ModBase.LogLevel.Msgbox - : ModBase.LogLevel.Hint, + LauncherRuntime.ModeDebug + ? LauncherLogLevel.Msgbox + : LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Homepage.Error.Download", address)); } } @@ -398,7 +398,7 @@ private void OnlineLoaderSub(ModLoader.LoaderTask task) /// public void ForceRefresh() { - ModBase.Log("[Page] 要求强制刷新主页"); + LauncherLog.Log("[Page] 要求强制刷新主页"); ClearCache(); // 实际的刷新 if (ModMain.frmMain.pageCurrent.page == FormMain.PageType.Launch) @@ -426,7 +426,7 @@ private void ClearCache() onlineLoader.input = ""; States.UI.SavedHomepageUrl = ""; States.UI.SavedHomepageVersion = ""; - ModBase.Log("[Page] 已清空主页缓存"); + LauncherLog.Log("[Page] 已清空主页缓存"); } /// @@ -449,7 +449,7 @@ private void LoadContent(string content) PanCustom.Children.Clear(); if (string.IsNullOrWhiteSpace(content)) { - ModBase.Log("[Page] 实例化:清空主页 UI,来源为空"); + LauncherLog.Log("[Page] 实例化:清空主页 UI,来源为空"); return; } @@ -461,16 +461,16 @@ private void LoadContent(string content) content = content.RegexReplace("xmlns[^\"']*(\"|')[^\"']*(\"|')", "").Replace("xmlns", ""); content = $"{content}"; - ModBase.Log($"[Page] 实例化:加载主页 UI 开始,最终内容长度:{content.Count()}"); - PanCustom.Children.Add((UIElement)ModBase.GetObjectFromXML(content, out var sanitizeResult)); + LauncherLog.Log($"[Page] 实例化:加载主页 UI 开始,最终内容长度:{content.Count()}"); + PanCustom.Children.Add((UIElement)CustomXamlLoader.Load(content, out var sanitizeResult)); _ShowSanitizeHints(sanitizeResult); _ApplyHomepageLivePatchesFromFile(); } catch (Exception ex) { - if (ModBase.ModeDebug) + if (LauncherRuntime.ModeDebug) { - ModBase.Log(ex, $"加载失败的主页内容:\r\n{content}"); + LauncherLog.Log(ex, $"加载失败的主页内容:\r\n{content}"); if (ModMain.MyMsgBox( ex is UnauthorizedAccessException ? ex.Message @@ -482,10 +482,10 @@ ex is UnauthorizedAccessException } else { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Homepage.LoadFailed.Title"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Launch.Homepage.LoadFailed.Title")); } @@ -493,7 +493,7 @@ ex is UnauthorizedAccessException } var loadCostTime = (DateTime.Now - loadStartTime).Milliseconds; - ModBase.Log($"[Page] 实例化:加载主页 UI 完成,耗时 {loadCostTime}ms"); + LauncherLog.Log($"[Page] 实例化:加载主页 UI 完成,耗时 {loadCostTime}ms"); if (loadCostTime > 3000) HintService.Hint(Lang.Text("Launch.Homepage.SlowWarning", Lang.Number(Math.Round(loadCostTime / 1000d, 1), "N1"))); } @@ -554,7 +554,7 @@ private void _EnsureHomepageLiveWatcher() } catch (Exception ex) { - ModBase.Log(ex, "[Page] Failed to start custom homepage live patch watcher", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "[Page] Failed to start custom homepage live patch watcher", LauncherLogLevel.Developer); } } @@ -566,7 +566,7 @@ private void _DisposeHomepageLiveWatcher() } catch (Exception ex) { - ModBase.Log(ex, "[Page] Failed to dispose custom homepage live patch watcher", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "[Page] Failed to dispose custom homepage live patch watcher", LauncherLogLevel.Developer); } _homepageLiveWatcher = null; @@ -582,7 +582,7 @@ private void _DisposeHomepageLiveWatcher() } catch (Exception ex) { - ModBase.Log(ex, "[Page] Failed to dispose custom homepage live patch debounce timer", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "[Page] Failed to dispose custom homepage live patch debounce timer", LauncherLogLevel.Developer); } _DeleteHomepageLiveSupportMarker(); @@ -590,7 +590,7 @@ private void _DisposeHomepageLiveWatcher() private void _QueueHomepageLivePatchApply() { - ModBase.RunInUi(() => + UiThread.Post(() => { _homepageLivePatchTimer ??= new DispatcherTimer { @@ -628,7 +628,7 @@ private void _ApplyHomepageLivePatchesFromFile() } catch (Exception ex) { - ModBase.Log(ex, "[Page] Failed to apply custom homepage live patches", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "[Page] Failed to apply custom homepage live patches", LauncherLogLevel.Developer); } } @@ -655,7 +655,7 @@ private static string _ReadHomepageLivePatchFile(string file) private static string _GetHomepageLiveDirectory() { - return Path.Combine(ModBase.exePath, "PCL"); + return Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL"); } private static void _WriteHomepageLiveSupportMarker(string directory) @@ -673,7 +673,7 @@ private static void _WriteHomepageLiveSupportMarker(string directory) } catch (Exception ex) { - ModBase.Log(ex, "[Page] Failed to write custom homepage live patch support marker", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "[Page] Failed to write custom homepage live patch support marker", LauncherLogLevel.Developer); } } @@ -693,7 +693,7 @@ private static void _DeleteHomepageLiveSupportMarker() } catch (Exception ex) { - ModBase.Log(ex, "[Page] Failed to delete custom homepage live patch support marker", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, "[Page] Failed to delete custom homepage live patch support marker", LauncherLogLevel.Developer); } } @@ -773,7 +773,7 @@ private static bool _TrySetElementProperty(FrameworkElement element, string prop { if (!_homepageLiveAllowedProperties.TryGetValue(propertyName, out var allowedPropertyName)) { - ModBase.Log($"[Page] Skipped unsupported live patch property {propertyName}", ModBase.LogLevel.Developer); + LauncherLog.Log($"[Page] Skipped unsupported live patch property {propertyName}", LauncherLogLevel.Developer); return false; } @@ -812,7 +812,7 @@ private static bool _TrySetElementProperty(FrameworkElement element, string prop } catch (Exception ex) { - ModBase.Log(ex, $"[Page] Failed to set live patch property {propertyName}", ModBase.LogLevel.Developer); + LauncherLog.Log(ex, $"[Page] Failed to set live patch property {propertyName}", LauncherLogLevel.Developer); return false; } } @@ -826,7 +826,7 @@ private static void _ReplacePanelChildren(Panel panel, string childrenXaml) var wrapped = $"{content}"; - if (ModBase.GetObjectFromXML(wrapped) is not Panel parsedPanel) return; + if (CustomXamlLoader.Load(wrapped) is not Panel parsedPanel) return; var children = parsedPanel.Children.OfType().ToList(); parsedPanel.Children.Clear(); diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.cs index dfb660ab2..a276805d4 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.cs @@ -82,7 +82,7 @@ private void BtnLogin_Click(object sender, EventArgs e) { ModProfile.isCreatingProfile = true; ModLaunch.mcLoginAuthLoader.Start(loginData, true); - while (ModLaunch.mcLoginAuthLoader.State == ModBase.LoadState.Loading) + while (ModLaunch.mcLoginAuthLoader.State == LoadState.Loading) { BtnLogin.Text = Lang.Number(ModLaunch.mcLoginAuthLoader.Progress, "P0"); await Task.Delay(50); @@ -90,15 +90,15 @@ private void BtnLogin_Click(object sender, EventArgs e) switch (ModLaunch.mcLoginAuthLoader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: ModMain.frmLaunchLeft.RefreshPage(true); break; - case ModBase.LoadState.Aborted: + case LoadState.Aborted: HintService.Hint(Lang.Text("Launch.Account.Auth.Cancelled")); break; - case ModBase.LoadState.Waiting: - case ModBase.LoadState.Loading: - case ModBase.LoadState.Failed: + case LoadState.Waiting: + case LoadState.Loading: + case LoadState.Failed: default: { if (ModLaunch.mcLoginAuthLoader.Error is null) @@ -121,10 +121,10 @@ private void BtnLogin_Click(object sender, EventArgs e) } else { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.Auth.LoginFailed"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Launch.Account.Auth.LoginFailed")); } } @@ -157,11 +157,11 @@ private void GetServerName() serverUri = await ApiLocation.TryRequestAsync(serverUriInput); using var resp = await HttpRequest.Create(serverUri).SendAsync(); var responseText = await resp.AsStringAsync(); - serverName = await Task.Run(() => ModBase.GetJson(responseText)["meta"]?["serverName"]?.ToString()); + serverName = await Task.Run(() => PCL.Core.Utils.JsonCompat.ParseNode(responseText)["meta"]?["serverName"]?.ToString()); } catch (Exception ex) { - ModBase.Log(ex, "从服务器获取名称失败"); + LauncherLog.Log(ex, "从服务器获取名称失败"); } if (serverUri is not null) TextServer.Text = serverUri; @@ -188,7 +188,7 @@ private void ComboName_TextChanged(object sender, TextChangedEventArgs e) private void Btn_Click(object sender, EventArgs e) { - ModBase.OpenWebsite(_isRegisterMode + LauncherProcess.OpenWebsite(_isRegisterMode ? Config.InstanceAuth.AuthRegisterAddress.ToString() : Config.InstanceAuth.AuthRegisterAddress.ToString().Replace("/auth/register", "/auth/forgot")); } diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.cs index cddc2f917..0c5600214 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.cs @@ -16,7 +16,7 @@ public PageLoginMs() private void BtnBack_Click(object sender, EventArgs e) { - ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true)); + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(true)); } private void BtnLogin_Click(object sender, EventArgs e) @@ -24,21 +24,21 @@ private void BtnLogin_Click(object sender, EventArgs e) BtnLogin.IsEnabled = false; BtnBack.Visibility = Visibility.Collapsed; BtnLogin.Text = Lang.Number(0d, "P0"); - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { ModProfile.selectedProfile = null; ModLaunch.mcLoginMsLoader.Start(ModProfile.GetLoginData(ModLaunch.McLoginType.Ms), true); - while (ModLaunch.mcLoginMsLoader.State == ModBase.LoadState.Loading) + while (ModLaunch.mcLoginMsLoader.State == LoadState.Loading) { - ModBase.RunInUi(() => BtnLogin.Text = Lang.Number(ModLaunch.mcLoginMsLoader.Progress, "P0")); + UiThread.Post(() => BtnLogin.Text = Lang.Number(ModLaunch.mcLoginMsLoader.Progress, "P0")); Thread.Sleep(50); } - if (ModLaunch.mcLoginMsLoader.State == ModBase.LoadState.Finished) - ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true)); - else if (ModLaunch.mcLoginMsLoader.State == ModBase.LoadState.Aborted) + if (ModLaunch.mcLoginMsLoader.State == LoadState.Finished) + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(true)); + else if (ModLaunch.mcLoginMsLoader.State == LoadState.Aborted) throw new ThreadInterruptedException(); else if (ModLaunch.mcLoginMsLoader.Error is null) throw new Exception(Lang.Text("Launch.Account.Microsoft.Error.Unknown")); @@ -62,24 +62,24 @@ private void BtnLogin_Click(object sender, EventArgs e) } else if (ex is AuthenticationException && ex.Message.ContainsF("SSL/TLS")) { - ModBase.Log( + LauncherLog.Log( ex, $"{Lang.Text("Launch.Account.Microsoft.LoginFailed.Message")}\r\n{ex.Message}", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Launch.Account.Microsoft.Error.OperationFailed")); } else { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.Microsoft.LoginFailed.Title"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Launch.Account.Microsoft.LoginFailed.Title")); } } finally { - ModBase.RunInUi(() => + UiThread.Post(() => { BtnLogin.IsEnabled = true; BtnBack.Visibility = Visibility.Visible; diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginOffline.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginOffline.xaml.cs index 69f07c7d8..73f98282e 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginOffline.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginOffline.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using PCL.Core.Utils.Validate; using PCL.Core.App.Localization; @@ -19,10 +19,10 @@ public PageLoginOffline() private void BtnBack_Click(object sender, EventArgs e) { - ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true)); + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(true)); } - private void RadioUuid_Checked(object sender, ModBase.RouteEventArgs e) + private void RadioUuid_Checked(object sender, RouteEventArgs e) { if (RadioUuidCustom.Checked) { @@ -83,6 +83,6 @@ private void BtnLogin_Click(object sender, EventArgs e) ModProfile.selectedProfile = newProfile; ModProfile.isCreatingProfile = false; HintService.Hint(Lang.Text("Launch.Account.Profile.Created"), HintType.Success); - ModBase.RunInUi(() => ModMain.frmLaunchLeft.RefreshPage(true)); + UiThread.Post(() => ModMain.frmLaunchLeft.RefreshPage(true)); } } diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginProfile.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginProfile.xaml.cs index 424833422..0ef09a4b7 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginProfile.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginProfile.xaml.cs @@ -38,21 +38,21 @@ public void Reload() /// public void RefreshProfileList() { - ModBase.Log("[Profile] 刷新档案列表"); + LauncherLog.Log("[Profile] 刷新档案列表"); ProfileCollection.Clear(); ModProfile.GetProfile(); try { foreach (var Profile in ModProfile.profileList) ProfileCollection.Add(new ProfileItem(Profile)); - ModBase.Log("[Profile] 档案列表刷新完成"); + LauncherLog.Log("[Profile] 档案列表刷新完成"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Launch.Account.Profile.Error.Read"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Launch.Account.Profile.Error.Read")); } @@ -73,7 +73,7 @@ public ProfileItem(ModProfile.McProfile profile) { Profile = profile; Info = (string)ModProfile.GetProfileInfo(profile); - var logoPath = ModBase.pathTemp + $@"Cache\Skin\Head\{profile.SkinHeadId}.png"; + var logoPath = LauncherPaths.TempWithSlash + $@"Cache\Skin\Head\{profile.SkinHeadId}.png"; if (File.Exists(logoPath) && new FileInfo(logoPath).Length != 0L) { Logo = logoPath; @@ -100,17 +100,17 @@ private void SelectProfile(object sender, MouseButtonEventArgs e) var item = (MyListItem)sender; var tag = (ModProfile.McProfile)item.Tag; ModProfile.selectedProfile = (ModProfile.McProfile)((MyListItem)sender).Tag; - ModBase.Log($"[Profile] 选定档案: {tag.Username}, 以 {tag.Type} 方式验证"); + LauncherLog.Log($"[Profile] 选定档案: {tag.Username}, 以 {tag.Type} 方式验证"); ModProfile.lastUsedProfile = ModProfile.profileList.IndexOf((ModProfile.McProfile)((MyListItem)sender).Tag); // 获取当前档案的序号 ModProfile.SaveProfile(); // 保存档案配置,确保切换后的档案被正确保存 // 清除登录验证缓存,确保使用新档案的验证信息 - ModLaunch.mcLoginMsLoader.State = ModBase.LoadState.Waiting; - ModLaunch.mcLoginAuthLoader.State = ModBase.LoadState.Waiting; - ModLaunch.mcLoginLegacyLoader.State = ModBase.LoadState.Waiting; + ModLaunch.mcLoginMsLoader.State = LoadState.Waiting; + ModLaunch.mcLoginAuthLoader.State = LoadState.Waiting; + ModLaunch.mcLoginLegacyLoader.State = LoadState.Waiting; - ModBase.RunInUi(() => + UiThread.Post(() => { ModMain.frmLaunchLeft.RefreshPage(true); ModMain.frmLaunchLeft.BtnLaunch.IsEnabled = true; @@ -156,10 +156,10 @@ private void ProfileContMenuBuild(MyListItem sender, EventArgs e) // 创建档案 private void BtnNew_Click(object sender, EventArgs e) { - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { ModProfile.CreateProfile(); - ModBase.RunInUi(() => RefreshProfileList()); + UiThread.Post(() => RefreshProfileList()); }); } @@ -171,7 +171,7 @@ private void EditProfileUuid(object sender, EventArgs e) private void CopyProfileUuid(object sender, EventArgs e) { - if (sender is MyIconButton { Tag: ModProfile.McProfile profile }) ModBase.ClipboardSet(profile.Uuid); + if (sender is MyIconButton { Tag: ModProfile.McProfile profile }) LauncherProcess.ClipboardSet(profile.Uuid); } // 编辑验证服务器名称 @@ -189,7 +189,7 @@ private void DeleteProfile(object sender, EventArgs e) forceWait: true) == 2) return; ModProfile.RemoveProfile((ModProfile.McProfile)((MyIconButton)sender).Tag); - ModBase.RunInUi(() => RefreshProfileList()); + UiThread.Post(() => RefreshProfileList()); } diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginProfileSkin.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginProfileSkin.xaml.cs index a3a40608a..f67ceaa38 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginProfileSkin.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginProfileSkin.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Input; using PCL.Core.App.Localization; @@ -23,24 +23,24 @@ public PageLoginProfileSkin() /// public void Reload() { - ModBase.Log("[Profile] 刷新档案界面"); + LauncherLog.Log("[Profile] 刷新档案界面"); Skin.Clear(); if (ModProfile.selectedProfile.Type == ModLaunch.McLoginType.Ms) { BtnEdit.Visibility = Visibility.Visible; - ModBase.Log("[Profile] 使用正版皮肤加载器"); + LauncherLog.Log("[Profile] 使用正版皮肤加载器"); Skin.loader = PageLaunchLeft.skinMs; } else if (ModProfile.selectedProfile.Type == ModLaunch.McLoginType.Auth) { BtnEdit.Visibility = Visibility.Visible; - ModBase.Log("[Profile] 使用 Authlib 皮肤加载器"); + LauncherLog.Log("[Profile] 使用 Authlib 皮肤加载器"); Skin.loader = PageLaunchLeft.skinAuth; } else { BtnEdit.Visibility = Visibility.Collapsed; - ModBase.Log("[Profile] 使用离线皮肤加载器"); + LauncherLog.Log("[Profile] 使用离线皮肤加载器"); Skin.loader = PageLaunchLeft.skinLegacy; } @@ -88,12 +88,12 @@ private void BtnEditPassword_Click(object sender, RoutedEventArgs e) { if (ModProfile.selectedProfile.Type == ModLaunch.McLoginType.Ms) { - ModBase.OpenWebsite("https://account.live.com/password/Change"); + LauncherProcess.OpenWebsite("https://account.live.com/password/Change"); } else if (ModProfile.selectedProfile.Type == ModLaunch.McLoginType.Auth) { var server = ModProfile.selectedProfile.Server; - ModBase.OpenWebsite(server.Replace("/api/yggdrasil/authserver" + (server.EndsWithF("/") ? "/" : ""), + LauncherProcess.OpenWebsite(server.Replace("/api/yggdrasil/authserver" + (server.EndsWithF("/") ? "/" : ""), "/user/profile")); } else @@ -112,7 +112,7 @@ private void BtnEditName_Click(object sender, RoutedEventArgs e) private void ChangeProfile(object sender, EventArgs e) { ModProfile.selectedProfile = null; - ModBase.RunInUi(() => + UiThread.Post(() => { ModMain.frmLaunchLeft.RefreshPage(true); ModMain.frmLaunchLeft.BtnLaunch.IsEnabled = false; @@ -125,7 +125,7 @@ private void Skin_Click(object sender, RoutedEventArgs e) if (ModProfile.selectedProfile.Type == ModLaunch.McLoginType.Ms) ModProfile.ChangeSkinMs(); else if (ModProfile.selectedProfile.Type == ModLaunch.McLoginType.Auth) - ModBase.OpenWebsite(ModProfile.selectedProfile.Server.BeforeFirst("api/yggdrasil/authserver") + + LauncherProcess.OpenWebsite(ModProfile.selectedProfile.Server.BeforeFirst("api/yggdrasil/authserver") + "user/closet"); else HintService.Hint(Lang.Text("Launch.Account.ProfileSkin.SkinUnsupported")); @@ -149,7 +149,7 @@ private void BtnSkinCape_Click(object sender, RoutedEventArgs e) if (ModProfile.selectedProfile.Type == ModLaunch.McLoginType.Ms) Skin.BtnSkinCape_Click(sender, e); else if (ModProfile.selectedProfile.Type == ModLaunch.McLoginType.Auth) - ModBase.OpenWebsite(ModProfile.selectedProfile.Server.BeforeFirst("api/yggdrasil/authserver") + + LauncherProcess.OpenWebsite(ModProfile.selectedProfile.Server.BeforeFirst("api/yggdrasil/authserver") + "user/closet"); else HintService.Hint(Lang.Text("Launch.Account.ProfileSkin.CapeUnsupported")); diff --git a/Plain Craft Launcher 2/Pages/PageLogLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageLogLeft.xaml.cs index e73fea7f8..fd37cedf0 100644 --- a/Plain Craft Launcher 2/Pages/PageLogLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLogLeft.xaml.cs @@ -84,10 +84,10 @@ private void Reload() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "构建游戏实时日志 UI 出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("LogPage.Error.OperationFailed")); } } @@ -103,7 +103,7 @@ private void OnLogOutput(ModWatcher.Watcher sender, ModWatcher.LogOutputEventArg margin = new Thickness(0d, 12d, 0d, 0d); else margin = new Thickness(0d); - ModBase.RunInUi(() => + UiThread.Post(() => { var paragraph = new Paragraph(new Run(e.logText)) { Foreground = e.color, Margin = margin }; flowDocuments[uuid].Blocks.Add(paragraph); @@ -141,10 +141,10 @@ private void OnLogOutput(ModWatcher.Watcher sender, ModWatcher.LogOutputEventArg public void Add(ModWatcher.Watcher watcher) { - var uuid = ModBase.GetUuid(); + var uuid = LauncherRuntime.GetUuid(); shownLogs.Add(new KeyValuePair(uuid, watcher)); watcher.LogOutput += OnLogOutput; - ModBase.RunInUi(() => flowDocuments.Add(uuid, new FlowDocument())); // TODO:在 UI 线程创建 + UiThread.Post(() => flowDocuments.Add(uuid, new FlowDocument())); // TODO:在 UI 线程创建 SelectionChange(uuid); ModMain.frmMain.BtnExtraLog.ShowRefresh(); } @@ -170,7 +170,7 @@ public void SelectionChange(int uuid) } } - ModBase.RunInUi(() => + UiThread.Post(() => { ModMain.frmLogRight.Reload(); Reload(); @@ -195,7 +195,7 @@ public void RemoveItem(int uuid) } else { - ModBase.RunInUi(() => + UiThread.Post(() => { ModMain.frmLogRight.Reload(); Reload(); @@ -214,7 +214,7 @@ public void Remove_Click(object sender, RoutedEventArgs e) } // 点击选项 - public void Version_Change(object sender, ModBase.RouteEventArgs e) + public void Version_Change(object sender, RouteEventArgs e) { SelectionChange((int)((MyListItem)sender).Tag); } diff --git a/Plain Craft Launcher 2/Pages/PageLogRight.xaml.cs b/Plain Craft Launcher 2/Pages/PageLogRight.xaml.cs index 0925fce9d..867f4e3a0 100644 --- a/Plain Craft Launcher 2/Pages/PageLogRight.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLogRight.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Windows; using System.Windows.Documents; using System.Windows.Media; @@ -111,7 +111,7 @@ private void RefreshLabText() private void OnLogOutput(ModWatcher.Watcher sender, ModWatcher.LogOutputEventArgs e) { - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.frmLogLeft.currentLog is not null) { @@ -136,12 +136,12 @@ private void SliderMaxLog_ValueChanged(object o, bool user) #region 卡片按钮 - private void BtnOperationClear_Click(object sender, ModBase.RouteEventArgs e) + private void BtnOperationClear_Click(object sender, RouteEventArgs e) { ModMain.frmLogLeft.flowDocuments[ModMain.frmLogLeft.currentUuid].Blocks.Clear(); } - private void BtnOperationExport_Click(object sender, ModBase.RouteEventArgs e) + private void BtnOperationExport_Click(object sender, RouteEventArgs e) { var savePath = SystemDialogs.SelectSaveFile(Lang.Text("LogPage.Export.SelectLocation"), Lang.Text("LogPage.Export.GameLog.FileName", ModMain.frmLogLeft.currentLog.version.Name), @@ -150,10 +150,10 @@ private void BtnOperationExport_Click(object sender, ModBase.RouteEventArgs e) return; File.WriteAllLines(savePath, ModMain.frmLogLeft.currentLog.fullLog); HintService.Hint(Lang.Text("LogPage.Export.Success"), HintType.Success); - ModBase.OpenExplorer(savePath); + LauncherProcess.OpenExplorer(savePath); } - private void BtnOperationKill_Click(object sender, ModBase.RouteEventArgs e) + private void BtnOperationKill_Click(object sender, RouteEventArgs e) { if (ModMain.frmLogLeft.currentLog.State <= ModWatcher.Watcher.MinecraftState.Running) { @@ -163,7 +163,7 @@ private void BtnOperationKill_Click(object sender, ModBase.RouteEventArgs e) } } - private void BtnOperationExportStackDump_Click(object sender, ModBase.RouteEventArgs e) + private void BtnOperationExportStackDump_Click(object sender, RouteEventArgs e) { var formattedDate = DateTime.Now.ToString("G", CultureInfo.InvariantCulture) .Replace("/", "-") @@ -176,23 +176,23 @@ private void BtnOperationExportStackDump_Click(object sender, ModBase.RouteEvent return; HintService.Hint(Lang.Text("LogPage.ExportStack.Progress")); BtnOperationExportStackDump.IsEnabled = false; - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { var dump = ModMain.frmLogLeft.currentLog.ExportStackDump(savePath); File.WriteAllLines(savePath, dump); - ModBase.RunInUi(() => + UiThread.Post(() => { HintService.Hint(Lang.Text("LogPage.ExportStack.Success"), HintType.Success); BtnOperationExportStackDump.IsEnabled = true; }); - ModBase.OpenExplorer(savePath); + LauncherProcess.OpenExplorer(savePath); }); } private void OnGameExit() { - ModBase.RunInUi(() => BtnOperationKill.IsEnabled = false); - ModBase.RunInUi(() => BtnOperationExportStackDump.IsEnabled = false); + UiThread.Post(() => BtnOperationKill.IsEnabled = false); + UiThread.Post(() => BtnOperationExportStackDump.IsEnabled = false); } #endregion diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.cs index 1a0c22460..bbdf50a44 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.cs @@ -33,7 +33,7 @@ private void PageSelectLeft_Initialized(object sender, EventArgs e) { ModFolder.mcFolderListLoader.PreviewFinish += _ => { - if (ModMain.frmSelectLeft is not null) ModBase.RunInUiWait(McFolderListUI); + if (ModMain.frmSelectLeft is not null) UiThread.Invoke(McFolderListUI); }; } @@ -113,7 +113,7 @@ void AddMenuItem(string name, string header, string svgIcon = null, Thickness? p ModMain.frmSelectLeft.Refresh_Click); AddMenuItem("Delete", ModFolder.mcFolderList.Count == 1 && - folder.Location == Path.Combine(ModBase.exePath, ".minecraft") + @"\" + folder.Location == Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, ".minecraft") + @"\" ? Lang.Text("Select.Folder.Clear") : Lang.Text("Common.Action.Delete"), iconDelete, new Thickness(0, 0, 0, 2), ModMain.frmSelectLeft.Delete_Click); @@ -216,7 +216,7 @@ void AddMenuItem(string name, string header, string svgIcon = null, Thickness? p }); // 创建新文件夹按钮 - if (!Directory.Exists(Path.Combine(ModBase.exePath, ".minecraft"))) + if (!Directory.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, ".minecraft"))) { var itemCreate = new MyListItem { @@ -280,7 +280,7 @@ void AddMenuItem(string name, string header, string svgIcon = null, Thickness? p if (ModFolder.mcFolderList.Count == 0) throw new ArgumentNullException("没有可用的 Minecraft 文件夹"); - States.Game.SelectedFolder = ModFolder.mcFolderList[0].Location.Replace(ModBase.exePath, "$"); + States.Game.SelectedFolder = ModFolder.mcFolderList[0].Location.Replace(LauncherPaths.ExecutableDirectoryWithSlash, "$"); ((MyListItem)ModMain.frmSelectLeft.PanList.Children[1]).Checked = true; } catch (Exception ex) @@ -384,10 +384,10 @@ private void Add_Click() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.Add", newFolder), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Folder.Error.Add", newFolder)); } } @@ -410,21 +410,21 @@ public static void AddFolder(string folderPath, string displayName, bool showHin // 3. 能够找到可安装 Mod 的实例 // 4. 该实例的隔离文件夹下不存在 mods // 满足以上全部条件则视为根目录整合包 - ModBase.RunInThread(() => + UiThread.RunInThread(() => { try { if (!folderPath.EndsWith(@"\")) folderPath += @"\"; - if (!ModBase.CheckPermission(folderPath)) + if (!LegacyFileFacade.CheckPermission(folderPath)) { if (!showHint) throw new Exception("PCL 没有访问文件夹的权限:" + folderPath); HintService.Hint(Lang.Text("Select.Folder.AccessDenied"), HintType.Error); return; } - if (!ModBase.CheckPermission(folderPath + @"versions\")) + if (!LegacyFileFacade.CheckPermission(folderPath + @"versions\")) foreach (var Folder in new DirectoryInfo(folderPath).GetDirectories()) - if (ModBase.CheckPermission(Path.Combine(Folder.FullName, "versions"))) + if (LegacyFileFacade.CheckPermission(Path.Combine(Folder.FullName, "versions"))) { folderPath = Folder.FullName + @"\"; break; @@ -454,7 +454,7 @@ public static void AddFolder(string folderPath, string displayName, bool showHin if (!isAdded) folders.Add($"{displayName}>{folderPath}"); States.Game.Folders = folders.ToArray().Join("|"); - States.Game.SelectedFolder = folderPath.Replace(ModBase.exePath, "$"); + States.Game.SelectedFolder = folderPath.Replace(LauncherPaths.ExecutableDirectoryWithSlash, "$"); ModFolder.mcFolderListLoader.Start(isForceRestart: true); if (isReplace) return; if (showHint) HintService.Hint(Lang.Text("Select.Folder.Added", displayName), HintType.Success); @@ -471,15 +471,15 @@ public static void AddFolder(string folderPath, string displayName, bool showHin if (modIndieFolder.Exists && modIndieFolder.EnumerateFiles().Any()) return; Config.Instance.IndieV1[version.PathInstance] = 2; Config.Instance.IndieV2[version.PathInstance] = false; - ModBase.Log("[Setup] 已自动关闭单版本隔离:" + version.Name, ModBase.LogLevel.Debug); + LauncherLog.Log("[Setup] 已自动关闭单版本隔离:" + version.Name, LauncherLogLevel.Debug); } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.AddNew"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Folder.Error.AddNew")); } }); // 加上斜杠…… @@ -495,12 +495,12 @@ public void Create_Click() return; } - if (!Directory.Exists(ModBase.exePath + @".minecraft\")) + if (!Directory.Exists(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\")) { - Directory.CreateDirectory(ModBase.exePath + @".minecraft\"); - Directory.CreateDirectory(ModBase.exePath + @".minecraft\versions\"); + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\"); + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\versions\"); States.Game.SelectedFolder = @"$.minecraft\"; - ModFolder.McFolderLauncherProfilesJsonCreate(ModBase.exePath + @".minecraft\"); + ModFolder.McFolderLauncherProfilesJsonCreate(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\"); HintService.Hint(Lang.Text("Select.Folder.CreateSuccess"), HintType.Success); } @@ -571,10 +571,10 @@ public void Remove_Click(object sender, RoutedEventArgs e) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.Remove"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Folder.Error.Remove")); } } @@ -589,7 +589,7 @@ public void Delete_Click(object sender, RoutedEventArgs e) var isClearing = folder.type is ModFolder.McFolder.Types.Original or ModFolder.McFolder.Types.RenamedOriginal - && folder.Location == ModBase.exePath + @".minecraft\" + && folder.Location == LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\" && ModFolder.mcFolderList.Count == 1; var deleteText = Lang.Text(isClearing ? "Select.Folder.Clear" : "Common.Action.Delete"); @@ -621,34 +621,34 @@ folder.type is ModFolder.McFolder.Types.Original or ModFolder.McFolder.Types.Ren folders.RemoveAt(index); States.Game.Folders = string.Join("|", folders); - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { HintService.Hint(inProgress); - ModBase.DeleteDirectory(folder.Location); + LegacyFileFacade.DeleteDirectory(folder.Location); if (isClearing) Directory.CreateDirectory(folder.Location); HintService.Hint(success, HintType.Success); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.Operate", deleteText, folder.Name), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Select.Folder.Error.Operate", deleteText, folder.Name)); } finally { ModFolder.mcFolderListLoader.Start(isForceRestart: true); } - }, "Folder Delete " + ModBase.GetUuid(), ThreadPriority.BelowNormal); + }, "Folder Delete " + LauncherRuntime.GetUuid(), ThreadPriority.BelowNormal); } public void Open_Click(object sender, RoutedEventArgs e) { - ModBase.OpenExplorer(((MyListItem)((Popup)((ContextMenu)((MyMenuItem)sender).Parent).Parent).PlacementTarget) + LauncherProcess.OpenExplorer(((MyListItem)((Popup)((ContextMenu)((MyMenuItem)sender).Parent).Parent).PlacementTarget) .Info); } @@ -666,7 +666,7 @@ public void RefreshCurrent() public static void RefreshCurrent(string folder) { - ModBase.WriteIni(Path.Combine(folder, "PCL.ini"), "InstanceCache", ""); + LegacyIniStore.Shared.Write(Path.Combine(folder, "PCL.ini"), "InstanceCache", ""); if (folder == ModFolder.mcFolderSelected) ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); @@ -716,16 +716,16 @@ public void Rename_Click(object sender, RoutedEventArgs e) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.Rename"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Folder.Error.Rename")); } } // 点击选项 - public void Folder_Change(MyListItem sender, ModBase.RouteEventArgs e) + public void Folder_Change(MyListItem sender, RouteEventArgs e) { if (!e.raiseByMouse || !sender.Checked) return; @@ -738,7 +738,7 @@ public void Folder_Change(MyListItem sender, ModBase.RouteEventArgs e) } // 更换 - States.Game.SelectedFolder = ((ModFolder.McFolder)sender.Tag).Location.Replace(ModBase.exePath, "$"); + States.Game.SelectedFolder = ((ModFolder.McFolder)sender.Tag).Location.Replace(LauncherPaths.ExecutableDirectoryWithSlash, "$"); ModFolder.mcFolderListLoader.Start(isForceRestart: true); ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.RunOnUpdated, 1, @"versions\"); // 刷新实例列表 @@ -758,7 +758,7 @@ private void Item_MouseMove(object sender, MouseEventArgs e) } catch (Exception ex) { - ModBase.Log(ex, "开始拖拽操作失败"); + LauncherLog.Log(ex, "开始拖拽操作失败"); } } @@ -815,7 +815,7 @@ private void Item_DragLeave(object sender, DragEventArgs e) } catch (Exception ex) { - ModBase.Log(ex, "拖拽离开处理失败"); + LauncherLog.Log(ex, "拖拽离开处理失败"); } e.Handled = true; @@ -884,17 +884,17 @@ private void Item_Drop(object sender, DragEventArgs e) UpdateFolderOrder(); var direction = sourceIndex < targetIndex ? "后面" : "前面"; - ModBase.Log( + LauncherLog.Log( $"[Control] 文件夹拖拽排序:{sourceFolder.Name} -> 位置 {newTargetIndex} (在 {targetFolder.Name} {direction})", - ModBase.LogLevel.Debug); + LauncherLogLevel.Debug); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Folder.Error.DragDrop"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Folder.Error.DragDrop")); } finally diff --git a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.cs b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.cs index 8b8ae4149..818a6b0d2 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.cs @@ -81,7 +81,7 @@ private void ReloadTimer_Tick(object sender, EventArgs e) var elapsed = (DateTime.Now - lastInputTime).TotalMilliseconds; var currentDelay = reloadTimer.Interval.TotalMilliseconds; - if (elapsed >= currentDelay && ModInstanceList.mcInstanceListLoader.State == ModBase.LoadState.Finished && + if (elapsed >= currentDelay && ModInstanceList.mcInstanceListLoader.State == LoadState.Finished && !isRefreshing) { isRefreshing = true; @@ -116,7 +116,7 @@ private void LoaderInit() private void Load_Click(object sender, MouseButtonEventArgs e) { - if (ModInstanceList.mcInstanceListLoader.State == ModBase.LoadState.Failed) + if (ModInstanceList.mcInstanceListLoader.State == LoadState.Failed) ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); } @@ -366,10 +366,10 @@ void PutMethod(StackPanel stack) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Instance.Error.UiUpdate"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Select.Instance.Error.UiUpdate")); } } @@ -409,10 +409,10 @@ public static MyListItem McVersionListItem(McInstance mcInstance) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Instance.Error.IconLoad"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Select.Instance.Error.IconLoad")); newItem.Logo = "pack://application:,,,/images/Blocks/RedstoneBlock.png"; } @@ -543,12 +543,12 @@ public static void DeleteVersion(MyListItem item, McInstance mcInstance) { case 1: { - ModBase.IniClearCache(Path.Combine(mcInstance.PathIndie, "options.txt")); + LegacyIniStore.Shared.ClearCache(Path.Combine(mcInstance.PathIndie, "options.txt")); ((DynamicCacheConfigStorage)ConfigService.GetProvider(ConfigSource.GameInstance)).InvalidateCache( mcInstance.PathInstance); if (isShiftPressed) { - ModBase.DeleteDirectory(mcInstance.PathInstance); + LegacyFileFacade.DeleteDirectory(mcInstance.PathInstance); HintService.Hint(Lang.Text("Select.Instance.Delete.PermanentSuccess", mcInstance.Name), HintType.Success); } @@ -603,14 +603,14 @@ public static void DeleteVersion(MyListItem item, McInstance mcInstance) } catch (OperationCanceledException ex) { - ModBase.Log(ex, $"删除实例 {mcInstance.Name} 被主动取消"); + LauncherLog.Log(ex, $"删除实例 {mcInstance.Name} 被主动取消"); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Select.Instance.Error.Delete", mcInstance.Name), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Select.Instance.Error.Delete", mcInstance.Name)); } } diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs index f42eefd32..f341da05e 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupAbout.xaml.cs @@ -1,4 +1,4 @@ -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.Text.Json.Serialization; using System.Windows; using System.Windows.Input; @@ -33,9 +33,9 @@ private void PageOtherAbout_Loaded(object sender, RoutedEventArgs e) return; isLoaded = true; - ItemAboutPcl.Info = ItemAboutPcl.Info.Replace("%VERSION%", ModBase.VersionBaseName) - .Replace("%VERSIONCODE%", ModBase.VersionCode.ToString()).Replace("%BRANCH%", ModBase.VersionBranchName) - .Replace("%COMMIT_HASH%", ModBase.CommitHashShort); + ItemAboutPcl.Info = ItemAboutPcl.Info.Replace("%VERSION%", LauncherEnvironment.VersionBaseName) + .Replace("%VERSIONCODE%", LauncherEnvironment.VersionCode.ToString()).Replace("%BRANCH%", LauncherEnvironment.VersionBranchName) + .Replace("%COMMIT_HASH%", LauncherEnvironment.CommitHashShort); if (!Lang.IsChineseMainland) { @@ -63,7 +63,7 @@ private async void LoadContributersAsync() } catch (Exception ex) { - ModBase.Log(ex, Lang.Text("Setup.About.Error.LoadContributorsFailed")); + LauncherLog.Log(ex, Lang.Text("Setup.About.Error.LoadContributorsFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupFeedback.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupFeedback.xaml.cs index 022da0f58..986d5179a 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupFeedback.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupFeedback.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Text.Json.Serialization; @@ -107,7 +107,7 @@ private MyListItem CreateFeedbackItem(Feedback item, string logo) Title = item.Title, Type = MyListItem.CheckType.Clickable, Info = $"{item.User} | {Lang.Date(item.Time)}", - Logo = ModBase.pathImage + logo, + Logo = LauncherPaths.ImageBaseUri + logo, Tags = item.Type }; @@ -127,7 +127,7 @@ private void ShowFeedbackDetail(Feedback item) { case 2: { - ModBase.OpenWebsite(item.Url); + LauncherProcess.OpenWebsite(item.Url); break; } } diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupGameLink.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupGameLink.xaml.cs index 00ef65287..a8bb32285 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupGameLink.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupGameLink.xaml.cs @@ -80,16 +80,16 @@ public void Reset() try { Config.Link.Reset(); - ModBase.Log("[Setup] 已初始化联机页设置"); + LauncherLog.Log("[Setup] 已初始化联机页设置"); HintService.Hint(Lang.Text("Setup.GameLink.Initialized"), HintType.Success, false); Reload(); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.GameLink.Error.InitFailed"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.GameLink.Error.InitFailed")); } @@ -130,10 +130,10 @@ private void LinkProtocolPerferenceChange(object sender, SelectionChangedEventAr } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.GameLink.Error.ConfigChangeFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Setup.GameLink.Error.ConfigChangeFailed")); } } @@ -145,10 +145,10 @@ private void BtnNetTest_Click(object sender, MouseButtonEventArgs e) { BtnNetTest.IsEnabled = false; BtnNetTest.Text = Lang.Text("Setup.GameLink.NetworkTest.Testing"); - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { var status = CliNetTest.GetNetStatusAsync().GetAwaiter().GetResult(); - ModBase.RunInUi(() => + UiThread.Post(() => { TextUdpNatType.Text = Lang.Text("Setup.GameLink.NetworkTest.UdpNatType", CliNetTest.GetNatTypeString(status.UdpNatType)); @@ -165,9 +165,9 @@ private void BtnNetTest_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log(ex, + LauncherLog.Log(ex, "[Link] 获取网络测试结果失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Setup.GameLink.Error.NetworkTestFailed")); BtnNetTest.IsEnabled = true; BtnNetTest.Text = Lang.Text("Setup.GameLink.NetworkTest.Start"); diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupGameManage.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupGameManage.xaml.cs index 741c36f8a..215b270d6 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupGameManage.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupGameManage.xaml.cs @@ -81,15 +81,15 @@ public void Reset() { Config.Download.Reset(); Config.Tool.Reset(); - ModBase.Log("[Setup] 已初始化其他页设置"); + LauncherLog.Log("[Setup] 已初始化其他页设置"); HintService.Hint(Lang.Text("Setup.GameManage.Initialized"), HintType.Success, false); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.GameManage.Error.InitFailed"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.GameManage.Error.InitFailed")); } @@ -142,7 +142,7 @@ private void SliderLoad() }); } - private void SliderDownloadThread_PreviewChange(object sender, ModBase.RouteEventArgs e) + private void SliderDownloadThread_PreviewChange(object sender, RouteEventArgs e) { if (SliderDownloadThread.Value < 100) return; diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupJava.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupJava.xaml.cs index a54559166..b7ce43b7d 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupJava.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupJava.xaml.cs @@ -105,7 +105,7 @@ private MyListItem ItemBuild(JavaEntry j) return; } - ModBase.OpenExplorer(j.Installation.JavaFolder); + LauncherProcess.OpenExplorer(j.Installation.JavaFolder); }; var btnInfo = new MyIconButton(); btnInfo.SvgIcon = "lucide/info"; @@ -179,10 +179,10 @@ void UpdateEnableStyle(bool isCurEnable) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Java.EnableFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Setup.Java.EnableFailed")); } }; @@ -191,7 +191,7 @@ void UpdateEnableStyle(bool isCurEnable) return item; } - private void BtnAdd_Click(object sender, ModBase.RouteEventArgs e) + private void BtnAdd_Click(object sender, RouteEventArgs e) { var ret = SystemDialogs.SelectFile(Lang.Text("Setup.Java.SelectFile.Filter"), Lang.Text("Setup.Java.SelectFile.Title")); if (string.IsNullOrEmpty(ret) || !File.Exists(ret)) diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.cs index de15879d0..5a93fb4e9 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.cs @@ -92,19 +92,19 @@ public void Reload() catch (NullReferenceException ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Launch.Error.ConfigReset"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Launch.Error.ConfigReset")); Reset(); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Launch.Error.LoadFailed"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Setup.Launch.Error.LoadFailed")); } } @@ -115,15 +115,15 @@ public void Reset() try { Config.Launch.Reset(); - ModBase.Log("[Setup] 已初始化启动设置"); + LauncherLog.Log("[Setup] 已初始化启动设置"); HintService.Hint(Lang.Text("Setup.Launch.Initialized"), HintType.Success, false); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Launch.Error.InitFailed"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Launch.Error.InitFailed")); } @@ -131,7 +131,7 @@ public void Reset() } // 将控件改变路由到设置改变 - private void RadioBoxChange(object senderRaw, ModBase.RouteEventArgs e) + private void RadioBoxChange(object senderRaw, RouteEventArgs e) { var sender = (MyRadioBox)senderRaw; var gotCfg = sender.Tag?.ToString()?.Split("/") ?? Array.Empty(); @@ -226,7 +226,7 @@ public void RefreshRam(bool showAnim) var ramAvailable = Math.Round((double)phyRam.Available / 1024 / 1024 / 1024, 1); var ramGameActual = Math.Round(Math.Min(ramGame, ramAvailable), 5); var ramUsed = Math.Round(ramTotal - ramAvailable, 5); - var ramEmpty = Math.Round(ModBase.MathClamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); + var ramEmpty = Math.Round(LauncherMath.Clamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); // 设置最大可用内存 if (ramTotal <= 1.5d) SliderRamCustom.MaxValue = (int)Math.Round(Math.Max(Math.Floor((ramTotal - 0.3d) / 0.1d), 1d)); diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLauncherLanguage.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLauncherLanguage.xaml.cs index 636728e91..8b7fc656a 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLauncherLanguage.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLauncherLanguage.xaml.cs @@ -52,16 +52,16 @@ public void Reset() Config.Preference.Localization.LanguageConfig.SetDefaultValue(); Config.Preference.Localization.FormatCultureConfig.SetDefaultValue(); LocalizationService.ApplyFromConfig(); - ModBase.Log("[Setup] 已初始化启动器-语言页设置"); + LauncherLog.Log("[Setup] 已初始化启动器-语言页设置"); HintService.Hint(Lang.Text("Setup.Language.Reset.Success"), HintType.Success, false); Reload(); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "初始化启动器-语言页设置失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLauncherMisc.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLauncherMisc.xaml.cs index ed084d231..3a9a3dc7d 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLauncherMisc.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLauncherMisc.xaml.cs @@ -69,16 +69,16 @@ public void Reset() Config.Network.Reset(); Config.Debug.Reset(); Config.System.Reset(); - ModBase.Log("[Setup] 已初始化启动器-杂项页设置"); + LauncherLog.Log("[Setup] 已初始化启动器-杂项页设置"); HintService.Hint(Lang.Text("Setup.Misc.Initialized"), HintType.Success, false); Reload(); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Misc.Error.InitFailed"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Misc.Error.InitFailed")); } @@ -93,7 +93,7 @@ private void ComboChange(object senderRaw, SelectionChangedEventArgs e) SetByTag(sender.Tag?.ToString(), sender.SelectedIndex); } - private void RadioBoxChange(object senderRaw, ModBase.RouteEventArgs e) + private void RadioBoxChange(object senderRaw, RouteEventArgs e) { var sender = (MyRadioBox)senderRaw; var gotCfg = sender.Tag?.ToString()?.Split("/") ?? Array.Empty(); @@ -201,12 +201,12 @@ private void ComboSystemActivity_OnSelectionChanged(object sender, SelectionChan private void BtnSystemSettingExp_Click(object sender, MouseButtonEventArgs e) { var savePath = - SystemDialogs.SelectSaveFile(Lang.Text("Setup.Misc.System.ExportSettings.SaveTitle"), "PCL 全局配置.json", Lang.Text("Setup.Misc.System.ExportSettings.Filter"), ModBase.exePath); + SystemDialogs.SelectSaveFile(Lang.Text("Setup.Misc.System.ExportSettings.SaveTitle"), "PCL 全局配置.json", Lang.Text("Setup.Misc.System.ExportSettings.Filter"), LauncherPaths.ExecutableDirectoryWithSlash); if (string.IsNullOrWhiteSpace(savePath)) return; File.Copy(ConfigService.SharedConfigPath, savePath, true); HintService.Hint(Lang.Text("Setup.Misc.System.ExportSettings.Success"), HintType.Success); - ModBase.OpenExplorer(savePath); + LauncherProcess.OpenExplorer(savePath); } private void BtnSystemSettingImp_Click(object sender, MouseButtonEventArgs e) diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.cs index d84d9a710..c18b164c5 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.cs @@ -72,7 +72,7 @@ private void PageOtherLeft_Unloaded(object sender, RoutedEventArgs e) public void Reset(object sender, EventArgs e) { - switch (ModBase.Val(((MyIconButton)sender).Tag)) + switch (LauncherText.Val(((MyIconButton)sender).Tag)) { case (double)FormMain.PageSubType.SetupLaunch: { @@ -152,21 +152,21 @@ public void Reset(object sender, EventArgs e) public static void TryFeedback() // Handles ItemFeedback.Click { - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { - if (!ModBase.CanFeedback(true)) + if (!LauncherFeedbackService.CanFeedback(true)) return; switch (ModMain.MyMsgBox(Lang.Text("Setup.Left.Feedback.Message"), Lang.Text("Setup.Left.Feedback.Title"), Lang.Text("Setup.Left.Feedback.SubmitNew"), Lang.Text("Setup.Left.Feedback.ViewList"), Lang.Text("Common.Action.Cancel"))) { case 1: { - ModBase.Feedback(); + LauncherFeedbackService.Feedback(); break; } case 2: { - ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/issues/"); + LauncherProcess.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/issues/"); break; } } @@ -175,7 +175,7 @@ public static void TryFeedback() // Handles ItemFeedback.Click public void Refresh(object sender, EventArgs e) // 由边栏按钮匿名调用 { - switch (ModBase.Val(((MyIconButton)sender).Tag)) + switch (LauncherText.Val(((MyIconButton)sender).Tag)) { case (double)FormMain.PageSubType.SetupFeedback: { @@ -238,13 +238,13 @@ public PageSetupLeft() /// /// 勾选事件改变页面。 /// - private void PageCheck(object senderRaw, ModBase.RouteEventArgs e) + private void PageCheck(object senderRaw, RouteEventArgs e) { var sender = (MyListItem)senderRaw; // 尚未初始化控件属性时,sender.Tag 为 Nothing,会跳过切换,且由于 PageID 默认为 0 而切换到第一个页面 // 若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False) if (sender.Tag is not null) - PageChange((FormMain.PageSubType)ModBase.Val(sender.Tag)); + PageChange((FormMain.PageSubType)LauncherText.Val(sender.Tag)); } /// @@ -345,10 +345,10 @@ public void PageChange(FormMain.PageSubType id) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"切换分页面失败(ID {(int)id})", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Setup.Error.OperationFailed")); } finally diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLog.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLog.xaml.cs index 428f4eef3..5065b434c 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLog.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLog.xaml.cs @@ -118,10 +118,10 @@ private static void ExportLog(IEnumerable sourceFiles) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Log.ExportFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Setup.Log.ExportFailed")); } finally diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs index 81e60bb2a..1bf706d7f 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs @@ -156,19 +156,19 @@ public void Reload() } catch (NullReferenceException ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Ui.Error.ConfigReset"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.ConfigReset")); Reset(); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Ui.Error.LoadFailed"), - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Setup.Ui.Error.LoadFailed")); } } @@ -179,15 +179,15 @@ public void Reset() try { Config.Preference.Reset(); - ModBase.Log("[Setup] 已初始化个性化设置!"); + LauncherLog.Log("[Setup] 已初始化个性化设置!"); HintService.Hint(Lang.Text("Setup.Ui.Initialized"), HintType.Success, false); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Ui.Error.InitFailed"), - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.InitFailed")); } @@ -223,7 +223,7 @@ private void TextBoxChange(object senderRaw, RoutedEventArgs e) SetByTag(sender.Tag?.ToString(), sender.Text); } - private void RadioBoxChange(object senderRaw, ModBase.RouteEventArgs e) + private void RadioBoxChange(object senderRaw, RouteEventArgs e) { var sender = (MyRadioBox)senderRaw; var gotCfg = sender.Tag?.ToString()?.Split("/") ?? Array.Empty(); @@ -249,7 +249,7 @@ private void ComboMotdFontChange(object sender, SelectionChangedEventArgs e) // 背景图片 private void BtnUIBgOpen_Click(object sender, MouseButtonEventArgs e) { - ModBase.OpenExplorer(ModBase.exePath + @"PCL\Pictures\"); + LauncherProcess.OpenExplorer(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures\"); } private void BtnBackgroundRefresh_Click(object sender, MouseButtonEventArgs e) @@ -289,7 +289,7 @@ private void BtnBackgroundClear_Click(object sender, MouseButtonEventArgs e) Lang.Text("Common.Dialog.Warning"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1) { - ModBase.DeleteDirectory(ModBase.exePath + @"PCL\Pictures"); + LegacyFileFacade.DeleteDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures"); BackgroundRefresh(false, true); HintService.Hint(Lang.Text("Setup.Ui.Background.Clear.Success"), HintType.Success); } @@ -305,8 +305,8 @@ public static void BackgroundRefresh(bool isHint, bool refresh) try { // 获取可用的图片文件 - Directory.CreateDirectory(ModBase.exePath + @"PCL\Pictures\"); - var pic = ModBase.EnumerateFiles(ModBase.exePath + @"PCL\Pictures\").Where(file => + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures\"); + var pic = LegacyFileFacade.EnumerateFiles(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures\").Where(file => !(file.Extension.Equals(".ini", StringComparison.OrdinalIgnoreCase) || file.Extension.Equals(".db", StringComparison.OrdinalIgnoreCase))).Select(file => file.FullName) .ToList(); @@ -322,19 +322,19 @@ public static void BackgroundRefresh(bool isHint, bool refresh) ModVideoBack.VideoStop(); if (videoEx.Message.Contains("0xC00D109B")) - ModBase.Log( + LauncherLog.Log( $""" 刷新背景内容失败,该视频文件可能并非 H.264(AVC)格式。 你可以尝试使用视频转码工具打开视频文件并设定目标格式为 H.264(AVC),然后转码该视频。 文件:{videoAddress} """, - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.BackgroundVideoUnsupported")); else - ModBase.Log( + LauncherLog.Log( videoEx, $"刷新背景内容失败({videoAddress})", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); } }; @@ -375,12 +375,12 @@ 你可以尝试使用视频转码工具打开视频文件并设定目标格式 { ModMain.frmMain.ImgBack.Background = null; ModVideoBack.VideoStop(); - ModBase.Log("[UI] 加载背景内容:" + address); + LauncherLog.Log("[UI] 加载背景内容:" + address); ModMain.frmMain.ImgBack.Background = new MyBitmap(address); _ = Config.Preference.Background.WallpaperSuitMode; ModMain.frmMain.ImgBack.Visibility = Visibility.Visible; if (isHint) - HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", ModBase.GetFileNameFromPath(address)), HintType.Success, + HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", LegacyFileFacade.GetFileNameFromPath(address)), HintType.Success, false); } catch (Exception ex) @@ -388,19 +388,19 @@ 你可以尝试使用视频转码工具打开视频文件并设定目标格式 try { ModMain.frmMain.VideoBack.MediaFailed += videoHandler; - ModBase.Log(ex, "[UI] 加载背景图片失败" + address); - if (ModBase.ModeDebug) + LauncherLog.Log(ex, "[UI] 加载背景图片失败" + address); + if (LauncherRuntime.ModeDebug) HintService.Hint(Lang.Text("Setup.Ui.Background.ImageLoadFailed", address)); ModMain.frmMain.ImgBack.Visibility = Visibility.Visible; ModMain.frmMain.VideoBack.Source = new Uri(address, UriKind.Absolute); ModVideoBack.VideoPlay(); if (isHint) - HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", ModBase.GetFileNameFromPath(address)), HintType.Success, + HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", LegacyFileFacade.GetFileNameFromPath(address)), HintType.Success, false); } catch (Exception playEx) { - ModBase.Log(playEx, "播放背景内容时出现未知错误:"); + LauncherLog.Log(playEx, "播放背景内容时出现未知错误:"); } } } @@ -412,10 +412,10 @@ 你可以尝试使用视频转码工具打开视频文件并设定目标格式 catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "刷新背景内容时出现未知错误", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); } } @@ -431,74 +431,74 @@ private void BtnLogoChange_Click(object sender, MouseButtonEventArgs e) try { // 拷贝文件 - File.Delete(ModBase.exePath + @"PCL\Logo.png"); - ModBase.CopyFile(fileName, ModBase.exePath + @"PCL\Logo.png"); + File.Delete(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); + LegacyFileFacade.CopyFile(fileName, LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); // 设置当前显示 ModMain.frmMain.ImageTitleLogo.Source = null; // 防止因为 Source 属性前后的值相同而不更新 (#5628) - ModMain.frmMain.ImageTitleLogo.Source = ModBase.exePath + @"PCL\Logo.png"; + ModMain.frmMain.ImageTitleLogo.Source = LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"; } catch (Exception ex) { if (ex.Message.Contains("参数无效")) - ModBase.Log( + LauncherLog.Log( """ 改变标题栏图片失败,该图片文件可能并非标准格式。 你可以尝试使用画图打开该文件并重新保存,这会让图片变为标准格式。 """, - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.TitleImageInvalidFormat")); else - ModBase.Log( + LauncherLog.Log( ex, "设置标题栏图片失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); ModMain.frmMain.ImageTitleLogo.Source = null; } } - private void RadioLogoType3_Check(object sender, ModBase.RouteEventArgs e) + private void RadioLogoType3_Check(object sender, RouteEventArgs e) { if (!(ModAnimation.AniControlEnabled == 0 && e.raiseByMouse)) return; Refresh: ; // 已有图片则不再选择 - if (File.Exists(ModBase.exePath + @"PCL\Logo.png")) + if (File.Exists(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png")) { try { ModMain.frmMain.ImageTitleLogo.Source = null; // 防止因为 Source 属性前后的值相同而不更新 (#5628) - ModMain.frmMain.ImageTitleLogo.Source = ModBase.exePath + @"PCL\Logo.png"; + ModMain.frmMain.ImageTitleLogo.Source = LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"; } catch (Exception ex) { if (ex.Message.Contains("参数无效")) - ModBase.Log( + LauncherLog.Log( """ 调整标题栏图片失败,该图片文件可能并非标准格式。 你可以尝试使用画图打开该文件并重新保存,这会让图片变为标准格式。 """, - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.TitleImageResizeInvalidFormat")); else - ModBase.Log( + LauncherLog.Log( ex, "调整标题栏图片失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); ModMain.frmMain.ImageTitleLogo.Source = null; e.handled = true; try { - File.Delete(ModBase.exePath + @"PCL\Logo.png"); + File.Delete(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); } catch (Exception exx) { - ModBase.Log( + LauncherLog.Log( exx, "清理错误的标题栏图片失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); } } @@ -518,16 +518,16 @@ private void RadioLogoType3_Check(object sender, ModBase.RouteEventArgs e) try { // 拷贝文件 - File.Delete(ModBase.exePath + @"PCL\Logo.png"); - ModBase.CopyFile(fileName, ModBase.exePath + @"PCL\Logo.png"); + File.Delete(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); + LegacyFileFacade.CopyFile(fileName, LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); goto Refresh; } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "复制标题栏图片失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); } } @@ -537,16 +537,16 @@ private void BtnLogoDelete_Click(object sender, MouseButtonEventArgs e) { try { - File.Delete(ModBase.exePath + @"PCL\Logo.png"); + File.Delete(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); RadioLogoType1.SetChecked(true, true); HintService.Hint(Lang.Text("Setup.Ui.Logo.Clear.Success"), HintType.Success); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "清空标题栏图片失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); } } @@ -554,7 +554,7 @@ private void BtnLogoDelete_Click(object sender, MouseButtonEventArgs e) // 背景音乐 private void BtnMusicOpen_Click(object sender, MouseButtonEventArgs e) { - ModBase.OpenExplorer(ModBase.exePath + @"PCL\Musics\"); + LauncherProcess.OpenExplorer(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics\"); } private void BtnMusicRefresh_Click(object sender, MouseButtonEventArgs e) @@ -571,7 +571,7 @@ public void MusicRefreshUI() PanMusicVolume.Visibility = Visibility.Visible; PanMusicDetail.Visibility = Visibility.Visible; BtnMusicClear.Visibility = Visibility.Visible; - CardMusic.Title = Lang.Text("Setup.Ui.Music.TitleWithCount", ModBase.EnumerateFiles(ModBase.exePath + @"PCL\Musics\").Count()); + CardMusic.Title = Lang.Text("Setup.Ui.Music.TitleWithCount", LegacyFileFacade.EnumerateFiles(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics\").Count()); } else { @@ -589,7 +589,7 @@ private void BtnMusicClear_Click(object sender, MouseButtonEventArgs e) if (ModMain.MyMsgBox(Lang.Text("Setup.Ui.Music.Clear.Confirm.Message"), Lang.Text("Common.Dialog.Warning"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1) - ModBase.RunInThread(() => + UiThread.RunInThread(() => { HintService.Hint(Lang.Text("Setup.Ui.Music.Deleting")); // 停止播放音乐 @@ -600,30 +600,30 @@ private void BtnMusicClear_Click(object sender, MouseButtonEventArgs e) // 删除文件 try { - ModBase.DeleteDirectory(ModBase.exePath + @"PCL\Musics"); + LegacyFileFacade.DeleteDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics"); // DisableSMTCSupport() HintService.Hint(Lang.Text("Setup.Ui.Music.Delete.Success"), HintType.Success); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "删除背景音乐失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); } try { - Directory.CreateDirectory(ModBase.exePath + @"PCL\Musics"); - ModBase.RunInUi(() => ModMusic.MusicRefreshPlay(false)); + Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics"); + UiThread.Post(() => ModMusic.MusicRefreshPlay(false)); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "重建背景音乐文件夹失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); } }); @@ -656,7 +656,7 @@ private void BtnCustomRefresh_Click(object sender, MouseButtonEventArgs e) private void BtnCustomTutorial_Click(object sender, MouseButtonEventArgs e) { - ModBase.OpenWebsite("https://docs.pclc.cc/ce/customization/xaml-format"); + LauncherProcess.OpenWebsite("https://docs.pclc.cc/ce/customization/xaml-format"); } // 主题 @@ -670,7 +670,7 @@ private void ThemeColor_Change(object senderRaw, SelectionChangedEventArgs e) // 赞助 private void BtnLauncherDonate_Click(object sender, MouseButtonEventArgs e) { - ModBase.OpenWebsite("https://afdian.com/a/LTCat"); + LauncherProcess.OpenWebsite("https://afdian.com/a/LTCat"); } // 滑动条 @@ -871,10 +871,10 @@ public static void HiddenRefresh() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "刷新功能隐藏项目失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Setup.Ui.Error.OperationFailed")); } } diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs index 6aa432467..2d9f1c5ba 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs @@ -26,7 +26,7 @@ private void Init() ComboSystemUpdateChannel.SelectedIndex = (int)Config.Update.UpdateChannel; ComboSystemUpdateMode.SelectedIndex = (int)Config.Update.UpdateMode; - TextCurrentVersion.Text = "PCL CE " + VersionNameFormat(ModBase.VersionBaseName); + TextCurrentVersion.Text = "PCL CE " + VersionNameFormat(LauncherEnvironment.VersionBaseName); ModAnimation.AniControlEnabled -= 1; CheckUpdate(); } @@ -36,26 +36,26 @@ private async Task IsLatestAsync() try { // 修复:使用 dynamic 绕过命名空间重名导致的编译期类型冲突, - // 或者你可以尝试替换为 PCL.Core.App.SemVer.Parse(ModBase.versionBaseName) + // 或者你可以尝试替换为 PCL.Core.App.SemVer.Parse(LauncherEnvironment.VersionBaseName) if (await UpdateManager.remoteServer.IsLatestAsync( UpdateManager.IsCurrentVersionBeta ? UpdateChannel.beta : UpdateChannel.stable, SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, - SemVer.Parse(ModBase.VersionBaseName), - ModBase.VersionCode)) + SemVer.Parse(LauncherEnvironment.VersionBaseName), + LauncherEnvironment.VersionCode)) { - ModBase.Log("[Update] 已是最新版本"); + LauncherLog.Log("[Update] 已是最新版本"); return UpdateStatus.Latest; } - ModBase.Log("[Update] 有可用的新版本"); + LauncherLog.Log("[Update] 有可用的新版本"); return UpdateStatus.Available; } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, Lang.Text("Setup.Update.Error.NetworkFailed"), - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Setup.Update.Error.NetworkFailed")); return UpdateStatus.Error; } @@ -63,7 +63,7 @@ private async Task IsLatestAsync() public async void CheckUpdate() { - ModBase.Log("[Update] 开始检查更新"); + LauncherLog.Log("[Update] 开始检查更新"); CardUpdate.Visibility = Visibility.Collapsed; CardCheck.Visibility = Visibility.Visible; TextCurrentDesc.Text = Lang.Text("Setup.Update.Checking"); @@ -96,20 +96,20 @@ public async void CheckUpdate() { TextCurrentDesc.Text = Lang.Text("Setup.Update.CheckFailed"); if (checkUpdateEx is not null) - ModBase.Log( + LauncherLog.Log( checkUpdateEx, "[Update] 检查更新失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Update.Check.Failed")); else - ModBase.Log( + LauncherLog.Log( "[Update] 检查更新失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Update.Check.Failed")); return; } - if (UpdateManager.updateLoader is not null && UpdateManager.updateLoader.State == ModBase.LoadState.Loading) + if (UpdateManager.updateLoader is not null && UpdateManager.updateLoader.State == LoadState.Loading) { BtnUpdate_Timer(); BtnUpdate.IsEnabled = false; @@ -150,9 +150,9 @@ public async void CheckUpdate() public void BtnUpdate_Timer() { - while (UpdateManager.updateLoader is not null && UpdateManager.updateLoader.State == ModBase.LoadState.Loading) + while (UpdateManager.updateLoader is not null && UpdateManager.updateLoader.State == LoadState.Loading) { - ModBase.RunInUi(() => BtnUpdate.Text = Lang.Number(UpdateManager.updateLoader.Progress, "P2")); + UiThread.Post(() => BtnUpdate.Text = Lang.Number(UpdateManager.updateLoader.Progress, "P2")); Thread.Sleep(200); } } @@ -169,7 +169,7 @@ private void BtnUpdate_Click(object sender, MouseButtonEventArgs e) SystemInfo.IsArm64System ? "Arm64" : "x64"), Lang.Text("Setup.Update.DotNetMissing.Title"), Lang.Text("Setup.Update.DotNetMissing.DownloadRuntime"), Lang.Text("Common.Action.Cancel"), - button1Action: () => ModBase.OpenWebsite("https://get.dot.net/8"), forceWait: true); + button1Action: () => LauncherProcess.OpenWebsite("https://get.dot.net/8"), forceWait: true); return; } @@ -265,12 +265,12 @@ private void TextMirrorCDK_PasswordChanged(object sender, EventArgs e) private void BtnGetMirrorCDK_Click(object sender, MouseButtonEventArgs e) { - ModBase.OpenWebsite("https://mirrorchyan.com/"); + LauncherProcess.OpenWebsite("https://mirrorchyan.com/"); } private void BtnChangelog_Click(object sender, MouseButtonEventArgs e) { - ModBase.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases/v" + ModBase.VersionBaseName); + LauncherProcess.OpenWebsite("https://github.com/PCL-Community/PCL2-CE/releases/v" + LauncherEnvironment.VersionBaseName); } public string VersionNameFormat(string str) diff --git a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs index 82f031ed0..7417748d5 100644 --- a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs @@ -40,7 +40,7 @@ private void Page_Loaded(object sender, RoutedEventArgs e) timer.Start(); // 非调试模式隐藏线程数 - if (!ModBase.ModeDebug) + if (!LauncherRuntime.ModeDebug) { RowDefinitions[12].Height = new GridLength(0d); RowDefinitions[13].Height = new GridLength(0d); @@ -61,7 +61,7 @@ private void Watcher() { // 无任务 LabProgress.Text = Lang.Number(1d, "P0"); - LabSpeed.Text = ModBase.GetString(0) + "/s"; + LabSpeed.Text = LauncherText.GetReadableFileSize(0) + "/s"; LabFile.Text = Lang.Number(0, "N0"); LabThread.Text = Lang.Number(0, "N0") + " / " + Lang.Number(ModNet.NetTaskThreadLimit, "N0"); } @@ -70,13 +70,13 @@ private void Watcher() // 有任务,输出基本信息 var tasks = ModLoader.loaderTaskbar.Where(l => l.show).ToList(); // 筛选掉启动 MC 的任务(#6270) var rawPercent = tasks.Any() - ? ModBase.MathClamp( + ? LauncherMath.Clamp( tasks.Average(l => l.Progress), 0, 1) : 1d; var predictText = Lang.Number(rawPercent, "P2"); LabProgress.Text = rawPercent > 0.999999d ? Lang.Number(1d, "P0") : predictText; - LabSpeed.Text = ModBase.GetString(ModNet.NetManager.Speed) + "/s"; + LabSpeed.Text = LauncherText.GetReadableFileSize(ModNet.NetManager.Speed) + "/s"; LabFile.Text = ModNet.NetManager.FileRemain < 0 ? "0*" : Lang.Number(ModNet.NetManager.FileRemain, "N0"); LabThread.Text = Lang.Number(ModNet.NetManager.ThreadCount, "N0") + " / " + Lang.Number(ModNet.NetTaskThreadLimit, "N0"); @@ -87,10 +87,10 @@ private void Watcher() catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "任务管理左栏监视出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Speed.Error.OperationFailed")); } @@ -103,10 +103,10 @@ private void Watcher() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "任务管理右栏监视出错", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Speed.Error.OperationFailed")); } } @@ -124,12 +124,12 @@ public void TaskRefresh(ModLoader.LoaderBase loader) // 已有此卡片 Grid card = rightCards[loader.name]; var newValue = loader.Progress + (double)loader.State; - if (ModBase.Val(card.Tag) == newValue) + if (LauncherText.Val(card.Tag) == newValue) return; card.Tag = newValue; if (card.Children.Count <= 3) { - ModBase.Log("[Watcher] 元素不足的卡片:" + loader.name, ModBase.LogLevel.Debug); + LauncherLog.Log("[Watcher] 元素不足的卡片:" + loader.name, LauncherLogLevel.Debug); return; } @@ -138,20 +138,20 @@ public void TaskRefresh(ModLoader.LoaderBase loader) { switch (loader.State) { - case ModBase.LoadState.Failed: + case LoadState.Failed: { #region 失败,更新卡片 card.RowDefinitions.Clear(); card.Children.Clear(); - card.Children.Add((UIElement)ModBase.GetObjectFromXML( + card.Children.Add((UIElement)CustomXamlLoader.Load( "")); - var tb = (TextBlock)ModBase.GetObjectFromXML( + var tb = (TextBlock)CustomXamlLoader.Load( ""); tb.Text = loader.Error.ToString(); tb.MouseLeftButtonDown += (sender, _) => { - ModBase.ClipboardSet(((TextBlock)sender).Text, false); + LauncherProcess.ClipboardSet(((TextBlock)sender).Text, false); HintService.Hint(Lang.Text("Speed.Error.Copied"), HintType.Success); }; card.Children.Add(tb); @@ -160,7 +160,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) #endregion - case ModBase.LoadState.Finished: + case LoadState.Finished: { #region 完成,销毁卡片并返回 @@ -170,8 +170,8 @@ public void TaskRefresh(ModLoader.LoaderBase loader) #endregion - case ModBase.LoadState.Loading: - case ModBase.LoadState.Waiting: + case LoadState.Loading: + case LoadState.Waiting: { #region 进度不同,更新卡片 @@ -181,9 +181,9 @@ public void TaskRefresh(ModLoader.LoaderBase loader) { if (card.Children.Count < loaderList.Count * 2) { - ModBase.Log( + LauncherLog.Log( $"[Watcher] 刷新任务管理卡片 {loader.name} 失败:卡片中仅有 {card.Children.Count} 个子项,要求至少有 {loaderList.Count * 2} 个子项", - ModBase.LogLevel.Debug); + LauncherLogLevel.Debug); break; } @@ -192,13 +192,13 @@ public void TaskRefresh(ModLoader.LoaderBase loader) { switch (SubTask.State) { - case ModBase.LoadState.Waiting: + case LoadState.Waiting: { if ((string)((FrameworkElement)card.Children[row * 2]).Tag != "Waiting") { card.Children.RemoveAt(row * 2); card.Children.Insert(row * 2, - (UIElement)ModBase.GetObjectFromXML( + (UIElement)CustomXamlLoader.Load( "")); @@ -206,13 +206,13 @@ public void TaskRefresh(ModLoader.LoaderBase loader) break; } - case ModBase.LoadState.Loading: + case LoadState.Loading: { if ((string)((FrameworkElement)card.Children[row * 2]).Tag != "Loading") { card.Children.RemoveAt(row * 2); card.Children.Insert(row * 2, - (UIElement)ModBase.GetObjectFromXML( + (UIElement)CustomXamlLoader.Load( $"")); } else @@ -223,13 +223,13 @@ public void TaskRefresh(ModLoader.LoaderBase loader) break; } - case ModBase.LoadState.Finished: + case LoadState.Finished: { if ((string)((FrameworkElement)card.Children[row * 2]).Tag != "Finished") { card.Children.RemoveAt(row * 2); card.Children.Insert(row * 2, - (UIElement)ModBase.GetObjectFromXML( + (UIElement)CustomXamlLoader.Load( $"")); } @@ -242,10 +242,10 @@ public void TaskRefresh(ModLoader.LoaderBase loader) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"刷新任务管理卡片 {loader.name} 失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Speed.Error.OperationFailed")); } } while (false); @@ -258,14 +258,14 @@ public void TaskRefresh(ModLoader.LoaderBase loader) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"更新任务管理显示失败({loader.State})", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Speed.Error.OperationFailed")); } } - else if (!(loader.State == ModBase.LoadState.Aborted || loader.State == ModBase.LoadState.Finished)) + else if (!(loader.State == LoadState.Aborted || loader.State == LoadState.Finished)) { try { @@ -273,7 +273,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) var cardXAML = $@" + Tag=""{loader.Progress + (double)loader.State}"" Title=""{LauncherText.EscapeXml(loader.name)}"" Margin=""0,0,0,15""> @@ -288,18 +288,18 @@ public void TaskRefresh(ModLoader.LoaderBase loader) { switch (SubTask.State) { - case ModBase.LoadState.Waiting: + case LoadState.Waiting: { cardXAML += $""; break; } - case ModBase.LoadState.Loading: + case LoadState.Loading: { cardXAML += $""; break; } - case ModBase.LoadState.Finished: + case LoadState.Finished: { cardXAML += $""; @@ -314,7 +314,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) } } - cardXAML += $""; + cardXAML += $""; row += 1; } @@ -323,18 +323,18 @@ public void TaskRefresh(ModLoader.LoaderBase loader) MyCard card; try { - card = (MyCard)ModBase.GetObjectFromXML(cardXAML); + card = (MyCard)CustomXamlLoader.Load(cardXAML); } catch (Exception ex) { - ModBase.Log(ex, "新建任务管理卡片失败"); - ModBase.Log($"出错的卡片内容:\r\n{cardXAML}"); + LauncherLog.Log(ex, "新建任务管理卡片失败"); + LauncherLog.Log($"出错的卡片内容:\r\n{cardXAML}"); throw; } ModMain.frmSpeedRight.PanMain.Children.Insert(0, card); rightCards.Add(loader.name, card); - ModBase.Log($"[Watcher] 新建任务管理卡片:{loader.name}"); + LauncherLog.Log($"[Watcher] 新建任务管理卡片:{loader.name}"); // 添加取消按钮 var cancel = new MyIconButton { @@ -355,11 +355,11 @@ public void TaskRefresh(ModLoader.LoaderBase loader) }); rightCards.Remove(loader.name); ModLoader.loaderTaskbar.Remove(loader); - ModBase.Log($"[Taskbar] 关闭任务管理卡片:{loader.name},且移出任务列表"); - ModBase.RunInThread(() => loader.Abort()); + LauncherLog.Log($"[Taskbar] 关闭任务管理卡片:{loader.name},且移出任务列表"); + UiThread.RunInThread(() => loader.Abort()); }; // 如果已经失败,再刷新一次,修改成失败的控件 - if (loader.State == ModBase.LoadState.Failed) + if (loader.State == LoadState.Failed) { card.Tag = null; // 避免重复导致刷新无效 TaskRefresh(loader); @@ -370,20 +370,20 @@ public void TaskRefresh(ModLoader.LoaderBase loader) catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "添加任务管理卡片失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Speed.Error.OperationFailed")); } } } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "刷新任务管理显示失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Speed.Error.OperationFailed")); } } @@ -391,13 +391,13 @@ public void TaskRefresh(ModLoader.LoaderBase loader) public void TaskRemove(ModLoader.LoaderBase loader) { if (rightCards.ContainsKey(loader.name)) - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { // 移除已有的卡片 Grid card = rightCards[loader.name]; ModMain.frmSpeedRight.PanMain.Children.Remove(card); rightCards.Remove(loader.name); - ModBase.Log($"[Watcher] 移除任务管理卡片:{loader.name}"); + LauncherLog.Log($"[Watcher] 移除任务管理卡片:{loader.name}"); }); } diff --git a/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs b/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs index 116ccbe29..21fc99e1c 100644 --- a/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs @@ -55,7 +55,7 @@ private void LoaderInit() if (lobbyAnnouncementLoader is null) { var loaders = new List(); - loaders.Add(new ModLoader.LoaderTask(Lang.Text("Link.Mod.Task.InitLobbyUi"), _ => ModBase.RunInUi(() => + loaders.Add(new ModLoader.LoaderTask(Lang.Text("Link.Mod.Task.InitLobbyUi"), _ => UiThread.Post(() => { HintAnnounce.Visibility = Visibility.Visible; HintAnnounce.Theme = MyHint.Themes.Blue; @@ -68,7 +68,7 @@ private void LoaderInit() private async void OnServerExceptionHandler(Exception ex) { - ModBase.RunInUi(() => HintService.Hint( + UiThread.Post(() => HintService.Hint( Lang.Text("Tools.GameLink.Error.ServerMessage", ex.Message), HintType.Error)); @@ -76,7 +76,7 @@ private async void OnServerExceptionHandler(Exception ex) { await LobbyService.LeaveLobbyAsync(); - ModBase.RunInUi(() => + UiThread.Post(() => { CardPlayerList.Title = Lang.Text("Tools.GameLink.Member.ListLoading"); StackPlayerList.Children.Clear(); @@ -85,7 +85,7 @@ private async void OnServerExceptionHandler(Exception ex) } catch (Exception secEx) { - ModBase.Log(secEx, "Occurred an exception when exit server."); + LauncherLog.Log(secEx, "Occurred an exception when exit server."); HintService.Hint(Lang.Text("Tools.GameLink.Error.ServerExit"), HintType.Error); } } @@ -140,8 +140,8 @@ private static async void InitTask(ModLoader.LoaderTask task) private void OnServerStartedHandler() { - ModBase.Log("Received server started event."); - ModBase.RunInUi(() => + LauncherLog.Log("Received server started event."); + UiThread.Post(() => { LabFinishId.Text = LobbyService.CurrentLobbyCode; StackPlayerList.Children.Clear(); @@ -156,7 +156,7 @@ private async void OnServerShuttedDownHandler() { await LobbyService.LeaveLobbyAsync(); - ModBase.RunInUi(() => + UiThread.Post(() => { CardPlayerList.Title = Lang.Text("Tools.GameLink.Member.ListLoading"); StackPlayerList.Children.Clear(); @@ -165,14 +165,14 @@ private async void OnServerShuttedDownHandler() } catch (Exception ex) { - ModBase.Log(ex, "Occurred an exception when exit server."); + LauncherLog.Log(ex, "Occurred an exception when exit server."); HintService.Hint(Lang.Text("Tools.GameLink.Error.ServerExit"), HintType.Error); } } private void OnClientPingHandler(long latency) { - ModBase.RunInUi(() => + UiThread.Post(() => { LabFinishQuality.Text = Lang.Text("Tools.GameLink.Finish.Connected"); LabFinishPing.Text = Lang.Text("Tools.GameLink.Finish.PingMs", latency); @@ -182,7 +182,7 @@ private void OnClientPingHandler(long latency) private void OnUserStopGame() { - ModBase.RunInUi(() => + UiThread.Post(() => { CardPlayerList.Title = Lang.Text("Tools.GameLink.Member.ListLoading"); StackPlayerList.Children.Clear(); @@ -194,8 +194,8 @@ private void OnUserStopGame() private void OnPlayersChanged(object sender, NotifyCollectionChangedEventArgs e) { - ModBase.Log("接收到玩家列表改变事件"); - ModBase.RunInUi(() => + LauncherLog.Log("接收到玩家列表改变事件"); + UiThread.Post(() => { switch (e.Action) { @@ -231,7 +231,7 @@ private void OnDiscoveredWorldsChanged(object sender, NotifyCollectionChangedEve { LogWrapper.Info("[Lobby] Found new world changes"); - ModBase.RunInUi(() => + UiThread.Post(() => { #region 处理集合变更 @@ -364,7 +364,7 @@ private async Task _LinkAnnounceUpdateAsync() // 获取公告信息 private void GetAnnouncement() { - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -389,7 +389,7 @@ private void GetAnnouncement() if (cacheVer == States.Link.AnnounceCacheVer) { LogWrapper.Info("[Link] Using cached announcement data"); - jObj = (JsonObject)ModBase.GetJson(States.Link.AnnounceCache); + jObj = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(States.Link.AnnounceCache); } else { @@ -402,7 +402,7 @@ private void GetAnnouncement() ContentType = "application/json", Timeout = 7000 }); - jObj = (JsonObject)ModBase.GetJson(received); + jObj = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(received); // 更新缓存 States.Link.AnnounceCache = received; @@ -432,7 +432,7 @@ private void GetAnnouncement() if (jObj["version"].ToObject() > LobbyInfoProvider.ProtocolVersion) { - ModBase.RunInUi(() => + UiThread.Post(() => { HintAnnounce.Theme = MyHint.Themes.Red; HintAnnounce.Text = Lang.Text("Tools.GameLink.Error.UpdateRequired"); @@ -454,7 +454,7 @@ private void GetAnnouncement() // 版本过滤 var minVer = notice["minVer"].ToObject(); var maxVer = notice["maxVer"].ToObject(); - if (ModBase.VersionCode < minVer || ModBase.VersionCode > maxVer) continue; + if (LauncherEnvironment.VersionCode < minVer || LauncherEnvironment.VersionCode > maxVer) continue; // 类型映射 var type = LinkAnnounceType.Notice; @@ -490,15 +490,15 @@ private void GetAnnouncement() if (string.IsNullOrWhiteSpace(States.Link.NaidRefreshToken)) { - ModBase.RunInUi(() => LabNatayarkUserName.Text = Lang.Text("Tools.GameLink.Natayark.Login")); + UiThread.Post(() => LabNatayarkUserName.Text = Lang.Text("Tools.GameLink.Natayark.Login")); } else { - ModBase.RunInUi(() => LabNatayarkUserName.Text = Lang.Text("Tools.GameLink.Natayark.Loading")); + UiThread.Post(() => LabNatayarkUserName.Text = Lang.Text("Tools.GameLink.Natayark.Loading")); if (string.IsNullOrEmpty(NatayarkProfileManager.NaidProfile.Username)) ReloadNaidData(); else - ModBase.RunInUi(() => + UiThread.Post(() => { if (NatayarkProfileManager.NaidProfile.Status == 0) { @@ -518,7 +518,7 @@ private void GetAnnouncement() catch (Exception ex) { LobbyInfoProvider.IsLobbyAvailable = false; - ModBase.RunInUi(() => + UiThread.Post(() => { HintAnnounce.Theme = MyHint.Themes.Red; HintAnnounce.Text = Lang.Text("Tools.GameLink.Error.ConnectFailed"); @@ -564,7 +564,7 @@ private void PlayerInfoClick(object sender, MouseButtonEventArgs e) private void ReloadNaidData() { - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -601,7 +601,7 @@ private void ReloadNaidData() #region 3. UI 状态更新 - ModBase.RunInUi(() => + UiThread.Post(() => { var profile = NatayarkProfileManager.NaidProfile; @@ -624,9 +624,9 @@ private void ReloadNaidData() { #region 错误处理 - ModBase.Log(ex, "Failed to refresh Natayark ID info, re-login required"); + LauncherLog.Log(ex, "Failed to refresh Natayark ID info, re-login required"); - ModBase.RunInUi(() => + UiThread.Post(() => { LabNatayarkUserName.Text = Lang.Text("Tools.GameLink.Natayark.FetchFailed"); LabNatayarkUserName.Opacity = 0.6; @@ -654,7 +654,7 @@ private void LabNatayarkUserName_MouseLeftButtonUp(object sender, MouseButtonEve BtnNatayarkUserName.IsEnabled = false; ModWebServer.StartNaidAuthorize(() => { - ModBase.RunInUi(() => BtnNatayarkUserName.IsEnabled = true); + UiThread.Post(() => BtnNatayarkUserName.IsEnabled = true); HintService.Hint(Lang.Text("Tools.GameLink.Natayark.LoginComplete"), HintType.Success); ReloadNaidData(); }); @@ -666,7 +666,7 @@ private void LabNatayarkUserName_MouseLeftButtonUp(object sender, MouseButtonEve States.Link.NaidRefreshTokenConfig.Reset(); States.Link.NaidRefreshToken = ""; LabNatayarkUserName.Text = Lang.Text("Tools.GameLink.Natayark.Login"); - ModBase.Log("[Link] 已退出登录 Natayark Network"); + LauncherLog.Log("[Link] 已退出登录 Natayark Network"); HintService.Hint(Lang.Text("Tools.GameLink.Natayark.LogoutComplete"), HintType.Success, false); } } @@ -681,16 +681,16 @@ private async void BtnNetTest_Click(object sender, MouseButtonEventArgs e) BtnNatTest.IsEnabled = false; LabNatType.Text = Lang.Text("Tools.GameLink.Nat.Testing"); var status = await CliNetTest.GetNetStatusAsync(); - ModBase.RunInUi(() => LabNatType.Text = Lang.Text("Tools.GameLink.Nat.Result", + UiThread.Post(() => LabNatType.Text = Lang.Text("Tools.GameLink.Nat.Result", CliNetTest.GetNatTypeString(status.UdpNatType), CliNetTest.GetNatTypeString(status.TcpNatType))); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "[Link] 获取网络测试结果失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Tools.GameLink.Error.NetworkTestFailed")); BtnNatTest.IsEnabled = true; LabNatType.Text = Lang.Text("Tools.GameLink.Nat.Failed"); @@ -710,7 +710,7 @@ private void PasteLobbyId(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log(ex, "从剪贴板识别大厅编号出错"); + LauncherLog.Log(ex, "从剪贴板识别大厅编号出错"); return; } @@ -783,12 +783,12 @@ private async void BtnCreate_Click(object sender, MouseButtonEventArgs e) private async Task CreateLobbyAsync(int port) { - ModBase.Log("[Link] 创建大厅,端口:" + port); + LauncherLog.Log("[Link] 创建大厅,端口:" + port); var username = LobbyInfoProvider.GetUsername(); - ModBase.RunInUi(() => + UiThread.Post(() => { BtnFinishPing.Visibility = Visibility.Collapsed; LabFinishPing.Text = "-ms"; @@ -808,7 +808,7 @@ private async Task CreateLobbyAsync(int port) var res = await LobbyService.CreateLobbyAsync(port, username).ConfigureAwait(true); if (!res) - ModBase.RunInUi(() => + UiThread.Post(() => { CardPlayerList.Title = Lang.Text("Tools.GameLink.Member.ListLoading"); StackPlayerList.Children.Clear(); @@ -822,12 +822,12 @@ private async void BtnJoin_Click(object sender, MouseButtonEventArgs e) if (!ModLink.LobbyPrecheck()) return; - ModBase.Log("Start to join lobby."); + LauncherLog.Log("Start to join lobby."); var id = TextJoinLobbyId.Text; var username = LobbyInfoProvider.GetUsername(); - ModBase.RunInUi(() => + UiThread.Post(() => { BtnFinishPing.Visibility = Visibility.Visible; LabFinishPing.Text = "-ms"; @@ -845,7 +845,7 @@ private async void BtnJoin_Click(object sender, MouseButtonEventArgs e) var res = await LobbyService.JoinLobbyAsync(id, username).ConfigureAwait(true); if (!res) - ModBase.RunInUi(() => + UiThread.Post(() => { CardPlayerList.Title = Lang.Text("Tools.GameLink.Member.ListLoading"); StackPlayerList.Children.Clear(); @@ -864,7 +864,7 @@ private void TextJoinLobbyId_KeyDown(object sender, KeyEventArgs e) #region PanLoad | 加载中页面 // 承接状态切换的 UI 改变 - private void OnLoadStateChanged(ModLoader.LoaderBase loader, ModBase.LoadState newState, ModBase.LoadState oldState) + private void OnLoadStateChanged(ModLoader.LoaderBase loader, LoadState newState, LoadState oldState) { } @@ -872,9 +872,9 @@ private void OnLoadStateChanged(ModLoader.LoaderBase loader, ModBase.LoadState n private static void SetLoadDesc(string intro, string step) { - ModBase.Log("连接步骤:" + intro); + LauncherLog.Log("连接步骤:" + intro); _loadStep = step; - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { if (ModMain.frmToolsGameLink is null || !ModMain.frmToolsGameLink.LabLoadDesc.IsLoaded) return; @@ -886,7 +886,7 @@ private static void SetLoadDesc(string intro, string step) // 承接重试 private void CardLoad_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { - if (initLoader.State != ModBase.LoadState.Failed) + if (initLoader.State != LoadState.Failed) return; initLoader.Start(isForceRestart: true); } @@ -894,14 +894,14 @@ private void CardLoad_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) // 取消加载 private void CancelLoad(object sender, EventArgs eventArgs) { - if (initLoader.State == ModBase.LoadState.Loading) + if (initLoader.State == LoadState.Loading) { CurrentSubpage = Subpages.PanSelect; initLoader.Abort(); } else { - initLoader.State = ModBase.LoadState.Waiting; + initLoader.State = LoadState.Waiting; } } @@ -943,7 +943,7 @@ private void CardResized(object sender, SizeChangedEventArgs sizeChangedEventArg #region PanFinish | 加载完成页面 // 退出 - private async void BtnFinishExit_Click(object sender, ModBase.RouteEventArgs routeEventArgs) + private async void BtnFinishExit_Click(object sender, RouteEventArgs routeEventArgs) { if (ModMain.MyMsgBox( Lang.Text(LobbyService.IsHost @@ -962,20 +962,20 @@ private async void BtnFinishExit_Click(object sender, ModBase.RouteEventArgs rou } // 复制大厅编号 - private void BtnFinishCopy_Click(object sender, ModBase.RouteEventArgs routeEventArgs) + private void BtnFinishCopy_Click(object sender, RouteEventArgs routeEventArgs) { - ModBase.ClipboardSet(LabFinishId.Text); + LauncherProcess.ClipboardSet(LabFinishId.Text); } // 复制 IP - private void BtnFinishCopyIp_Click(object sender, ModBase.RouteEventArgs routeEventArgs) + private void BtnFinishCopyIp_Click(object sender, RouteEventArgs routeEventArgs) { var ip = $"127.0.0.1:{LobbyInfoProvider.McForward.LocalPort}"; ModMain.MyMsgBox(Lang.Text("Tools.GameLink.CopyIp.Message", ip), Lang.Text("Tools.GameLink.CopyIp.Title"), Lang.Text("Common.Action.Copy"), Lang.Text("Tools.GameLink.CopyIp.Back"), - button1Action: () => ModBase.ClipboardSet(ip)); + button1Action: () => LauncherProcess.ClipboardSet(ip)); } #endregion @@ -997,7 +997,7 @@ public Subpages CurrentSubpage if (field == value) return; field = value; - ModBase.Log("[Link] 子页面更改为 " + ModBase.GetStringFromEnum(value)); + LauncherLog.Log("[Link] 子页面更改为 " + LauncherText.GetStringFromEnum(value)); PageOnContentExit(); } } = States.Link.LinkEula ? Subpages.PanSelect : Subpages.PanEula; diff --git a/Plain Craft Launcher 2/Pages/PageTools/PageToolsLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageTools/PageToolsLeft.xaml.cs index c5df4295e..fa2e4c5c3 100644 --- a/Plain Craft Launcher 2/Pages/PageTools/PageToolsLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageTools/PageToolsLeft.xaml.cs @@ -55,7 +55,7 @@ public void Refresh(object sender, EventArgs e) var button = (MyIconButton)sender; if (button.Tag is null) return; - double id = ModBase.Val(button.Tag); + double id = LauncherText.Val(button.Tag); switch (id) { case (double)FormMain.PageSubType.ToolsGameLink: @@ -79,13 +79,13 @@ public void Refresh(object sender, EventArgs e) /// /// 勾选事件改变页面。 /// - private void PageCheck(object senderRaw, ModBase.RouteEventArgs e) + private void PageCheck(object senderRaw, RouteEventArgs e) { var sender = (MyListItem)senderRaw; // 尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0 // 若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False) if (sender.Tag is not null) - PageChange((FormMain.PageSubType)ModBase.Val(sender.Tag)); + PageChange((FormMain.PageSubType)LauncherText.Val(sender.Tag)); } public object PageGet(FormMain.PageSubType? id = null) @@ -128,10 +128,10 @@ public void PageChange(FormMain.PageSubType id) } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"切换分页面失败(ID {(int)id})", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Tools.Error.OperationFailed")); } finally diff --git a/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs b/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs index d6229d1aa..a0864956d 100644 --- a/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs @@ -50,7 +50,7 @@ private void MeLoaded() TextDownloadFolder.Validate(); if (!string.IsNullOrEmpty(TextDownloadFolder.ValidateResult) || string.IsNullOrEmpty(TextDownloadFolder.Text)) - TextDownloadFolder.Text = ModBase.exePath + @"PCL\MyDownload\"; + TextDownloadFolder.Text = LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\MyDownload\"; TextDownloadFolder.Validate(); TextDownloadName.Validate(); @@ -91,23 +91,23 @@ private static void DownloadState(ModLoader.LoaderCombo loader) { switch (loader.State) { - case ModBase.LoadState.Finished: + case LoadState.Finished: { HintService.Hint(Lang.Text("Tools.Test.CustomDownload.Finished", loader.name), HintType.Success); Console.Beep(); break; } - case ModBase.LoadState.Failed: + case LoadState.Failed: { - ModBase.Log( + LauncherLog.Log( loader.Error, $"{loader.name}失败", - ModBase.LogLevel.Msgbox, + LauncherLogLevel.Msgbox, userSummary: Lang.Text("Tools.Test.Error.OperationFailed")); Console.Beep(); break; } - case ModBase.LoadState.Aborted: + case LoadState.Aborted: { HintService.Hint(Lang.Text("Tools.Test.CustomDownload.Aborted", loader.name)); break; @@ -134,21 +134,21 @@ public static void StartCustomDownload(string url, string fileName, string folde try { Directory.CreateDirectory(folder); - ModBase.CheckPermissionWithException(folder); + LegacyFileFacade.CheckPermissionWithException(folder); } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, $"访问文件夹失败({folder})", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Tools.Test.Error.OperationFailed")); return; } - ModBase.Log("[Download] 自定义下载文件名:" + fileName); - ModBase.Log("[Download] 自定义下载文件目标:" + folder); - var uuid = ModBase.GetUuid(); + LauncherLog.Log("[Download] 自定义下载文件名:" + fileName); + LauncherLog.Log("[Download] 自定义下载文件目标:" + folder); + var uuid = LauncherRuntime.GetUuid(); ModLoader.LoaderBase loaderdownload; if (new HttpValidator().Validate(url).IsValid) loaderdownload = new LoaderDownload(Lang.Text("Tools.Test.CustomDownload.LoaderName", fileName), @@ -166,10 +166,10 @@ public static void StartCustomDownload(string url, string fileName, string folde catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "开始自定义下载失败", - ModBase.LogLevel.Feedback, + LauncherLogLevel.Feedback, userSummary: Lang.Text("Tools.Test.Error.OperationFailed")); } } @@ -189,7 +189,7 @@ public static void Jrrp() public static void RubbishClear() { - ModBase.RunInUi(() => + UiThread.Post(() => { if (ModMain.frmToolsTest is not null && ModMain.frmToolsTest.BtnClear is not null) ModMain.frmToolsTest.BtnClear.IsEnabled = false; @@ -209,11 +209,11 @@ public static void RubbishClear() // 删除 PCL 的缓存 - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { - if (!ModWatcher.hasRunningMinecraft && ModLaunch.mcLaunchLoader.State != ModBase.LoadState.Loading) + if (!ModWatcher.hasRunningMinecraft && ModLaunch.mcLaunchLoader.State != LoadState.Loading) { if (ModNet.HasDownloadingTask()) { @@ -247,9 +247,9 @@ public static void RubbishClear() foreach (var dirInfo in cleanMcFolderList) { - num += ModBase.DeleteDirectory( + num += LegacyFileFacade.DeleteDirectory( dirInfo.FullName + (dirInfo.FullName.EndsWith(@"\") ? "" : @"\") + @"crash-reports\", true); - num += ModBase.DeleteDirectory( + num += LegacyFileFacade.DeleteDirectory( dirInfo.FullName + (dirInfo.FullName.EndsWith(@"\") ? "" : @"\") + @"logs\", true); foreach (var fileInfo in dirInfo.EnumerateFiles("*")) if (fileInfo.Name.StartsWith("hs_err_pid") || fileInfo.Name.EndsWith(".log") || @@ -262,11 +262,11 @@ public static void RubbishClear() foreach (var dirInfo2 in dirInfo.EnumerateDirectories()) if ((dirInfo2.Name ?? "") == (dirInfo2.Name + "-natives" ?? "") || dirInfo2.Name == "natives-windows-x86_64") - num += ModBase.DeleteDirectory(dirInfo2.FullName, true); + num += LegacyFileFacade.DeleteDirectory(dirInfo2.FullName, true); } - num += ModBase.DeleteDirectory(ModBase.pathTemp, true); - num += ModBase.DeleteDirectory(Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL"), true); + num += LegacyFileFacade.DeleteDirectory(LauncherPaths.TempWithSlash, true); + num += LegacyFileFacade.DeleteDirectory(Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL"), true); if (num != 0) { ModMain.MyMsgBox(Lang.Text("Tools.Test.Clean.ClearedMessage", num), @@ -286,15 +286,15 @@ public static void RubbishClear() } catch (Exception ex) { - ModBase.Log( + LauncherLog.Log( ex, "清理垃圾失败", - ModBase.LogLevel.Hint, + LauncherLogLevel.Hint, userSummary: Lang.Text("Tools.Test.Error.OperationFailed")); } finally { - ModBase.RunInUiWait(() => + UiThread.Invoke(() => { if (ModMain.frmToolsTest is not null && ModMain.frmToolsTest.BtnClear is not null) ModMain.frmToolsTest.BtnClear.IsEnabled = true; @@ -323,7 +323,7 @@ private void TextDownloadUrl_TextChanged(object sender, TextChangedEventArgs e) try { if (!string.IsNullOrEmpty(TextDownloadName.Text) || string.IsNullOrEmpty(TextDownloadUrl.Text)) return; - TextDownloadName.Text = ModBase.GetFileNameFromPath(WebUtility.UrlDecode(TextDownloadUrl.Text)); + TextDownloadName.Text = LegacyFileFacade.GetFileNameFromPath(WebUtility.UrlDecode(TextDownloadUrl.Text)); } catch { @@ -346,7 +346,7 @@ private void BtnDownloadOpen_Click(object sender, MouseButtonEventArgs e) } catch (Exception ex) { - ModBase.Log(ex, "打开下载文件夹失败"); + LauncherLog.Log(ex, "打开下载文件夹失败"); } } @@ -387,7 +387,7 @@ private void BtnSkinSave_Click(object sender, MouseButtonEventArgs e) { var id = TextSkinID.Text; HintService.Hint(Lang.Text("Tools.Test.Skin.Fetching")); - ModBase.RunInNewThread(() => + PCL.Core.App.Basics.RunInNewThread(() => { try { @@ -400,10 +400,10 @@ private void BtnSkinSave_Click(object sender, MouseButtonEventArgs e) var result = (string)ModProfile.McLoginMojangUuid(id, true); result = ModSkin.McSkinGetAddress(result, "Mojang"); result = ModSkin.McSkinDownload(result); - ModBase.RunInUi(() => + UiThread.Post(() => { var path = SystemDialogs.SelectSaveFile(Lang.Text("Tools.Test.Skin.Save"), $"{id}.png", Lang.Text("Tools.Test.Skin.FileFilter")); - ModBase.CopyFile(result, path); + LegacyFileFacade.CopyFile(result, path); HintService.Hint(Lang.Text("Tools.Test.Skin.Saved", id), HintType.Success); }); } @@ -413,11 +413,11 @@ private void BtnSkinSave_Click(object sender, MouseButtonEventArgs e) if (ex.ToString().Contains("429")) { HintService.Hint(Lang.Text("Tools.Test.Skin.TooFrequent"), HintType.Error); - ModBase.Log($"获取正版皮肤失败({id}):获取皮肤太过频繁,请 5 分钟后再试!"); + LauncherLog.Log($"获取正版皮肤失败({id}):获取皮肤太过频繁,请 5 分钟后再试!"); } else { - ModBase.Log(ex, $"获取正版皮肤失败({id})"); + LauncherLog.Log(ex, $"获取正版皮肤失败({id})"); } } }); @@ -494,7 +494,7 @@ private void BtnLaunchCount_Click(object sender, MouseButtonEventArgs e) private async void BtnAchievementPreview_Click(object sender, MouseButtonEventArgs e) { var url = GetAchievementUrl(); - ModBase.Log("[Net] 获取网络结果" + url); + LauncherLog.Log("[Net] 获取网络结果" + url); await LoadImageAsync(url); } @@ -523,17 +523,17 @@ private async Task LoadImageAsync(string imageUrl) else if (response.StatusCode == HttpStatusCode.NotFound) Dispatcher.Invoke(() => { - ModBase.Log("获取成就图片失败(404)"); + LauncherLog.Log("获取成就图片失败(404)"); HintService.Hint(Lang.Text("Tools.Test.Achievement.FetchFailed"), HintType.Error); }); else - Dispatcher.Invoke(() => ModBase.Log("获取成就图片失败(" + (int)response.StatusCode + ")")); + Dispatcher.Invoke(() => LauncherLog.Log("获取成就图片失败(" + (int)response.StatusCode + ")")); } catch (Exception ex) { - Dispatcher.Invoke(() => ModBase.Log(ex, "获取成就图片失败")); + Dispatcher.Invoke(() => LauncherLog.Log(ex, "获取成就图片失败")); } } @@ -545,7 +545,7 @@ private async void BtnAchievementSave_Click(object sender, MouseButtonEventArgs private async Task DownloadImageToLocalAsync(string imageUrl) { - var savePath = ModBase.pathTemp + @"Download\" + ModBase.GetHash(imageUrl) + ".png"; + var savePath = LauncherPaths.TempWithSlash + @"Download\" + LauncherText.GetHash(imageUrl) + ".png"; var client = NetworkService.GetClient(); try { @@ -565,12 +565,12 @@ private async Task DownloadImageToLocalAsync(string imageUrl) SystemDialogs.SelectSaveFile(Lang.Text("Tools.Test.Achievement.Save"), AchievementTitleTextBox.Text + ".png", Lang.Text("Tools.Test.Achievement.FileFilter")); if (string.IsNullOrEmpty(path)) { - ModBase.Log("用户取消了保存操作"); + LauncherLog.Log("用户取消了保存操作"); File.Delete(savePath); return; } - ModBase.CopyFile(savePath, path); + LegacyFileFacade.CopyFile(savePath, path); File.Delete(savePath); HintService.Hint(Lang.Text("Tools.Test.Achievement.Saved"), HintType.Success); } @@ -578,20 +578,20 @@ private async Task DownloadImageToLocalAsync(string imageUrl) else if (response.StatusCode == HttpStatusCode.NotFound) { // 捕获 404 错误 - ModBase.Log("获取成就图片失败(404)"); + LauncherLog.Log("获取成就图片失败(404)"); HintService.Hint(Lang.Text("Tools.Test.Achievement.FetchFailed"), HintType.Error); } else { // 处理其他非成功状态码 - ModBase.Log("获取成就图片失败(" + (int)response.StatusCode + ")"); + LauncherLog.Log("获取成就图片失败(" + (int)response.StatusCode + ")"); } } catch (Exception ex) { // 捕获所有其他异常(如网络连接问题) - ModBase.Log(ex, "获取成就图片失败"); + LauncherLog.Log(ex, "获取成就图片失败"); } } @@ -655,7 +655,7 @@ private void LoadAndGenerateHead(string skinPath) catch (Exception ex) { - ModBase.Log(ex, "生成头像失败"); + LauncherLog.Log(ex, "生成头像失败"); HintService.Hint(Lang.Text("Tools.Test.Avatar.GenerateFailed", ex.Message), HintType.Error); SkinPreviewBorder.Visibility = Visibility.Collapsed; } From e7a7c8cd9b41a46dcfd6314eb50bf4631c7d9e42 Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 1 Jul 2026 02:31:56 +0800 Subject: [PATCH 06/16] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=85=BC=E5=AE=B9exts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Utils/EnumerableTextExtensionsTest.cs | 17 + .../Utils/Exts/EnumerableTextExtensions.cs | 35 + .../GlobalCompatibilityAliases.cs | 7 - .../Compatibility/LauncherLegacyTypes.cs | 563 +++++++++++++++- .../Compatibility/ModBase.Declarations.cs | 611 ------------------ .../Compatibility/ModBase.LegacyFiles.cs | 272 -------- .../Compatibility/ModBase.LegacyIni.cs | 53 -- .../Compatibility/ModBase.LegacyLog.cs | 123 ---- .../Compatibility/ModBase.LegacySearch.cs | 112 ---- .../Compatibility/ModBase.LegacySystem.cs | 386 ----------- .../Compatibility/ModBase.LegacyText.cs | 397 ------------ .../Compatibility/ModBase.LegacyUi.cs | 136 ---- Plain Craft Launcher 2/Controls/MyImage.cs | 2 +- .../Controls/MyVirtualizingElement.cs | 5 +- Plain Craft Launcher 2/GlobalUsings.cs | 5 + .../Infrastructure/LauncherMath.cs | 4 +- .../Infrastructure/LauncherRuntime.cs | 4 +- .../Infrastructure/LauncherText.cs | 14 +- .../Modules/Minecraft/McInstance.cs | 7 +- .../Modules/Minecraft/ModComp.cs | 6 +- .../Modules/Minecraft/ModLibrary.cs | 2 +- .../Modules/Minecraft/ModLocalComp.cs | 8 +- .../PageDownloadCompFavorites.xaml.cs | 4 +- .../PageInstanceCompResource.xaml.cs | 3 +- .../PageInstance/PageInstanceSaves.xaml.cs | 2 +- .../PageInstanceSavesDatapack.xaml.cs | 3 +- .../Pages/PageSetup/PageSetupUpdate.xaml.cs | 4 +- 27 files changed, 647 insertions(+), 2138 deletions(-) create mode 100644 PCL.Core.Test/Utils/EnumerableTextExtensionsTest.cs create mode 100644 PCL.Core/Utils/Exts/EnumerableTextExtensions.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/GlobalCompatibilityAliases.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs delete mode 100644 Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs create mode 100644 Plain Craft Launcher 2/GlobalUsings.cs diff --git a/PCL.Core.Test/Utils/EnumerableTextExtensionsTest.cs b/PCL.Core.Test/Utils/EnumerableTextExtensionsTest.cs new file mode 100644 index 000000000..7d59fe229 --- /dev/null +++ b/PCL.Core.Test/Utils/EnumerableTextExtensionsTest.cs @@ -0,0 +1,17 @@ +using System.Collections; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.Utils.Exts; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class EnumerableTextExtensionsTest +{ + [TestMethod] + public void JoinSkipsNullElementsAndKeepsSeparators() + { + IEnumerable values = new object?[] { "a", null, "b" }; + + Assert.AreEqual("a||b", values.Join("|")); + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/Exts/EnumerableTextExtensions.cs b/PCL.Core/Utils/Exts/EnumerableTextExtensions.cs new file mode 100644 index 000000000..662038daa --- /dev/null +++ b/PCL.Core/Utils/Exts/EnumerableTextExtensions.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections; +using System.Text; + +namespace PCL.Core.Utils.Exts; + +/// +/// Text helpers for enumerable values. +/// +public static class EnumerableTextExtensions +{ + /// + /// Joins an enumerable into a string. Null elements are skipped, matching string builder based launcher formatting. + /// + public static string Join(this IEnumerable source, string separator) + { + ArgumentNullException.ThrowIfNull(source); + separator ??= string.Empty; + + var builder = new StringBuilder(); + var isFirst = true; + foreach (var item in source) + { + if (isFirst) + isFirst = false; + else + builder.Append(separator); + + if (item is not null) + builder.Append(item); + } + + return builder.ToString(); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/GlobalCompatibilityAliases.cs b/Plain Craft Launcher 2/Compatibility/GlobalCompatibilityAliases.cs deleted file mode 100644 index ac9c660eb..000000000 --- a/Plain Craft Launcher 2/Compatibility/GlobalCompatibilityAliases.cs +++ /dev/null @@ -1,7 +0,0 @@ -global using LoadState = PCL.ModBase.LoadState; -global using MyColor = PCL.ModBase.MyColor; -global using MyRect = PCL.ModBase.MyRect; -global using RouteEventArgs = PCL.ModBase.RouteEventArgs; -global using CancelledException = PCL.ModBase.CancelledException; -global using RestartException = PCL.ModBase.RestartException; -global using FileChecker = PCL.ModBase.FileChecker; \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs b/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs index 04988d0dd..77c92cb8c 100644 --- a/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs +++ b/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs @@ -1,22 +1,575 @@ +using System.Collections; +using System.Windows.Media; +using Color = System.Windows.Media.Color; +using ColorConverter = System.Windows.Media.ColorConverter; + namespace PCL; /// -/// 顶层兼容集合类型,用于逐步移除调用点中的 ModBase 前缀。 +/// 模块加载状态。 +/// +public enum LoadState +{ + Waiting, + Loading, + Finished, + Failed, + Aborted +} + +/// +/// 支持负数与浮点数的矩形。 +/// +public class MyRect +{ + public MyRect() + { + } + + public MyRect(double left, double top, double width, double height) + { + Left = left; + Top = top; + Width = width; + Height = height; + } + + public double Width { get; set; } + public double Height { get; set; } + public double Left { get; set; } + public double Top { get; set; } +} + +/// +/// 支持小数与常见 WPF / Drawing 类型互转的颜色。 +/// +public class MyColor +{ + public double a = 255d; + public double b; + public double g; + public double r; + + public MyColor() + { + } + + public MyColor(Color color) + { + a = color.A; + r = color.R; + g = color.G; + b = color.B; + } + + public MyColor(string hexString) + { + var color = (Color)ColorConverter.ConvertFromString(hexString); + a = color.A; + r = color.R; + g = color.G; + b = color.B; + } + + public MyColor(double newA, MyColor color) + { + a = newA; + r = color.r; + g = color.g; + b = color.b; + } + + public MyColor(double newR, double newG, double newB) + { + a = 255d; + r = newR; + g = newG; + b = newB; + } + + public MyColor(double newA, double newR, double newG, double newB) + { + a = newA; + r = newR; + g = newG; + b = newB; + } + + public MyColor(Brush brush) + { + var color = ((SolidColorBrush)brush).Color; + a = color.A; + r = color.R; + g = color.G; + b = color.B; + } + + public MyColor(SolidColorBrush brush) : this(brush.Color) + { + } + + public MyColor(object? obj) + { + switch (obj) + { + case null: + a = 255d; + r = 255d; + g = 255d; + b = 255d; + break; + case SolidColorBrush brush: + var color = brush.Color; + a = color.A; + r = color.R; + g = color.G; + b = color.B; + break; + default: + a = Convert.ToDouble(((dynamic)obj).A); + r = Convert.ToDouble(((dynamic)obj).R); + g = Convert.ToDouble(((dynamic)obj).G); + b = Convert.ToDouble(((dynamic)obj).B); + break; + } + } + + public static implicit operator MyColor(string value) + { + return new MyColor(value); + } + + public static implicit operator MyColor(Color value) + { + return new MyColor(value); + } + + public static implicit operator MyColor(SolidColorBrush value) + { + return new MyColor(value.Color); + } + + public static implicit operator MyColor(Brush value) + { + return new MyColor(value); + } + + public static implicit operator Color(MyColor value) + { + return Color.FromArgb( + NumberUtils.ClampToByte(value.a), + NumberUtils.ClampToByte(value.r), + NumberUtils.ClampToByte(value.g), + NumberUtils.ClampToByte(value.b)); + } + + public static implicit operator System.Drawing.Color(MyColor value) + { + return System.Drawing.Color.FromArgb( + NumberUtils.ClampToByte(value.a), + NumberUtils.ClampToByte(value.r), + NumberUtils.ClampToByte(value.g), + NumberUtils.ClampToByte(value.b)); + } + + public static implicit operator SolidColorBrush(MyColor value) + { + return new SolidColorBrush((Color)value); + } + + public static implicit operator Brush(MyColor value) + { + return new SolidColorBrush((Color)value); + } + + public static MyColor operator +(MyColor left, MyColor right) + { + return new MyColor + { + a = left.a + right.a, + r = left.r + right.r, + g = left.g + right.g, + b = left.b + right.b + }; + } + + public static MyColor operator -(MyColor left, MyColor right) + { + return new MyColor + { + a = left.a - right.a, + r = left.r - right.r, + g = left.g - right.g, + b = left.b - right.b + }; + } + + public static MyColor operator *(MyColor left, double right) + { + return new MyColor + { + a = left.a * right, + r = left.r * right, + g = left.g * right, + b = left.b * right + }; + } + + public static MyColor operator /(MyColor left, double right) + { + return new MyColor + { + a = left.a / right, + r = left.r / right, + g = left.g / right, + b = left.b / right + }; + } + + public static bool operator ==(MyColor? left, MyColor? right) + { + if (left is null && right is null) return true; + if (left is null || right is null) return false; + return left.a == right.a && left.r == right.r && left.g == right.g && left.b == right.b; + } + + public static bool operator !=(MyColor? left, MyColor? right) + { + return !(left == right); + } + + private static double Hue(double value1, double value2, double hue) + { + if (hue < 0d) hue += 1d; + if (hue > 1d) hue -= 1d; + if (hue < 0.16667d) return value1 + (value2 - value1) * 6d * hue; + if (hue < 0.5d) return value2; + if (hue < 0.66667d) return value1 + (value2 - value1) * (4d - hue * 6d); + return value1; + } + + public MyColor FromHSL(double sourceHue, double sourceSaturation, double sourceLightness) + { + if (sourceSaturation == 0d) + { + r = sourceLightness * 2.55d; + g = r; + b = r; + } + else + { + var hue = sourceHue / 360d; + var saturation = sourceSaturation / 100d; + var lightness = sourceLightness / 100d; + saturation = lightness < 0.5d + ? saturation * lightness + lightness + : saturation * (1d - lightness) + lightness; + lightness = 2d * lightness - saturation; + r = 255d * Hue(lightness, saturation, hue + 1d / 3d); + g = 255d * Hue(lightness, saturation, hue); + b = 255d * Hue(lightness, saturation, hue - 1d / 3d); + } + + a = 255d; + return this; + } + + public MyColor FromHSL2(double sourceHue, double sourceSaturation, double sourceLightness) + { + if (sourceSaturation == 0d) + { + r = sourceLightness * 2.55d; + g = r; + b = r; + } + else + { + sourceHue = (sourceHue + 3600000d) % 360d; + var centers = new[] + { + +0.1d, -0.06d, -0.3d, -0.19d, -0.15d, -0.24d, -0.32d, -0.09d, + +0.18d, +0.05d, -0.12d, -0.02d, +0.1d, -0.06d + }; + var centerIndex = sourceHue / 30d; + var lowerIndex = (int)Math.Round(Math.Floor(centerIndex)); + var visualCenter = 50d - + ((1d - centerIndex + lowerIndex) * centers[lowerIndex] + + (centerIndex - lowerIndex) * centers[lowerIndex + 1]) * sourceSaturation; + sourceLightness = (sourceLightness < visualCenter + ? sourceLightness / visualCenter + : 1d + (sourceLightness - visualCenter) / (100d - visualCenter)) * 50d; + FromHSL(sourceHue, sourceSaturation, sourceLightness); + } + + a = 255d; + return this; + } + + public MyColor Alpha(double value) + { + a = value; + return this; + } + + public override string ToString() + { + return $"({a},{r},{g},{b})"; + } + + public override bool Equals(object? obj) + { + return obj is MyColor other && this == other; + } + + public override int GetHashCode() + { + return HashCode.Combine(a, r, g, b); + } +} + +/// +/// 可以使用 Equals 和等号的 List。 /// -public class SafeList : ModBase.SafeList +public class EqualableList : List { + public override bool Equals(object? obj) + { + if (obj is not List other || other.Count != Count) + return false; + + for (var i = 0; i < other.Count; i++) + if (!EqualityComparer.Default.Equals(other[i], this[i])) + return false; + return true; + } + + public static bool operator ==(EqualableList? left, EqualableList? right) + { + return EqualityComparer>.Default.Equals(left, right); + } + + public static bool operator !=(EqualableList? left, EqualableList? right) + { + return !(left == right); + } + + public override int GetHashCode() + { + var hash = new HashCode(); + foreach (var item in this) + hash.Add(item); + return hash.ToHashCode(); + } +} + +/// +/// 线程安全的 List。枚举时返回浅表快照。 +/// +public class SafeList : IEnumerable, IDisposable, ICollection +{ + private readonly List _items; + private readonly ReaderWriterLockSlim _lock = new(); + public SafeList() { + _items = []; + } + + public SafeList(IEnumerable data) + { + _items = new List(data); + } + + public T this[int index] + { + get + { + _lock.EnterReadLock(); + try + { + return _items[index]; + } + finally + { + _lock.ExitReadLock(); + } + } + set + { + _lock.EnterWriteLock(); + try + { + _items[index] = value; + } + finally + { + _lock.ExitWriteLock(); + } + } + } + + public int Count + { + get + { + _lock.EnterReadLock(); + try + { + return _items.Count; + } + finally + { + _lock.ExitReadLock(); + } + } } - public SafeList(IEnumerable data) : base(data) + public bool IsReadOnly => false; + + public void Add(T item) + { + _lock.EnterWriteLock(); + try + { + _items.Add(item); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public bool Remove(T item) + { + _lock.EnterWriteLock(); + try + { + return _items.Remove(item); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public void Clear() + { + _lock.EnterWriteLock(); + try + { + _items.Clear(); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public bool Contains(T item) + { + _lock.EnterReadLock(); + try + { + return _items.Contains(item); + } + finally + { + _lock.ExitReadLock(); + } + } + + public void CopyTo(T[] array, int arrayIndex) + { + ToList().CopyTo(array, arrayIndex); + } + + public void Dispose() + { + _lock.Dispose(); + GC.SuppressFinalize(this); + } + + public IEnumerator GetEnumerator() + { + return ToList().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + public void RemoveAt(int index) + { + _lock.EnterWriteLock(); + try + { + _items.RemoveAt(index); + } + finally + { + _lock.ExitWriteLock(); + } + } + + public List ToList() + { + _lock.EnterReadLock(); + try + { + return new List(_items); + } + finally + { + _lock.ExitReadLock(); + } } } /// -/// 顶层兼容集合类型,用于逐步移除调用点中的 ModBase 前缀。 +/// 文件校验规则。 +/// +public class FileChecker +{ + public long actualSize = -1; + public bool canUseExistsFile = true; + public string? hash; + public bool isJson; + public long minSize = -1; + + public FileChecker(long minSize = -1, long actualSize = -1, string? hash = null, + bool canUseExistsFile = true, bool isJson = false) + { + this.actualSize = actualSize; + this.minSize = minSize; + this.hash = hash; + this.canUseExistsFile = canUseExistsFile; + this.isJson = isJson; + } + + public string Check(string localPath) + { + return LegacyFileFacade.CheckFile(localPath, minSize, actualSize, hash ?? string.Empty, isJson); + } +} + +/// +/// 指示接取到这个异常的函数进行重试。 +/// +public class RestartException : Exception +{ +} + +/// +/// 指示用户手动取消了操作,或用户已知晓操作被取消的原因。 +/// +public class CancelledException : Exception; + +/// +/// 用于储存 RaiseByMouse 的 EventArgs。 /// -public class EqualableList : ModBase.EqualableList +public sealed class RouteEventArgs(bool raiseByMouse = false) : EventArgs { + public bool handled = false; + public bool raiseByMouse = raiseByMouse; } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs b/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs deleted file mode 100644 index c06e9d575..000000000 --- a/Plain Craft Launcher 2/Compatibility/ModBase.Declarations.cs +++ /dev/null @@ -1,611 +0,0 @@ -using System.Windows.Media; -using PCL.Core.Utils; -using Brush = System.Windows.Media.Brush; -using Color = System.Windows.Media.Color; -using ColorConverter = System.Windows.Media.ColorConverter; - -namespace PCL; - -public static partial class ModBase -{ - #region 声明 - - // 下列版本信息由更新器自动修改 - public static readonly string VersionBaseName = LauncherEnvironment.VersionBaseName; - public static readonly string VersionStandardCode = LauncherEnvironment.VersionStandardCode; - public static readonly string UpstreamVersion = LauncherEnvironment.UpstreamVersion; - public static readonly string CommitHash = LauncherEnvironment.CommitHash; - public static readonly string CommitHashShort = LauncherEnvironment.CommitHashShort; - public static readonly int VersionCode = LauncherEnvironment.VersionCode; - -#if DEBUG - public const string VersionBranchName = "Debug"; - public const string VersionBranchCode = "100"; -#elif DEBUGCI - public const string VersionBranchName = "CI"; - public const string VersionBranchCode = "50"; -#else - public const string VersionBranchName = "Publish"; - public const string VersionBranchCode = "0"; -#endif - - /// - /// 主窗口句柄。 - /// - public static nint frmHandle - { - get => LauncherEnvironment.MainWindowHandle; - set => LauncherEnvironment.MainWindowHandle = value; - } - - /// - /// 程序可执行文件所在目录,以“\”结尾。 - /// - public static string exePath => LauncherPaths.ExecutableDirectoryWithSlash; - - /// - /// 程序内嵌图片文件夹路径,以“/”结尾。 - /// - public static string pathImage => LauncherPaths.ImageBaseUri; - - /// - /// 当前程序的语言。 - /// - public static string currentLang - { - get => LauncherEnvironment.CurrentLanguage; - set => LauncherEnvironment.CurrentLanguage = value; - } - - /// - /// 设置对象。 - /// - public static ModSetup setup - { - get => LauncherEnvironment.Setup; - set => LauncherEnvironment.Setup = value; - } - - /// - /// 程序的打开计时。 - /// - public static long applicationStartTick - { - get => LauncherRuntime.ApplicationStartTick; - set => LauncherRuntime.ApplicationStartTick = value; - } - - /// - /// 程序打开时的时间。 - /// - public static DateTime applicationOpenTime - { - get => LauncherRuntime.ApplicationOpenTime; - set => LauncherRuntime.ApplicationOpenTime = value; - } - - /// - /// 程序是否已结束。 - /// - public static bool isProgramEnded - { - get => LauncherRuntime.IsProgramEnded; - set => LauncherRuntime.IsProgramEnded = value; - } - - /// - /// 程序的缓存文件夹路径,以 \ 结尾。 - /// - public static string pathTemp - { - get => LauncherPaths.TempWithSlash; - set => LauncherPaths.TempWithSlash = value; - } - - /// - /// AppData 中的 PCL 文件夹路径,以 \ 结尾。 - /// - public static string pathAppdata - { - get => LauncherPaths.LegacyAppDataWithSlash; - set => LauncherPaths.LegacyAppDataWithSlash = value; - } - - /// - /// AppData 中的 PCLCE 配置文件夹路径,以 \ 结尾。 - /// - public static string pathAppdataConfig - { - get => LauncherPaths.SharedConfigWithSlash; - set => LauncherPaths.SharedConfigWithSlash = value; - } - - #endregion - - #region 自定义类 - - /// - /// 支持小数与常见类型隐式转换的颜色。 - /// - public class MyColor - { - public double a = 255d; - public double b; - public double g; - public double r; - - // 构造函数 - public MyColor() - { - } - - public MyColor(Color col) - { - a = col.A; - r = col.R; - g = col.G; - b = col.B; - } - - public MyColor(string hexString) - { - var stringColor = (Color)ColorConverter.ConvertFromString(hexString); - a = stringColor.A; - r = stringColor.R; - g = stringColor.G; - b = stringColor.B; - } - - public MyColor(double newA, MyColor col) - { - a = newA; - r = col.r; - g = col.g; - b = col.b; - } - - public MyColor(double newR, double newG, double newB) - { - a = 255d; - r = newR; - g = newG; - b = newB; - } - - public MyColor(double newA, double newR, double newG, double newB) - { - a = newA; - r = newR; - g = newG; - b = newB; - } - - public MyColor(Brush brush) - { - var color = ((SolidColorBrush)brush).Color; - a = color.A; - r = color.R; - g = color.G; - b = color.B; - } - - public MyColor(SolidColorBrush brush) - { - var color = brush.Color; - a = color.A; - r = color.R; - g = color.G; - b = color.B; - } - - public MyColor(object obj) - { - switch (obj) - { - case null: - a = 255d; - r = 255d; - g = 255d; - b = 255d; - break; - case SolidColorBrush brush: - { - // 避免反复获取 Color 对象造成性能下降 - var color = brush.Color; - a = color.A; - r = color.R; - g = color.G; - b = color.B; - break; - } - default: - a = Convert.ToDouble(((dynamic)obj).A); - r = Convert.ToDouble(((dynamic)obj).R); - g = Convert.ToDouble(((dynamic)obj).G); - b = Convert.ToDouble(((dynamic)obj).B); - break; - } - } - - // 类型转换 - public static implicit operator MyColor(string str) - { - return new MyColor(str); - } - - public static implicit operator MyColor(Color col) - { - return new MyColor(col); - } - - public static implicit operator Color(MyColor conv) - { - return Color.FromArgb( - MathByte(conv.a), - MathByte(conv.r), - MathByte(conv.g), - MathByte(conv.b)); - } - - public static implicit operator System.Drawing.Color(MyColor conv) - { - return System.Drawing.Color.FromArgb( - MathByte(conv.a), - MathByte(conv.r), - MathByte(conv.g), - MathByte(conv.b)); - } - - public static implicit operator MyColor(SolidColorBrush bru) - { - return new MyColor(bru.Color); - } - - public static implicit operator SolidColorBrush(MyColor conv) - { - return new SolidColorBrush(Color.FromArgb( - MathByte(conv.a), - MathByte(conv.r), - MathByte(conv.g), - MathByte(conv.b))); - } - - public static implicit operator MyColor(Brush bru) - { - return new MyColor(bru); - } - - public static implicit operator Brush(MyColor conv) - { - return new SolidColorBrush(Color.FromArgb( - MathByte(conv.a), - MathByte(conv.r), - MathByte(conv.g), - MathByte(conv.b))); - } - - // 颜色运算 - public static MyColor operator +(MyColor a, MyColor b) - { - return new MyColor { a = a.a + b.a, b = a.b + b.b, g = a.g + b.g, r = a.r + b.r }; - } - - public static MyColor operator -(MyColor a, MyColor b) - { - return new MyColor { a = a.a - b.a, b = a.b - b.b, g = a.g - b.g, r = a.r - b.r }; - } - - public static MyColor operator *(MyColor a, double b) - { - return new MyColor { a = a.a * b, b = a.b * b, g = a.g * b, r = a.r * b }; - } - - public static MyColor operator /(MyColor a, double b) - { - return new MyColor { a = a.a / b, b = a.b / b, g = a.g / b, r = a.r / b }; - } - - public static bool operator ==(MyColor a, MyColor b) - { - if (a is null && b is null) - return true; - if (a is null || b is null) - return false; - return a.a == b.a && a.r == b.r && a.g == b.g && a.b == b.b; - } - - public static bool operator !=(MyColor a, MyColor b) - { - if (a is null && b is null) - return false; - if (a is null || b is null) - return true; - return !(a.a == b.a && a.r == b.r && a.g == b.g && a.b == b.b); - } - - // HSL - public double Hue(double v1, double v2, double vH) - { - if (vH < 0d) - vH += 1d; - if (vH > 1d) - vH -= 1d; - if (vH < 0.16667d) - return v1 + (v2 - v1) * 6d * vH; - if (vH < 0.5d) - return v2; - if (vH < 0.66667d) - return v1 + (v2 - v1) * (4d - vH * 6d); - return v1; - } - - public MyColor FromHSL(double sH, double sS, double sL) - { - if (sS == 0d) - { - r = sL * 2.55d; - g = r; - b = r; - } - else - { - var h = sH / 360d; - var s = sS / 100d; - var l = sL / 100d; - s = l < 0.5d ? s * l + l : s * (1.0d - l) + l; - l = 2d * l - s; - r = 255d * Hue(l, s, h + 1d / 3d); - g = 255d * Hue(l, s, h); - b = 255d * Hue(l, s, h - 1d / 3d); - } - - a = 255d; - return this; - } - - public MyColor FromHSL2(double sH, double sS, double sL) - { - if (sS == 0d) - { - r = sL * 2.55d; - g = r; - b = r; - } - else - { - // 初始化 - sH = (sH + 3600000d) % 360d; - var cent = new[] - { - +0.1d, -0.06d, -0.3d, -0.19d, -0.15d, -0.24d, -0.32d, -0.09d, +0.18d, +0.05d, -0.12d, -0.02d, +0.1d, - -0.06d - }; // 0, 30, 60 - // 90, 120, 150 - // 180, 210, 240 - // 270, 300, 330 - // 最后两位与前两位一致,加是变亮,减是变暗 - // 计算色调对应的亮度片区 - var center = sH / 30.0d; - var intCenter = (int)Math.Round(Math.Floor(center)); // 亮度片区编号 - center = 50d - - ((1d - center + intCenter) * cent[intCenter] + (center - intCenter) * cent[intCenter + 1]) * - sS; - // center = 50 + (cent(intCenter) + (center - intCenter) * (cent(intCenter + 1) - cent(intCenter))) * sS - sL = (sL < center ? sL / center : 1d + (sL - center) / (100d - center)) * 50d; - FromHSL(sH, sS, sL); - } - - a = 255d; - return this; - } - - public MyColor Alpha(double sA) - { - a = sA; - return this; - } - - public override string ToString() - { - return "(" + a + "," + r + "," + g + "," + b + ")"; - } - - public override bool Equals(object obj) - { - return obj is MyColor other && a == other.a && r == other.r && g == other.g && b == other.b; - } - } - - /// - /// 支持负数与浮点数的矩形。 - /// - public class MyRect - { - // 构造函数 - public MyRect() - { - } - - public MyRect(double left, double top, double width, double height) - { - Left = left; - Top = top; - Width = width; - Height = height; - } - - // 属性 - public double Width { get; set; } - public double Height { get; set; } - public double Left { get; set; } - public double Top { get; set; } - } - - /// - /// 模块加载状态枚举。 - /// - public enum LoadState - { - Waiting, - Loading, - Finished, - Failed, - Aborted - } - - /// - /// 执行返回值。 - /// - public enum ProcessReturnValues - { - /// - /// 执行成功,或进程被中断。 - /// - Aborted = -1, - - /// - /// 执行成功。 - /// - Success = 0, - - /// - /// 执行失败。 - /// - Fail = 1, - - /// - /// 执行时出现未经处理的异常。 - /// - Exception = 2, - - /// - /// 执行超时。 - /// - Timeout = 3, - - /// - /// 取消执行。可能是由于不满足执行的前置条件。 - /// - Cancel = 4, - - /// - /// 任务成功完成。 - /// - TaskDone = 5 - } - - /// - /// 可以使用 Equals 和等号的 List。 - /// - public class EqualableList : List - { - public override bool Equals(object obj) - { - if (obj as List is null) - // 类型不同 - return false; - - // 类型相同 - var objList = (List)obj; - if (objList.Count != Count) - return false; - for (int i = 0, loopTo = objList.Count - 1; i <= loopTo; i++) - if (!objList[i].Equals(this[i])) - return false; - return true; - } - - public static bool operator ==(EqualableList left, EqualableList right) - { - return EqualityComparer>.Default.Equals(left, right); - } - - public static bool operator !=(EqualableList left, EqualableList right) - { - return !(left == right); - } - } - - #endregion - - #region 数学 - - /// - /// 2~65 进制的转换。 - /// - public static string RadixConvert(string input, int fromRadix, int toRadix) - { - return RadixUtils.Convert(input, fromRadix, toRadix); - } - - /// - /// 计算二阶贝塞尔曲线。 - /// - public static double MathBezier( - double x, - double x1, - double y1, - double x2, - double y2, - double acc = 0.01d) - { - return InterpolationUtils.CubicBezierY(x, x1, y1, x2, y2, acc); - } - - /// - /// 将一个数字限制为 0~255 的 Byte 值。 - /// - public static byte MathByte(double d) - { - return NumberUtils.ClampToByte(d); - } - - /// - /// 提供 MyColor 类型支持的 Math.Round。 - /// - public static MyColor MathRound(MyColor col, int w = 0) - { - return new MyColor - { - a = Math.Round(col.a, w), - r = Math.Round(col.r, w), - g = Math.Round(col.g, w), - b = Math.Round(col.b, w) - }; - } - - /// - /// 获取两数间的百分比。小数点精确到 6 位。 - /// - /// - public static double MathPercent(double valueA, double valueB, double percent) - { - return NumberUtils.Lerp(valueA, valueB, percent); - } - - /// - /// 获取两颜色间的百分比,根据 RGB 计算。小数点精确到 6 位。 - /// - public static MyColor MathPercent(MyColor valueA, MyColor valueB, double percent) - { - return MathRound(valueA * (1d - percent) + valueB * percent, 6); // 解决Double计算错误 - } - - /// - /// 将数值限定在某个范围内。 - /// - public static double MathClamp(double value, double min, double max) - { - return NumberUtils.Clamp(value, min, max); - } - - /// - /// 符号函数。 - /// - public static int MathSgn(double value) - { - return NumberUtils.Sign(value); - } - - #endregion -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs deleted file mode 100644 index 00584f3ad..000000000 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyFiles.cs +++ /dev/null @@ -1,272 +0,0 @@ -using System.IO; -using System.Text; - -namespace PCL; - -public static partial class ModBase -{ - #region LegacyFiles - - // 路径处理 - /// - /// 从文件路径或者 Url 获取不包含文件名的路径,或获取文件夹的父文件夹路径。 - /// 取决于原路径格式,路径以 / 或 \ 结尾。 - /// 不包含路径将会抛出异常。 - /// - public static string GetPathFromFullPath(string filePath) - { - return LegacyFileFacade.GetPathFromFullPath(filePath); - } - - /// - /// 从文件路径或者 Url 获取不包含路径的文件名。不包含文件名将会抛出异常。 - /// - public static string GetFileNameFromPath(string filePath) - { - return LegacyFileFacade.GetFileNameFromPath(filePath); - } - - /// - /// 从文件路径或者 Url 获取不包含路径与扩展名的文件名。不包含文件名将会抛出异常。 - /// - public static string GetFileNameWithoutExtentionFromPath(string filePath) - { - return LegacyFileFacade.GetFileNameWithoutExtensionFromPath(filePath); - } - - /// - /// 从文件夹路径获取文件夹名。 - /// - public static string GetFolderNameFromPath(string folderPath) - { - return LegacyFileFacade.GetFolderNameFromPath(folderPath); - } - - // 读取、写入、复制文件 - /// - /// 复制文件。会自动创建文件夹、会覆盖已有的文件。 - /// - public static void CopyFile(string fromPath, string toPath) - { - LegacyFileFacade.CopyFile(fromPath, toPath); - } - - /// - /// 读取文件,如果失败则返回空数组。 - /// - public static byte[] ReadFileBytes(string filePath, Encoding encoding = null) - { - return LegacyFileFacade.ReadBytes(filePath, encoding); - } - - /// - /// 读取文件,如果失败则返回空字符串。 - /// - public static string ReadFile(string filePath, Encoding encoding = null) - { - return LegacyFileFacade.ReadText(filePath, encoding); - } - - /// - /// 读取流中的所有文本。 - /// - public static string ReadFile(Stream stream, Encoding encoding = null) - { - return LegacyFileFacade.ReadText(stream, encoding); - } - - /// - /// 写入文件。 - /// - public static void WriteFile(string filePath, string text, bool append = false, Encoding? encoding = null) - { - LegacyFileFacade.WriteText(filePath, text, append, encoding); - } - - /// - /// 写入文件。 - /// 如果 CanThrow 设置为 False,返回是否写入成功。 - /// - public static void WriteFile(string filePath, byte[] content, bool append = false) - { - LegacyFileFacade.WriteBytes(filePath, content, append); - } - - /// - /// 将流写入文件。 - /// - public static bool WriteFile(string filePath, Stream stream) - { - return LegacyFileFacade.WriteStream(filePath, stream); - } - - /// - /// 解码 Bytes。 - /// - public static string DecodeBytes(byte[] bytes) - { - return LegacyFileFacade.DecodeBytes(bytes); - } - - public static object GetHexString(Memory bytes) - { - return LegacyFileFacade.GetHexString(bytes); - } - - // 文件校验 - /// - /// 获取文件 MD5,若失败则返回空字符串。 - /// - public static string GetFileMD5(string filePath) - { - return LegacyFileFacade.GetFileMd5(filePath); - } - - /// - /// 获取文件 SHA512,若失败则返回空字符串。 - /// - public static string GetFileSHA512(string filePath) - { - return LegacyFileFacade.GetFileSha512(filePath); - } - - /// - /// 获取文件 SHA256,若失败则返回空字符串。 - /// - public static string GetFileSHA256(string filePath) - { - return LegacyFileFacade.GetFileSha256(filePath); - } - - /// - /// 获取文件 SHA1,若失败则返回空字符串。 - /// - public static string GetFileSHA1(string filePath) - { - return LegacyFileFacade.GetFileSha1(filePath); - } - - /// - /// 获取流的 SHA1,若失败则返回空字符串。 - /// - public static string GetAuthSHA1(Stream inputStream) - { - return LegacyFileFacade.GetStreamSha1(inputStream); - } - - /// - /// 文件的校验规则。 - /// - public class FileChecker - { - public long actualSize = -1; - public bool canUseExistsFile = true; - public string hash; - public bool isJson; - public long minSize = -1; - - public FileChecker(long minSize = -1, long actualSize = -1, string hash = null, - bool canUseExistsFile = true, bool isJson = false) - { - this.actualSize = actualSize; - this.minSize = minSize; - this.hash = hash; - this.canUseExistsFile = canUseExistsFile; - this.isJson = isJson; - } - - /// - /// 检查文件。若成功则返回 Nothing,失败则返回错误的描述文本,描述文本不以句号结尾。不会抛出错误。 - /// - public string Check(string localPath) - { - return LegacyFileFacade.CheckFile(localPath, minSize, actualSize, hash, isJson); - } - } - - /// - /// 等待文件就绪可读,在指定超时时间内轮询检查文件是否存在且内容非空。 - /// - public static void WaitForFileReady(string filePath, int timeoutMs = 2000) - { - LegacyFileFacade.WaitForFileReady(filePath, timeoutMs); - } - - /// - /// 等待文件就绪可读,在指定超时时间内轮询检查文件是否存在且内容非空。 - /// - public static void WaitForFileReady(string filePath, int timeoutMs, bool requireJson) - { - LegacyFileFacade.WaitForFileReady(filePath, timeoutMs, requireJson); - } - - /// - /// 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 Jar 以 zip 方式解压。 - /// 会尝试创建,但不会清空目标文件夹。 - /// - public static void ExtractFile(string compressFilePath, string destDirectory, Encoding encode = null, - Action progressIncrementHandler = null) - { - LegacyFileFacade.ExtractFile(compressFilePath, destDirectory, encode, progressIncrementHandler); - } - - /// - /// 删除文件夹,返回删除的文件个数。通过参数选择是否抛出异常。 - /// - public static int DeleteDirectory(string path, bool ignoreIssue = false) - { - return LegacyFileFacade.DeleteDirectory(path, ignoreIssue); - } - - /// - /// 复制文件夹,失败会抛出异常。 - /// - public static void CopyDirectory(string fromPath, string toPath, Action progressIncrementHandler = null) - { - LegacyFileFacade.CopyDirectory(fromPath, toPath, progressIncrementHandler); - } - - /// - /// 遍历文件夹中的所有文件。 - /// - public static IEnumerable EnumerateFiles(string directory) - { - return LegacyFileFacade.EnumerateFiles(directory); - } - - /// - /// 若路径长度大于指定值,则将长路径转换为短路径。 - /// - public static string ShortenPath(string longPath, int shortenThreshold = 247) - { - return LegacyFileFacade.ShortenPath(longPath, shortenThreshold); - } - - public static void MoveDirectory(string sourceDir, string targetDir) - { - LegacyFileFacade.MoveDirectory(sourceDir, targetDir); - } - - public static void CreateSymbolicLink(string linkPath, string targetPath, int flags) - { - LegacyFileFacade.CreateSymbolicLink(linkPath, targetPath, flags); - } - - /// - /// 检查是否拥有某一文件夹的 I/O 权限。如果文件夹不存在,会返回 False。 - /// - public static bool CheckPermission(string path) - { - return LegacyFileFacade.CheckPermission(path); - } - - /// - /// 检查是否拥有某一文件夹的 I/O 权限。如果出错,则抛出异常。 - /// - public static void CheckPermissionWithException(string path) - { - LegacyFileFacade.CheckPermissionWithException(path); - } - - #endregion -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs deleted file mode 100644 index 1ed135bb4..000000000 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyIni.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace PCL; - -public static partial class ModBase -{ - #region LegacyIni - - /// - /// 清除某 ini 文件的运行时缓存。 - /// - /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 - public static void IniClearCache(string fileName) - { - LegacyIniStore.Shared.ClearCache(fileName); - } - - /// - /// 读取 ini 文件。这可能会使用到缓存。 - /// - /// 文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。 - /// 键。 - /// 没有找到键时返回的默认值。 - public static string ReadIni(string fileName, string key, string defaultValue = "") - { - return LegacyIniStore.Shared.Read(fileName, key, defaultValue); - } - - /// - /// 判断 ini 文件中是否包含某个键。这可能会使用到缓存。 - /// - public static bool HasIniKey(string fileName, string key) - { - return LegacyIniStore.Shared.ContainsKey(fileName, key); - } - - /// - /// 从 ini 文件中移除某个键。这会更新缓存。 - /// - public static void DeleteIniKey(string fileName, string key) - { - LegacyIniStore.Shared.Delete(fileName, key); - } - - /// - /// 写入 ini 文件,这会更新缓存。 - /// 若 Value 为 Nothing,则删除该键。 - /// - public static void WriteIni(string fileName, string key, string value) - { - LegacyIniStore.Shared.Write(fileName, key, value); - } - - #endregion -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs deleted file mode 100644 index 65ec693bb..000000000 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyLog.cs +++ /dev/null @@ -1,123 +0,0 @@ -using PCL.Core.Utils; - -namespace PCL; - -public static partial class ModBase -{ - #region Debug - - public static bool ModeDebug - { - get => LauncherRuntime.ModeDebug; - set => LauncherRuntime.ModeDebug = value; - } - - // Log - public enum LogLevel - { - /// - /// 不提示,只记录日志。 - /// - Normal = 0, - - /// - /// 只提示开发者。 - /// - Developer = 1, - - /// - /// 只提示开发者与调试模式用户。 - /// - Debug = 2, - - /// - /// 弹出提示所有用户。 - /// - Hint = 3, - - /// - /// 弹窗,不要求反馈。 - /// - Msgbox = 4, - - /// - /// 弹窗,要求反馈。 - /// - Feedback = 5, - - /// - /// 弹出 Windows 原生弹窗,要求反馈。在无法保证 WPF 窗口能正常运行时使用此级别。 - /// 在第二次触发后会直接结束程序。 - /// - Critical = 6 - } - - /// - /// 输出 Log。 - /// - /// 如果要求弹窗,指定弹窗的标题。 - public static void Log(string text, LogLevel level = LogLevel.Normal, string? title = null, - string? userSummary = null) - { - LauncherLog.Log(text, (LauncherLogLevel)level, title, userSummary); - } - - /// - /// 输出错误信息。 - /// - /// 错误描述,仅用于日志和错误详情。 - /// 可选的本地化用户摘要;不会写入日志。 - public static void Log(Exception ex, string desc, LogLevel level = LogLevel.Debug, string? title = null, - string? userSummary = null) - { - LauncherLog.Log(ex, desc, (LauncherLogLevel)level, title, userSummary); - } - - public static string Base64Decode(string text) - { - return Base64Utils.DecodeToString(text); - } - - public static string Base64Encode(string text) - { - return Base64Utils.EncodeString(text); - } - - public static string Base64Encode(byte[] bytes) - { - return Base64Utils.EncodeBytes(bytes); - } - - // 反馈 - public static void Feedback(bool showMsgbox = true, bool forceOpenLog = false) - { - LauncherFeedbackService.Feedback(showMsgbox, forceOpenLog); - } - - public static bool CanFeedback(bool showHint) - { - return LauncherFeedbackService.CanFeedback(showHint); - } - - /// - /// 在日志中输出系统诊断信息。 - /// - public static void FeedbackInfo() - { - LauncherFeedbackService.FeedbackInfo(); - } - - // 断言 - public static void DebugAssert(bool exp) - { - LauncherLog.DebugAssert(exp); - } - - // 获取当前的堆栈信息 - public static string GetStackTrace() - { - return LauncherLog.GetStackTrace(); - } - - #endregion -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs deleted file mode 100644 index 3797ff3cd..000000000 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySearch.cs +++ /dev/null @@ -1,112 +0,0 @@ -using CoreSimilaritySearch = PCL.Core.Utils.SimilaritySearch; - -namespace PCL; - -public static partial class ModBase -{ - #region 搜索 - - private static List> ToCoreSearchSources(IEnumerable sources) - { - var result = new List>(); - if (sources is null) - return result; - - foreach (var source in sources) - { - if (source.aliases is null) - continue; - result.AddRange( - source.aliases.Select(alias => new KeyValuePair(alias, source.weight))); - } - - return result; - } - - /// - /// 用于搜索的项目。 - /// - public class SearchEntry - { - /// - /// 是否完全匹配。 - /// - public bool absoluteRight; - - /// - /// 该项目对应的源数据。 - /// - public T item; - - /// - /// 该项目用于搜索的文本源。 - /// 在搜索时,会对每个文本源单独加权,但单个文本源内的多个别名只取最高的一个的相似度。 - /// - public List searchSource; - - /// - /// 相似度。 - /// - public double similarity; - } - - /// - /// 单个用于搜索的文本源。 - /// - public class SearchSource - { - public string[] aliases; - public double weight; - - public SearchSource(string[] aliases, double weight = 1) - { - this.aliases = aliases; - this.weight = weight; - } - - public SearchSource(string text, double weight = 1) - { - aliases = [text]; - this.weight = weight; - } - } - - /// - /// 本地搜索返回的最大模糊结果数。 - /// - public const int MaxLocalSearchDepth = 25; - - /// - /// 进行多段文本加权搜索,获取相似度较高的数项结果。 - /// - /// 返回的最大模糊结果数。 - /// 返回结果要求的最低相似度。 - public static List> Search( - List> entries, - string query, - int maxBlurCount = 5, - double minBlurSimilarity = 0.1d) - { - if (entries is null || entries.Count == 0) - return []; - - var coreEntries = entries - .Select((entry, index) => new Core.Utils.SearchEntry<(SearchEntry Legacy, int Index)>( - (entry, index), - ToCoreSearchSources(entry.searchSource))) - .ToList(); - - var coreResults = CoreSimilaritySearch.Search(coreEntries, query, maxBlurCount, minBlurSimilarity); - foreach (var coreEntry in coreResults) - { - coreEntry.Item.Legacy.absoluteRight = coreEntry.AbsoluteRight; - coreEntry.Item.Legacy.similarity = coreEntry.Similarity; - } - - return coreResults - .Select(result => result.Item.Legacy) - .ToList(); - } - - #endregion -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs deleted file mode 100644 index 0d7cf7365..000000000 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacySystem.cs +++ /dev/null @@ -1,386 +0,0 @@ -using System.Collections; -using System.IO; -using PCL.Core.App; -using PCL.Core.Utils; -using PCL.Core.Utils.Codecs; -using PCL.Core.Utils.Exts; - -namespace PCL; - -public static partial class ModBase -{ - #region 系统 - - public static bool IsUtf8CodePage() - { - return EncodingUtils.IsDefaultEncodingUtf8(); - } - - /// - /// 线程安全的 List。 - /// 通过在 For Each 循环中使用一个浅表副本规避多线程操作或移除自身导致的异常。 - /// - public class SafeList : IEnumerable, IDisposable, ICollection - { - private readonly List _internalList; - private readonly ReaderWriterLockSlim _lock = new(); - - public SafeList() - { - _internalList = []; - } - - public SafeList(IEnumerable data) - { - _internalList = new List(data); - } - - public T this[int index] - { - get => _internalList[index]; - set => _internalList[index] = value; - } - - public void Add(T item) - { - _lock.EnterWriteLock(); - try - { - _internalList.Add(item); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public bool Remove(T item) - { - _lock.EnterWriteLock(); - try - { - return _internalList.Remove(item); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public void Clear() - { - _lock.EnterWriteLock(); - try - { - _internalList.Clear(); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public int Count - { - get - { - _lock.EnterReadLock(); - try - { - return _internalList.Count; - } - finally - { - _lock.ExitReadLock(); - } - } - } - - public bool IsReadOnly => ((ICollection)_internalList).IsReadOnly; - - public bool Contains(T item) - { - return ((ICollection)_internalList).Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - ((ICollection)_internalList).CopyTo(array, arrayIndex); - } - - public void Dispose() - { - _lock.Dispose(); - } - - public IEnumerator GetEnumerator() - { - return ToList().GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public List ToList() - { - _lock.EnterReadLock(); - try - { - return _internalList.ToList(); - } - finally - { - _lock.ExitReadLock(); - } - } - - public void RemoveAt(int index) - { - _lock.EnterWriteLock(); - try - { - _internalList.RemoveAt(index); - } - finally - { - _lock.ExitWriteLock(); - } - } - } - - /// - /// 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。 - /// - public static string pathPure - { - get => LauncherPaths.PureAsciiDirectory; - set => LauncherPaths.PureAsciiDirectory = value; - } - - /// - /// 指示接取到这个异常的函数进行重试。 - /// - public class RestartException : Exception - { - } - - /// - /// 指示用户手动取消了操作,或用户已知晓操作被取消的原因。 - /// - public class CancelledException : Exception - { - } - - /// - /// 判断对象是否为某个泛型类型的实例。 - /// - public static bool IsInstanceOfGenericType(this Type genericType, object obj) - { - return ReflectionUtils.IsInstanceOfGenericType(genericType, obj); - } - - /// - /// 获取一个全程序内不会重复的数字(伪 Uuid)。 - /// - public static int GetUuid() - { - return LauncherRuntime.GetUuid(); - } - - /// - /// 将元素与 List 的混合体拆分为元素组。 - /// - public static List GetFullList(IList data) - { - return CollectionUtils.FlattenMixedList(data); - } - - /// - /// 数组去重。 - /// - public static List Distinct(this ICollection arr, ComparisonBoolean isEqual) - { - return CollectionUtils.DistinctByComparison(arr, (left, right) => isEqual(left, right), true); - } - - /// - /// 对集合的每个元素执行指定操作。 - /// - public static IEnumerable ForEach(this IEnumerable collection, Action action) - { - foreach (var item in collection) - action(item); - return collection; - } - - /// - /// 用于储存 RaiseByMouse 的 EventArgs。 - /// - public sealed class RouteEventArgs(bool raiseByMouse = false) : EventArgs - { - public bool handled = false; - public bool raiseByMouse = raiseByMouse; - } - - /// - /// 前台运行文件。 - /// - public static void ShellOnly(string fileName, string arguments = "") - { - LauncherProcess.ShellOnly(fileName, arguments); - } - - /// - /// 前台运行文件并返回返回值。 - /// - public static ProcessReturnValues ShellAndGetExitCode(string fileName, string arguments = "", int timeout = 1000000) - { - return (ProcessReturnValues)LauncherProcess.ShellAndGetExitCode(fileName, arguments, timeout); - } - - /// - /// 静默运行文件并返回输出流字符串。执行失败会抛出异常。 - /// - public static string ShellAndGetOutput(string fileName, string arguments = "", int timeout = 1000000, - string workingDirectory = null) - { - return LauncherProcess.ShellAndGetOutput(fileName, arguments, timeout, workingDirectory); - } - - /// - /// 在新的工作线程中执行代码。 - /// - public static Thread RunInNewThread(Action action, string name = null, - ThreadPriority priority = ThreadPriority.Normal) - { - return Basics.RunInNewThread(action, name ?? "Runtime New Invoke " + GetUuid() + "#", priority); - } - - /// - /// 确保在 UI 线程中执行代码。 - /// 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。 - /// - public static Output RunInUiWait(Func action) - { - return UiThread.Invoke(action); - } - - /// - /// 确保在 UI 线程中执行代码。 - /// 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。 - /// - public static void RunInUiWait(Action action) - { - UiThread.Invoke(action); - } - - /// - /// 确保在 UI 线程中执行代码,代码按触发顺序执行。 - /// 如果当前并非 UI 线程,也不阻断当前线程的执行。 - /// - public static void RunInUi(Action action, bool forceWaitUntilLoaded = false) - { - UiThread.Post(action, forceWaitUntilLoaded); - } - - /// - /// 确保在工作线程中执行代码。 - /// - public static void RunInThread(Action action) - { - UiThread.RunInThread(action); - } - - /// - /// 使用优化的归并排序算法进行稳定排序。 - /// - public static List Sort(this IList list, ComparisonBoolean sortRule) - { - return SortUtils.Sort(list, (left, right) => sortRule(left, right)); - } - - public delegate bool ComparisonBoolean(T left, T right); - - /// - /// 返回列表的浅表副本。 - /// - public static IList Clone(this IList list) - { - return new List(list); - } - - /// - /// 尝试从字典中获取某项,如果该项不存在,则返回默认值。 - /// - public static TValue GetOrDefault( - this Dictionary dict, - TKey key, - TValue defaultValue = default) - { - return DictionaryExtensions.GetOrDefault(dict, key, defaultValue); - } - - /// - /// 将某项添加到以列表作为值的字典中。 - /// - public static void AddToList( - this Dictionary> dict, - TKey key, - TValue value) - { - DictionaryExtensions.AddToList(dict, key, value); - } - - /// - /// 获取程序启动参数。 - /// - public static object GetProgramArgument(string name, object? defaultValue = null) - { - return LauncherArguments.Get(name, defaultValue); - } - - /// - /// 打开网页。 - /// - public static void OpenWebsite(string url) - { - LauncherProcess.OpenWebsite(url); - } - - /// - /// 打开 explorer。 - /// 若不以 \ 结尾,则将视作文件路径,打开并选中此文件。 - /// - public static void OpenExplorer(string location) - { - LauncherProcess.OpenExplorer(location); - } - - /// - /// 设置剪贴板。将在另一线程运行,且不会抛出异常。 - /// - public static void ClipboardSet(string text, bool showSuccessHint = true) - { - LauncherProcess.ClipboardSet(text, showSuccessHint); - } - - /// - /// 从剪切板粘贴文件或文件夹 - /// - public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool copyDir = true) - { - return LauncherProcess.PasteFileFromClipboard(dest, copyFile, copyDir); - } - - /// - /// 获取程序打包资源的输入流。 - /// - public static Stream GetResourceStream(string path) - { - return Basics.GetResourceStream(path); - } - - #endregion -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs deleted file mode 100644 index bd7d80e1e..000000000 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyText.cs +++ /dev/null @@ -1,397 +0,0 @@ -using System.Collections; -using System.Runtime.CompilerServices; -using System.Text; -using System.Text.RegularExpressions; -using Microsoft.VisualBasic; -using PCL.Core.App.Localization; -using PCL.Core.IO; -using PCL.Core.Utils; -using PCL.Core.Utils.Exts; -using PCL.Core.Utils.Hash; - -namespace PCL; - -public static partial class ModBase -{ - #region 文本 - - public static char vbLq = Convert.ToChar(8220); - public static char vbRq = Convert.ToChar(8221); - - /// - /// 返回一个枚举对应的字符串。 - /// - /// 一个已经实例化的枚举类型。 - public static string GetStringFromEnum(Enum enumData) - { - return Enum.GetName(enumData.GetType(), enumData); - } - - /// - /// 将文件大小转化为适合的文本形式,如“1.28 M”。 - /// - /// 以字节为单位的大小表示。 - public static string GetString(long fileSize) - { - return ByteStream.GetReadableLength(fileSize, provider: Lang.Culture); - } - - /// - /// 获取 JSON 对象。 - /// - public static JsonNode GetJson(string data) - { - try - { - return JsonCompat.ParseNode(data); - } - catch (Exception ex) - { - var dataText = data ?? ""; - var length = dataText.Length; - throw new Exception("格式化 JSON 失败:" + (length > 2000 - ? string.Concat(dataText.AsSpan(0, 500), $"...(全长 {length} 个字符)...", dataText.AsSpan(length - 500)) - : dataText), ex); - } - } - - /// - /// 将第一个字符转换为大写,其余字符转换为小写。 - /// - public static string Capitalize(this string word) - { - return TextUtils.CapitalizeInvariant(word); - } - - /// - /// 将字符串统一至某个长度,过短则以 Code 将其右侧填充,过长则截取靠左的指定长度。 - /// - public static string StrFill(string str, string code, byte length) - { - return TextUtils.LeftPadOrTrim(str, code, length); - } - - /// - /// 将一个小数显示为固定的小数点后位数形式,将向零取整。 - /// 如 12 保留 2 位则输出 12.00,而 95.678 保留 2 位则输出 95.67。 - /// - public static string StrFillNum(double num, int length) - { - return Lang.Number(num, $"F{length}"); - } - - /// - /// 移除字符串首尾的标点符号、回车,以及括号中、冒号后的补充说明内容。 - /// - public static object StrTrim(string str, bool removeQuote = true) - { - return TextUtils.TrimDisplayName(str, removeQuote); - } - - /// - /// 连接字符串。 - /// - public static string Join(this IEnumerable list, string split) - { - var builder = new StringBuilder(); - var isFirst = true; - foreach (var element in list) - { - if (isFirst) - isFirst = false; - else - builder.Append(split); - if (element is not null) - builder.Append(element); - } - - return builder.ToString(); - } - - /// - /// 分割字符串。 - /// - public static string[] Split(this string fullStr, string splitStr) - { - return splitStr.Length == 1 - ? fullStr.Split(splitStr[0]) - : fullStr.Split([splitStr], StringSplitOptions.None); - } - - /// - /// 获取字符串哈希值。 - /// - public static ulong GetHash(string str) - { - var getHashRet = 5381UL; - for (int i = 0, loopTo = str.Length - 1; i <= loopTo; i++) - getHashRet = (getHashRet << 5) ^ getHashRet ^ str[i]; - return getHashRet ^ 0xA98F501BC684032FUL; - } - - /// - /// 获取字符串 MD5。 - /// - public static string GetStringMD5(string str) - { - return (string)GetHexString(MD5Provider.Instance.ComputeHash(str)); - } - - /// - /// 检查字符串中的字符是否均为 ASCII 字符。 - /// - public static bool IsASCII(this string input) - { - return input.All(c => c < 128); - } - - /// - /// 获取在子字符串第一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024。 - /// 如果未找到子字符串则不裁切。 - /// - public static string BeforeFirst(this string str, string text, bool ignoreCase = false) - { - return StringSliceExtensions.BeforeFirst(str, text, ignoreCase); - } - - /// - /// 获取在子字符串最后一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024/11。 - /// 如果未找到子字符串则不裁切。 - /// - public static string BeforeLast(this string str, string text, bool ignoreCase = false) - { - return StringSliceExtensions.BeforeLast(str, text, ignoreCase); - } - - /// - /// 获取在子字符串第一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 11/08。 - /// 如果未找到子字符串则不裁切。 - /// - public static string AfterFirst(this string str, string text, bool ignoreCase = false) - { - return StringSliceExtensions.AfterFirst(str, text, ignoreCase); - } - - /// - /// 获取在子字符串最后一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 08。 - /// 如果未找到子字符串则不裁切。 - /// - public static string AfterLast(this string str, string text, bool ignoreCase = false) - { - return StringSliceExtensions.AfterLast(str, text, ignoreCase); - } - - /// - /// 获取处于两个子字符串之间的部分,裁切尽可能多的内容。 - /// 等效于 AfterLast 后接 BeforeFirst。 - /// 如果未找到子字符串则不裁切。 - /// - public static string Between(this string str, string after, string before, bool ignoreCase = false) - { - return StringSliceExtensions.Between(str, after, before, ignoreCase); - } - - /// - /// 高速的 StartsWith。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool StartsWithF(this string str, string prefix, bool ignoreCase = false) - { - return str.StartsWith(prefix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 高速的 EndsWith。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool EndsWithF(this string str, string suffix, bool ignoreCase = false) - { - return str.EndsWith(suffix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 支持可变大小写判断的 Contains。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool ContainsF(this string str, string subStr, bool ignoreCase = false) - { - return str.IndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0; - } - - /// - /// 高速的 IndexOf。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfF(this string str, string subStr, bool ignoreCase = false) - { - return str.IndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 高速的 IndexOf。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfF(this string str, string subStr, int startIndex, bool ignoreCase = false) - { - return str.IndexOf(subStr, startIndex, - ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 高速的 LastIndexOf。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfF(this string str, string subStr, bool ignoreCase = false) - { - return str.LastIndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 高速的 LastIndexOf。 - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfF(this string str, string subStr, int startIndex, bool ignoreCase = false) - { - return str.LastIndexOf(subStr, startIndex, - ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - /// - /// 不会报错的 Val。 - /// 如果输入有误,返回 0。 - /// - public static double Val(object str) - { - try - { - return str is "&" ? 0d : Conversion.Val(str); - } - catch - { - return 0d; - } - } - - // 转义 - /// - /// 为字符串进行 XML 转义。 - /// - public static string EscapeXml(string str) - { - if (str.StartsWithF("{")) - str = "{}" + str; // #4187 - return TextUtils.EscapeXml(str); - } - - /// - /// 为字符串进行 Like 关键字转义。 - /// - public static string EscapeLikePattern(string input) - { - return TextUtils.EscapeLikePattern(input); - } - - // 正则 - /// - /// 搜索字符串中的所有正则匹配项。 - /// - public static List RegexSearch(this string str, string regex, RegexOptions options = RegexOptions.None) - { - try - { - return RegexExtensions.RegexSearch(str, regex, options); - } - catch (Exception ex) - { - Log(ex, "正则匹配全部项出错"); - return []; - } - } - - /// - /// 搜索字符串中的所有正则匹配项。 - /// - /// 要搜索的字符串 - /// 正则表达式对象 - /// 所有匹配项的列表 - public static List RegexSearch(this string str, Regex regex) - { - try - { - return regex.Matches(str).Select(item => item.Value).ToList(); - } - catch (Exception ex) - { - Log(ex, "正则匹配全部项出错"); - return []; - } - } - - /// - /// 获取字符串中的第一个正则匹配项,若无匹配则返回 Nothing。 - /// - public static string RegexSeek(this string str, string regex, RegexOptions options = RegexOptions.None) - { - try - { - return RegexExtensions.RegexSeek(str, regex, options); - } - catch (Exception ex) - { - Log(ex, "正则匹配第一项出错"); - return null; - } - } - - /// - /// 获取字符串中的第一个正则匹配项,若无匹配则返回 Nothing。 - /// - public static string RegexSeek(this string str, Regex regex, RegexOptions options = RegexOptions.None) - { - try - { - return RegexExtensions.RegexSeek(str, regex); - } - catch (Exception ex) - { - Log(ex, "正则匹配第一项出错"); - return null; - } - } - - /// - /// 检查字符串是否匹配某正则模式。 - /// - public static bool RegexCheck(this string str, string regex, RegexOptions options = RegexOptions.None) - { - try - { - return RegexExtensions.RegexCheck(str, regex, options); - } - catch (Exception ex) - { - Log(ex, "正则检查出错"); - return false; - } - } - - /// - /// 进行正则替换,会抛出错误。 - /// - public static string RegexReplace(this string allContents, string searchRegex, string replaceTo, - RegexOptions options = RegexOptions.None) - { - return RegexExtensions.RegexReplace(allContents, searchRegex, replaceTo, options); - } - - /// - /// 对每个正则匹配分别进行替换,会抛出错误。 - /// - public static string RegexReplaceEach(this string allContents, string searchRegex, MatchEvaluator replaceTo, - RegexOptions options = RegexOptions.None) - { - return RegexExtensions.RegexReplaceEach(allContents, searchRegex, replaceTo, options); - } - - #endregion -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs b/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs deleted file mode 100644 index ddd9584ae..000000000 --- a/Plain Craft Launcher 2/Compatibility/ModBase.LegacyUi.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Xml.Linq; - -namespace PCL; - -public static partial class ModBase -{ - #region UI - - public static void SetLaunchFont(string fontName = null) - { - LauncherFontService.SetLaunchFont(fontName); - } - - // 边距改变 - /// - /// 相对增减控件的左边距。 - /// - public static void DeltaLeft(FrameworkElement control, double newValue) - { - LayoutExtensions.DeltaLeft(control, newValue); - } - - /// - /// 设置控件的左边距。(仅针对置左控件) - /// - public static void SetLeft(FrameworkElement control, double newValue) - { - LayoutExtensions.SetLeft(control, newValue); - } - - /// - /// 相对增减控件的上边距。 - /// - public static void DeltaTop(FrameworkElement control, double newValue) - { - LayoutExtensions.DeltaTop(control, newValue); - } - - /// - /// 设置控件的顶边距。(仅针对置上控件) - /// - public static void SetTop(FrameworkElement control, double newValue) - { - LayoutExtensions.SetTop(control, newValue); - } - - // DPI 转换 - public static int dpi => DpiUtils.Dpi; - - /// - /// 将经过 DPI 缩放的 WPF 尺寸转化为实际的像素尺寸。 - /// - public static double GetPixelSize(double wPFSize) - { - return DpiUtils.GetPixelSize(wPFSize); - } - - /// - /// 将实际的像素尺寸转化为经过 DPI 缩放的 WPF 尺寸。 - /// - public static double GetWPFSize(double pixelSize) - { - return DpiUtils.GetWpfSize(pixelSize); - } - - // UI 截图 - /// - /// 将某个控件的呈现转换为图片。 - /// - public static ImageBrush ControlBrush(FrameworkElement uI) - { - return VisualCapture.ControlBrush(uI); - } - - /// - /// 将某个控件的模拟呈现转换为图片。 - /// - public static ImageBrush ControlBrush(FrameworkElement uI, double width, double height, double left = 0d, - double top = 0d) - { - return VisualCapture.ControlBrush(uI, width, height, left, top); - } - - /// - /// 将 UI 内容固定为图片并进行 Clear。 - /// - public static void ControlFreeze(Panel uI) - { - VisualCapture.ControlFreeze(uI); - } - - /// - /// 将 UI 内容固定为图片并进行 Clear。 - /// - public static void ControlFreeze(Border uI) - { - VisualCapture.ControlFreeze(uI); - } - - /// - /// 将 XElement 转换为对应 UI 对象(不返回 XAML 清理结果)。 - /// - public static object GetObjectFromXML(XElement str) - { - return CustomXamlLoader.Load(str); - } - - /// - /// 将 XML 转换为对应 UI 对象。 - /// - public static object GetObjectFromXML(string str) - { - return CustomXamlLoader.Load(str); - } - - /// - /// 将 XML 转换为对应 UI 对象,并输出 XAML 清理结果。 - /// - public static object GetObjectFromXML(string str, out XamlEventSanitizer.SanitizeResult sanitizeResult) - { - return CustomXamlLoader.Load(str, out sanitizeResult); - } - - /// - /// 当前线程是否为主线程。 - /// - public static bool RunInUi() - { - return UiThread.CheckAccess(); - } - - #endregion -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/MyImage.cs b/Plain Craft Launcher 2/Controls/MyImage.cs index dc2b5f24f..5a0a95421 100644 --- a/Plain Craft Launcher 2/Controls/MyImage.cs +++ b/Plain Craft Launcher 2/Controls/MyImage.cs @@ -129,7 +129,7 @@ public static Task DownloadImageAsync(string url) public static string GetTempPath(string url) { - return Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{LauncherText.GetStringMD5(url)}.png"); + return Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{LauncherText.GetStringMd5(url)}.png"); } private static readonly ConcurrentDictionary> _downloadTasks = new(); diff --git a/Plain Craft Launcher 2/Controls/MyVirtualizingElement.cs b/Plain Craft Launcher 2/Controls/MyVirtualizingElement.cs index a143c3fc1..4409543c2 100644 --- a/Plain Craft Launcher 2/Controls/MyVirtualizingElement.cs +++ b/Plain Craft Launcher 2/Controls/MyVirtualizingElement.cs @@ -75,11 +75,12 @@ public FrameworkElement Init() /// public static FrameworkElement TryInit(FrameworkElement element) { - if (typeof(MyVirtualizingElement<>).IsInstanceOfGenericType(element)) + if (ReflectionUtils.IsInstanceOfGenericType(typeof(MyVirtualizingElement<>), element)) { var method = element.GetType().GetMethod("Init", Type.EmptyTypes); return (FrameworkElement)method.Invoke(element, null); } - return element is MyVirtualizingElement ? ((MyVirtualizingElement)element).Init() : element; + + return element is MyVirtualizingElement virtualizingElement ? virtualizingElement.Init() : element; } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/GlobalUsings.cs b/Plain Craft Launcher 2/GlobalUsings.cs new file mode 100644 index 000000000..a0ad62114 --- /dev/null +++ b/Plain Craft Launcher 2/GlobalUsings.cs @@ -0,0 +1,5 @@ +global using PCL.Core.IO; +global using PCL.Core.UI; +global using PCL.Core.Utils; +global using PCL.Core.Utils.Exts; +global using PCL.Core.Utils.OS; \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs b/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs index 40e13cf23..094491265 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs @@ -1,9 +1,7 @@ -using PCL.Core.Utils; - namespace PCL; /// -/// PCL2 数值与旧颜色插值工具。用于替代调用点中的 ModBase 数学 API。 +/// PCL2 数值与旧颜色插值工具。用于承载 PCL2 数学 API。 /// public static class LauncherMath { diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs b/Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs index d63a6ee6b..f6134e93e 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs @@ -1,9 +1,7 @@ -using PCL.Core.Utils; - namespace PCL; /// -/// 运行期状态,承接历史 ModBase 全局运行态字段。 +/// 运行期状态,承接启动器全局运行态字段。 /// public static class LauncherRuntime { diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherText.cs b/Plain Craft Launcher 2/Infrastructure/LauncherText.cs index d3b99fb3d..0226527f3 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherText.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherText.cs @@ -1,15 +1,13 @@ -using System.Collections; +using System.Collections; using System.Text.RegularExpressions; using Microsoft.VisualBasic; using PCL.Core.App.Localization; -using PCL.Core.IO; -using PCL.Core.Utils; using PCL.Core.Utils.Hash; namespace PCL; /// -/// PCL2 文本、兼容解析与展示格式化工具。用于替代调用点中的 ModBase 文本相关 API。 +/// PCL2 文本、兼容解析与展示格式化工具。用于承载 PCL2 文本相关 API。 /// public static class LauncherText { @@ -50,13 +48,13 @@ public static object StrTrim(string str, bool removeQuote = true) public static ulong GetHash(string str) { - var hash = 5381UL; - for (var i = 0; i < str.Length; i++) - hash = (hash << 5) ^ hash ^ str[i]; + var hash = str.Aggregate( + 5381UL, + (current, t) => (current << 5) ^ current ^ t); return hash ^ 0xA98F501BC684032FUL; } - public static string GetStringMD5(string str) + public static string GetStringMd5(string str) { return BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(str).AsSpan()); } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs b/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs index 390d32da7..cd3cc462f 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs @@ -291,8 +291,7 @@ public McInstanceInfo Info } // 从 JSON 的 ID 中获取 - regex = ((string)JsonObject["id"]).RegexSeek(RegexPatterns.MinecraftJsonVersion, - RegexOptions.IgnoreCase); + regex = ((string)JsonObject["id"]).RegexSeek(RegexPatterns.MinecraftJsonVersion); if (regex is not null) { field.VanillaName = regex; @@ -303,7 +302,7 @@ public McInstanceInfo Info LauncherLog.Log("[Minecraft] 无法完全确认 MC 版本号的版本:" + Name); field.Reliable = false; // 从文件夹名中获取 - regex = Name.RegexSeek(RegexPatterns.MinecraftJsonVersion, RegexOptions.IgnoreCase); + regex = Name.RegexSeek(RegexPatterns.MinecraftJsonVersion); if (regex is not null) { field.VanillaName = regex; @@ -314,7 +313,7 @@ public McInstanceInfo Info var jsonRaw = (JsonObject)JsonObject.DeepClone(); jsonRaw.Remove("libraries"); var jsonRawText = jsonRaw.ToString(); - regex = jsonRawText.RegexSeek(RegexPatterns.MinecraftJsonVersion, RegexOptions.IgnoreCase); + regex = jsonRawText.RegexSeek(RegexPatterns.MinecraftJsonVersion); if (regex is not null) { field.VanillaName = regex; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs index 11ac2046c..ae89c95c9 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs @@ -1445,7 +1445,7 @@ private async Task GetChineseDescriptionAsync() var para = FromCurseForge ? "modId" : "project_id"; string result = null; - var descHash = $"{Id}{LauncherText.GetStringMD5(Description)}"; + var descHash = $"{Id}{LauncherText.GetStringMd5(Description)}"; var cacheFilePath = $@"{LauncherPaths.TempWithSlash}Cache\CompTranslation.ini"; var cacheTranslation = LegacyIniStore.Shared.Read(cacheFilePath, descHash); if (!string.IsNullOrWhiteSpace(cacheTranslation)) @@ -1784,9 +1784,9 @@ public KeyValuePair GetControlTitle(bool hasModLoaderDescription if (isModLoader && !ex.Contains("版") && lowerEx.Replace("forge", "").Replace("fabric", "").Replace("quilt", "").Length <= 3) - ex = ex.Replace("Edition", "", StringComparison.OrdinalIgnoreCase) + ex = TextUtils.CapitalizeInvariant(ex.Replace("Edition", "", StringComparison.OrdinalIgnoreCase) .Replace("edition", "", StringComparison.OrdinalIgnoreCase) - .Trim().Capitalize() + Lang.Text("Download.Comp.Detail.CompItem.EditionSuffix"); + .Trim()) + Lang.Text("Download.Comp.Detail.CompItem.EditionSuffix"); // 规范化名称大小写 ex = ex.Replace("forge", "Forge").Replace("neo", "Neo").Replace("fabric", "Fabric") diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs index 2595fa171..b81b2d339 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs @@ -622,7 +622,7 @@ public static List McLibNetFilesFromTokens(List libs, } // 去重并返回 - return result.Distinct((a, b) => (a.LocalPath ?? "") == (b.LocalPath ?? "")); + return CollectionUtils.DistinctByComparison(result, (a, b) => (a.LocalPath ?? "") == (b.LocalPath ?? ""), true); } /// diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs index ce2c06e2a..6c71031ae 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs @@ -1163,7 +1163,7 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = LauncherText.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); + var md5 = LauncherText.GetStringMd5(logoItem.Length + logoItem.CompressedLength + path); Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { @@ -1256,7 +1256,7 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = LauncherText.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); + var md5 = LauncherText.GetStringMd5(logoItem.Length + logoItem.CompressedLength + path); Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { @@ -1321,7 +1321,7 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = LauncherText.GetStringMD5(logoItem.Length + logoItem.CompressedLength + path); + var md5 = LauncherText.GetStringMd5(logoItem.Length + logoItem.CompressedLength + path); Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { @@ -1614,7 +1614,7 @@ private void LookupMetadata(ZipArchive jar) if (packPngEntry is not null) try { - var md5 = LauncherText.GetStringMD5(packPngEntry.Length + packPngEntry.CompressedLength + path); + var md5 = LauncherText.GetStringMd5(packPngEntry.Length + packPngEntry.CompressedLength + path); Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = packPngEntry.Open()) { diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs index ab7089bf7..f3bdd24d6 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs @@ -90,7 +90,7 @@ private List LoaderInput() LauncherLog.Log(ex, "[Favorites] 加载收藏夹列表时出错"); } - return (List)targetList.Clone(); // 复制而不是直接引用! + return targetList is null ? [] : [..targetList]; // 复制而不是直接引用! } private void CompFavoritesGet(ModLoader.LoaderTask, List> task) @@ -465,7 +465,7 @@ private void Load_State(object sender, MyLoading.MyLoadingState state, MyLoading private void Btn_FavoritesCancel_Clicked(object sender, RouteEventArgs e) { - foreach (var Items in selectedItemList.Clone()) + foreach (var Items in new List(selectedItemList)) Items_CancelFavorites(Items); if (compItemList.Any()) { diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs index 9226128dd..6b6d0185b 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs @@ -1719,7 +1719,8 @@ private void DoSort() // 批量更新UI元素 PanList.Children.Clear(); - items.ForEach(i => PanList.Children.Add(i)); + foreach (var item in items) + PanList.Children.Add(item); } catch (Exception ex) diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs index d98fa9cea..c67f3372c 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs @@ -191,7 +191,7 @@ private void RefreshUI() if (File.Exists(saveLogo)) { var target = - $@"{PageInstanceLeft.McInstance.PathInstance}PCL\ImgCache\{LauncherText.GetStringMD5(saveLogo)}.png"; + $@"{PageInstanceLeft.McInstance.PathInstance}PCL\ImgCache\{LauncherText.GetStringMd5(saveLogo)}.png"; LegacyFileFacade.CopyFile(saveLogo, target); saveLogo = target; } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs index 03896bfd8..433cb2d2e 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs @@ -980,7 +980,8 @@ private void DoSort() // 批量更新UI元素 PanList.Children.Clear(); - items.ForEach(i => PanList.Children.Add(i)); + foreach (var item in items) + PanList.Children.Add(item); } catch (Exception ex) diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs index 2d9f1c5ba..cf8940ff0 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUpdate.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using PCL.Core.App; @@ -160,7 +160,7 @@ public void BtnUpdate_Timer() private void BtnUpdate_Click(object sender, MouseButtonEventArgs e) { // 检查 .NET 版本 - if (!updateInfo.VersionName.StartsWithF("2.13.") && !ModBase + if (!updateInfo.VersionName.StartsWithF("2.13.") && !LauncherProcess .ShellAndGetOutput("cmd", "/c dotnet --list-runtimes") .ContainsF("Microsoft.WindowsDesktop.App 8.0.", true)) { From 9ae418a5d03d654ae86006a82f8074a26a399121 Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 1 Jul 2026 03:26:29 +0800 Subject: [PATCH 07/16] types --- PCL.Core.Test/Utils/ConcurrentListTest.cs | 30 ++ PCL.Core/Utils/ConcurrentList.cs | 176 +++++++++++ .../Controls/RouteEventArgs.cs | 10 + Plain Craft Launcher 2/FormMain.xaml.cs | 2 +- .../Modules/Base/LoadState.cs | 13 + .../Modules/Base/LoaderInputList.cs | 30 ++ .../Modules/Base/ModAnimation.cs | 16 +- .../Modules/Base/ModLoader.cs | 6 +- .../Minecraft/LaunchRestartException.cs | 6 + .../Modules/Minecraft/ModAssets.cs | 6 +- .../Modules/Minecraft/ModComp.cs | 4 +- .../Modules/Minecraft/ModDownload.cs | 6 +- .../Modules/Minecraft/ModJava.cs | 4 +- .../Modules/Minecraft/ModLaunch.cs | 4 +- .../Modules/Minecraft/ModLibrary.cs | 12 +- .../Modules/Minecraft/ModModpack.cs | 60 ++-- Plain Craft Launcher 2/Modules/ModLink.cs | 4 +- .../Modules/Network/Facade/ModNet.cs | 15 +- .../Modules/Network/Loaders/LoaderDownload.cs | 10 +- .../Modules/Network/Management/NetManager.cs | 4 +- .../Modules/Network/Models/DownloadFile.cs | 12 +- .../Network/Models/FileCheckOptions.cs | 28 ++ .../Modules/UI/HintService.cs | 5 +- .../UI/Theme/MyColor.cs} | 283 ------------------ .../Pages/PageDownload/ModDownloadLib.cs | 113 ++++--- .../Pages/PageLaunch/MySkin.xaml.cs | 8 +- .../Pages/PageLaunch/PageLaunchLeft.xaml.cs | 30 +- 27 files changed, 460 insertions(+), 437 deletions(-) create mode 100644 PCL.Core.Test/Utils/ConcurrentListTest.cs create mode 100644 PCL.Core/Utils/ConcurrentList.cs create mode 100644 Plain Craft Launcher 2/Controls/RouteEventArgs.cs create mode 100644 Plain Craft Launcher 2/Modules/Base/LoadState.cs create mode 100644 Plain Craft Launcher 2/Modules/Base/LoaderInputList.cs create mode 100644 Plain Craft Launcher 2/Modules/Minecraft/LaunchRestartException.cs create mode 100644 Plain Craft Launcher 2/Modules/Network/Models/FileCheckOptions.cs rename Plain Craft Launcher 2/{Compatibility/LauncherLegacyTypes.cs => Modules/UI/Theme/MyColor.cs} (57%) diff --git a/PCL.Core.Test/Utils/ConcurrentListTest.cs b/PCL.Core.Test/Utils/ConcurrentListTest.cs new file mode 100644 index 000000000..046ac6fc2 --- /dev/null +++ b/PCL.Core.Test/Utils/ConcurrentListTest.cs @@ -0,0 +1,30 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.Utils; + +namespace PCL.Core.Test.Utils; + +[TestClass] +public class ConcurrentListTest +{ + [TestMethod] + public void EnumerationUsesSnapshot() + { + var list = new ConcurrentList([1, 2]); + var snapshot = list.ToList(); + + list.Add(3); + + CollectionAssert.AreEqual(new[] { 1, 2 }, snapshot); + CollectionAssert.AreEqual(new[] { 1, 2, 3 }, list.ToList()); + } + + [TestMethod] + public void RemoveAtUpdatesList() + { + var list = new ConcurrentList(["a", "b", "c"]); + + list.RemoveAt(1); + + CollectionAssert.AreEqual(new[] { "a", "c" }, list.ToList()); + } +} \ No newline at end of file diff --git a/PCL.Core/Utils/ConcurrentList.cs b/PCL.Core/Utils/ConcurrentList.cs new file mode 100644 index 000000000..3d1c1da93 --- /dev/null +++ b/PCL.Core/Utils/ConcurrentList.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace PCL.Core.Utils; + +/// +/// Thread-safe list wrapper whose enumeration returns a shallow snapshot. +/// +public sealed class ConcurrentList : ICollection, IReadOnlyList, IDisposable +{ + private readonly List _items; + private readonly ReaderWriterLockSlim _sync = new(); + + public ConcurrentList() + { + _items = []; + } + + public ConcurrentList(IEnumerable items) + { + ArgumentNullException.ThrowIfNull(items); + _items = items.ToList(); + } + + public T this[int index] + { + get + { + _sync.EnterReadLock(); + try + { + return _items[index]; + } + finally + { + _sync.ExitReadLock(); + } + } + set + { + _sync.EnterWriteLock(); + try + { + _items[index] = value; + } + finally + { + _sync.ExitWriteLock(); + } + } + } + + public int Count + { + get + { + _sync.EnterReadLock(); + try + { + return _items.Count; + } + finally + { + _sync.ExitReadLock(); + } + } + } + + public bool IsReadOnly => false; + + public void Add(T item) + { + _sync.EnterWriteLock(); + try + { + _items.Add(item); + } + finally + { + _sync.ExitWriteLock(); + } + } + + public bool Remove(T item) + { + _sync.EnterWriteLock(); + try + { + return _items.Remove(item); + } + finally + { + _sync.ExitWriteLock(); + } + } + + public void RemoveAt(int index) + { + _sync.EnterWriteLock(); + try + { + _items.RemoveAt(index); + } + finally + { + _sync.ExitWriteLock(); + } + } + + public void Clear() + { + _sync.EnterWriteLock(); + try + { + _items.Clear(); + } + finally + { + _sync.ExitWriteLock(); + } + } + + public bool Contains(T item) + { + _sync.EnterReadLock(); + try + { + return _items.Contains(item); + } + finally + { + _sync.ExitReadLock(); + } + } + + public void CopyTo(T[] array, int arrayIndex) + { + Snapshot().CopyTo(array, arrayIndex); + } + + public List Snapshot() + { + _sync.EnterReadLock(); + try + { + return [.._items]; + } + finally + { + _sync.ExitReadLock(); + } + } + + public List ToList() + { + return Snapshot(); + } + + public IEnumerator GetEnumerator() + { + return Snapshot().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Dispose() + { + _sync.Dispose(); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/RouteEventArgs.cs b/Plain Craft Launcher 2/Controls/RouteEventArgs.cs new file mode 100644 index 000000000..addbdb532 --- /dev/null +++ b/Plain Craft Launcher 2/Controls/RouteEventArgs.cs @@ -0,0 +1,10 @@ +namespace PCL; + +/// +/// 用于储存 RaiseByMouse 的 EventArgs。 +/// +public sealed class RouteEventArgs(bool raiseByMouse = false) : EventArgs +{ + public bool handled = false; + public bool raiseByMouse = raiseByMouse; +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/FormMain.xaml.cs b/Plain Craft Launcher 2/FormMain.xaml.cs index a1478eb65..d3d2ae81c 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.cs +++ b/Plain Craft Launcher 2/FormMain.xaml.cs @@ -1191,7 +1191,7 @@ ModMain.frmInstanceSchematic is not null && ModModpack.ModpackInstall(filePath); return; } - catch (CancelledException ex) + catch (OperationCanceledException) { return; // 用户主动取消 } diff --git a/Plain Craft Launcher 2/Modules/Base/LoadState.cs b/Plain Craft Launcher 2/Modules/Base/LoadState.cs new file mode 100644 index 000000000..b996f08bc --- /dev/null +++ b/Plain Craft Launcher 2/Modules/Base/LoadState.cs @@ -0,0 +1,13 @@ +namespace PCL; + +/// +/// 模块加载状态。 +/// +public enum LoadState +{ + Waiting, + Loading, + Finished, + Failed, + Aborted +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Base/LoaderInputList.cs b/Plain Craft Launcher 2/Modules/Base/LoaderInputList.cs new file mode 100644 index 000000000..c65e48994 --- /dev/null +++ b/Plain Craft Launcher 2/Modules/Base/LoaderInputList.cs @@ -0,0 +1,30 @@ +namespace PCL; + +/// +/// 用作加载器输入的列表,按元素顺序比较相等性。 +/// +public sealed class LoaderInputList : List +{ + public override bool Equals(object? obj) + { + return obj is List other && this.SequenceEqual(other); + } + + public static bool operator ==(LoaderInputList? left, LoaderInputList? right) + { + return ReferenceEquals(left, right) || (left is not null && right is not null && left.SequenceEqual(right)); + } + + public static bool operator !=(LoaderInputList? left, LoaderInputList? right) + { + return !(left == right); + } + + public override int GetHashCode() + { + var hash = new HashCode(); + foreach (var item in this) + hash.Add(item); + return hash.ToHashCode(); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs index 8fd702211..ecb601ee5 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Collections.Concurrent; using System.Text; using System.Windows; @@ -13,6 +13,14 @@ namespace PCL; public static partial class ModAnimation { + private sealed class ScaleDelta(double left, double top, double width, double height) + { + public double Left { get; } = left; + public double Top { get; } = top; + public double Width { get; } = width; + public double Height { get; } = height; + } + private static int aniCount; private static int aniFPSCounter; private static long aniFPSTimer; @@ -1011,11 +1019,11 @@ public static AniData AaColor(FrameworkElement obj, DependencyProperty prop, str public static AniData AaScale(object obj, double value, int time = 400, int delay = 0, AniEase ease = null, bool after = false, bool absolute = false) { - MyRect changeRect; + ScaleDelta changeRect; if (absolute) - changeRect = new MyRect(-0.5d * value, -0.5d * value, value, value); + changeRect = new ScaleDelta(-0.5d * value, -0.5d * value, value, value); else - changeRect = new MyRect( + changeRect = new ScaleDelta( Convert.ToDouble(-0.5d * ((dynamic)obj).ActualWidth * value), Convert.ToDouble(-0.5d * ((dynamic)obj).ActualHeight * value), Convert.ToDouble(((dynamic)obj).ActualWidth * value), diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.cs b/Plain Craft Launcher 2/Modules/Base/ModLoader.cs index 56cc805e1..92caa75ca 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModLoader.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Windows.Shell; using Microsoft.VisualBasic.CompilerServices; using PCL.Core.App; @@ -18,7 +18,7 @@ public enum LoaderFolderRunType } // 任务栏进度条 - public static SafeList loaderTaskbar = new(); + public static ConcurrentList loaderTaskbar = new(); public static double loaderTaskbarProgress; // 平滑后的进度 private static TaskbarItemProgressState loaderTaskbarProgressLast = TaskbarItemProgressState.None; @@ -637,7 +637,7 @@ public override void Start(object input = null, bool isForceRestart = false) State = LoadState.Finished; lastFinishedTime = TimeUtils.GetTimeTick(); } - catch (CancelledException ex) + catch (OperationCanceledException ex) { if (LauncherRuntime.ModeDebug) LauncherLog.Log(ex, diff --git a/Plain Craft Launcher 2/Modules/Minecraft/LaunchRestartException.cs b/Plain Craft Launcher 2/Modules/Minecraft/LaunchRestartException.cs new file mode 100644 index 000000000..d7d129826 --- /dev/null +++ b/Plain Craft Launcher 2/Modules/Minecraft/LaunchRestartException.cs @@ -0,0 +1,6 @@ +namespace PCL; + +/// +/// 指示微软登录流程重新开始。 +/// +public sealed class LaunchRestartException : Exception; \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs index b2f55e3c1..bfc9456cc 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Runtime.InteropServices; using PCL.Core.App.Localization; using PCL.Core.Utils; @@ -190,7 +190,7 @@ public static List McAssetsFixList(McInstance mcInstance, bool che return new DownloadFile( ModDownload.DlSourceAssetsGet(McAssetsUrl(hash)), token.localPath, - new FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: hash)); + new FileCheckOptions(actualSize: token.size == 0L ? -1 : token.size, hash: hash)); }).ToList(); // 如果不检查 Hash,则立即处理 var result = new List(); @@ -217,7 +217,7 @@ public static List McAssetsFixList(McInstance mcInstance, bool che result.Add(new DownloadFile( ModDownload.DlSourceAssetsGet(McAssetsUrl(hash)), token.localPath, - new FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: hash))); + new FileCheckOptions(actualSize: token.size == 0L ? -1 : token.size, hash: hash))); } } catch (Exception ex) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs index ae89c95c9..b5cbf0599 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Collections.Concurrent; using System.IO; using System.IO.Compression; @@ -3090,7 +3090,7 @@ public string StatusDescription public DownloadFile ToNetFile(string localAddress) { return new DownloadFile(DownloadUrls, localAddress + (localAddress.EndsWithF(@"\") ? CompFileNameSanitize(FileName) : ""), - new FileChecker(hash: Hash), true); + new FileCheckOptions(hash: Hash), true); } /// diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs index 03d2343ab..429ca68be 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.IO; using System.Net; using System.Text; @@ -37,7 +37,7 @@ public static DownloadFile DlClientJarGet(McInstance version, bool returnNothing version.JsonObject["downloads"]["client"]["url"] is null) throw new Exception(Lang.Text("Minecraft.Download.Error.NoJarDownloadInfo", version.Name)); // 检查文件 - var checker = new FileChecker(1024L, (long)(version.JsonObject["downloads"]["client"]["size"] ?? -1), + var checker = new FileCheckOptions(1024L, (long)(version.JsonObject["downloads"]["client"]["size"] ?? -1), (string)version.JsonObject["downloads"]["client"]["sha1"]); if (returnNothingOnFileUseable && checker.Check(version.PathInstance + version.Name + ".jar") is null) return null; // 通过校验 @@ -64,7 +64,7 @@ public static DownloadFile DlClientAssetIndexGet(McInstance version) if (string.IsNullOrEmpty(indexUrl)) return null; return new DownloadFile(DlSourceLauncherOrMetaGet(indexUrl), indexAddress, - new FileChecker(canUseExistsFile: false)); + new FileCheckOptions(canUseExistingFile: false)); } /// diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs index 3109b2aba..50a770428 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using PCL.Core.App; using PCL.Core.App.Localization; using PCL.Core.IO; @@ -456,7 +456,7 @@ private static void JavaFileList(ModLoader.LoaderTask if (ignoreHash.Contains((string)checkHash)) continue; // 跳过 3 个无意义大量重复文件(#3827) - var checker = new FileChecker(actualSize: (long)info["size"], hash: (string)info["sha1"]); + var checker = new FileCheckOptions(actualSize: (long)info["size"], hash: (string)info["sha1"]); var filePath = Path.GetFullPath(Path.Combine(lastJavaBaseDir, File.Key)); if (!Files.IsPathWithinDirectory(filePath, lastJavaBaseDir)) throw new Exception($"{filePath} 不在 {lastJavaBaseDir} 中"); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs index 8e167ec5b..95c99b833 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; @@ -915,7 +915,7 @@ private static string[] MsLoginStep1New(ModLoader.LoaderTask McLibNetFilesFromInstance(McInstance mcInstance // 校验文件 if (authlibDownloadInfo is not null) { - var checker = new FileChecker(hash: authlibDownloadInfo["checksums"]["sha256"].ToString()); + var checker = new FileCheckOptions(hash: authlibDownloadInfo["checksums"]["sha256"].ToString()); if (checker.Check(authlibTargetFile) is not null) { // 开始下载 @@ -455,7 +455,7 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance downloadAddress.Replace("authlib-injector.yushi.moe", "bmclapi2.bangbang93.com/mirrors/authlib-injector") }, authlibTargetFile, - new FileChecker(hash: authlibDownloadInfo["checksums"]["sha256"].ToString()))); + new FileCheckOptions(hash: authlibDownloadInfo["checksums"]["sha256"].ToString()))); } } @@ -505,7 +505,7 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance var assetPath = $@"{ModFolder.mcFolderSelected}labymod-neo\assets\{assetName}.jar"; var assetUrl = $"https://releases.r2.labymod.net/api/v1/download/assets/labymod4/{channelType}/{labyModCommitRef}/{assetName}/{assetSHA1}.jar"; - var checker = new FileChecker(hash: assetSHA1); + var checker = new FileCheckOptions(hash: assetSHA1); if (checker.Check(assetPath) is null) continue; result.Add(new DownloadFile(new[] { assetUrl }, assetPath, checker)); @@ -547,7 +547,7 @@ public static List McLibNetFilesFromTokens(List libs, foreach (var token in libs) { // 检查文件 - var checker = new FileChecker(actualSize: token.size == 0L ? -1 : token.size, hash: token.Sha1); + var checker = new FileCheckOptions(actualSize: token.size == 0L ? -1 : token.size, hash: token.Sha1); if (checker.Check(token.LocalPath) is null) continue; if (token.IsLocal) @@ -608,7 +608,7 @@ public static List McLibNetFilesFromTokens(List libs, urls.Add(token.Url); LauncherLog.Log( $"[Download] 获取到 LabyMod 主要库文件的 Size = {token.size},SHA1 = {token.Sha1},由于 LabyMod 乱写 Size,已忽略 Size"); - checker = new FileChecker(hash: token.Sha1); // 只校验 SHA1 + checker = new FileCheckOptions(hash: token.Sha1); // 只校验 SHA1 } else if (urls.Count <= 2) { diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs index 221a87886..36fb97004 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs @@ -5,12 +5,10 @@ using System.Text.RegularExpressions; using PCL.Core.App; using PCL.Core.App.Localization; -using PCL.Core.UI; using PCL.Core.Utils.Validate; using PCL.Network; using PCL.Network.Loaders; using static PCL.ModLoader; -using PCL.Core.Utils; namespace PCL; @@ -32,7 +30,7 @@ public static void ModpackInstall() { ModpackInstall(file); } - catch (CancelledException ex) + catch (OperationCanceledException ex) { } catch (Exception ex) @@ -50,7 +48,7 @@ public static void ModpackInstall() /// 构建并启动安装给定的整合包文件的加载器,并返回该加载器。若失败则抛出异常。 /// 必须在工作线程执行。 /// - /// + /// public static LoaderCombo ModpackInstall(string file, string instanceName = null, string logo = null, string resourceId = null, bool isOnlineInstall = false) { @@ -65,7 +63,7 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.InvalidGamePathChars", targetFolder), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } // 获取整合包种类与关键 Json @@ -98,7 +96,7 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam if (archive.GetEntry("manifest.json") is not null) { - var json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(archive.GetEntry("manifest.json").Open(), + var json = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(archive.GetEntry("manifest.json").Open(), Encoding.UTF8)); if (json["addons"] is null) { @@ -156,7 +154,7 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam if (fullNames[1] == "manifest.json") { - var json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(Entry.Open(), Encoding.UTF8)); + var json = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(Entry.Open(), Encoding.UTF8)); if (json["addons"] is null) { packType = 0; @@ -350,7 +348,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip JsonObject json; try { - json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( + json = (JsonObject)JsonCompat.ParseNode( LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "manifest.json").Open())); } catch (Exception ex) @@ -372,7 +370,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); if (string.IsNullOrEmpty(instanceName)) - throw new CancelledException(); + throw new OperationCanceledException(); } // 获取 Mod API 版本信息 @@ -473,7 +471,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip do { tryCount += 1; - ret = (JsonArray)((JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ModDownload.DlModRequest( + ret = (JsonArray)((JsonObject)JsonCompat.ParseNode(ModDownload.DlModRequest( "https://api.curseforge.com/v1/mods/files", "POST", "{\"fileIds\": [" + modList.Join(",") + "]}", "application/json", allowMirror)))["data"]; @@ -648,7 +646,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip if (loaderTaskbar.Any(l => (l.name ?? "") == (loaderName ?? ""))) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } // 启动 @@ -673,7 +671,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr JsonObject json; try { - json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( + json = (JsonObject)JsonCompat.ParseNode( LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "modrinth.index.json").Open())); } catch (Exception ex) @@ -742,7 +740,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); if (string.IsNullOrEmpty(instanceName)) - throw new CancelledException(); + throw new OperationCanceledException(); } // 解压 @@ -800,11 +798,11 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr { ModMain.MyMsgBox(Lang.Text("Minecraft.Download.Modpack.PathOutsideInstance.Message", targetPath), Lang.Text("Minecraft.Download.Modpack.PathOutsideInstance.Title"), isWarn: true); - throw new CancelledException(); + throw new OperationCanceledException(); } fileList.Add(new DownloadFile(urls, targetPath, - new FileChecker(actualSize: ((JsonNode)File["fileSize"]).ToObject(), + new FileCheckOptions(actualSize: ((JsonNode)File["fileSize"]).ToObject(), hash: File["hashes"]["sha1"].ToString()), true)); } @@ -888,7 +886,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr if (loaderTaskbar.Any(l => (l.name ?? "") == (loaderName ?? ""))) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } // 启动 @@ -911,7 +909,7 @@ private static LoaderCombo InstallPackHMCL(string fileAddress, ZipArchiv JsonObject json; try { - json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( + json = (JsonObject)JsonCompat.ParseNode( LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "modpack.json").Open(), Encoding.UTF8)); } catch (Exception ex) @@ -928,7 +926,7 @@ private static LoaderCombo InstallPackHMCL(string fileAddress, ZipArchiv instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); if (string.IsNullOrEmpty(instanceName)) - throw new CancelledException(); + throw new OperationCanceledException(); // 解压 var installTemp = ModMain.RequestTaskTempFolder(); var installLoaders = new List(); @@ -966,7 +964,7 @@ private static LoaderCombo InstallPackHMCL(string fileAddress, ZipArchiv if (loaderTaskbar.Any(l => (l.name ?? "") == (loaderName ?? ""))) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } // 启动 @@ -994,7 +992,7 @@ private static LoaderCombo InstallPackMCBBS(string fileAddress, ZipArchi archive.GetEntry(archiveBaseFolder + "manifest.json"); using (var stream = entry.Open()) { - json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(stream, Encoding.UTF8)); + json = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(stream, Encoding.UTF8)); } } catch (Exception ex) @@ -1014,7 +1012,7 @@ private static LoaderCombo InstallPackMCBBS(string fileAddress, ZipArchi instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); - if (string.IsNullOrEmpty(instanceName)) throw new CancelledException(); + if (string.IsNullOrEmpty(instanceName)) throw new OperationCanceledException(); } // 解压与路径准备 @@ -1096,7 +1094,7 @@ private static LoaderCombo InstallPackMCBBS(string fileAddress, ZipArchi if (loaderTaskbar.Any(l => l.name == loaderName)) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } // 启动任务 @@ -1124,11 +1122,11 @@ private static LoaderCombo InstallPackLauncherPack(string fileAddress, Z Lang.Text("Common.Action.Install"), Lang.Text("Common.Action.Continue"), forceWait: true); var targetFolder = SystemDialogs.SelectFolder(Lang.Text("Minecraft.Download.Modpack.SelectTargetFolder.Title")); if (string.IsNullOrEmpty(targetFolder)) - throw new CancelledException(); + throw new OperationCanceledException(); if (Directory.GetFileSystemEntries(targetFolder).Length > 0) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.TargetFolderMustBeEmpty"), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } // 解压 @@ -1232,18 +1230,18 @@ private static LoaderCombo InstallPackCompress(string fileAddress, ZipAr Lang.Text("Common.Action.Install"), Lang.Text("Common.Action.Continue"), forceWait: true); var targetFolder = SystemDialogs.SelectFolder(Lang.Text("Minecraft.Download.Modpack.SelectTargetFolder.Title")); if (string.IsNullOrEmpty(targetFolder)) - throw new CancelledException(); + throw new OperationCanceledException(); if (targetFolder.Contains("!") || targetFolder.Contains(";")) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.InvalidGamePathChars", targetFolder), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } if (Directory.GetFileSystemEntries(targetFolder).Length > 0) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.TargetFolderMustBeEmpty"), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } // 解压 @@ -1297,7 +1295,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive MMCPackInfo packInfo = null; try { - packJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode( + packJson = (JsonObject)JsonCompat.ParseNode( LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "mmc-pack.json").Open(), Encoding.UTF8)); packInstance = LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "instance.cfg").Open(), Encoding.UTF8); @@ -1317,7 +1315,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive foreach (var entry in archive.Entries) if (!entry.FullName.EndsWith("/") && entry.FullName.StartsWith(archiveBaseFolder + "patches/")) { - var patch = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText( + var patch = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText( archive.GetEntry(entry.FullName).Open(), Encoding.UTF8)); patches.Add(new KeyValuePair(patch, (int)(patch["order"] is not null ? patch["order"] : 0))); @@ -1541,7 +1539,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive instanceName = ModMain.MyMsgBoxInput(Lang.Text("Minecraft.Download.Modpack.InputInstanceName"), "", "", [validate]); if (string.IsNullOrEmpty(instanceName)) - throw new CancelledException(); + throw new OperationCanceledException(); // 解压 var installTemp = ModMain.RequestTaskTempFolder(); var versionFolder = $@"{ModFolder.mcFolderSelected}versions\{instanceName}"; @@ -1713,7 +1711,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive if (loaderTaskbar.Any(l => (l.name ?? "") == (loaderName ?? ""))) { HintService.Hint(Lang.Text("Minecraft.Download.Modpack.Installing"), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } // 启动 diff --git a/Plain Craft Launcher 2/Modules/ModLink.cs b/Plain Craft Launcher 2/Modules/ModLink.cs index e21d1d34a..7d4b24d28 100644 --- a/Plain Craft Launcher 2/Modules/ModLink.cs +++ b/Plain Craft Launcher 2/Modules/ModLink.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using PCL.Core.App; @@ -334,7 +334,7 @@ public static int DownloadEasyTier() // 1. Download EasyTier loaders.Add(new LoaderDownload(Lang.Text("Link.Mod.Task.DownloadEasyTier"), new List { - new(addresses.ToArray(), dlTargetPath, new FileChecker(1024 * 64)) + new(addresses.ToArray(), dlTargetPath, new FileCheckOptions(1024 * 64)) }) { ProgressWeight = 15 }); // 2. Extract files diff --git a/Plain Craft Launcher 2/Modules/Network/Facade/ModNet.cs b/Plain Craft Launcher 2/Modules/Network/Facade/ModNet.cs index 592a65500..da81177fe 100644 --- a/Plain Craft Launcher 2/Modules/Network/Facade/ModNet.cs +++ b/Plain Craft Launcher 2/Modules/Network/Facade/ModNet.cs @@ -104,14 +104,21 @@ public static Task NetDownloadByClient(string url, string localFile, bool useBro return FileDownloader.DownloadAsync(url, localFile, useBrowserUserAgent); } - public static void NetDownloadByLoader(string url, string localFile, ModLoader.LoaderBase? loaderToSyncProgress = null, - FileChecker? check = null, bool useBrowserUserAgent = false) + public static void NetDownloadByLoader( + string url, + string localFile, + ModLoader.LoaderBase? loaderToSyncProgress = null, + FileCheckOptions? check = null, + bool useBrowserUserAgent = false) { FileDownloader.DownloadAsync(url, localFile, useBrowserUserAgent).GetAwaiter().GetResult(); } - public static void NetDownloadByLoader(IEnumerable urls, string localFile, - ModLoader.LoaderBase? loaderToSyncProgress = null, FileChecker? check = null, + public static void NetDownloadByLoader( + IEnumerable urls, + string localFile, + ModLoader.LoaderBase? loaderToSyncProgress = null, + FileCheckOptions? check = null, bool useBrowserUserAgent = false) { FileDownloader.DownloadAsync(urls, localFile, useBrowserUserAgent).GetAwaiter().GetResult(); diff --git a/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownload.cs b/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownload.cs index b2a16011f..f01710ac3 100644 --- a/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownload.cs +++ b/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownload.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.IO; using PCL.Core.App; using PCL.Core.Utils; @@ -7,7 +7,7 @@ namespace PCL.Network.Loaders; public class LoaderDownload : ModLoader.LoaderBase { - public SafeList files; + public ConcurrentList files; private int _fileRemain; private readonly object _fileRemainLock = new(); private CancellationTokenSource? _cancellationTokenSource; @@ -22,7 +22,7 @@ public override double Progress public LoaderDownload(string name, List fileTasks) { base.name = name; - files = new SafeList(fileTasks ?? new List()); + files = new ConcurrentList(fileTasks ?? new List()); } public void RefreshStat() { } @@ -30,7 +30,7 @@ public void RefreshStat() { } public override void Start(object input = null, bool isForceRestart = false) { if (input is List inputFiles) - files = new SafeList(inputFiles); + files = new ConcurrentList(inputFiles); lock (lockState) { @@ -116,7 +116,7 @@ private async Task ProcessFileAsync(DownloadFile file, CancellationToken cancell if (State >= LoadState.Finished) return; Directory.CreateDirectory(Path.GetDirectoryName(file.LocalPath) ?? throw new IOException("下载路径无效")); - if (file.Check?.canUseExistsFile == true && file.Check.Check(file.LocalPath) is null) + if (file.Check?.CanUseExistingFile == true && file.Check.Check(file.LocalPath) is null) { file.IsCopy = true; file.State = NetState.Finished; diff --git a/Plain Craft Launcher 2/Modules/Network/Management/NetManager.cs b/Plain Craft Launcher 2/Modules/Network/Management/NetManager.cs index 15d899564..3e8c8b398 100644 --- a/Plain Craft Launcher 2/Modules/Network/Management/NetManager.cs +++ b/Plain Craft Launcher 2/Modules/Network/Management/NetManager.cs @@ -1,4 +1,4 @@ -using PCL.Network.Loaders; +using PCL.Network.Loaders; namespace PCL.Network; @@ -9,7 +9,7 @@ public sealed class NetManager public Dictionary Files { get; } = new(); public object LockFiles { get; } = new(); - public SafeList Tasks { get; } = new(); + public ConcurrentList Tasks { get; } = new(); public object LockRemain { get; } = new(); public int FileRemain { diff --git a/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs b/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs index 57c42e6b3..bdf3a75e9 100644 --- a/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs +++ b/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs @@ -1,4 +1,4 @@ -using PCL.Network.Loaders; +using PCL.Network.Loaders; namespace PCL.Network; @@ -8,7 +8,7 @@ public class DownloadFile public string LocalPath { get; set; } public string LocalName { get; } public List Urls { get; } - public FileChecker? Check { get; } + public FileCheckOptions? Check { get; } public bool UseBrowserUserAgent { get; } public string CustomUserAgent { get; } public NetState State { get; set; } = NetState.WaitingToCheck; @@ -39,8 +39,12 @@ public double Progress } } - public DownloadFile(IEnumerable urls, string localPath, FileChecker? checker = null, - bool useBrowserUserAgent = false, string customUserAgent = "") + public DownloadFile( + IEnumerable urls, + string localPath, + FileCheckOptions? checker = null, + bool useBrowserUserAgent = false, + string customUserAgent = "") { Urls = urls.Where(url => !string.IsNullOrWhiteSpace(url)).Distinct().ToList(); LocalPath = localPath; diff --git a/Plain Craft Launcher 2/Modules/Network/Models/FileCheckOptions.cs b/Plain Craft Launcher 2/Modules/Network/Models/FileCheckOptions.cs new file mode 100644 index 000000000..45616f2dc --- /dev/null +++ b/Plain Craft Launcher 2/Modules/Network/Models/FileCheckOptions.cs @@ -0,0 +1,28 @@ +namespace PCL.Network; + +/// +/// 文件下载后的校验规则。 +/// +public sealed class FileCheckOptions( + long minSize = -1, + long actualSize = -1, + string? hash = null, + bool canUseExistingFile = true, + bool validateJson = false) +{ + public long MinSize { get; } = minSize; + public long ActualSize { get; } = actualSize; + public string? Hash { get; } = hash; + public bool CanUseExistingFile { get; } = canUseExistingFile; + public bool ValidateJson { get; } = validateJson; + + public string? Check(string localPath) + { + return Files.CheckAsync(localPath, MinSize, ActualSize, Hash, ValidateJson).GetAwaiter().GetResult(); + } + + public Task CheckAsync(string localPath) + { + return Files.CheckAsync(localPath, MinSize, ActualSize, Hash, ValidateJson); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/UI/HintService.cs b/Plain Craft Launcher 2/Modules/UI/HintService.cs index bd5c86313..320f2b273 100644 --- a/Plain Craft Launcher 2/Modules/UI/HintService.cs +++ b/Plain Craft Launcher 2/Modules/UI/HintService.cs @@ -1,5 +1,4 @@ using System.Windows; -using PCL.Core.UI; namespace PCL; @@ -12,9 +11,9 @@ private struct HintMessage public bool Log; } - private static SafeList HintWaiting + private static ConcurrentList HintWaiting { - get => field ??= new SafeList(); + get => field ??= new ConcurrentList(); set; } diff --git a/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs b/Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs similarity index 57% rename from Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs rename to Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs index 77c92cb8c..a6d81b3b7 100644 --- a/Plain Craft Launcher 2/Compatibility/LauncherLegacyTypes.cs +++ b/Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs @@ -1,45 +1,9 @@ -using System.Collections; using System.Windows.Media; using Color = System.Windows.Media.Color; using ColorConverter = System.Windows.Media.ColorConverter; namespace PCL; -/// -/// 模块加载状态。 -/// -public enum LoadState -{ - Waiting, - Loading, - Finished, - Failed, - Aborted -} - -/// -/// 支持负数与浮点数的矩形。 -/// -public class MyRect -{ - public MyRect() - { - } - - public MyRect(double left, double top, double width, double height) - { - Left = left; - Top = top; - Width = width; - Height = height; - } - - public double Width { get; set; } - public double Height { get; set; } - public double Left { get; set; } - public double Top { get; set; } -} - /// /// 支持小数与常见 WPF / Drawing 类型互转的颜色。 /// @@ -326,250 +290,3 @@ public override int GetHashCode() return HashCode.Combine(a, r, g, b); } } - -/// -/// 可以使用 Equals 和等号的 List。 -/// -public class EqualableList : List -{ - public override bool Equals(object? obj) - { - if (obj is not List other || other.Count != Count) - return false; - - for (var i = 0; i < other.Count; i++) - if (!EqualityComparer.Default.Equals(other[i], this[i])) - return false; - return true; - } - - public static bool operator ==(EqualableList? left, EqualableList? right) - { - return EqualityComparer>.Default.Equals(left, right); - } - - public static bool operator !=(EqualableList? left, EqualableList? right) - { - return !(left == right); - } - - public override int GetHashCode() - { - var hash = new HashCode(); - foreach (var item in this) - hash.Add(item); - return hash.ToHashCode(); - } -} - -/// -/// 线程安全的 List。枚举时返回浅表快照。 -/// -public class SafeList : IEnumerable, IDisposable, ICollection -{ - private readonly List _items; - private readonly ReaderWriterLockSlim _lock = new(); - - public SafeList() - { - _items = []; - } - - public SafeList(IEnumerable data) - { - _items = new List(data); - } - - public T this[int index] - { - get - { - _lock.EnterReadLock(); - try - { - return _items[index]; - } - finally - { - _lock.ExitReadLock(); - } - } - set - { - _lock.EnterWriteLock(); - try - { - _items[index] = value; - } - finally - { - _lock.ExitWriteLock(); - } - } - } - - public int Count - { - get - { - _lock.EnterReadLock(); - try - { - return _items.Count; - } - finally - { - _lock.ExitReadLock(); - } - } - } - - public bool IsReadOnly => false; - - public void Add(T item) - { - _lock.EnterWriteLock(); - try - { - _items.Add(item); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public bool Remove(T item) - { - _lock.EnterWriteLock(); - try - { - return _items.Remove(item); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public void Clear() - { - _lock.EnterWriteLock(); - try - { - _items.Clear(); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public bool Contains(T item) - { - _lock.EnterReadLock(); - try - { - return _items.Contains(item); - } - finally - { - _lock.ExitReadLock(); - } - } - - public void CopyTo(T[] array, int arrayIndex) - { - ToList().CopyTo(array, arrayIndex); - } - - public void Dispose() - { - _lock.Dispose(); - GC.SuppressFinalize(this); - } - - public IEnumerator GetEnumerator() - { - return ToList().GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void RemoveAt(int index) - { - _lock.EnterWriteLock(); - try - { - _items.RemoveAt(index); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public List ToList() - { - _lock.EnterReadLock(); - try - { - return new List(_items); - } - finally - { - _lock.ExitReadLock(); - } - } -} - -/// -/// 文件校验规则。 -/// -public class FileChecker -{ - public long actualSize = -1; - public bool canUseExistsFile = true; - public string? hash; - public bool isJson; - public long minSize = -1; - - public FileChecker(long minSize = -1, long actualSize = -1, string? hash = null, - bool canUseExistsFile = true, bool isJson = false) - { - this.actualSize = actualSize; - this.minSize = minSize; - this.hash = hash; - this.canUseExistsFile = canUseExistsFile; - this.isJson = isJson; - } - - public string Check(string localPath) - { - return LegacyFileFacade.CheckFile(localPath, minSize, actualSize, hash ?? string.Empty, isJson); - } -} - -/// -/// 指示接取到这个异常的函数进行重试。 -/// -public class RestartException : Exception -{ -} - -/// -/// 指示用户手动取消了操作,或用户已知晓操作被取消的原因。 -/// -public class CancelledException : Exception; - -/// -/// 用于储存 RaiseByMouse 的 EventArgs。 -/// -public sealed class RouteEventArgs(bool raiseByMouse = false) : EventArgs -{ - public bool handled = false; - public bool raiseByMouse = raiseByMouse; -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs index ea69d2efe..49db1f3bd 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs @@ -12,12 +12,9 @@ using PCL.Core.App.Localization; using PCL.Core.IO.Net.Http; using PCL.Core.Minecraft; -using PCL.Core.UI; -using PCL.Core.Utils; +using PCL.Core.Utils.Codecs; using PCL.Network; using PCL.Network.Loaders; -using PCL.Core.IO.Net.Http; -using PCL.Core.App.Localization; namespace PCL; @@ -56,7 +53,7 @@ private static void CancelUnsafeCacheSubfolder(string childFolderName, string re var message = "远程版本名" + reason + ":" + childFolderName; LauncherLog.Log("[Download] " + message); HintService.Hint(message, HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } #region Minecraft 下载 @@ -160,7 +157,7 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa new List { new(ModDownload.DlSourceLauncherOrMetaGet(jsonUrl), Path.Combine(versionFolder, id + ".json"), - new FileChecker(canUseExistsFile: false, isJson: true)) + new FileCheckOptions(canUseExistingFile: false, validateJson: true)) }) { ProgressWeight = 2d }); // 获取支持库文件地址 loaders.Add(new ModLoader.LoaderTask>( @@ -224,7 +221,7 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa new List { new(ModDownload.DlSourceLauncherOrMetaGet(jsonUrl ?? ""), Path.Combine(instanceFolder, instanceName + ".json"), - new FileChecker(canUseExistsFile: false, isJson: true)) + new FileCheckOptions(canUseExistingFile: false, validateJson: true)) }) { ProgressWeight = 3d }); // 下载支持库文件 @@ -281,7 +278,7 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa // 顺手添加 Json 项目 try { - var versionJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(Path.Combine(instanceFolder, instanceName + ".json"))); + var versionJson = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(Path.Combine(instanceFolder, instanceName + ".json"))); versionJson.Add("clientVersion", id); LegacyFileFacade.WriteFile(Path.Combine(instanceFolder, instanceName + ".json"), versionJson.ToString()); } @@ -455,7 +452,7 @@ private static void McDownloadMenuSaveServer(object sender, RoutedEventArgs e) new List { new(ModDownload.DlSourceLauncherOrMetaGet(jsonUrl), Path.Combine(versionFolder, id + ".json"), - new FileChecker(canUseExistsFile: false, isJson: true)) + new FileCheckOptions(canUseExistingFile: false, validateJson: true)) }) { ProgressWeight = 2d }); // 构建服务端 loaders.Add(new ModLoader.LoaderTask>( @@ -479,7 +476,7 @@ private static void McDownloadMenuSaveServer(object sender, RoutedEventArgs e) } var jarUrl = (string)mcInstance.JsonObject["downloads"]["server"]["url"]; - var checker = new FileChecker(1024L, + var checker = new FileCheckOptions(1024L, (long)(mcInstance.JsonObject["downloads"]["server"]["size"] ?? -1), (string)mcInstance.JsonObject["downloads"]["server"]["sha1"]); task.output = new List @@ -562,7 +559,7 @@ public static void McDownloadMenuSave(object sender, RoutedEventArgs e) new List { new(ModDownload.DlSourceLauncherOrMetaGet(jsonUrl), Path.Combine(versionFolder, id + ".json"), - new FileChecker(canUseExistsFile: false, isJson: true)) + new FileCheckOptions(canUseExistingFile: false, validateJson: true)) }) { ProgressWeight = 2d }); // 获取支持库文件地址 loaders.Add(new ModLoader.LoaderTask>( @@ -942,7 +939,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta // 构造文件请求 task.output = new List - { new(sources.ToArray(), target, new FileChecker(300 * 1024)) }; + { new(sources.ToArray(), target, new FileCheckOptions(300 * 1024)) }; }) { ProgressWeight = 8d @@ -1012,7 +1009,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar")); task.Progress = 0.06d; // 进行安装 - var useJavaWrapper = PCL.Core.Utils.Codecs.EncodingUtils.IsDefaultEncodingUtf8(); + var useJavaWrapper = EncodingUtils.IsDefaultEncodingUtf8(); Retry: ; try @@ -1181,7 +1178,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta task.Progress = 0.9d; // 构造文件请求 task.output = new List - { new(sources.ToArray(), targetFolder, new FileChecker(64 * 1024)) }; + { new(sources.ToArray(), targetFolder, new FileCheckOptions(64 * 1024)) }; }) { ProgressWeight = 6d @@ -1411,7 +1408,7 @@ private static void McDownloadLiteLoaderSave(ModDownload.DlLiteLoaderListEntry d (downloadInfo.Inherit == "1.8" ? "ant/dist/" : "build/libs/") + downloadInfo.FileName); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new FileChecker(1024 * 1024)) }) + new List { new(address.ToArray(), target, new FileCheckOptions(1024 * 1024)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -1482,10 +1479,10 @@ private static void McDownloadLiteLoaderSave(ModDownload.DlLiteLoaderListEntry d DateTime.ParseExact(downloadInfo.ReleaseTime, "yyyy/MM/dd HH:mm", CultureInfo.InvariantCulture)); versionJson.Add("type", "release"); versionJson.Add("arguments", - (JsonNode)PCL.Core.Utils.JsonCompat.ParseNode("{\"game\":[\"--tweakClass\",\"" + downloadInfo.jsonToken["tweakClass"] + - "\"]}")); + (JsonNode)JsonCompat.ParseNode("{\"game\":[\"--tweakClass\",\"" + downloadInfo.jsonToken["tweakClass"] + + "\"]}")); versionJson.Add("libraries", downloadInfo.jsonToken["libraries"]?.DeepClone()); - versionJson["libraries"].AsArray().Add(PCL.Core.Utils.JsonCompat.ParseNode("{\"name\": \"com.mumfrey:liteloader:" + + versionJson["libraries"].AsArray().Add(JsonCompat.ParseNode("{\"name\": \"com.mumfrey:liteloader:" + downloadInfo.jsonToken["version"] + "\",\"url\": \"https://dl.liteloader.com/versions/\"}")); versionJson.Add("mainClass", "net.minecraft.launchwrapper.Launch"); @@ -1647,14 +1644,14 @@ public static void McDownloadForgelikeSave(ModDownload.DlForgelikeEntry info) var url = neo.UrlBase + "-installer.jar"; files.Add(new DownloadFile( new[] { url.Replace("maven.neoforged.net/releases", "bmclapi2.bangbang93.com/maven"), url }, target, - new FileChecker(64 * 1024))); + new FileCheckOptions(64 * 1024))); } else if (info.forgeType == ModDownload.DlForgelikeEntry.ForgelikeType.Cleanroom) { // Cleanroom var clr = (ModDownload.DlCleanroomListEntry)info; var url = clr.UrlBase + "-installer.jar"; - files.Add(new DownloadFile(new[] { url }, target, new FileChecker(64 * 1024))); + files.Add(new DownloadFile(new[] { url }, target, new FileCheckOptions(64 * 1024))); } else { @@ -1665,7 +1662,7 @@ public static void McDownloadForgelikeSave(ModDownload.DlForgelikeEntry info) { $"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/{forge.Inherit}-{forge.FileVersion}/forge-{forge.Inherit}-{forge.FileVersion}-{forge.Category}.{forge.FileExtension}", $"https://files.minecraftforge.net/maven/net/minecraftforge/forge/{forge.Inherit}-{forge.FileVersion}/forge-{forge.Inherit}-{forge.FileVersion}-{forge.Category}.{forge.FileExtension}" - }, target, new FileChecker(64 * 1024, hash: forge.Hash))); + }, target, new FileCheckOptions(64 * 1024, hash: forge.Hash))); } // 构造加载器 @@ -2033,14 +2030,14 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask + Basics.RunInNewThread(() => { try { LauncherLog.Log("[Download] 刷新 Forge 推荐版本缓存开始"); var result = ModNet.NetGetCodeByLoader("https://bmclapi2.bangbang93.com/forge/promos"); if (result.Length < 1000) throw new Exception(Lang.Text("Minecraft.Download.Error.ForgePromosResultTooShort", result)); - var resultJson = (JsonNode)PCL.Core.Utils.JsonCompat.ParseNode(result); + var resultJson = (JsonNode)JsonCompat.ParseNode(result); var recommendedList = new List(); foreach (JsonObject Version in resultJson.AsArray()) { @@ -2605,7 +2602,7 @@ public static string McDownloadForgeRecommendedGet(string mcInstance) return null; } - var json = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(list); + var json = (JsonObject)JsonCompat.ParseNode(list); if (json is null || !(mcInstance ?? "null").Contains(".") || !json.ContainsKey(mcInstance)) return null; return (json[mcInstance] ?? "").ToString(); @@ -2883,7 +2880,7 @@ public static void McDownloadFabricLoaderSave(JsonObject downloadInfo) var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileCheckOptions(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3008,7 +3005,7 @@ public static void McDownloadLegacyFabricLoaderSave(JsonObject downloadInfo) var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileCheckOptions(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3060,7 +3057,7 @@ public static void McDownloadLegacyFabricLoaderSave(JsonObject downloadInfo) { "https://meta.legacyfabric.net/v2/versions/loader/" + minecraftName + "/" + legacyFabricVersion + "/profile/json" - }, Path.Combine(versionFolder, id + ".json"), new FileChecker(isJson: true)) + }, Path.Combine(versionFolder, id + ".json"), new FileCheckOptions(validateJson: true)) }; }) { @@ -3234,7 +3231,7 @@ public static void McDownloadQuiltLoaderSave(JsonObject downloadInfo) var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileCheckOptions(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3287,7 +3284,7 @@ public static void McDownloadQuiltLoaderSave(JsonObject downloadInfo) { "https://meta.quiltmc.org/v3/versions/loader/" + minecraftName + "/" + quiltVersion + "/profile/json" - }, Path.Combine(versionFolder, id + ".json"), new FileChecker(isJson: true)) + }, Path.Combine(versionFolder, id + ".json"), new FileCheckOptions(validateJson: true)) }; // 新建 mods 文件夹 Directory.CreateDirectory($@"{mcFolder ?? ModFolder.mcFolderSelected}mods\"); @@ -3402,7 +3399,7 @@ public static void McDownloadLabyModProductionLoaderSave() var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileCheckOptions(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3450,7 +3447,7 @@ public static void McDownloadLabyModSnapshotLoaderSave() var address = new List(); address.Add(url); loaders.Add(new LoaderDownload(Lang.Text("Minecraft.Download.Stage.DownloadMainFile"), - new List { new(address.ToArray(), target, new FileChecker(1024 * 64)) }) + new List { new(address.ToArray(), target, new FileCheckOptions(1024 * 64)) }) { ProgressWeight = 15d }); // 启动 var loader = @@ -3502,7 +3499,7 @@ public static void McDownloadLabyModSnapshotLoaderSave() new[] { $"https://releases.r2.labymod.net/api/v1/download/manifest/labymod4/{labyModChannel}/{minecraftName}/{labyModCommitRef}.json" - }, Path.Combine(versionFolder, id + ".json"), new FileChecker(isJson: true)) + }, Path.Combine(versionFolder, id + ".json"), new FileCheckOptions(validateJson: true)) }; task.Progress = 1d; }) @@ -3577,7 +3574,7 @@ public static void McDownloadLabyModSnapshotLoaderSave() // 顺手添加 Json 项目 try { - var versionJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(Path.Combine(versionFolder, versionName + ".json"))); + var versionJson = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(Path.Combine(versionFolder, versionName + ".json"))); versionJson.Add("clientVersion", id); LegacyFileFacade.WriteFile(Path.Combine(versionFolder, versionName + ".json"), versionJson.ToString()); } @@ -3930,7 +3927,7 @@ public static bool McInstall(McInstallRequest request, string type = mcInstallDe return true; } - catch (CancelledException ex) + catch (OperationCanceledException ex) { return false; } @@ -3966,7 +3963,7 @@ public static bool McInstall(McInstallRequest request, string type = mcInstallDe /// /// 获取合并安装加载器列表,并进行前期的缓存清理与 Java 检查工作。 /// - /// + /// public static List McInstallLoader(McInstallRequest request, bool dontFixLibraries = false, bool ignoreDump = false) { @@ -4073,7 +4070,7 @@ request.forgeEntry is not null || request.neoForgeEntry is not null || { HintService.Hint(Lang.Text("Minecraft.Download.Error.InstanceAlreadyExists", request.targetInstanceName, ""), HintType.Error); - throw new CancelledException(); + throw new OperationCanceledException(); } var loaderList = new List(); @@ -4481,7 +4478,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!minecraftJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Minecraft", minecraftJsonPath, minecraftJsonText.Substring(0, Math.Min(minecraftJsonText.Length, 1000)))); - minecraftJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(minecraftJsonText); + minecraftJson = (JsonObject)JsonCompat.ParseNode(minecraftJsonText); } if (hasOptiFine) @@ -4490,7 +4487,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!optiFineJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "OptiFine", optiFineJsonPath, optiFineJsonText.Substring(0, Math.Min(optiFineJsonText.Length, 1000)))); - optiFineJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(optiFineJsonText); + optiFineJson = (JsonObject)JsonCompat.ParseNode(optiFineJsonText); } if (hasForge) @@ -4499,7 +4496,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!forgeJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Forge", forgeJsonPath, forgeJsonText.Substring(0, Math.Min(forgeJsonText.Length, 1000)))); - forgeJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(forgeJsonText); + forgeJson = (JsonObject)JsonCompat.ParseNode(forgeJsonText); } if (hasNeoForge) @@ -4508,7 +4505,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!neoForgeJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "NeoForge", neoForgeJsonPath, neoForgeJsonText.Substring(0, Math.Min(neoForgeJsonText.Length, 1000)))); - neoForgeJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(neoForgeJsonText); + neoForgeJson = (JsonObject)JsonCompat.ParseNode(neoForgeJsonText); } if (hasCleanroom) @@ -4517,7 +4514,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!cleanroomJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Cleanroom", cleanroomJsonPath, cleanroomJsonText.Substring(0, Math.Min(cleanroomJsonText.Length, 1000)))); - cleanroomJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(cleanroomJsonText); + cleanroomJson = (JsonObject)JsonCompat.ParseNode(cleanroomJsonText); } if (hasLiteLoader) @@ -4526,7 +4523,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!liteLoaderJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "LiteLoader", liteLoaderJsonPath, liteLoaderJsonText.Substring(0, Math.Min(liteLoaderJsonText.Length, 1000)))); - liteLoaderJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(liteLoaderJsonText); + liteLoaderJson = (JsonObject)JsonCompat.ParseNode(liteLoaderJsonText); } if (hasFabric) @@ -4535,7 +4532,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!fabricJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Fabric", fabricJsonPath, fabricJsonText.Substring(0, Math.Min(fabricJsonText.Length, 1000)))); - fabricJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(fabricJsonText); + fabricJson = (JsonObject)JsonCompat.ParseNode(fabricJsonText); } if (hasLegacyFabric) @@ -4544,7 +4541,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!legacyFabricJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Legacy Fabric", fabricJsonPath, legacyFabricJsonText.Substring(0, Math.Min(legacyFabricJsonText.Length, 1000)))); - legacyFabricJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(legacyFabricJsonText); + legacyFabricJson = (JsonObject)JsonCompat.ParseNode(legacyFabricJsonText); } if (hasQuilt) @@ -4553,7 +4550,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!quiltJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Quilt", quiltJsonPath, quiltJsonText.Substring(0, Math.Min(quiltJsonText.Length, 1000)))); - quiltJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(quiltJsonText); + quiltJson = (JsonObject)JsonCompat.ParseNode(quiltJsonText); } if (hasLabyMod) @@ -4562,7 +4559,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!labyModJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "LabyMod", labyModJsonPath, labyModJsonText.Substring(0, Math.Min(labyModJsonText.Length, 1000)))); - labyModJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(labyModJsonText); + labyModJson = (JsonObject)JsonCompat.ParseNode(labyModJsonText); } #endregion diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs index 4420f96d6..76c49d9c6 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs @@ -1,4 +1,4 @@ -using System.Drawing; +using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; @@ -20,7 +20,7 @@ public partial class MySkin // 点击 private bool isSkinMouseDown; - public ModLoader.LoaderTask, string> loader; + public ModLoader.LoaderTask, string> loader; public MySkin() { @@ -97,7 +97,7 @@ public void BtnSkinSave_Click(object sender, RoutedEventArgs e) Save(loader); } - public static void Save(ModLoader.LoaderTask, string> loader) + public static void Save(ModLoader.LoaderTask, string> loader) { var address = loader.output; if (loader.State != LoadState.Finished) @@ -279,7 +279,7 @@ public void RefreshClick(object sender, RoutedEventArgs e) /// /// 刷新皮肤缓存。 /// - public static void RefreshCache(ModLoader.LoaderTask, string> sender = null) + public static void RefreshCache(ModLoader.LoaderTask, string> sender = null) { var hasLoaderRunning = PageLaunchLeft.skinLoaders.Any(skinLoader => skinLoader.State == LoadState.Loading); diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs index ff733a795..828868a2a 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -138,7 +138,7 @@ public void PageLaunchLeft_Loaded(object sender, RoutedEventArgs e) File.Delete(packInstallPath); } } - catch (CancelledException ex) + catch (OperationCanceledException ex) { LauncherLog.Log(ex, "自动安装整合包被用户取消:" + packInstallPath); } @@ -820,17 +820,17 @@ public void RefreshPage(bool anim, ModLaunch.McLoginType targetLoginType = defau #region 皮肤 // 正版皮肤 - public static ModLoader.LoaderTask, string> skinMs = new("Loader Skin Ms", SkinMsLoad, + public static ModLoader.LoaderTask, string> skinMs = new("Loader Skin Ms", SkinMsLoad, SkinMsInput, ThreadPriority.AboveNormal); - private static EqualableList SkinMsInput() + private static LoaderInputList SkinMsInput() { // 获取名称 - return new EqualableList + return new LoaderInputList { ModProfile.selectedProfile.Username, ModProfile.selectedProfile.Uuid }; } - private static void SkinMsLoad(ModLoader.LoaderTask, string> data) + private static void SkinMsLoad(ModLoader.LoaderTask, string> data) { // 清空已有皮肤 // 如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载 @@ -912,16 +912,16 @@ private static void SkinMsLoad(ModLoader.LoaderTask, strin } // 离线皮肤 - public static ModLoader.LoaderTask, string> skinLegacy = new("Loader Skin Legacy", + public static ModLoader.LoaderTask, string> skinLegacy = new("Loader Skin Legacy", SkinLegacyLoad, SkinLegacyInput, ThreadPriority.AboveNormal); - private static EqualableList SkinLegacyInput() + private static LoaderInputList SkinLegacyInput() { - return new EqualableList + return new LoaderInputList { ModProfile.selectedProfile.Username, ModProfile.selectedProfile.Uuid }; } - private static void SkinLegacyLoad(ModLoader.LoaderTask, string> data) + private static void SkinLegacyLoad(ModLoader.LoaderTask, string> data) { // 清空已有皮肤 UiThread.Post(() => @@ -938,17 +938,17 @@ private static void SkinLegacyLoad(ModLoader.LoaderTask, s } // Authlib-Injector 皮肤 - public static ModLoader.LoaderTask, string> skinAuth = new("Loader Skin Auth", + public static ModLoader.LoaderTask, string> skinAuth = new("Loader Skin Auth", SkinAuthLoad, SkinAuthInput, ThreadPriority.AboveNormal); - private static EqualableList SkinAuthInput() + private static LoaderInputList SkinAuthInput() { // 获取名称 - return new EqualableList + return new LoaderInputList { ModProfile.selectedProfile.Username, ModProfile.selectedProfile.Uuid }; } - private static void SkinAuthLoad(ModLoader.LoaderTask, string> data) + private static void SkinAuthLoad(ModLoader.LoaderTask, string> data) { // 清空已有皮肤 // 如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载 @@ -1020,7 +1020,7 @@ private static void SkinAuthLoad(ModLoader.LoaderTask, str // 全部皮肤加载器 // 需要放在其中元素的后面,否则会因为它提前被加载而莫名其妙变成 Nothing - public static List, string>> skinLoaders = new() + public static List, string>> skinLoaders = new() { skinMs, skinLegacy, skinAuth }; #endregion From 741d57f6b55d14b20bab129284344c72c1b20a4f Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 1 Jul 2026 03:58:29 +0800 Subject: [PATCH 08/16] NColor --- PCL.Core.Test/UI/NColorTest.cs | 53 ++++ PCL.Core/UI/NColor.cs | 238 ++++++++++++-- .../Controls/AnimatedBackgroundGrid.cs | 2 +- .../Controls/MyHint.xaml.cs | 8 +- .../Controls/MyIconButton.xaml.cs | 66 ++-- .../Controls/MyIconTextButton.xaml.cs | 2 +- .../Controls/MyMsg/MyMsgInput.xaml.cs | 6 +- .../Controls/MyMsg/MyMsgMarkdown.xaml.cs | 6 +- .../Controls/MyMsg/MyMsgSelect.xaml.cs | 6 +- .../Controls/MyMsg/MyMsgText.xaml.cs | 6 +- .../Controls/MyRadioButton.xaml.cs | 38 +-- Plain Craft Launcher 2/Controls/MyTextBox.cs | 2 +- .../Controls/MyToast.xaml.cs | 2 +- .../Controls/SvgIconControlHelper.cs | 5 +- .../Infrastructure/LauncherMath.cs | 14 +- .../Modules/Base/ModAnimation.cs | 33 +- .../Modules/Minecraft/ModStyle.cs | 5 +- .../Modules/UI/Theme/MyColor.cs | 292 ------------------ .../Modules/UI/Theme/ThemeManager.cs | 16 +- .../Pages/PageLaunch/MyMsgLogin.xaml.cs | 15 +- 20 files changed, 388 insertions(+), 427 deletions(-) create mode 100644 PCL.Core.Test/UI/NColorTest.cs delete mode 100644 Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs diff --git a/PCL.Core.Test/UI/NColorTest.cs b/PCL.Core.Test/UI/NColorTest.cs new file mode 100644 index 000000000..3ce027ad1 --- /dev/null +++ b/PCL.Core.Test/UI/NColorTest.cs @@ -0,0 +1,53 @@ +using System.Windows.Media; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.UI; + +namespace PCL.Core.Test.UI; + +[TestClass] +public class NColorTest +{ + [TestMethod] + public void FromArgbUsesAlphaFirstOrder() + { + var color = NColor.FromArgb(10d, 20d, 30d, 40d); + + Assert.AreEqual(10f, color.A); + Assert.AreEqual(20f, color.R); + Assert.AreEqual(30f, color.G); + Assert.AreEqual(40f, color.B); + } + + [TestMethod] + public void WithAlphaKeepsRgbChannels() + { + var color = new NColor(20d, 30d, 40d).WithAlpha(128d); + + Assert.AreEqual(128f, color.A); + Assert.AreEqual(20f, color.R); + Assert.AreEqual(30f, color.G); + Assert.AreEqual(40f, color.B); + } + + [TestMethod] + public void LerpInterpolatesAndRoundsChannels() + { + var color = NColor.Lerp(new NColor(0d, 0d, 0d), new NColor(10d, 20d, 30d), 0.5d); + + Assert.AreEqual(5f, color.R); + Assert.AreEqual(10f, color.G); + Assert.AreEqual(15f, color.B); + Assert.AreEqual(255f, color.A); + } + + [TestMethod] + public void ObjectConstructorAcceptsWpfBrush() + { + var color = new NColor(new SolidColorBrush(Color.FromArgb(8, 1, 2, 3))); + + Assert.AreEqual(8f, color.A); + Assert.AreEqual(1f, color.R); + Assert.AreEqual(2f, color.G); + Assert.AreEqual(3f, color.B); + } +} \ No newline at end of file diff --git a/PCL.Core/UI/NColor.cs b/PCL.Core/UI/NColor.cs index 15487a6fb..b60a7bda2 100644 --- a/PCL.Core/UI/NColor.cs +++ b/PCL.Core/UI/NColor.cs @@ -53,6 +53,11 @@ public NColor(float r, float g, float b, float a = 255f) _color = new Vector4(r, g, b, a); } + public NColor(double r, double g, double b, double a = 255d) + : this((float)r, (float)g, (float)b, (float)a) + { + } + public NColor(Color color) : this(color.R, color.G, color.B, color.A) { } @@ -81,8 +86,7 @@ public NColor(string str) { // 忽略 } - - + if (string.IsNullOrWhiteSpace(str)) throw new ArgumentException("颜色字符串不能为空。", nameof(str)); @@ -130,10 +134,60 @@ public NColor(string str) _color = new Vector4(r, g, b, a); } + public NColor(object? obj) + { + switch (obj) + { + case null: + _color = new Vector4(255f, 255f, 255f, 255f); + break; + case NColor color: + _color = color._color; + break; + case Color color: + _color = new Vector4(color.R, color.G, color.B, color.A); + break; + case System.Drawing.Color color: + _color = new Vector4(color.R, color.G, color.B, color.A); + break; + case SolidColorBrush brush: + var brushColor = brush.Color; + _color = new Vector4(brushColor.R, brushColor.G, brushColor.B, brushColor.A); + break; + case Brush brush: + var solidBrush = (SolidColorBrush)brush; + var solidBrushColor = solidBrush.Color; + _color = new Vector4(solidBrushColor.R, solidBrushColor.G, solidBrushColor.B, solidBrushColor.A); + break; + case string str: + _color = new NColor(str)._color; + break; + default: + _color = new Vector4( + Convert.ToSingle(((dynamic)obj).R), + Convert.ToSingle(((dynamic)obj).G), + Convert.ToSingle(((dynamic)obj).B), + Convert.ToSingle(((dynamic)obj).A)); + break; + } + } + public NColor(float a, NColor color) : this(color.R, color.G, color.B, a) { } + public NColor(double a, NColor color) : this(color.R, color.G, color.B, (float)a) + { + } + + public NColor(double a, Brush brush) : this(a, (NColor)brush) + { + } + + public NColor(double a, SolidColorBrush brush) : this(a, (NColor)brush) + { + } + public NColor(float r, float g, float b) : this(r, g, b, 255f) { } @@ -146,21 +200,91 @@ public NColor(Brush brush) : this((SolidColorBrush)brush) { } - private NColor(Vector4 v) => _color = v; + private NColor(Vector4 v) + { + _color = v; + } + + public static NColor FromArgb(double a, double r, double g, double b) + { + return new NColor(r, g, b, a); + } + + public NColor WithAlpha(double value) + { + var color = this; + color.A = (float)value; + return color; + } + + public static NColor Lerp(NColor from, NColor to, double progress) + { + var p = (float)progress; + return Round(from * (1f - p) + to * p, 6); + } + + public static NColor Round(NColor color, int digits = 0) + { + return new NColor( + Math.Round(color.R, digits), + Math.Round(color.G, digits), + Math.Round(color.B, digits), + Math.Round(color.A, digits)); + } #endregion #region 运算符重载 - public static NColor operator +(NColor a, NColor b) => new(a._color + b._color); - public static NColor operator -(NColor a, NColor b) => new(a._color - b._color); - public static NColor operator *(NColor a, float b) => new(a._color * b); + public static NColor operator +(NColor a, NColor b) + { + return new NColor(a._color + b._color); + } + + public static NColor operator -(NColor a, NColor b) + { + return new NColor(a._color - b._color); + } + + public static NColor operator *(NColor a, float b) + { + return new NColor(a._color * b); + } - public static NColor operator /(NColor a, float b) => - b == 0 ? throw new DivideByZeroException("除数不能为零。") : new NColor(a._color / b); + public static NColor operator *(NColor a, double b) + { + return new NColor(a._color * (float)b); + } - public static bool operator ==(NColor a, NColor b) => a._color == b._color; - public static bool operator !=(NColor a, NColor b) => a._color != b._color; + public static NColor operator *(float a, NColor b) + { + return new NColor(b._color * a); + } + + public static NColor operator *(double a, NColor b) + { + return new NColor(b._color * (float)a); + } + + public static NColor operator /(NColor a, float b) + { + return b == 0 ? throw new DivideByZeroException("除数不能为零。") : new NColor(a._color / b); + } + + public static NColor operator /(NColor a, double b) + { + return b == 0 ? throw new DivideByZeroException("除数不能为零。") : new NColor(a._color / (float)b); + } + + public static bool operator ==(NColor a, NColor b) + { + return a._color == b._color; + } + + public static bool operator !=(NColor a, NColor b) + { + return a._color != b._color; + } #endregion @@ -218,6 +342,39 @@ public static NColor FromHsl(double sH, double sS, double sL) return color; } + private static readonly double[] _PerceptualCenterOffsets = + [ + +0.10d, -0.06d, -0.30d, -0.19d, + -0.15d, -0.24d, -0.32d, -0.09d, + +0.18d, +0.05d, -0.12d, -0.02d, + +0.10d + ]; + + public static NColor FromPerceptualHsl(double hue, double saturation, double lightness) + { + if (saturation == 0d) + return FromHsl(hue, saturation, lightness); + + hue %= 360d; + if (hue < 0d) + hue += 360d; + + var segmentPosition = hue / 30d; + var segmentIndex = (int)segmentPosition; + var segmentBlend = segmentPosition - segmentIndex; + + var centerOffset = _PerceptualCenterOffsets[segmentIndex] + + (_PerceptualCenterOffsets[segmentIndex + 1] - _PerceptualCenterOffsets[segmentIndex]) * + segmentBlend; + + var visualCenter = 50d - centerOffset * saturation; + var adjustedLightness = lightness < visualCenter + ? lightness / visualCenter * 50d + : (1d + (lightness - visualCenter) / (100d - visualCenter)) * 50d; + + return FromHsl(hue, saturation, adjustedLightness); + } + private static double _Hue(double v1, double v2, double vH) { if (vH < 0) vH += 1; @@ -232,21 +389,66 @@ private static double _Hue(double v1, double v2, double vH) } #endregion - + + public override string ToString() + { + return $"({A},{R},{G},{B})"; + } + #region 隐式转换 - public static implicit operator Color(NColor color) => - Color.FromArgb( + public static implicit operator Color(NColor color) + { + return Color.FromArgb( (byte)Math.Clamp(color.A, 0, 255), (byte)Math.Clamp(color.R, 0, 255), (byte)Math.Clamp(color.G, 0, 255), (byte)Math.Clamp(color.B, 0, 255)); - public static implicit operator Brush(NColor color) => new SolidColorBrush(color); - public static implicit operator SolidColorBrush(NColor color) => new(color); + } - public static implicit operator NColor(Color color) => new(color); - public static implicit operator NColor(Brush brush) => new(brush); - public static implicit operator NColor(SolidColorBrush brush) => new(brush); + public static implicit operator System.Drawing.Color(NColor color) + { + return System.Drawing.Color.FromArgb( + (byte)Math.Clamp(color.A, 0, 255), + (byte)Math.Clamp(color.R, 0, 255), + (byte)Math.Clamp(color.G, 0, 255), + (byte)Math.Clamp(color.B, 0, 255)); + } + + public static implicit operator Brush(NColor color) + { + return new SolidColorBrush(color); + } + + public static implicit operator SolidColorBrush(NColor color) + { + return new SolidColorBrush(color); + } + + public static implicit operator NColor(Color color) + { + return new NColor(color); + } + + public static implicit operator NColor(System.Drawing.Color color) + { + return new NColor(color); + } + + public static implicit operator NColor(string value) + { + return new NColor(value); + } + + public static implicit operator NColor(Brush brush) + { + return new NColor(brush); + } + + public static implicit operator NColor(SolidColorBrush brush) + { + return new NColor(brush); + } #endregion } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs b/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs index a0a9f2bd0..9fdfbc608 100644 --- a/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs +++ b/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs @@ -61,7 +61,7 @@ private static void _BackgroundBrushChanged(DependencyObject d, DependencyProper new[] { ModAnimation.AaColor(grid.AnimatableElement, grid._animatableBrushProperty, - new MyColor(brush) - grid.AnimatableBrush, 300) + new NColor(brush) - grid.AnimatableBrush, 300) }, "MyCard Theme " + grid.uuid); await Task.Delay(300); grid.AnimatableBrush = brush; diff --git a/Plain Craft Launcher 2/Controls/MyHint.xaml.cs b/Plain Craft Launcher 2/Controls/MyHint.xaml.cs index a4e150246..dc80f66ea 100644 --- a/Plain Craft Launcher 2/Controls/MyHint.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyHint.xaml.cs @@ -127,10 +127,10 @@ private void UpdateUI() } var s = ThemeService.CurrentTone; - Background = new MyColor().FromHSL2(hue, 90, s.L7 * 100); - BorderBrush = new MyColor().FromHSL2(hue, 90, s.L2 * 100); - LabText.Foreground = new MyColor().FromHSL2(hue, 90, s.L2 * 100); - BtnClose.Foreground = new MyColor().FromHSL2(hue, 90, s.L2 * 100); + Background = NColor.FromPerceptualHsl(hue, 90, s.L7 * 100); + BorderBrush = NColor.FromPerceptualHsl(hue, 90, s.L2 * 100); + LabText.Foreground = NColor.FromPerceptualHsl(hue, 90, s.L2 * 100); + BtnClose.Foreground = NColor.FromPerceptualHsl(hue, 90, s.L2 * 100); // 根据提示气泡对齐方向刷新边框 // 此处依赖 HasBorder 的副作用进行范围检查 diff --git a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs index 8e2d68985..082496039 100644 --- a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs @@ -117,30 +117,30 @@ public SolidColorBrush Foreground // 自定义事件 public event ClickEventHandler? Click; - private static MyColor GetTransparentBackground() + private static NColor _GetTransparentBackground() { - return new MyColor(0d, 255d, 255d, 255d); + return NColor.FromArgb(0d, 255d, 255d, 255d); } - private MyColor? GetBaseFillColor() + private NColor? GetBaseFillColor() { return Theme switch { - Themes.Red => new MyColor(160d, 255d, 76d, 76d), + Themes.Red => NColor.FromArgb(160d, 255d, 76d, 76d), Themes.Black => ThemeManager.IsDarkMode - ? new MyColor(160d, 255d, 255d, 255d) - : new MyColor(160d, 0d, 0d, 0d), - Themes.Custom => new MyColor(160d, Foreground), - _ => null + ? NColor.FromArgb(160d, 255d, 255d, 255d) + : NColor.FromArgb(160d, 0d, 0d, 0d), + Themes.Custom => new NColor(160d, Foreground), + _ => new NColor() }; } private void EnsureBaseBrushes() { - PanBack.Background ??= GetTransparentBackground(); + PanBack.Background ??= _GetTransparentBackground(); var baseFill = GetBaseFillColor(); if (baseFill is not null && !IsUsingSvgIcon) - Path.Fill ??= baseFill; + Path.Fill ??= baseFill.Value; } private void AnimateActiveSvgIconBrush(string resourceKey, int duration) @@ -149,7 +149,7 @@ private void AnimateActiveSvgIconBrush(string resourceKey, int duration) SvgIconControlHelper.AnimateSvgIconBrushTo(ShapeSvgIcon, resourceKey, duration, ColorAnimationKey); } - private void AnimateActiveSvgIconBrush(MyColor color, int duration) + private void AnimateActiveSvgIconBrush(NColor color, int duration) { if (IsUsingSvgIcon) SvgIconControlHelper.AnimateSvgIconBrushTo(ShapeSvgIcon, color, duration, ColorAnimationKey); @@ -188,7 +188,7 @@ private void SetActiveIconBrush(Brush brush) animations.Add(ModAnimation.AaColor( PanBack, BackgroundProperty, - new MyColor(50d, 255d, 255d, 255d) - PanBack.Background, + NColor.FromArgb(50d, 255d, 255d, 255d) - PanBack.Background, animationColorIn)); break; } @@ -196,21 +196,21 @@ private void SetActiveIconBrush(Brush brush) { if (IsUsingSvgIcon) AnimateActiveSvgIconBrush( - new MyColor(255d, 76d, 76d), + new NColor(255d, 76d, 76d), animationColorIn); else animations.Add(ModAnimation.AaColor( Path, Shape.FillProperty, - new MyColor(255d, 76d, 76d) - Path.Fill, + new NColor(255d, 76d, 76d) - Path.Fill, animationColorIn)); break; } case Themes.Black: { var blackHoverColor = ThemeManager.IsDarkMode - ? new MyColor(230d, 255d, 255d, 255d) - : new MyColor(230d, 0d, 0d, 0d); + ? NColor.FromArgb(230d, 255d, 255d, 255d) + : NColor.FromArgb(230d, 0d, 0d, 0d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(blackHoverColor, animationColorIn); else @@ -223,7 +223,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.Custom: { - var customHoverColor = new MyColor(255d, Foreground); + var customHoverColor = new NColor(255d, Foreground); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(customHoverColor, animationColorIn); else @@ -255,12 +255,12 @@ private void SetActiveIconBrush(Brush brush) "ColorBrush4", animationColorOut)); - PanBack.Background = GetTransparentBackground(); + PanBack.Background = _GetTransparentBackground(); break; } case Themes.White: { - var whiteNormalColor = new MyColor(234d, 242d, 254d); + var whiteNormalColor = new NColor(234d, 242d, 254d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(whiteNormalColor, animationColorOut); else @@ -273,13 +273,13 @@ private void SetActiveIconBrush(Brush brush) animations.Add(ModAnimation.AaColor( PanBack, BackgroundProperty, - GetTransparentBackground() - PanBack.Background, + _GetTransparentBackground() - PanBack.Background, animationColorOut)); break; } case Themes.Red: { - var redNormalColor = new MyColor(160d, 255d, 76d, 76d); + var redNormalColor = NColor.FromArgb(160d, 255d, 76d, 76d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(redNormalColor, animationColorOut); else @@ -289,14 +289,14 @@ private void SetActiveIconBrush(Brush brush) redNormalColor - Path.Fill, animationColorOut)); - PanBack.Background = GetTransparentBackground(); + PanBack.Background = _GetTransparentBackground(); break; } case Themes.Black: { var blackNormalColor = ThemeManager.IsDarkMode - ? new MyColor(160d, 255d, 255d, 255d) - : new MyColor(160d, 0d, 0d, 0d); + ? NColor.FromArgb(160d, 255d, 255d, 255d) + : NColor.FromArgb(160d, 0d, 0d, 0d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(blackNormalColor, animationColorOut); else @@ -306,12 +306,12 @@ private void SetActiveIconBrush(Brush brush) blackNormalColor - Path.Fill, animationColorOut)); - PanBack.Background = GetTransparentBackground(); + PanBack.Background = _GetTransparentBackground(); break; } case Themes.Custom: { - var customNormalColor = new MyColor(160d, Foreground); + var customNormalColor = new NColor(160d, Foreground); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(customNormalColor, animationColorOut); else @@ -321,7 +321,7 @@ private void SetActiveIconBrush(Brush brush) customNormalColor - Path.Fill, animationColorOut)); - PanBack.Background = GetTransparentBackground(); + PanBack.Background = _GetTransparentBackground(); break; } } @@ -337,22 +337,22 @@ private void ApplyNonAnimatedTheme() SetActiveIconResource("ColorBrush4"); break; case Themes.White: - SetActiveIconBrush(new MyColor(234d, 242d, 254d)); + SetActiveIconBrush(new NColor(234d, 242d, 254d)); break; case Themes.Red: - SetActiveIconBrush(new MyColor(160d, 255d, 76d, 76d)); + SetActiveIconBrush(NColor.FromArgb(160d, 255d, 76d, 76d)); break; case Themes.Black: SetActiveIconBrush(ThemeManager.IsDarkMode - ? new MyColor(160d, 255d, 255d, 255d) - : new MyColor(160d, 0d, 0d, 0d)); + ? NColor.FromArgb(160d, 255d, 255d, 255d) + : NColor.FromArgb(160d, 0d, 0d, 0d)); break; case Themes.Custom: - SetActiveIconBrush(new MyColor(160d, Foreground)); + SetActiveIconBrush(new NColor(160d, Foreground)); break; } - PanBack.Background = GetTransparentBackground(); + PanBack.Background = _GetTransparentBackground(); } private void Button_MouseUp(object sender, MouseButtonEventArgs e) diff --git a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs index f63fd202c..accd12c5d 100644 --- a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs @@ -199,7 +199,7 @@ private void StartBackgroundAnimation(string resourceKey, int duration) ModAnimation.AniStart(ModAnimation.AaColor(this, BackgroundProperty, resourceKey, duration), ColorAnimationKey); } - private void StartBackgroundAnimation(MyColor delta, int duration) + private void StartBackgroundAnimation(NColor delta, int duration) { ModAnimation.AniStart(ModAnimation.AaColor(this, BackgroundProperty, delta, duration), ColorAnimationKey); } diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs index 155927f28..fe76f68a0 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs @@ -78,8 +78,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new MyColor(140d, 80d, 0d, 0d) - : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? NColor.FromArgb(140d, 80d, 0d, 0d) + : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -118,7 +118,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs index bd1032e51..2a45c0706 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs @@ -76,8 +76,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new MyColor(140d, 80d, 0d, 0d) - : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? NColor.FromArgb(140d, 80d, 0d, 0d) + : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -117,7 +117,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs index 0df63d3ed..d3d700518 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs @@ -109,8 +109,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new MyColor(140d, 80d, 0d, 0d) - : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? NColor.FromArgb(140d, 80d, 0d, 0d) + : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -149,7 +149,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs index 1c491f27e..cb6112c4f 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs @@ -75,8 +75,8 @@ private void Load(object sender, RoutedEventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new MyColor(140d, 80d, 0d, 0d) - : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? NColor.FromArgb(140d, 80d, 0d, 0d) + : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -116,7 +116,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs index c0f4da34d..c12abb0f8 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs @@ -327,7 +327,7 @@ private void RefreshColor(object obj = null, object e = null) if (Checked) { // 勾选 - var color3 = new MyColor(ThemeManager.AppResources["ColorObject3"]); + var color3 = new NColor(ThemeManager.AppResources["ColorObject3"]); ModAnimation.AniStart( new[] { @@ -338,7 +338,7 @@ private void RefreshColor(object obj = null, object e = null) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new MyColor(255d, 255d, 255d) - Background, animationTimeOfCheck), + new NColor(255d, 255d, 255d) - Background, animationTimeOfCheck), "MyRadioButton Color " + Uuid); } else if (isMouseDown) @@ -346,8 +346,8 @@ private void RefreshColor(object obj = null, object e = null) // 按下 ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new MyColor(120d, - new MyColor(ThemeManager.AppResources["ColorObject8"])) - Background, 60), + new NColor(120d, + new NColor(ThemeManager.AppResources["ColorObject8"])) - Background, 60), "MyRadioButton Color " + Uuid); } else if (IsMouseOver) @@ -357,15 +357,15 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseIn), + new NColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseIn), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new MyColor(255d, 255d, 255d) - LabText.Foreground, + new NColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfMouseIn) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new MyColor(50d, - new MyColor(ThemeManager.AppResources["ColorObject8"])) - Background, + new NColor(50d, + new NColor(ThemeManager.AppResources["ColorObject8"])) - Background, animationTimeOfMouseIn), "MyRadioButton Color " + Uuid); } else @@ -375,15 +375,15 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, + new NColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseOut), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new MyColor(255d, 255d, 255d) - LabText.Foreground, + new NColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfMouseOut) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new MyColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - + new NColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - Background, animationTimeOfMouseOut), "MyRadioButton Color " + Uuid); } @@ -398,9 +398,9 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfCheck), + new NColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfCheck), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new MyColor(255d, 255d, 255d) - LabText.Foreground, + new NColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfCheck) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( @@ -442,7 +442,7 @@ private void RefreshColor(object obj = null, object e = null) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new MyColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - + new NColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - Background, animationTimeOfMouseOut), "MyRadioButton Color " + Uuid); } @@ -462,15 +462,15 @@ private void RefreshColor(object obj = null, object e = null) { if (Checked) { - Background = new MyColor(255d, 255d, 255d); + Background = new NColor(255d, 255d, 255d); ShapeLogo.SetResourceReference(Shape.FillProperty, "ColorBrush3"); LabText.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush3"); } else { Background = (Brush)ThemeManager.AppResources["ColorBrushSemiTransparent"]; - ShapeLogo.Fill = new MyColor(255d, 255d, 255d); - LabText.Foreground = new MyColor(255d, 255d, 255d); + ShapeLogo.Fill = new NColor(255d, 255d, 255d); + LabText.Foreground = new NColor(255d, 255d, 255d); } break; @@ -480,8 +480,8 @@ private void RefreshColor(object obj = null, object e = null) if (Checked) { SetResourceReference(BackgroundProperty, "ColorBrush3"); - ShapeLogo.Fill = new MyColor(255d, 255d, 255d); - LabText.Foreground = new MyColor(255d, 255d, 255d); + ShapeLogo.Fill = new NColor(255d, 255d, 255d); + LabText.Foreground = new NColor(255d, 255d, 255d); } else { diff --git a/Plain Craft Launcher 2/Controls/MyTextBox.cs b/Plain Craft Launcher 2/Controls/MyTextBox.cs index c396eb805..cc48e162d 100644 --- a/Plain Craft Launcher 2/Controls/MyTextBox.cs +++ b/Plain Craft Launcher 2/Controls/MyTextBox.cs @@ -380,7 +380,7 @@ private void RefreshColor() private void RefreshTextColor() { var newColor = IsEnabled ? ThemeManager.colorGray1 : ThemeManager.colorGray4; - if (((SolidColorBrush)Foreground).Color.R == newColor.r) + if (((SolidColorBrush)Foreground).Color.R == newColor.R) return; if (IsLoaded && ModAnimation.AniControlEnabled == 0 && !string.IsNullOrEmpty(Text)) { diff --git a/Plain Craft Launcher 2/Controls/MyToast.xaml.cs b/Plain Craft Launcher 2/Controls/MyToast.xaml.cs index 5a9ba7ac6..ebeffbb43 100644 --- a/Plain Craft Launcher 2/Controls/MyToast.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyToast.xaml.cs @@ -210,7 +210,7 @@ private void UpdateColors() _ => 210d }; var res = System.Windows.Application.Current.Resources; - var accent = new MyColor().FromHSL2(baseHue, 75, 60); + var accent = NColor.FromPerceptualHsl(baseHue, 75, 60); var bg = ThemeService.IsDarkMode ? new SolidColorBrush(LabColor.FromLch(0.35)) : (Brush)res["ColorBrushBackground"]; diff --git a/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs b/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs index 97af0fc5f..23384bee0 100644 --- a/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs +++ b/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs @@ -1,7 +1,6 @@ using System.Windows; using System.Windows.Media; using System.Windows.Shapes; -using PCL.Core.UI; using PCL.Core.UI.Controls.SvgIcon; namespace PCL; @@ -60,13 +59,13 @@ internal static void AnimateSvgIconBrushTo( internal static void AnimateSvgIconBrushTo( SvgIcon svgIcon, - MyColor color, + NColor color, int duration, string? animationKey = null) { if (svgIcon.Visibility == Visibility.Visible) svgIcon.AnimateIconBrushTo( - new NColor((Color)color), + color, TimeSpan.FromMilliseconds(duration), animationKey: animationKey); } diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs b/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs index 094491265..cf70c4c33 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs @@ -15,19 +15,13 @@ public static double Percent(double valueA, double valueB, double percent) return NumberUtils.Lerp(valueA, valueB, percent); } - public static MyColor Percent(MyColor valueA, MyColor valueB, double percent) + public static NColor Percent(NColor valueA, NColor valueB, double percent) { - return Round(valueA * (1d - percent) + valueB * percent, 6); + return NColor.Lerp(valueA, valueB, percent); } - public static MyColor Round(MyColor color, int digits = 0) + public static NColor Round(NColor color, int digits = 0) { - return new MyColor - { - a = Math.Round(color.a, digits), - r = Math.Round(color.r, digits), - g = Math.Round(color.g, digits), - b = Math.Round(color.b, digits) - }; + return NColor.Round(color, digits); } } \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs index ecb601ee5..3bc8ddad5 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs @@ -6,7 +6,6 @@ using System.Windows.Media; using PCL.Core.App; using PCL.Core.App.Localization; -using PCL.Core.Utils; using PCL.Network; namespace PCL; @@ -317,14 +316,16 @@ private static AniData AniRun(AniData ani) case AniType.Color: { // 利用 Last 记录了余下的小数值 - var delta = LauncherMath.Percent(new MyColor(0d, 0d, 0d, 0d), (MyColor)ani.value, - ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)) + - (MyColor)ani.valueLast; + var delta = LauncherMath.Percent( + NColor.FromArgb(0d, 0d, 0d, 0d), + (NColor)ani.value, + ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)) + + (NColor)ani.valueLast; var obj = (FrameworkElement)((dynamic)ani.obj)[0]; var prop = (DependencyProperty)((dynamic)ani.obj)[1]; - var newColor = new MyColor(obj.GetValue(prop)) + delta; + var newColor = new NColor(obj.GetValue(prop)) + delta; obj.SetValue(prop, prop.PropertyType.Name == "Color" ? (Color)newColor : (SolidColorBrush)newColor); - ani.valueLast = newColor - new MyColor(obj.GetValue(prop)); + ani.valueLast = newColor - new NColor(obj.GetValue(prop)); break; } @@ -963,7 +964,7 @@ public static AniData AaDouble(ParameterizedThreadStart lambda, double value, in public static AniData AaColor( FrameworkElement obj, DependencyProperty prop, - MyColor value, + NColor value, int time = 400, int delay = 0, AniEase ease = null, @@ -973,7 +974,7 @@ public static AniData AaColor( { typeMain = AniType.Color, timeTotal = time, ease = ease ?? new AniEaseLinear(), obj = new object[] { obj, prop, "" }, value = value, isAfter = after, timeFinished = -delay, - valueLast = new MyColor(0d, 0d, 0d, 0d) + valueLast = NColor.FromArgb(0d, 0d, 0d, 0d) }; } @@ -989,16 +990,22 @@ public static AniData AaColor( /// 是否等到以前的动画完成后才继续本动画。 /// /// - public static AniData AaColor(FrameworkElement obj, DependencyProperty prop, string res, int time = 400, - int delay = 0, AniEase ease = null, bool after = false) + public static AniData AaColor( + FrameworkElement obj, + DependencyProperty prop, + string res, + int time = 400, + int delay = 0, + AniEase ease = null, + bool after = false) { return new AniData { typeMain = AniType.Color, timeTotal = time, ease = ease ?? new AniEaseLinear(), obj = new object[] { obj, prop, res }, - value = new MyColor(System.Windows.Application.Current.FindResource(res)) - - new MyColor(obj.GetValue(prop)), - isAfter = after, timeFinished = -delay, valueLast = new MyColor(0d, 0d, 0d, 0d) + value = new NColor(System.Windows.Application.Current.FindResource(res)) + - new NColor(obj.GetValue(prop)), + isAfter = after, timeFinished = -delay, valueLast = NColor.FromArgb(0d, 0d, 0d, 0d) }; } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs index 3e9ac5ef1..9cac9bbfe 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs @@ -4,10 +4,9 @@ using System.Windows.Documents; using System.Windows.Media; using System.Windows.Threading; +using PCL.Core.App.Localization; using PCL.Core.UI.Controls; -using PCL.Core.Utils; -using PCL.Core.App.Localization; namespace PCL; internal static class ModStyle @@ -259,7 +258,7 @@ public static void SetColorfulTextLab(string text, TextBlock lab, bool isDarkMod lab.Inlines.Add(curRun); } - curRun.Foreground = new SolidColorBrush(new MyColor(color)); + curRun.Foreground = new SolidColorBrush(new NColor(color)); curRun.FontWeight = hasBlodProperty ? FontWeights.Bold : FontWeights.Normal; curRun.FontStyle = hasItalicProperty ? FontStyles.Italic : FontStyles.Normal; curRun.TextDecorations = hasStrickThroughProperty ? TextDecorations.Strikethrough : null; diff --git a/Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs b/Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs deleted file mode 100644 index a6d81b3b7..000000000 --- a/Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs +++ /dev/null @@ -1,292 +0,0 @@ -using System.Windows.Media; -using Color = System.Windows.Media.Color; -using ColorConverter = System.Windows.Media.ColorConverter; - -namespace PCL; - -/// -/// 支持小数与常见 WPF / Drawing 类型互转的颜色。 -/// -public class MyColor -{ - public double a = 255d; - public double b; - public double g; - public double r; - - public MyColor() - { - } - - public MyColor(Color color) - { - a = color.A; - r = color.R; - g = color.G; - b = color.B; - } - - public MyColor(string hexString) - { - var color = (Color)ColorConverter.ConvertFromString(hexString); - a = color.A; - r = color.R; - g = color.G; - b = color.B; - } - - public MyColor(double newA, MyColor color) - { - a = newA; - r = color.r; - g = color.g; - b = color.b; - } - - public MyColor(double newR, double newG, double newB) - { - a = 255d; - r = newR; - g = newG; - b = newB; - } - - public MyColor(double newA, double newR, double newG, double newB) - { - a = newA; - r = newR; - g = newG; - b = newB; - } - - public MyColor(Brush brush) - { - var color = ((SolidColorBrush)brush).Color; - a = color.A; - r = color.R; - g = color.G; - b = color.B; - } - - public MyColor(SolidColorBrush brush) : this(brush.Color) - { - } - - public MyColor(object? obj) - { - switch (obj) - { - case null: - a = 255d; - r = 255d; - g = 255d; - b = 255d; - break; - case SolidColorBrush brush: - var color = brush.Color; - a = color.A; - r = color.R; - g = color.G; - b = color.B; - break; - default: - a = Convert.ToDouble(((dynamic)obj).A); - r = Convert.ToDouble(((dynamic)obj).R); - g = Convert.ToDouble(((dynamic)obj).G); - b = Convert.ToDouble(((dynamic)obj).B); - break; - } - } - - public static implicit operator MyColor(string value) - { - return new MyColor(value); - } - - public static implicit operator MyColor(Color value) - { - return new MyColor(value); - } - - public static implicit operator MyColor(SolidColorBrush value) - { - return new MyColor(value.Color); - } - - public static implicit operator MyColor(Brush value) - { - return new MyColor(value); - } - - public static implicit operator Color(MyColor value) - { - return Color.FromArgb( - NumberUtils.ClampToByte(value.a), - NumberUtils.ClampToByte(value.r), - NumberUtils.ClampToByte(value.g), - NumberUtils.ClampToByte(value.b)); - } - - public static implicit operator System.Drawing.Color(MyColor value) - { - return System.Drawing.Color.FromArgb( - NumberUtils.ClampToByte(value.a), - NumberUtils.ClampToByte(value.r), - NumberUtils.ClampToByte(value.g), - NumberUtils.ClampToByte(value.b)); - } - - public static implicit operator SolidColorBrush(MyColor value) - { - return new SolidColorBrush((Color)value); - } - - public static implicit operator Brush(MyColor value) - { - return new SolidColorBrush((Color)value); - } - - public static MyColor operator +(MyColor left, MyColor right) - { - return new MyColor - { - a = left.a + right.a, - r = left.r + right.r, - g = left.g + right.g, - b = left.b + right.b - }; - } - - public static MyColor operator -(MyColor left, MyColor right) - { - return new MyColor - { - a = left.a - right.a, - r = left.r - right.r, - g = left.g - right.g, - b = left.b - right.b - }; - } - - public static MyColor operator *(MyColor left, double right) - { - return new MyColor - { - a = left.a * right, - r = left.r * right, - g = left.g * right, - b = left.b * right - }; - } - - public static MyColor operator /(MyColor left, double right) - { - return new MyColor - { - a = left.a / right, - r = left.r / right, - g = left.g / right, - b = left.b / right - }; - } - - public static bool operator ==(MyColor? left, MyColor? right) - { - if (left is null && right is null) return true; - if (left is null || right is null) return false; - return left.a == right.a && left.r == right.r && left.g == right.g && left.b == right.b; - } - - public static bool operator !=(MyColor? left, MyColor? right) - { - return !(left == right); - } - - private static double Hue(double value1, double value2, double hue) - { - if (hue < 0d) hue += 1d; - if (hue > 1d) hue -= 1d; - if (hue < 0.16667d) return value1 + (value2 - value1) * 6d * hue; - if (hue < 0.5d) return value2; - if (hue < 0.66667d) return value1 + (value2 - value1) * (4d - hue * 6d); - return value1; - } - - public MyColor FromHSL(double sourceHue, double sourceSaturation, double sourceLightness) - { - if (sourceSaturation == 0d) - { - r = sourceLightness * 2.55d; - g = r; - b = r; - } - else - { - var hue = sourceHue / 360d; - var saturation = sourceSaturation / 100d; - var lightness = sourceLightness / 100d; - saturation = lightness < 0.5d - ? saturation * lightness + lightness - : saturation * (1d - lightness) + lightness; - lightness = 2d * lightness - saturation; - r = 255d * Hue(lightness, saturation, hue + 1d / 3d); - g = 255d * Hue(lightness, saturation, hue); - b = 255d * Hue(lightness, saturation, hue - 1d / 3d); - } - - a = 255d; - return this; - } - - public MyColor FromHSL2(double sourceHue, double sourceSaturation, double sourceLightness) - { - if (sourceSaturation == 0d) - { - r = sourceLightness * 2.55d; - g = r; - b = r; - } - else - { - sourceHue = (sourceHue + 3600000d) % 360d; - var centers = new[] - { - +0.1d, -0.06d, -0.3d, -0.19d, -0.15d, -0.24d, -0.32d, -0.09d, - +0.18d, +0.05d, -0.12d, -0.02d, +0.1d, -0.06d - }; - var centerIndex = sourceHue / 30d; - var lowerIndex = (int)Math.Round(Math.Floor(centerIndex)); - var visualCenter = 50d - - ((1d - centerIndex + lowerIndex) * centers[lowerIndex] + - (centerIndex - lowerIndex) * centers[lowerIndex + 1]) * sourceSaturation; - sourceLightness = (sourceLightness < visualCenter - ? sourceLightness / visualCenter - : 1d + (sourceLightness - visualCenter) / (100d - visualCenter)) * 50d; - FromHSL(sourceHue, sourceSaturation, sourceLightness); - } - - a = 255d; - return this; - } - - public MyColor Alpha(double value) - { - a = value; - return this; - } - - public override string ToString() - { - return $"({a},{r},{g},{b})"; - } - - public override bool Equals(object? obj) - { - return obj is MyColor other && this == other; - } - - public override int GetHashCode() - { - return HashCode.Combine(a, r, g, b); - } -} diff --git a/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs b/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs index 0570c3ada..75fe1dacc 100644 --- a/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs +++ b/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs @@ -14,17 +14,17 @@ public static class ThemeManager public static ResourceDictionary AppResources => System.Windows.Application.Current.Resources; - public static MyColor colorGray1 = new(AppResources["ColorObjectGray1"]); - public static MyColor colorGray4 = new(AppResources["ColorObjectGray4"]); - public static MyColor colorGray5 = new(AppResources["ColorObjectGray5"]); - public static MyColor colorSemiTransparent = new(AppResources["ColorBrushSemiTransparent"]); + public static NColor colorGray1 = new(AppResources["ColorObjectGray1"]); + public static NColor colorGray4 = new(AppResources["ColorObjectGray4"]); + public static NColor colorGray5 = new(AppResources["ColorObjectGray5"]); + public static NColor colorSemiTransparent = new(AppResources["ColorBrushSemiTransparent"]); public static void ThemeRefresh(int newTheme = -1) { - colorGray1 = new MyColor(AppResources["ColorObjectGray1"]); - colorGray4 = new MyColor(AppResources["ColorObjectGray4"]); - colorGray5 = new MyColor(AppResources["ColorObjectGray5"]); - colorSemiTransparent = new MyColor(AppResources["ColorBrushSemiTransparent"]); + colorGray1 = new NColor(AppResources["ColorObjectGray1"]); + colorGray4 = new NColor(AppResources["ColorObjectGray4"]); + colorGray5 = new NColor(AppResources["ColorObjectGray5"]); + colorSemiTransparent = new NColor(AppResources["ColorBrushSemiTransparent"]); ThemeRefreshMain(); } diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs index ebed3be9b..a88c2aad5 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs @@ -1,11 +1,10 @@ -using System.Windows.Controls; +using System.Text.Json.Serialization; +using System.Windows.Controls; using System.Windows.Input; using PCL.Core.App; using PCL.Core.App.Localization; -using PCL.Core.UI.Controls; -using PCL.Core.Utils; using PCL.Core.IO.Net.Http; -using System.Text.Json.Serialization; +using PCL.Core.UI.Controls; namespace PCL; @@ -108,7 +107,7 @@ await Task.Delay(delayTime) } // 获取结果 var ctx = await result.AsStringAsync().ConfigureAwait(false); - var resultJson = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(ctx); + var resultJson = (JsonObject)JsonCompat.ParseNode(ctx); ModProfile.ProfileLog($"令牌过期时间:{resultJson["expires_in"]} 秒"); HintService.Hint(Lang.Text("Launch.Account.LoginDialog.Success"), HintType.Success); Finished(new[] { resultJson["access_token"].ToString(), resultJson["refresh_token"].ToString() }); @@ -173,8 +172,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? new MyColor(140d, 80d, 0d, 0d) - : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? NColor.FromArgb(140d, 80d, 0d, 0d) + : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -209,7 +208,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), From 62d2b4c9fc3b37fe7812283516440ba5c8dbf35d Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Thu, 2 Jul 2026 16:26:41 +0800 Subject: [PATCH 09/16] =?UTF-8?q?=E5=88=A0=E9=99=A4=20wrapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PCL.Core.Test/Utils/NumberUtilsTest.cs | 10 ++ PCL.Core/Utils/NumberUtils.cs | 49 +++++++ PCL.Core/Utils/SimilaritySearch.cs | 120 +++++++++--------- Plain Craft Launcher 2/Controls/MyImage.cs | 6 +- .../Controls/MyLoading.xaml.cs | 3 +- .../Controls/MyPageRight.cs | 14 +- .../Controls/MyScrollViewer.cs | 4 +- .../Controls/MySlider.xaml.cs | 5 +- Plain Craft Launcher 2/FormMain.xaml.cs | 20 ++- Plain Craft Launcher 2/GlobalUsings.cs | 4 +- .../Infrastructure/LauncherArguments.cs | 23 ---- .../Infrastructure/LauncherFeedbackService.cs | 2 - .../Infrastructure/LauncherFontService.cs | 4 +- .../Infrastructure/LauncherLog.cs | 1 - .../Infrastructure/LauncherMath.cs | 27 ---- .../Infrastructure/LauncherPaths.cs | 1 - .../Infrastructure/LauncherProcess.cs | 69 +++++++--- .../Infrastructure/LauncherSearch.cs | 84 ------------ .../Infrastructure/LauncherStringHash.cs | 16 +++ .../Infrastructure/LauncherText.cs | 92 -------------- .../Infrastructure/LegacyFileFacade.cs | 3 - .../Modules/Base/ModAnimation.cs | 50 ++++---- .../Modules/Base/ModLoader.cs | 4 +- .../Modules/Base/ModSetup.cs | 4 +- .../Modules/Minecraft/McInstance.cs | 18 +-- .../Modules/Minecraft/McInstanceInfo.cs | 32 ++--- .../Modules/Minecraft/McVersionComparer.cs | 6 +- .../Modules/Minecraft/ModAssets.cs | 2 +- .../Modules/Minecraft/ModComp.cs | 64 +++++----- .../Modules/Minecraft/ModDownload.cs | 4 +- .../Modules/Minecraft/ModInstanceList.cs | 6 +- .../Modules/Minecraft/ModLaunch.cs | 14 +- .../Modules/Minecraft/ModLibrary.cs | 10 +- .../Modules/Minecraft/ModLocalComp.cs | 18 +-- .../Modules/Minecraft/ModModpack.cs | 12 +- .../Modules/Minecraft/ModProfile.cs | 8 +- .../Modules/Minecraft/ModSkin.cs | 4 +- Plain Craft Launcher 2/Modules/ModMain.cs | 16 +-- .../Modules/UI/HintService.cs | 4 +- .../Pages/PageDownload/Comp/PageComp.xaml.cs | 12 +- .../Pages/PageDownload/ModDownloadLib.cs | 10 +- .../PageDownloadCompFavorites.xaml.cs | 16 +-- .../PageDownload/PageDownloadLeft.xaml.cs | 6 +- .../Pages/PageInstance/MyLocalModItem.xaml.cs | 6 +- .../PageInstanceCompResource.xaml.cs | 29 ++--- .../PageInstance/PageInstanceExport.xaml.cs | 10 +- .../PageInstance/PageInstanceLeft.xaml.cs | 6 +- .../PageInstance/PageInstanceSaves.xaml.cs | 12 +- .../PageInstanceSavesDatapack.xaml.cs | 27 ++-- .../PageInstanceSavesLeft.xaml.cs | 6 +- .../PageInstance/PageInstanceSetup.xaml.cs | 4 +- .../Pages/PageLaunch/PageLaunchLeft.xaml.cs | 8 +- .../Pages/PageSetup/PageSetupLaunch.xaml.cs | 4 +- .../Pages/PageSetup/PageSetupLeft.xaml.cs | 8 +- .../Pages/PageSpeedLeft.xaml.cs | 14 +- .../Pages/PageTools/PageToolsGameLink.xaml.cs | 4 +- .../Pages/PageTools/PageToolsLeft.xaml.cs | 6 +- .../Pages/PageTools/PageToolsTest.xaml.cs | 4 +- 58 files changed, 439 insertions(+), 586 deletions(-) delete mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherArguments.cs delete mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherMath.cs delete mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherSearch.cs create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherStringHash.cs delete mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherText.cs diff --git a/PCL.Core.Test/Utils/NumberUtilsTest.cs b/PCL.Core.Test/Utils/NumberUtilsTest.cs index 680f43f81..be687930d 100644 --- a/PCL.Core.Test/Utils/NumberUtilsTest.cs +++ b/PCL.Core.Test/Utils/NumberUtilsTest.cs @@ -22,4 +22,14 @@ public void LerpRoundsToSixDigits() { Assert.AreEqual(0.333333d, NumberUtils.Lerp(0d, 1d, 1d / 3d)); } + + [TestMethod] + [DataRow("12.5", 12.5d)] + [DataRow("not-a-number", 0d)] + [DataRow("&", 0d)] + [DataRow(null, 0d)] + public void ParseDoubleOrZeroUsesExplicitParsing(string? value, double expected) + { + Assert.AreEqual(expected, NumberUtils.ParseDoubleOrZero(value)); + } } \ No newline at end of file diff --git a/PCL.Core/Utils/NumberUtils.cs b/PCL.Core/Utils/NumberUtils.cs index 4c7f8e23d..863f1a681 100644 --- a/PCL.Core/Utils/NumberUtils.cs +++ b/PCL.Core/Utils/NumberUtils.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; namespace PCL.Core.Utils; @@ -39,6 +40,54 @@ public static double Lerp( return digits >= 0 ? Math.Round(value, digits) : value; } + /// + /// 使用明确的数值解析规则将对象转换为 double;解析失败时返回 0。 + /// + public static double ParseDoubleOrZero(object? value) + { + switch (value) + { + case null: + return 0d; + case double doubleValue: + return doubleValue; + case float floatValue: + return floatValue; + case decimal decimalValue: + return (double)decimalValue; + case IConvertible convertible and not string: + try + { + return convertible.ToDouble(CultureInfo.InvariantCulture); + } + catch + { + // 继续尝试字符串解析。 + } + + break; + } + + var text = Convert.ToString(value, CultureInfo.InvariantCulture); + if (string.IsNullOrWhiteSpace(text) || text == "&") return 0d; + + text = text.Trim(); + if (double.TryParse( + text, + NumberStyles.Float, + CultureInfo.InvariantCulture, + out var invariantResult)) + return invariantResult; + if (double.TryParse( + text, + NumberStyles.Float, + CultureInfo.CurrentCulture, + out var currentResult)) + return currentResult; + + return 0d; + } + /// /// 将数值限制在指定闭区间。 /// diff --git a/PCL.Core/Utils/SimilaritySearch.cs b/PCL.Core/Utils/SimilaritySearch.cs index f6f417ce9..e8ea99a1b 100644 --- a/PCL.Core/Utils/SimilaritySearch.cs +++ b/PCL.Core/Utils/SimilaritySearch.cs @@ -1,114 +1,111 @@ -namespace PCL.Core.Utils; - using System; using System.Collections.Generic; using System.Linq; +namespace PCL.Core.Utils; + /// -/// 提供文本相似度搜索功能。 +/// 提供文本相似度搜索功能。 /// -public static class SimilaritySearch { - //region: SearchSimilarity Constants - // 这些常量来自原始算法,用于调整评分权重。 +public static class SimilaritySearch +{ + /// + /// 默认本地模糊搜索返回深度。 + /// + public const int MaxLocalSearchDepth = 25; /// - /// 匹配长度权重计算的指数底数。越长匹配的得分呈指数增长。 + /// 匹配长度权重计算的指数底数。越长匹配的得分呈指数增长。 /// private const double LengthPowerBase = 1.4; /// - /// 匹配长度权重计算的偏移量。 + /// 匹配长度权重计算的偏移量。 /// private const double LengthWeightOffset = 3.6; /// - /// 匹配位置邻近度的奖励因子。 + /// 匹配位置邻近度的奖励因子。 /// private const double PositionBonusFactor = 0.3; /// - /// 计算位置奖励时,允许的最大位置差异。 + /// 计算位置奖励时,允许的最大位置差异。 /// private const int MaxPositionBonusDistance = 3; /// - /// 源文本长度对最终得分的影响因子。 + /// 源文本长度对最终得分的影响因子。 /// private const double SourceLengthImpactFactor = 3.0; /// - /// 源文本长度惩罚的平滑参数。 + /// 源文本长度惩罚的平滑参数。 /// private const double SourceLengthSmoothing = 15.0; /// - /// 对长度为1的查询的得分奖励。 + /// 对长度为1的查询的得分奖励。 /// private const double ShortQueryBonusFactor = 2.0; - //endregion /// - /// 获取搜索文本的相似度。(已优化) + /// 获取搜索文本的相似度。(已优化) /// /// 被搜索的长内容。 /// 用户输入的搜索文本。 /// 一个表示相似度的 double 值。 - private static double _SearchSimilarity(string source, string query) { - if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(query)) { - return 0.0; - } + private static double _SearchSimilarity(string source, string query) + { + if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(query)) return 0.0; // 预处理:转为小写并移除空格,然后转换为 ReadOnlySpan 以提高性能。 var sourceSpan = source.ToLower().Replace(" ", "").AsSpan(); var querySpan = query.ToLower().Replace(" ", "").AsSpan(); - if (sourceSpan.IsEmpty || querySpan.IsEmpty) { - return 0.0; - } + if (sourceSpan.IsEmpty || querySpan.IsEmpty) return 0.0; // 使用布尔数组来跟踪源文本中已被匹配的字符,避免重复分配字符串。 var usedSourceIndices = new bool[sourceSpan.Length]; double weightedLengthSum = 0; var queryIndex = 0; - while (queryIndex < querySpan.Length) { + while (queryIndex < querySpan.Length) + { var longestMatchLength = 0; var bestMatchSourceStartIndex = -1; // 寻找以当前 queryIndex 为起点的最长匹配子串 - for (var sourceIndex = 0; sourceIndex < sourceSpan.Length; sourceIndex++) { + for (var sourceIndex = 0; sourceIndex < sourceSpan.Length; sourceIndex++) + { var currentMatchLength = 0; // 计算从当前 sourceIndex 和 queryIndex 开始的匹配长度 // 同时确保源字符未被使用 - while ((queryIndex + currentMatchLength) < querySpan.Length && - (sourceIndex + currentMatchLength) < sourceSpan.Length && + while (queryIndex + currentMatchLength < querySpan.Length && + sourceIndex + currentMatchLength < sourceSpan.Length && !usedSourceIndices[sourceIndex + currentMatchLength] && - sourceSpan[sourceIndex + currentMatchLength] == querySpan[queryIndex + currentMatchLength]) { + sourceSpan[sourceIndex + currentMatchLength] == querySpan[queryIndex + currentMatchLength]) currentMatchLength++; - } // 卫语句:如果当前匹配不比最长匹配更长,则直接继续下一次循环 - if (currentMatchLength <= longestMatchLength) { - continue; - } + if (currentMatchLength <= longestMatchLength) continue; // 如果满足条件,更新最长匹配信息 longestMatchLength = currentMatchLength; bestMatchSourceStartIndex = sourceIndex; } - if (longestMatchLength > 0) { - // 标记源中对应的字符为已使用 - for (var i = 0; i < longestMatchLength; i++) { - usedSourceIndices[bestMatchSourceStartIndex + i] = true; - } + if (longestMatchLength > 0) + { + for (var i = 0; i < longestMatchLength; i++) usedSourceIndices[bestMatchSourceStartIndex + i] = true; // 根据长度加成 var incrementWeight = Math.Pow(LengthPowerBase, 3 + longestMatchLength) - LengthWeightOffset; // 根据位置加成 var positionDifference = Math.Abs(queryIndex - bestMatchSourceStartIndex); - var positionBonus = 1.0 + PositionBonusFactor * Math.Max(0, MaxPositionBonusDistance - positionDifference); + var positionBonus = + 1.0 + PositionBonusFactor * Math.Max(0, MaxPositionBonusDistance - positionDifference); incrementWeight *= positionBonus; weightedLengthSum += incrementWeight; @@ -127,9 +124,10 @@ private static double _SearchSimilarity(string source, string query) { } /// - /// 获取多段文本加权后的相似度。 + /// 获取多段文本加权后的相似度。 /// - private static double _SearchSimilarityWeighted(List> source, string query) { + private static double _SearchSimilarityWeighted(List> source, string query) + { if (source.Count == 0) return 0.0; var totalWeight = source.Sum(pair => pair.Value); @@ -141,9 +139,10 @@ private static double _SearchSimilarityWeighted(List - /// 检查一个条目的所有搜索源是否完全匹配查询的所有部分。 + /// 检查一个条目的所有搜索源是否完全匹配查询的所有部分。 /// - private static bool _IsAbsoluteMatch(IEnumerable> searchSources, string[] queryParts) { + private static bool _IsAbsoluteMatch(IEnumerable> searchSources, string[] queryParts) + { // 预处理搜索源:转小写并移除空格,避免在循环中重复操作 var processedSources = searchSources .Select(s => s.Key.Replace(" ", "").ToLower()) @@ -154,7 +153,7 @@ private static bool _IsAbsoluteMatch(IEnumerable> s } /// - /// 进行多段文本加权搜索,获取相似度较高的数项结果。 + /// 进行多段文本加权搜索,获取相似度较高的数项结果。 /// /// 搜索条目的泛型类型。 /// 要搜索的条目列表。 @@ -166,25 +165,21 @@ public static List> Search( List> entries, string query, int maxBlurCount = 5, - double minBlurSimilarity = 0.1) { - if (entries.Count == 0) { - return []; - } + double minBlurSimilarity = 0.1) + { + if (entries.Count == 0) return []; - if (string.IsNullOrWhiteSpace(query)) { - return entries; // 或者返回空列表,取决于业务需求 - } + if (string.IsNullOrWhiteSpace(query)) return entries; // 或者返回空列表,取决于业务需求 var queryParts = query.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Select(q => q.ToLower()) .ToArray(); - if (queryParts.Length == 0) { - return entries; - } + if (queryParts.Length == 0) return entries; // 1. 计算每个条目的相似度和是否完全匹配 - foreach (var entry in entries) { + foreach (var entry in entries) + { entry.Similarity = _SearchSimilarityWeighted(entry.SearchSource, query); entry.AbsoluteRight = _IsAbsoluteMatch(entry.SearchSource, queryParts); } @@ -196,7 +191,7 @@ public static List> Search( // 3. 构建最终结果列表 var sortedEntriesList = sortedEntries.ToList(); - + var absoluteMatches = sortedEntriesList.Where(e => e.AbsoluteRight); var blurMatches = sortedEntriesList @@ -208,28 +203,29 @@ public static List> Search( } /// -/// 用于搜索的项目。使用主构造函数 (C# 12+)。 +/// 用于搜索的项目。使用主构造函数 (C# 12+)。 /// /// 该项目对应的源数据类型。 -public class SearchEntry(T item, List> searchSource) { +public class SearchEntry(T item, List> searchSource) +{ /// - /// 该项目对应的源数据。 + /// 该项目对应的源数据。 /// public T Item { get; set; } = item; /// - /// 该项目用于搜索的源文本及其权重。 + /// 该项目用于搜索的源文本及其权重。 /// public List> SearchSource { get; set; } = searchSource; /// - /// 计算出的相似度。 + /// 计算出的相似度。 /// public double Similarity { get; set; } /// - /// 是否完全匹配。 - /// 如果查询的所有部分都能在搜索源中找到,则为 true。 + /// 是否完全匹配。 + /// 如果查询的所有部分都能在搜索源中找到,则为 true。 /// public bool AbsoluteRight { get; set; } -} +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/MyImage.cs b/Plain Craft Launcher 2/Controls/MyImage.cs index 5a0a95421..5b8cf6805 100644 --- a/Plain Craft Launcher 2/Controls/MyImage.cs +++ b/Plain Craft Launcher 2/Controls/MyImage.cs @@ -1,10 +1,9 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using PCL.Core.IO.Net.Http; -using PCL.Core.Utils; namespace PCL; @@ -129,7 +128,8 @@ public static Task DownloadImageAsync(string url) public static string GetTempPath(string url) { - return Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{LauncherText.GetStringMd5(url)}.png"); + return Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", + $"{BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(url).AsSpan())}.png"); } private static readonly ConcurrentDictionary> _downloadTasks = new(); diff --git a/Plain Craft Launcher 2/Controls/MyLoading.xaml.cs b/Plain Craft Launcher 2/Controls/MyLoading.xaml.cs index 64fb75c82..c3b4bcfd0 100644 --- a/Plain Craft Launcher 2/Controls/MyLoading.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyLoading.xaml.cs @@ -2,7 +2,6 @@ using System.Windows; using System.Windows.Input; using System.Windows.Media; -using PCL.Core.App.Localization; using static PCL.MyLoading; namespace PCL; @@ -110,7 +109,7 @@ private void RefreshText() else { while (ex.InnerException is not null) ex = ex.InnerException; - LabText.Text = LauncherText.StrTrim(ex.Message).ToString(); + LabText.Text = TextUtils.TrimDisplayName(ex.Message); if (new[] { "远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝", "操作已超时", "操作超时", "服务器超时", "连接超时" diff --git a/Plain Craft Launcher 2/Controls/MyPageRight.cs b/Plain Craft Launcher 2/Controls/MyPageRight.cs index c4d02137e..1fcee66d4 100644 --- a/Plain Craft Launcher 2/Controls/MyPageRight.cs +++ b/Plain Craft Launcher 2/Controls/MyPageRight.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; @@ -56,7 +56,7 @@ public PageStates PageState return; field = value; if (LauncherRuntime.ModeDebug) - LauncherLog.Log($"[UI] 页面状态切换为 {LauncherText.GetStringFromEnum(value)}"); + LauncherLog.Log($"[UI] 页面状态切换为 {value.ToString()}"); } } = PageStates.Empty; @@ -225,7 +225,7 @@ public void PageOnEnter() default: { - throw new Exception($"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnEnter 事件。"); + throw new Exception($"在状态为 {PageState.ToString()} 时触发了 PageOnEnter 事件。"); } } } @@ -381,7 +381,7 @@ private void PageOnEnterAnimationFinished() default: { throw new Exception( - $"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnEnterAnimationFinished 事件。"); + $"在状态为 {PageState.ToString()} 时触发了 PageOnEnterAnimationFinished 事件。"); } } } @@ -416,7 +416,7 @@ private void PageOnExitAnimationFinished() default: { throw new Exception( - $"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnExitAnimationFinished 事件。"); + $"在状态为 {PageState.ToString()} 时触发了 PageOnExitAnimationFinished 事件。"); } } } @@ -445,7 +445,7 @@ private void PageOnLoaderWaitFinished() default: { throw new Exception( - $"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnLoaderWaitFinished 事件。"); + $"在状态为 {PageState.ToString()} 时触发了 PageOnLoaderWaitFinished 事件。"); } } } @@ -478,7 +478,7 @@ private void PageOnLoaderStayFinished() default: { throw new Exception( - $"在状态为 {LauncherText.GetStringFromEnum(PageState)} 时触发了 PageOnLoaderWaitFinished 事件。"); + $"在状态为 {PageState.ToString()} 时触发了 PageOnLoaderWaitFinished 事件。"); } } } diff --git a/Plain Craft Launcher 2/Controls/MyScrollViewer.cs b/Plain Craft Launcher 2/Controls/MyScrollViewer.cs index fc3f596ab..06d0bdcd5 100644 --- a/Plain Craft Launcher 2/Controls/MyScrollViewer.cs +++ b/Plain Craft Launcher 2/Controls/MyScrollViewer.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -56,7 +56,7 @@ public void PerformVerticalOffsetDelta(double delta) { ModAnimation.AniStart(ModAnimation.AaDouble(animDelta => { - realOffset = LauncherMath.Clamp(realOffset + (double)animDelta, 0d, ExtentHeight - ActualHeight); + realOffset = NumberUtils.Clamp(realOffset + (double)animDelta, 0d, ExtentHeight - ActualHeight); ScrollToVerticalOffset(realOffset); }, delta * DeltaMult, 300, 0, new ModAnimation.AniEaseOutFluent((ModAnimation.AniEasePower)6), false)); } diff --git a/Plain Craft Launcher 2/Controls/MySlider.xaml.cs b/Plain Craft Launcher 2/Controls/MySlider.xaml.cs index eb415fb22..fd2a870ef 100644 --- a/Plain Craft Launcher 2/Controls/MySlider.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MySlider.xaml.cs @@ -2,7 +2,6 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; -using PCL.Core.App.Localization; namespace PCL; @@ -56,7 +55,7 @@ public int Value { try { - value = (int)Math.Round(LauncherMath.Clamp(value, 0d, MaxValue)); + value = (int)Math.Round(NumberUtils.Clamp(value, 0d, MaxValue)); if (_Value == value) return; @@ -162,7 +161,7 @@ private void DragStart(object sender, MouseButtonEventArgs e) public void DragDoing() { var percent = - LauncherMath.Clamp((Mouse.GetPosition(PanMain).X - ShapeDot.Width / 2d) / (ActualWidth - ShapeDot.Width), + NumberUtils.Clamp((Mouse.GetPosition(PanMain).X - ShapeDot.Width / 2d) / (ActualWidth - ShapeDot.Width), 0d, 1d); var newValue = (int)Math.Round(percent * MaxValue); diff --git a/Plain Craft Launcher 2/FormMain.xaml.cs b/Plain Craft Launcher 2/FormMain.xaml.cs index d3d2ae81c..dad207c85 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.cs +++ b/Plain Craft Launcher 2/FormMain.xaml.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using System.IO; using System.Net; using System.Runtime.InteropServices; @@ -9,13 +9,9 @@ using System.Windows.Media; using PCL.Core.App; using PCL.Core.App.IoC; -using PCL.Core.App.Localization; using PCL.Core.Logging; using PCL.Core.Minecraft; -using PCL.Core.UI; using PCL.Core.UI.Theme; -using PCL.Core.Utils; -using PCL.Core.Utils.OS; using PCL.Core.Utils.Validate; using PCL.Network; @@ -591,7 +587,7 @@ public static void EndProgramForce(LauncherExitCode returnCode = LauncherExitCod Thread.Sleep(500); // 防止 PCL 在记事本打开前就被掐掉 } - LauncherLog.Log("[System] 程序已退出,返回值:" + LauncherText.GetStringFromEnum(returnCode)); + LauncherLog.Log("[System] 程序已退出,返回值:" + returnCode); // If ReturnCode <> ProcessReturnValues.Success Then Environment.Exit(ReturnCode) // Process.GetCurrentProcess.Kill() Lifecycle.Shutdown((int)returnCode, force); @@ -894,7 +890,7 @@ private void HandleDrag(object sender, DragEventArgs e) _HandleDrag_PrevData = e.Data; _HandleDrag_PrevEffects = e.Effects; - LauncherLog.Log("[System] 设置拖放类型:" + LauncherText.GetStringFromEnum(e.Effects)); + LauncherLog.Log("[System] 设置拖放类型:" + e.Effects); } catch (Exception ex) { @@ -1676,7 +1672,7 @@ public void PageChange(PageStackData stack, PageSubType subType = PageSubType.De ModMain.frmDownloadLeft = new PageDownloadLeft(); foreach (var item in ModMain.frmDownloadLeft.PanItem.Children) if (item is MyListItem listItem && - LauncherText.Val(listItem.Tag) == (double)subType) + NumberUtils.ParseDoubleOrZero(listItem.Tag) == (double)subType) { listItem.SetChecked(true, true, stack == pageCurrent); break; @@ -1690,7 +1686,7 @@ public void PageChange(PageStackData stack, PageSubType subType = PageSubType.De ModMain.frmSetupLeft = new PageSetupLeft(); foreach (var item in ModMain.frmSetupLeft.PanItem.Children) if (item is MyListItem listItem && - LauncherText.Val(listItem.Tag) == (double)subType) + NumberUtils.ParseDoubleOrZero(listItem.Tag) == (double)subType) { listItem.SetChecked(true, true, stack == pageCurrent); break; @@ -1713,7 +1709,7 @@ public void PageChange(PageStackData stack, PageSubType subType = PageSubType.De ModMain.frmInstanceLeft = new PageInstanceLeft(); foreach (var item in ModMain.frmInstanceLeft.PanItem.Children) if (item is MyListItem listItem && - LauncherText.Val(listItem.Tag) == (double)subType) + NumberUtils.ParseDoubleOrZero(listItem.Tag) == (double)subType) { listItem.SetChecked(true, true, stack == pageCurrent); break; @@ -1727,7 +1723,7 @@ public void PageChange(PageStackData stack, PageSubType subType = PageSubType.De ModMain.frmInstanceSavesLeft = new PageInstanceSavesLeft(); foreach (var item in ModMain.frmInstanceSavesLeft.PanItem.Children) if (item is MyListItem listItem && - LauncherText.Val(listItem.Tag) == (double)subType) + NumberUtils.ParseDoubleOrZero(listItem.Tag) == (double)subType) { listItem.SetChecked(true, true, stack == pageCurrent); break; @@ -1926,7 +1922,7 @@ private void PageChangeActual(PageStackData stack, PageSubType subType) #endregion - LauncherLog.Log("[Control] 切换主要页面:" + LauncherText.GetStringFromEnum(stack) + ", " + (int)subType); + LauncherLog.Log("[Control] 切换主要页面:" + stack + ", " + (int)subType); } catch (Exception ex) { diff --git a/Plain Craft Launcher 2/GlobalUsings.cs b/Plain Craft Launcher 2/GlobalUsings.cs index a0ad62114..eb6675e6f 100644 --- a/Plain Craft Launcher 2/GlobalUsings.cs +++ b/Plain Craft Launcher 2/GlobalUsings.cs @@ -2,4 +2,6 @@ global using PCL.Core.UI; global using PCL.Core.Utils; global using PCL.Core.Utils.Exts; -global using PCL.Core.Utils.OS; \ No newline at end of file +global using PCL.Core.Utils.OS; +global using PCL.Core.App.Localization; +global using PCL.Core.Utils.Hash; \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherArguments.cs b/Plain Craft Launcher 2/Infrastructure/LauncherArguments.cs deleted file mode 100644 index 6c2c84d26..000000000 --- a/Plain Craft Launcher 2/Infrastructure/LauncherArguments.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.VisualBasic; - -namespace PCL; - -/// -/// PCL2 历史命令行参数解析兼容层。 -/// -public static class LauncherArguments -{ - public static object? Get(string name, object? defaultValue = null) - { - var allArguments = Interaction.Command().Split(" "); - for (int i = 0, loopTo = allArguments.Length - 1; i <= loopTo; i++) - if ((allArguments[i] ?? "") == ("-" + name ?? "")) - { - if (allArguments.Length == i + 1 || allArguments[i + 1].StartsWithF("-")) - return true; - return allArguments[i + 1]; - } - - return defaultValue; - } -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs b/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs index cd395ca63..9d99156be 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs @@ -1,9 +1,7 @@ using System.Globalization; using System.Runtime.InteropServices; using Microsoft.VisualBasic; -using PCL.Core.App.Localization; using PCL.Core.Logging; -using PCL.Core.Utils.OS; namespace PCL; diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs b/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs index b91a380ba..2e472e891 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs @@ -1,6 +1,4 @@ -using PCL.Core.App.Localization; - -namespace PCL; +namespace PCL; /// /// PCL2 启动器字体应用入口。 diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs b/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs index dce91a05f..a2ea1ecc4 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs @@ -1,6 +1,5 @@ using System.ComponentModel; using System.Diagnostics; -using PCL.Core.App.Localization; using PCL.Core.Logging; namespace PCL; diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs b/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs deleted file mode 100644 index cf70c4c33..000000000 --- a/Plain Craft Launcher 2/Infrastructure/LauncherMath.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace PCL; - -/// -/// PCL2 数值与旧颜色插值工具。用于承载 PCL2 数学 API。 -/// -public static class LauncherMath -{ - public static double Clamp(double value, double min, double max) - { - return NumberUtils.Clamp(value, min, max); - } - - public static double Percent(double valueA, double valueB, double percent) - { - return NumberUtils.Lerp(valueA, valueB, percent); - } - - public static NColor Percent(NColor valueA, NColor valueB, double percent) - { - return NColor.Lerp(valueA, valueB, percent); - } - - public static NColor Round(NColor color, int digits = 0) - { - return NColor.Round(color, digits); - } -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs b/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs index c2c8ea753..acb547c17 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs @@ -1,6 +1,5 @@ using System.IO; using PCL.Core.App; -using PCL.Core.Utils.OS; namespace PCL; diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs index 58fe9ea92..55588daf4 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs @@ -1,9 +1,7 @@ using System.Diagnostics; using System.IO; using System.Windows; -using PCL.Core.App.Localization; using PCL.Core.Logging; -using PCL.Core.Utils.OS; namespace PCL; @@ -17,10 +15,12 @@ public static void ShellOnly(string fileName, string arguments = "") try { fileName = LegacyFileFacade.ShortenPath(fileName); + using var program = new Process(); program.StartInfo.Arguments = arguments; program.StartInfo.FileName = fileName; program.StartInfo.UseShellExecute = true; + LauncherLog.Log($"[System] 执行外部命令:{fileName} {arguments}"); program.Start(); } @@ -42,11 +42,15 @@ public static LauncherExitCode ShellAndGetExitCode( try { LauncherLog.Log($"[System] 执行外部命令并等待返回码:{fileName} {arguments}"); + var result = ProcessRunner .CaptureAsync(fileName, arguments, timeout) .GetAwaiter() .GetResult(); - if (result.TimedOut) return LauncherExitCode.Timeout; + + if (result.TimedOut) + return LauncherExitCode.Timeout; + return result.ExitCode.HasValue ? (LauncherExitCode)result.ExitCode.Value : LauncherExitCode.Fail; @@ -65,10 +69,12 @@ public static string ShellAndGetOutput( string? workingDirectory = null) { LauncherLog.Log($"[System] 执行外部命令并等待返回结果:{fileName} {arguments}"); + var result = ProcessRunner .CaptureAsync(fileName, arguments, timeout, workingDirectory) .GetAwaiter() .GetResult(); + return result.CombinedOutput; } @@ -76,23 +82,29 @@ public static void OpenWebsite(string url) { try { - if (!url.StartsWithF("http", true) - && !url.StartsWithF("minecraft://", true)) + if (!url.StartsWithF("http", true) && + !url.StartsWithF("minecraft://", true)) throw new Exception($"{url} 不是一个有效的网址,它必须以 http 开头!"); + LauncherLog.Log($"[System] 正在打开网页:{url}"); + var psi = new ProcessStartInfo(url) { UseShellExecute = true }; + Process.Start(psi); } catch (Exception ex) { LauncherLog.Log(ex, $"无法打开网页({url})"); + ClipboardSet(url, false); + var message = ExceptionDetails.Compose( Lang.Text("SystemDialog.Browser.OpenFailed.Message", url), ex); + ModMain.MyMsgBox( message, Lang.Text("SystemDialog.Browser.OpenFailed.Title")); @@ -103,8 +115,11 @@ public static void OpenExplorer(string location) { try { - location = LegacyFileFacade.ShortenPath(location.Replace("/", @"\").Trim(' ', '"')); + location = LegacyFileFacade.ShortenPath( + location.Replace("/", @"\").Trim(' ', '"')); + LauncherLog.Log($"[System] 正在打开资源管理器:{location}"); + if (location.EndsWithF(@"\")) ShellOnly(location); else @@ -147,16 +162,24 @@ public static void ClipboardSet(string text, bool showSuccessHint = true) } if (success && showSuccessHint) - UiThread.Post(() => HintService.Hint(Lang.Text("Common.Hint.Copied"), HintType.Success)); + UiThread.Post(() => + HintService.Hint( + Lang.Text("Common.Hint.Copied"), + HintType.Success)); }); } - public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool copyDir = true) + public static int PasteFileFromClipboard( + string dest, + bool copyFile = true, + bool copyDir = true) { LauncherLog.Log($"[System] 从剪贴板粘贴文件到:{dest}"); + try { var files = Clipboard.GetFileDropList(); + if (files.Count.Equals(0)) { LauncherLog.Log("[System] 剪贴板内无文件可粘贴"); @@ -165,19 +188,21 @@ public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool var copiedFiles = 0; var copiedFolders = 0; - foreach (var i in files) + + foreach (var fileOrFolder in files) { - if (copyFile && File.Exists(i)) + if (copyFile && File.Exists(fileOrFolder)) try { - var thisDest = dest + LegacyFileFacade.GetFileNameFromPath(i); - if (File.Exists(thisDest)) + var targetPath = dest + LegacyFileFacade.GetFileNameFromPath(fileOrFolder); + + if (File.Exists(targetPath)) { - LauncherLog.Log($"[System] 已存在同名文件:{thisDest}"); + LauncherLog.Log($"[System] 已存在同名文件:{targetPath}"); } else { - File.Copy(i, thisDest); + File.Copy(fileOrFolder, targetPath); copiedFiles += 1; } } @@ -187,27 +212,29 @@ public static int PasteFileFromClipboard(string dest, bool copyFile = true, bool continue; } - if (copyDir && Directory.Exists(i)) + if (copyDir && Directory.Exists(fileOrFolder)) try { - var thisDest = dest + LegacyFileFacade.GetFolderNameFromPath(i); - if (Directory.Exists(thisDest)) + var targetPath = dest + LegacyFileFacade.GetFolderNameFromPath(fileOrFolder); + + if (Directory.Exists(targetPath)) { - LauncherLog.Log($"[System] 已存在同名文件夹:{thisDest}"); + LauncherLog.Log($"[System] 已存在同名文件夹:{targetPath}"); } else { - LegacyFileFacade.CopyDirectory(i, thisDest); + LegacyFileFacade.CopyDirectory(fileOrFolder, targetPath); copiedFolders += 1; } } catch (Exception ex) { - LauncherLog.Log(ex, "[System] 复制文件时出错"); + LauncherLog.Log(ex, "[System] 复制文件夹时出错"); } } - HintService.Hint(Lang.Text("Common.Hint.FilesPasted", copiedFiles, copiedFolders)); + HintService.Hint( + Lang.Text("Common.Hint.FilesPasted", copiedFiles, copiedFolders)); } catch (Exception ex) { diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherSearch.cs b/Plain Craft Launcher 2/Infrastructure/LauncherSearch.cs deleted file mode 100644 index 0285f0d19..000000000 --- a/Plain Craft Launcher 2/Infrastructure/LauncherSearch.cs +++ /dev/null @@ -1,84 +0,0 @@ -using CoreSimilaritySearch = PCL.Core.Utils.SimilaritySearch; - -namespace PCL; - -/// -/// PCL2 搜索调用点使用的兼容模型,内部使用 PCL.Core 的相似度搜索实现。 -/// -public static class LauncherSearch -{ - public const int MaxLocalSearchDepth = 25; - - public static List> Search( - List> entries, - string query, - int maxBlurCount = 5, - double minBlurSimilarity = 0.1d) - { - if (entries is null || entries.Count == 0) - return []; - - var coreEntries = entries - .Select((entry, index) => new Core.Utils.SearchEntry<(SearchEntry Entry, int Index)>( - (entry, index), - ToCoreSearchSources(entry.searchSource))) - .ToList(); - - var coreResults = CoreSimilaritySearch.Search(coreEntries, query, maxBlurCount, minBlurSimilarity); - foreach (var coreEntry in coreResults) - { - coreEntry.Item.Entry.absoluteRight = coreEntry.AbsoluteRight; - coreEntry.Item.Entry.similarity = coreEntry.Similarity; - } - - return coreResults.Select(result => result.Item.Entry).ToList(); - } - - private static List> ToCoreSearchSources(IEnumerable sources) - { - var result = new List>(); - if (sources is null) - return result; - - foreach (var source in sources) - { - if (source.aliases is null) - continue; - result.AddRange(source.aliases.Select(alias => new KeyValuePair(alias, source.weight))); - } - - return result; - } -} - -/// -/// 用于搜索的项目。 -/// -public class SearchEntry -{ - public bool absoluteRight; - public T item; - public List searchSource; - public double similarity; -} - -/// -/// 单个用于搜索的文本源。 -/// -public class SearchSource -{ - public string[] aliases; - public double weight; - - public SearchSource(string[] aliases, double weight = 1) - { - this.aliases = aliases; - this.weight = weight; - } - - public SearchSource(string text, double weight = 1) - { - aliases = [text]; - this.weight = weight; - } -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherStringHash.cs b/Plain Craft Launcher 2/Infrastructure/LauncherStringHash.cs new file mode 100644 index 000000000..4f1af2d7b --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherStringHash.cs @@ -0,0 +1,16 @@ +namespace PCL; + +/// +/// PCL2 历史字符串哈希算法。用于保持缓存文件名和登录头像编号等业务值稳定。 +/// +public static class LauncherStringHash +{ + public static ulong Compute(string value) + { + ArgumentNullException.ThrowIfNull(value); + var hash = value.Aggregate( + 5381UL, + (current, character) => (current << 5) ^ current ^ character); + return hash ^ 0xA98F501BC684032FUL; + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherText.cs b/Plain Craft Launcher 2/Infrastructure/LauncherText.cs deleted file mode 100644 index 0226527f3..000000000 --- a/Plain Craft Launcher 2/Infrastructure/LauncherText.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System.Collections; -using System.Text.RegularExpressions; -using Microsoft.VisualBasic; -using PCL.Core.App.Localization; -using PCL.Core.Utils.Hash; - -namespace PCL; - -/// -/// PCL2 文本、兼容解析与展示格式化工具。用于承载 PCL2 文本相关 API。 -/// -public static class LauncherText -{ - public static char LeftQuote { get; } = Convert.ToChar(8220); - public static char RightQuote { get; } = Convert.ToChar(8221); - - public static string GetStringFromEnum(Enum enumData) - { - return Enum.GetName(enumData.GetType(), enumData) ?? enumData.ToString(); - } - - public static string GetReadableFileSize(long fileSize) - { - return ByteStream.GetReadableLength(fileSize, provider: Lang.Culture); - } - - public static double Val(object? value) - { - try - { - return value is "&" ? 0d : Conversion.Val(value); - } - catch - { - return 0d; - } - } - - public static string StrFill(string str, string code, byte length) - { - return TextUtils.LeftPadOrTrim(str, code, length); - } - - public static object StrTrim(string str, bool removeQuote = true) - { - return TextUtils.TrimDisplayName(str, removeQuote); - } - - public static ulong GetHash(string str) - { - var hash = str.Aggregate( - 5381UL, - (current, t) => (current << 5) ^ current ^ t); - return hash ^ 0xA98F501BC684032FUL; - } - - public static string GetStringMd5(string str) - { - return BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(str).AsSpan()); - } - - public static string EscapeXml(string value) - { - return TextUtils.EscapeXml(value); - } - - public static string EscapeLikePattern(string value) - { - return TextUtils.EscapeLikePattern(value); - } - - public static string RegexReplaceEach(string str, string regex, MatchEvaluator evaluator, - RegexOptions options = RegexOptions.None) - { - return Regex.Replace(str, regex, evaluator, options); - } - - public static List RegexSearch(string str, string regex, RegexOptions options = RegexOptions.None) - { - return Regex.Matches(str, regex, options).Select(match => match.Value).ToList(); - } - - public static List RegexSearch(string str, Regex regex) - { - return regex.Matches(str).Select(match => match.Value).ToList(); - } - - public static List GetFullList(IList data) - { - return CollectionUtils.FlattenMixedList(data); - } -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs index 11ba28977..3a442ebcb 100644 --- a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs +++ b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs @@ -1,10 +1,7 @@ using System.Diagnostics; using System.IO; using System.Text; -using PCL.Core.IO; -using PCL.Core.Utils; using PCL.Core.Utils.Codecs; -using PCL.Core.Utils.Hash; using CoreDirectories = PCL.Core.IO.Directories; using CoreFiles = PCL.Core.IO.Files; diff --git a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs index 3bc8ddad5..1b069402f 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs @@ -51,7 +51,7 @@ public static void AniStart() { // 两帧之间的间隔时间 var deltaTime = - (long)Math.Round(LauncherMath.Clamp(TimeUtils.GetTimeTick() - aniLastTick, 0, 100000)); + (long)Math.Round(NumberUtils.Clamp(TimeUtils.GetTimeTick() - aniLastTick, 0, 100000)); if (deltaTime < minFrameGap) { // 限制 FPS @@ -63,7 +63,7 @@ public static void AniStart() // 记录 FPS if (LauncherRuntime.ModeDebug) { - if (LauncherMath.Clamp(aniLastTick - aniFPSTimer, 0d, 100000d) >= 500d) + if (NumberUtils.Clamp(aniLastTick - aniFPSTimer, 0d, 100000d) >= 500d) { aniFPS = aniFPSCounter; aniFPSCounter = 0; @@ -86,7 +86,7 @@ public static void AniStart() if (RandomUtils.NextInt(0, 64 * (LauncherRuntime.ModeDebug ? 5 : 30)) == 0 && ((aniFPS < 62 && aniFPS > 0) || aniCount > 4 || ModNet.NetManager.FileRemain != 0)) LauncherLog.Log( - $"[Report] FPS {aniFPS}, 动画 {aniCount}, 下载中 {ModNet.NetManager.FileRemain}({LauncherText.GetReadableFileSize(ModNet.NetManager.Speed)}/s)"); + $"[Report] FPS {aniFPS}, 动画 {aniCount}, 下载中 {ModNet.NetManager.FileRemain}({ByteStream.GetReadableLength(ModNet.NetManager.Speed, provider: Lang.Culture)}/s)"); }); } } @@ -215,7 +215,7 @@ private static AniData AniRun(AniData ani) { case AniType.Number: { - var delta = LauncherMath.Percent(0d, (double)ani.value, + var delta = NumberUtils.Lerp(0d, (double)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)); if (delta != 0d) switch (ani.typeSub) @@ -232,7 +232,7 @@ private static AniData AniRun(AniData ani) } case AniTypeSub.Opacity: { - ((dynamic)ani.obj).Opacity = LauncherMath.Clamp( + ((dynamic)ani.obj).Opacity = NumberUtils.Clamp( Convert.ToDouble(((dynamic)ani.obj).Opacity) + delta, 0d, 1d); break; } @@ -316,7 +316,7 @@ private static AniData AniRun(AniData ani) case AniType.Color: { // 利用 Last 记录了余下的小数值 - var delta = LauncherMath.Percent( + var delta = NColor.Lerp( NColor.FromArgb(0d, 0d, 0d, 0d), (NColor)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)) @@ -335,17 +335,17 @@ private static AniData AniRun(AniData ani) var delta = ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent); obj.Margin = new Thickness( obj.Margin.Left + - LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Left), delta), - obj.Margin.Top + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Top), delta), + NumberUtils.Lerp(0d, Convert.ToDouble(((dynamic)ani.value).Left), delta), + obj.Margin.Top + NumberUtils.Lerp(0d, Convert.ToDouble(((dynamic)ani.value).Top), delta), obj.Margin.Right + - LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Left), delta), + NumberUtils.Lerp(0d, Convert.ToDouble(((dynamic)ani.value).Left), delta), obj.Margin.Bottom + - LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Top), delta)); + NumberUtils.Lerp(0d, Convert.ToDouble(((dynamic)ani.value).Top), delta)); obj.Width = Math.Max( - obj.Width + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Width), delta), 0d); + obj.Width + NumberUtils.Lerp(0d, Convert.ToDouble(((dynamic)ani.value).Width), delta), 0d); obj.Height = Math.Max( - obj.Height + LauncherMath.Percent(0d, Convert.ToDouble(((dynamic)ani.value).Height), delta), + obj.Height + NumberUtils.Lerp(0d, Convert.ToDouble(((dynamic)ani.value).Height), delta), 0d); break; } @@ -401,7 +401,7 @@ private static AniData AniRun(AniData ani) obj.RenderTransform = new ScaleTransform(1d, 1d); } - var delta = LauncherMath.Percent(0d, (double)ani.value, + var delta = NumberUtils.Lerp(0d, (double)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)); ((ScaleTransform)obj.RenderTransform).ScaleX = Math.Max(((ScaleTransform)obj.RenderTransform).ScaleX + delta, 0d); @@ -419,7 +419,7 @@ private static AniData AniRun(AniData ani) obj.RenderTransform = new RotateTransform(0d); } - var delta = LauncherMath.Percent(0d, (double)ani.value, + var delta = NumberUtils.Lerp(0d, (double)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)); ((RotateTransform)obj.RenderTransform).Angle = ((RotateTransform)obj.RenderTransform).Angle + delta; break; @@ -559,7 +559,7 @@ public struct AniData public override string ToString() { return - $"{LauncherText.GetStringFromEnum(typeMain)} | {timeFinished}/{timeTotal}({Math.Round(timePercent * 100d)}%){(obj is null ? "" : $" | {obj}({obj.GetType().Name})")}"; + $"{(typeMain).ToString()} | {timeFinished}/{timeTotal}({Math.Round(timePercent * 100d)}%){(obj is null ? "" : $" | {obj}({obj.GetType().Name})")}"; } } @@ -1279,12 +1279,12 @@ public class AniEaseLinear : AniEase { public override double GetValue(double t) { - return LauncherMath.Clamp(t, 0d, 1d); + return NumberUtils.Clamp(t, 0d, 1d); } public override double GetDelta(double t1, double t0) { - return LauncherMath.Clamp(t1, 0d, 1d) - LauncherMath.Clamp(t0, 0d, 1d); + return NumberUtils.Clamp(t1, 0d, 1d) - NumberUtils.Clamp(t0, 0d, 1d); } } @@ -1303,7 +1303,7 @@ public AniEaseInFluent(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - return Math.Pow(LauncherMath.Clamp(t, 0d, 1d), (double)p); + return Math.Pow(NumberUtils.Clamp(t, 0d, 1d), (double)p); } } @@ -1321,7 +1321,7 @@ public AniEaseOutFluent(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - return 1d - Math.Pow(LauncherMath.Clamp(1d - t, 0d, 1d), (double)p); + return 1d - Math.Pow(NumberUtils.Clamp(1d - t, 0d, 1d), (double)p); } } @@ -1363,7 +1363,7 @@ public AniEaseOutFluentWithInitial(double initialPixelPerSecond, double totalSec public override double GetValue(double percent) { - var p = LauncherMath.Clamp(percent, 0d, 1d); + var p = NumberUtils.Clamp(percent, 0d, 1d); if (alpha == 0d) return p; // 退化到线性 return (alpha + 1d) * p / (1d + alpha * p); @@ -1385,7 +1385,7 @@ public AniEaseInBack(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - t = LauncherMath.Clamp(t, 0d, 1d); + t = NumberUtils.Clamp(t, 0d, 1d); return Math.Pow(t, p) * Math.Cos(1.5d * Math.PI * (1d - t)); } } @@ -1404,7 +1404,7 @@ public AniEaseOutBack(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - t = LauncherMath.Clamp(t, 0d, 1d); + t = NumberUtils.Clamp(t, 0d, 1d); return 1d - Math.Pow(1d - t, p) * Math.Cos(1.5d * Math.PI * t); } } @@ -1461,7 +1461,7 @@ public AniEaseInElastic(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - t = LauncherMath.Clamp(t, 0d, 1d); + t = NumberUtils.Clamp(t, 0d, 1d); return Math.Pow(t, (p - 1) * 0.25d) * Math.Cos((p - 3.5d) * Math.PI * Math.Pow(1d - t, 1.5d)); } } @@ -1480,7 +1480,7 @@ public AniEaseOutElastic(AniEasePower power = AniEasePower.Middle) public override double GetValue(double t) { - t = 1d - LauncherMath.Clamp(t, 0d, 1d); + t = 1d - NumberUtils.Clamp(t, 0d, 1d); return 1d - Math.Pow(t, (p - 1) * 0.25d) * Math.Cos((p - 3.5d) * Math.PI * Math.Pow(1d - t, 1.5d)); } } @@ -1501,7 +1501,7 @@ public static void AniStart(IList aniGroup, string name = "", bool refreshTime = // 添加到正在执行的动画组 var newEntry = new AniGroupEntry { - data = LauncherText.GetFullList(aniGroup), + data = CollectionUtils.FlattenMixedList(aniGroup), startTick = TimeUtils.GetTimeTick() }; if (string.IsNullOrEmpty(name)) diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.cs b/Plain Craft Launcher 2/Modules/Base/ModLoader.cs index 92caa75ca..2a8ff3e5e 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModLoader.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.cs @@ -94,7 +94,7 @@ public static double LoaderTaskbarProgressGet() if (!loaderTaskbar.Any()) return 1d; - return LauncherMath.Clamp( + return NumberUtils.Clamp( loaderTaskbar.Select(l => l.Progress).Average(), 0, 1 @@ -287,7 +287,7 @@ public LoadState State if (value == LoadState.Finished && Config.Debug.AddRandomDelay) Thread.Sleep(RandomUtils.NextInt(100, 2000)); field = value; - LauncherLog.Log($"[Loader] 加载器 {name} 状态改变:{LauncherText.GetStringFromEnum(value)}"); + LauncherLog.Log($"[Loader] 加载器 {name} 状态改变:{(value).ToString()}"); // 实现 ILoadingTrigger 接口与 OnStateChanged 回调 UiThread.Post(() => { diff --git a/Plain Craft Launcher 2/Modules/Base/ModSetup.cs b/Plain Craft Launcher 2/Modules/Base/ModSetup.cs index 38bf30d6b..320bfecf6 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModSetup.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModSetup.cs @@ -1,4 +1,4 @@ -using System.Net; +using System.Net; using System.Windows; using System.Windows.Media; using System.Windows.Media.Effects; @@ -603,7 +603,7 @@ public static void SystemDebugAnim(int value) { ModAnimation.aniSpeed = value >= 30 ? 200d - : LauncherMath.Clamp(value * 0.1d + 0.1d, 0.1d, 3d); + : NumberUtils.Clamp(value * 0.1d + 0.1d, 0.1d, 3d); } public static void SystemHttpProxy(string value) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs b/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs index cd3cc462f..35b5d7a72 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.IO; using System.IO.Compression; using System.Text.RegularExpressions; @@ -95,7 +95,7 @@ bool ShouldBeIndie() var isRelease = state != McInstanceState.Fool && state != McInstanceState.Old && state != McInstanceState.Snapshot; LauncherLog.Log( - $"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Config.Launch.IndieSolutionV2})判断,State {LauncherText.GetStringFromEnum(state)},IsRelease {isRelease},Modable {Modable}"); + $"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Config.Launch.IndieSolutionV2})判断,State {(state).ToString()},IsRelease {isRelease},Modable {Modable}"); return Config.Launch.IndieSolutionV2 switch { @@ -346,15 +346,15 @@ public McInstanceInfo Info { var segments = field.VanillaName.Split(" _-.".ToCharArray()); field.vanilla = new Version( - (int)Math.Round(LauncherText.Val(segments.Count() >= 2 ? segments[1] : "0")), - 0, (int)Math.Round(LauncherText.Val(segments.Count() >= 3 ? segments[2] : "0"))); + (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments.Count() >= 2 ? segments[1] : "0")), + 0, (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments.Count() >= 3 ? segments[2] : "0"))); } else if (field.VanillaName.RegexCheck(@"^[2-9][0-9]\.")) { var segments = field.VanillaName.Split(" _-.".ToCharArray()); - field.vanilla = new Version((int)Math.Round(LauncherText.Val(segments[0])), - (int)Math.Round(LauncherText.Val(segments.Count() >= 2 ? segments[1] : "0")), - (int)Math.Round(LauncherText.Val(segments.Count() >= 3 ? segments[2] : "0"))); + field.vanilla = new Version((int)Math.Round(NumberUtils.ParseDoubleOrZero(segments[0])), + (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments.Count() >= 2 ? segments[1] : "0")), + (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments.Count() >= 3 ? segments[2] : "0"))); } else { @@ -453,8 +453,8 @@ public JsonObject JsonObject subjsonList.Add(subjson); } subjsonList.Sort((left, right) => { - var leftVal = LauncherText.Val((left["priority"] ?? "0").ToString()); - var rightVal = LauncherText.Val((right["priority"] ?? "0").ToString()); + var leftVal = NumberUtils.ParseDoubleOrZero((left["priority"] ?? "0").ToString()); + var rightVal = NumberUtils.ParseDoubleOrZero((right["priority"] ?? "0").ToString()); return leftVal.CompareTo(rightVal); }); foreach (var Subjson in subjsonList) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs b/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs index 8a88eb360..92e516e39 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/McInstanceInfo.cs @@ -1,4 +1,4 @@ -using PCL.Core.App.Localization; +using PCL.Core.App.Localization; namespace PCL; @@ -157,7 +157,7 @@ public int OptiFineCode // 末尾数字,如 C5 beta4 中的 5 result *= 100; result = (int)Math.Round(result + - LauncherText.Val(OptiFine[1..].RegexSeek("[0-9]+"))); + NumberUtils.ParseDoubleOrZero(OptiFine[1..].RegexSeek("[0-9]+"))); // 测试标记(正式版为 99,Pre[x] 为 50+x,Beta[x] 为 x) result *= 100; if (OptiFine.ContainsF("pre", true)) @@ -165,12 +165,12 @@ public int OptiFineCode if (OptiFine.ContainsF("pre", true) || OptiFine.ContainsF("beta", true)) { var lastChar = OptiFine[^1..]; - if (LauncherText.Val(lastChar) == 0d && lastChar != "0") + if (NumberUtils.ParseDoubleOrZero(lastChar) == 0d && lastChar != "0") result += 1; // 为 pre 或 beta 结尾,视作 1 else result = (int)Math.Round(result + - LauncherText.Val(OptiFine.ToLower() + NumberUtils.ParseDoubleOrZero(OptiFine.ToLower() .RegexSeek("(?<=((pre)|(beta)))[0-9]+"))); } else @@ -206,25 +206,25 @@ public int ForgelikeCode { case var @case when @case > 4: { - return (int)Math.Round(LauncherText.Val(segments[0]) * 1000000d + - LauncherText.Val(segments[1]) * 10000d + - LauncherText.Val(segments[3])); + return (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments[0]) * 1000000d + + NumberUtils.ParseDoubleOrZero(segments[1]) * 10000d + + NumberUtils.ParseDoubleOrZero(segments[3])); } case 3: { - return (int)Math.Round(LauncherText.Val(segments[0]) * 1000000d + - LauncherText.Val(segments[1]) * 10000d + - LauncherText.Val(segments[2])); + return (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments[0]) * 1000000d + + NumberUtils.ParseDoubleOrZero(segments[1]) * 10000d + + NumberUtils.ParseDoubleOrZero(segments[2])); } case 2: { - return (int)Math.Round(LauncherText.Val(segments[0]) * 1000000d + - LauncherText.Val(segments[1]) * 10000d); + return (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments[0]) * 1000000d + + NumberUtils.ParseDoubleOrZero(segments[1]) * 10000d); } default: { - return (int)Math.Round(LauncherText.Val(segments[0]) * 1000000d); + return (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments[0]) * 1000000d); } } } @@ -284,7 +284,7 @@ public static bool IsFormatFit(string version) return false; if (version.RegexCheck(@"^1\.\d")) return true; - if (LauncherText.Val(version.RegexSeek(@"^[2-9]\d\.\d+")) > 25d) + if (NumberUtils.ParseDoubleOrZero(version.RegexSeek(@"^[2-9]\d\.\d+")) > 25d) return true; return false; } @@ -302,8 +302,8 @@ public static int VersionToDrop(string? version, bool allowSnapshot = false) var segments = version.BeforeFirst("-").Split("."); if (segments.Length < 2) return 0; - var major = (int)Math.Round(LauncherText.Val(segments[0])); - var minor = (int)Math.Round(LauncherText.Val(segments[1])); + var major = (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments[0])); + var minor = (int)Math.Round(NumberUtils.ParseDoubleOrZero(segments[1])); if (major == 1) return minor * 10; if (major < 25) return 0; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/McVersionComparer.cs b/Plain Craft Launcher 2/Modules/Minecraft/McVersionComparer.cs index e89522031..b88839b90 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/McVersionComparer.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/McVersionComparer.cs @@ -1,4 +1,4 @@ -using PCL.Core.App.Localization; +using PCL.Core.App.Localization; namespace PCL; @@ -63,7 +63,7 @@ public static int CompareVersion(string left, string right) leftValue = (-3).ToString(); if (leftValue == "experimental") leftValue = (-4).ToString(); - var leftValValue = LauncherText.Val(leftValue); + var leftValValue = NumberUtils.ParseDoubleOrZero(leftValue); if (rightValue == "rc") rightValue = (-1).ToString(); if (rightValue == "pre") @@ -72,7 +72,7 @@ public static int CompareVersion(string left, string right) rightValue = (-3).ToString(); if (rightValue == "experimental") rightValue = (-4).ToString(); - var rightValValue = LauncherText.Val(rightValue); + var rightValValue = NumberUtils.ParseDoubleOrZero(rightValue); if (leftValValue == 0d && rightValValue == 0d) { // 如果没有数值则直接比较字符串 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs index bfc9456cc..3014c0dae 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs @@ -110,7 +110,7 @@ public struct McAssetsToken public override string ToString() { - return $"{LauncherText.GetReadableFileSize(size)} | {localPath}"; + return $"{ByteStream.GetReadableLength(size, provider: Lang.Culture)} | {localPath}"; } } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs index b5cbf0599..c7f596243 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs @@ -1445,7 +1445,7 @@ private async Task GetChineseDescriptionAsync() var para = FromCurseForge ? "modId" : "project_id"; string result = null; - var descHash = $"{Id}{LauncherText.GetStringMd5(Description)}"; + var descHash = $"{Id}{BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(Description).AsSpan())}"; var cacheFilePath = $@"{LauncherPaths.TempWithSlash}Cache\CompTranslation.ini"; var cacheTranslation = LegacyIniStore.Shared.Read(cacheFilePath, descHash); if (!string.IsNullOrWhiteSpace(cacheTranslation)) @@ -2120,11 +2120,11 @@ public string GetModrinthAddress() address += "&offset=" + storage.modrinthOffset; // facets=[["categories:'game-mechanics'"],["categories:'forge'"],["versions:1.19.3"],["project_type:mod"]] var facets = new List(); - facets.Add($"[\"project_type:{LauncherText.GetStringFromEnum(type).ToLower()}\"]"); + facets.Add($"[\"project_type:{(type).ToString().ToLower()}\"]"); if (!string.IsNullOrEmpty(tag)) facets.Add($"[\"categories:'{tag.AfterLast("/")}'\"]"); if (modLoader != CompLoaderType.Any) - facets.Add($"[\"categories:'{LauncherText.GetStringFromEnum(modLoader).ToLower()}'\"]"); + facets.Add($"[\"categories:'{(modLoader).ToString().ToLower()}'\"]"); if (!string.IsNullOrEmpty(gameVersion)) facets.Add($"[\"versions:'{gameVersion}'\"]"); address += "&facets=[" + string.Join(",", facets) + "]"; @@ -2397,29 +2397,28 @@ public static void CompProjectsGet(ModLoader.LoaderTask foreach (var searchItem in searchRes) { if (searchItem.ChineseName.Contains("动态的树")) continue; - searchEntries.Add(new SearchEntry - { - item = searchItem, - searchSource = new List - { - new(searchItem.ChineseName.BeforeFirst(" (").Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries), 1), - new(searchItem.ChineseName.AfterFirst(" (") + (searchItem.CurseForgeSlug ?? "") + (searchItem.ModrinthSlug ?? ""), 0.5) - } - }); + var searchSource = searchItem.ChineseName.BeforeFirst(" (") + .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries) + .Select(alias => new KeyValuePair(alias, 1d)) + .ToList(); + searchSource.Add(new KeyValuePair( + searchItem.ChineseName.AfterFirst(" (") + (searchItem.CurseForgeSlug ?? "") + (searchItem.ModrinthSlug ?? ""), + 0.5d)); + searchEntries.Add(new SearchEntry(searchItem, searchSource)); } } - var searchResults = LauncherSearch.Search(searchEntries, request.searchText, 40, 0.2); + var searchResults = SimilaritySearch.Search(searchEntries, request.searchText, 40, 0.2); if (!searchResults.Any()) throw new Exception(Lang.Text("Download.Comp.List.NoResults")); string[] ExtractWords(SearchEntry result) { var word = ""; - if (result.item.CurseForgeSlug is not null) - word += result.item.CurseForgeSlug.Replace("-", " ").Replace("/", " ") + " "; - if (result.item.ModrinthSlug is not null) - word += result.item.ModrinthSlug.Replace("-", " ").Replace("/", " ") + " "; - word += result.item.ChineseName.AfterLast(" (").TrimEnd(')', ' ').BeforeFirst(" - ") + if (result.Item.CurseForgeSlug is not null) + word += result.Item.CurseForgeSlug.Replace("-", " ").Replace("/", " ") + " "; + if (result.Item.ModrinthSlug is not null) + word += result.Item.ModrinthSlug.Replace("-", " ").Replace("/", " ") + " "; + word += result.Item.ChineseName.AfterLast(" (").TrimEnd(')', ' ').BeforeFirst(" - ") .Replace(":", "").Replace("(", "").Replace(")", "").ToLower().Replace("/", " ").Replace("-", " "); var words = word.ToLower().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); words = words.Select(w => w.TrimStart('{', '[', '(').TrimEnd('}', ']', ')')).Where( @@ -2427,7 +2426,7 @@ string[] ExtractWords(SearchEntry result) { if (w.Length <= 1) return false; if (new[] { "the", "of", "mod", "and" }.Contains(w)) return false; - if (LauncherText.Val(w) > 0) return false; + if (NumberUtils.ParseDoubleOrZero(w) > 0) return false; if (w.Split(' ').Length > 3 && w.Contains("ftb")) return false; return true; }).Distinct().ToArray(); @@ -2439,9 +2438,9 @@ string[] ExtractWords(SearchEntry result) { foreach (var word in ExtractWords(result)) { - var similarity = result.searchSource.Any(s => s.aliases.Contains(request.searchText)) + var similarity = result.SearchSource.Any(s => string.Equals(s.Key, request.searchText, StringComparison.Ordinal)) ? 100000 - : result.similarity; + : result.Similarity; if (!wordWeights.ContainsKey(word)) wordWeights.Add(word, 0); wordWeights[word] += similarity; @@ -2652,22 +2651,19 @@ void processKeywords(ref string text) scores.Add(res, (Lang.IsChineseMainland && res.WikiId > 0 ? 0.2 : 0) + Math.Log10(Math.Max(res.DownloadCount, 1) * getDownloadCountMult(res)) / 9); - searchEntries.Add(new SearchEntry - { - item = res, - searchSource = new List - { - new((isChineseSearch ? res.TranslatedName : res.RawName).Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries), 1), - new(res.Description, 0.05) - } - }); + var searchSource = (isChineseSearch ? res.TranslatedName : res.RawName) + .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries) + .Select(alias => new KeyValuePair(alias, 1d)) + .ToList(); + searchSource.Add(new KeyValuePair(res.Description, 0.05d)); + searchEntries.Add(new SearchEntry(res, searchSource)); } - var searchRes = LauncherSearch.Search(searchEntries, rawFilter, 101, -1); + var searchRes = SimilaritySearch.Search(searchEntries, rawFilter, 101, -1); foreach (var item in searchRes) - scores[item.item] += - (item.absoluteRight ? 10 : item.similarity) / - (searchRes.First().absoluteRight ? 10 : searchRes.First().similarity); + scores[item.Item] += + (item.AbsoluteRight ? 10 : item.Similarity) / + (searchRes.First().AbsoluteRight ? 10 : searchRes.First().Similarity); } if (task.IsAborted) throw new ThreadInterruptedException(); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs index 429ca68be..079604a2b 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs @@ -234,7 +234,7 @@ public static List AllDrops field = new List(); else field = rawData.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) - .Select(d => (int)Math.Round(LauncherText.Val(d))).ToList(); + .Select(d => (int)Math.Round(NumberUtils.ParseDoubleOrZero(d))).ToList(); } return field.Count != 0 ? field : null; @@ -1412,7 +1412,7 @@ public static void DlNeoForgeListBmclapiMain(ModLoader.LoaderTask GetNeoForgeEntries(string latestJson, string latestLegacyJson) { - var versionNames = LauncherText.RegexSearch(latestLegacyJson + latestJson, RegexPatterns.DlNeoForgeVersion); + var versionNames = (latestLegacyJson + latestJson).RegexSearch(RegexPatterns.DlNeoForgeVersion); var versions = versionNames.Where(name => name != "47.1.82").Select(name => new DlNeoForgeListEntry(name)) .OrderByDescending(a => a).ToList(); // 这个版本虽然在版本列表中,但不能下载 if (!versions.Any()) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs index 874fac5fd..b75a50851 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using PCL.Core.App; using PCL.Core.App.Localization; using PCL.Core.Utils; @@ -92,12 +92,12 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) } // 根据文件夹名列表生成辨识码 - var folderListHash = LauncherText.GetHash(mcInstanceCacheVersion + "#" + string.Join("#", folderList)); + var folderListHash = LauncherStringHash.Compute(mcInstanceCacheVersion + "#" + string.Join("#", folderList)); var folderListCheck = (int)(folderListHash % (int.MaxValue - 1)); // 尝试使用缓存 var useCache = !mcInstanceListForceRefresh && - LauncherText.Val(LegacyIniStore.Shared.Read(Path.Combine(path, "PCL.ini"), + NumberUtils.ParseDoubleOrZero(LegacyIniStore.Shared.Read(Path.Combine(path, "PCL.ini"), "InstanceCache")) == folderListCheck; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs index 95c99b833..0f850bd87 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs @@ -396,7 +396,7 @@ private static void McLaunchStart(ModLoader.LoaderTask default: { throw new Exception(Lang.Text("Minecraft.Launch.Error.InvalidState", - LauncherText.GetStringFromEnum(launchLoader.State))); + (launchLoader.State).ToString())); } } @@ -515,7 +515,7 @@ public McLoginServer(McLoginType type) public override int GetHashCode() { - return (int)Math.Round(LauncherText.GetHash(UserName + Password + BaseUrl + (int)LoginType) % + return (int)Math.Round(LauncherStringHash.Compute(UserName + Password + BaseUrl + (int)LoginType) % (decimal)int.MaxValue); } } @@ -545,7 +545,7 @@ public McLoginMs() public override int GetHashCode() { return (int)Math.Round( - LauncherText.GetHash(OAuthRefreshToken + AccessToken + Uuid + UserName + ProfileJson) % + LauncherStringHash.Compute(OAuthRefreshToken + AccessToken + Uuid + UserName + ProfileJson) % (decimal)int.MaxValue); } } @@ -584,7 +584,7 @@ public McLoginLegacy() public override int GetHashCode() { return (int)Math.Round( - LauncherText.GetHash(UserName + SkinType + SkinName + (int)LoginType) % (decimal)int.MaxValue); + LauncherStringHash.Compute(UserName + SkinType + SkinName + (int)LoginType) % (decimal)int.MaxValue); } } @@ -918,8 +918,8 @@ private static string[] MsLoginStep1New(ModLoader.LoaderTask LauncherProcess.OpenWebsite("https://account.live.com/password/Change")) == 1) goto Retry; @@ -1996,7 +1996,7 @@ private static void McLaunchJava(ModLoader.LoaderTask task) if (ModInstanceList.McMcInstanceSelected.JsonObject["javaVersion"] is not null) { var majorVersion = - LauncherText.Val(ModInstanceList.McMcInstanceSelected.JsonObject["javaVersion"]["majorVersion"]); + NumberUtils.ParseDoubleOrZero(ModInstanceList.McMcInstanceSelected.JsonObject["javaVersion"]["majorVersion"]); if (LauncherRuntime.ModeDebug) LauncherLog.Log("[Launch] [Debug] JSON 中参数要求至少 Java " + majorVersion); if (majorVersion <= 8d) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs index 58c511042..87bd4f737 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs @@ -70,7 +70,7 @@ public string Name public override string ToString() { - return (IsNatives ? "[Native] " : "") + LauncherText.GetReadableFileSize(size) + " | " + LocalPath; + return (IsNatives ? "[Native] " : "") + ByteStream.GetReadableLength(size, provider: Lang.Culture) + " | " + LocalPath; } } @@ -269,7 +269,7 @@ public static List McLibListGetWithJson(JsonObject jsonObject, ? McLibGet((string)library["name"], customMcFolder: customMcFolder) : McLibGetByArtifactPath(artifactPath.ToString(), customMcFolder), init.size = (long)Math.Round( - LauncherText.Val(library["downloads"]["artifact"]["size"].ToString())), + NumberUtils.ParseDoubleOrZero(library["downloads"]["artifact"]["size"].ToString())), init.IsNatives = false, init.Sha1 = library["downloads"]["artifact"]["sha1"]?.ToString(), init.IsLocal = isLocal, init).init); } @@ -317,7 +317,7 @@ public static List McLibListGetWithJson(JsonObject jsonObject, .Replace("${arch}", Environment.Is64BitOperatingSystem ? "64" : "32") : McLibGetByArtifactPath(nativePath.ToString(), customMcFolder), size = (long)Math.Round( - LauncherText.Val(library["downloads"]["classifiers"]["natives-windows"]["size"] + NumberUtils.ParseDoubleOrZero(library["downloads"]["classifiers"]["natives-windows"]["size"] .ToString())), IsNatives = true, Sha1 = library["downloads"]["classifiers"]["natives-windows"]["sha1"].ToString(), @@ -642,9 +642,9 @@ public static string McLibGet(string original, bool withHead = true, bool ignore // 判断 OptiFine 是否应该使用 installer if (mcLibGetRet.Contains(@"optifine\OptiFine\1.") && splited[2].Split(".").Count() > 1) { - var majorVersion = (int)Math.Round(LauncherText.Val(splited[2].Split(".")[1].BeforeFirst("_"))); + var majorVersion = (int)Math.Round(NumberUtils.ParseDoubleOrZero(splited[2].Split(".")[1].BeforeFirst("_"))); var minorVersion = (int)Math.Round(splited[2].Split(".").Count() > 2 - ? LauncherText.Val(splited[2].Split(".")[2].BeforeFirst("_")) + ? NumberUtils.ParseDoubleOrZero(splited[2].Split(".")[2].BeforeFirst("_")) : 0d); if ((majorVersion == 12 || (majorVersion == 20 && minorVersion >= 4) || majorVersion >= 21) && File.Exists( $@"{customMcFolder}libraries\{splited[0].Replace(".", @"\")}\{splited[1]}\{splited[2]}\{splited[1]}-{splited[2]}-installer.jar")) // 仅在 1.12 (无法追溯) 和 1.20.4+ (#5376) 遇到此问题 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs index 6c71031ae..8c5cdc097 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.IO.Compression; using System.Text; using System.Text.RegularExpressions; @@ -460,7 +460,7 @@ public string Name set { if (_Name is null && value is not null && !value.Contains("modname") && value.ToLower() != "name" && - value.Length > 1 && (LauncherText.Val(value).ToString() ?? "") != (value ?? "")) _Name = value; + value.Length > 1 && (NumberUtils.ParseDoubleOrZero(value).ToString() ?? "") != (value ?? "")) _Name = value; } } @@ -577,7 +577,7 @@ public string ModId if (value is null) return; value = value.RegexSeek(RegexPatterns.ModIdMatch); - if (value is null || value.Length <= 1 || (LauncherText.Val(value).ToString() ?? "") == (value ?? "")) + if (value is null || value.Length <= 1 || (NumberUtils.ParseDoubleOrZero(value).ToString() ?? "") == (value ?? "")) return; if (value.ContainsF("name", true) || value.ContainsF("modid", true)) return; @@ -838,7 +838,7 @@ private void AddDependency(string modID, string versionRequirement = null) if (modID is null || modID.Length < 2) return; modID = modID.ToLower(); - if (modID == "name" || (LauncherText.Val(modID).ToString() ?? "") == (modID ?? "")) + if (modID == "name" || (NumberUtils.ParseDoubleOrZero(modID).ToString() ?? "") == (modID ?? "")) return; // 跳过 name 与纯数字 id if (versionRequirement is null || (!versionRequirement.Contains(".") && !versionRequirement.Contains("-")) || @@ -1163,7 +1163,7 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = LauncherText.GetStringMd5(logoItem.Length + logoItem.CompressedLength + path); + var md5 = BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(logoItem.Length + logoItem.CompressedLength + path).AsSpan()); Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { @@ -1256,7 +1256,7 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = LauncherText.GetStringMd5(logoItem.Length + logoItem.CompressedLength + path); + var md5 = BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(logoItem.Length + logoItem.CompressedLength + path).AsSpan()); Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { @@ -1321,7 +1321,7 @@ private void LookupMetadata(ZipArchive jar) var logoItem = jar.GetEntry(logoFile); if (logoItem is not null) { - var md5 = LauncherText.GetStringMd5(logoItem.Length + logoItem.CompressedLength + path); + var md5 = BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(logoItem.Length + logoItem.CompressedLength + path).AsSpan()); Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { @@ -1551,7 +1551,7 @@ private void LookupMetadata(ZipArchive jar) break; value = value.ToLower().RegexSeek(RegexPatterns.ModIdMatch); if (value is not null && value.ToLower() != "name" && value.Length > 1 && - (LauncherText.Val(value).ToString() ?? "") != (value ?? "")) + (NumberUtils.ParseDoubleOrZero(value).ToString() ?? "") != (value ?? "")) if (!possibleModId.Contains(value)) possibleModId.Add(value); break; @@ -1614,7 +1614,7 @@ private void LookupMetadata(ZipArchive jar) if (packPngEntry is not null) try { - var md5 = LauncherText.GetStringMd5(packPngEntry.Length + packPngEntry.CompressedLength + path); + var md5 = BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(packPngEntry.Length + packPngEntry.CompressedLength + path).AsSpan()); Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = packPngEntry.Open()) { diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs index 36fb97004..3c3cf4aad 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Text; @@ -1450,25 +1450,25 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive var javaMajors = (JsonArray)patchJson["compatibleJavaMajors"]; foreach (var Java in javaMajors) { - if (javaVersion > LauncherText.Val(Java)) + if (javaVersion > NumberUtils.ParseDoubleOrZero(Java)) continue; // 优先选择主要的版本 - if (LauncherText.Val(Java) == 21d) + if (NumberUtils.ParseDoubleOrZero(Java) == 21d) { javaVersion = 21; javaComponent = "java-runtime-delta"; } - else if (LauncherText.Val(Java) == 17d) + else if (NumberUtils.ParseDoubleOrZero(Java) == 17d) { javaVersion = 17; javaComponent = "java-runtime-gamma"; } - else if (LauncherText.Val(Java) == 11d) + else if (NumberUtils.ParseDoubleOrZero(Java) == 11d) { javaVersion = 11; javaComponent = null; } - else if (LauncherText.Val(Java) == 8d) + else if (NumberUtils.ParseDoubleOrZero(Java) == 8d) { javaVersion = 8; javaComponent = "jre-legacy"; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs index 9d615b25b..4dfed3227 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs @@ -1,4 +1,4 @@ -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.IO; using System.Net.Http; using System.Security.Cryptography; @@ -48,7 +48,7 @@ public static void ProfileLog(string content, LauncherLogLevel level = LauncherL public static object McLoginMojangUuid(string name, bool throwOnNotFound) { if (name.Trim().Length == 0) - return LauncherText.StrFill("", "0", 32); + return TextUtils.LeftPadOrTrim("", "0", 32); // 从缓存获取 var uuid = LegacyIniStore.Shared.Read(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini", name); if ((uuid?.Length ?? 0) == 32) @@ -591,8 +591,8 @@ public static string GetOfflineUuid(string userName, bool isSplited = false, boo { if (isLegacy) { - var fullUuid = LauncherText.StrFill(userName.Length.ToString("X"), "0", 16) + - LauncherText.StrFill(LauncherText.GetHash(userName).ToString("X"), "0", 16); + var fullUuid = TextUtils.LeftPadOrTrim(userName.Length.ToString("X"), "0", 16) + + TextUtils.LeftPadOrTrim(LauncherStringHash.Compute(userName).ToString("X"), "0", 16); return fullUuid.Substring(0, 12) + "3" + fullUuid.Substring(13, 3) + "9" + fullUuid.Substring(17, 15); } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs index 5192073f0..222a4ccfd 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.IO; using System.Text; using Microsoft.VisualBasic; @@ -146,7 +146,7 @@ public static string McSkinGetAddress(string uuid, string type) public static string McSkinDownload(string address) { var skinName = LegacyFileFacade.GetFileNameFromPath(address); - var fileAddress = LauncherPaths.TempWithSlash + @"Cache\Skin\" + LauncherText.GetHash(address) + ".png"; + var fileAddress = LauncherPaths.TempWithSlash + @"Cache\Skin\" + LauncherStringHash.Compute(address) + ".png"; lock (mcSkinDownloadLock) { if (!File.Exists(fileAddress)) diff --git a/Plain Craft Launcher 2/Modules/ModMain.cs b/Plain Craft Launcher 2/Modules/ModMain.cs index 68773e901..ba230fe9f 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.cs +++ b/Plain Craft Launcher 2/Modules/ModMain.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Collections.ObjectModel; using System.IO; using System.Runtime.InteropServices; @@ -773,10 +773,10 @@ private static void TimerFool() frmLaunchLeft.AprilPosTrans.Y += aprilSpeed.Y; // 大小改变 frmLaunchLeft.AprilScaleTrans.ScaleX = - LauncherMath.Clamp(1d - (Math.Abs(direction.X) - Math.Abs(direction.Y)) * (speedValue / 160d), 0.2d, + NumberUtils.Clamp(1d - (Math.Abs(direction.X) - Math.Abs(direction.Y)) * (speedValue / 160d), 0.2d, 1.8d); frmLaunchLeft.AprilScaleTrans.ScaleY = - LauncherMath.Clamp(1d - (Math.Abs(direction.Y) - Math.Abs(direction.X)) * (speedValue / 100d), 0.2d, + NumberUtils.Clamp(1d - (Math.Abs(direction.Y) - Math.Abs(direction.X)) * (speedValue / 100d), 0.2d, 1.8d); // 放弃提示 if (aprilDistance > 4000) @@ -982,16 +982,16 @@ public static string ArgumentReplace(string text, Func escapeHan } // 高级 - text = LauncherText.RegexReplaceEach(text, @"\{hint\}", m => replacer(PageToolsTest.GetRandomHint())); - text = LauncherText.RegexReplaceEach(text, @"\{cave\}", m => replacer(PageToolsTest.GetRandomCave())); - text = LauncherText.RegexReplaceEach(text, @"\{setup:([a-zA-Z0-9]+)\}", m => + text = (text).RegexReplaceEach(@"\{hint\}", m => replacer(PageToolsTest.GetRandomHint())); + text = (text).RegexReplaceEach(@"\{cave\}", m => replacer(PageToolsTest.GetRandomCave())); + text = (text).RegexReplaceEach(@"\{setup:([a-zA-Z0-9]+)\}", m => { if (ConfigService.TryGetConfigItemNoType(m.Groups[1].Value, out var item) && item.Source != ConfigSource.SharedEncrypt) return replacer(item.GetValueNoType(ModInstanceList.McMcInstanceSelected?.PathInstance)?.ToString() ?? ""); return replacer(""); }); - text = LauncherText.RegexReplaceEach(text, @"\{varible:([^:\}]+)(?::([^\}]+))?\}", m => replacer(CustomEvent.GetCustomVariable(m.Groups[1].Value, m.Groups[2].Value))); - text = LauncherText.RegexReplaceEach(text, @"\{variable:([^:\}]+)(?::([^\}]+))?\}", m => replacer(CustomEvent.GetCustomVariable(m.Groups[1].Value, m.Groups[2].Value))); + text = (text).RegexReplaceEach(@"\{varible:([^:\}]+)(?::([^\}]+))?\}", m => replacer(CustomEvent.GetCustomVariable(m.Groups[1].Value, m.Groups[2].Value))); + text = (text).RegexReplaceEach(@"\{variable:([^:\}]+)(?::([^\}]+))?\}", m => replacer(CustomEvent.GetCustomVariable(m.Groups[1].Value, m.Groups[2].Value))); return text; } diff --git a/Plain Craft Launcher 2/Modules/UI/HintService.cs b/Plain Craft Launcher 2/Modules/UI/HintService.cs index 320f2b273..a32bd9b73 100644 --- a/Plain Craft Launcher 2/Modules/UI/HintService.cs +++ b/Plain Craft Launcher 2/Modules/UI/HintService.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; namespace PCL; @@ -79,7 +79,7 @@ internal static void Tick() HintType.Warning => "lucide/triangle-alert", _ => "lucide/info" }, - DisplayDuration = (800d + LauncherMath.Clamp(currentHint.Text.Length, 5d, 23d) * 180d) * ModAnimation.aniSpeed + DisplayDuration = (800d + NumberUtils.Clamp(currentHint.Text.Length, 5d, 23d) * 180d) * ModAnimation.aniSpeed }; ModMain.frmMain.PanHint.Children.Add(toast); diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.cs index e44d5e25e..857b20004 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Markup; @@ -320,8 +320,8 @@ private ModComp.CompProjectRequest LoaderInput() var modLoader = ModComp.CompLoaderType.Any; if (PageType == ModComp.CompType.Mod || PageType == ModComp.CompType.ModPack) // 只有 Mod 考虑加载器 { - modLoader = (ModComp.CompLoaderType)LauncherText.Val(((MyComboBoxItem)ComboSearchLoader.SelectedItem).Tag); - if (gameVersion is not null && gameVersion.Contains(".") && LauncherText.Val(gameVersion.Split(".")[1]) < 14d && + modLoader = (ModComp.CompLoaderType)NumberUtils.ParseDoubleOrZero(((MyComboBoxItem)ComboSearchLoader.SelectedItem).Tag); + if (gameVersion is not null && gameVersion.Contains(".") && NumberUtils.ParseDoubleOrZero(gameVersion.Split(".")[1]) < 14d && modLoader == ModComp.CompLoaderType.Forge) // 1.14- // 选择了 Forge modLoader = ModComp.CompLoaderType.Any; // 此时,视作没有筛选 Mod Loader(因为部分老 Mod 没有设置自己支持的加载器) @@ -339,10 +339,10 @@ private ModComp.CompProjectRequest LoaderInput() : selectedTag; request.modLoader = (ModComp.CompLoaderType)(PageType == ModComp.CompType.Mod || PageType == ModComp.CompType.ModPack - ? LauncherText.Val(((MyComboBoxItem)ComboSearchLoader.SelectedItem).Tag) + ? NumberUtils.ParseDoubleOrZero(((MyComboBoxItem)ComboSearchLoader.SelectedItem).Tag) : (double)ModComp.CompLoaderType.Any); - request.source = (ModComp.CompSourceType)LauncherText.Val(((MyComboBoxItem)ComboSearchSource.SelectedItem).Tag); - request.sort = (ModComp.CompSortType)LauncherText.Val(((MyComboBoxItem)ComboSearchSort.SelectedItem).Tag); + request.source = (ModComp.CompSourceType)NumberUtils.ParseDoubleOrZero(((MyComboBoxItem)ComboSearchSource.SelectedItem).Tag); + request.sort = (ModComp.CompSortType)NumberUtils.ParseDoubleOrZero(((MyComboBoxItem)ComboSearchSort.SelectedItem).Tag); return request; } diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs index 49db1f3bd..3a9705dfa 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; @@ -612,7 +612,7 @@ public static void McDownloadOptiFine(ModDownload.DlOptiFineListEntry downloadIn { var id = downloadInfo.NameVersion; var versionFolder = Path.Combine(ModFolder.mcFolderSelected, "versions", id); - var isNewVersion = LauncherText.Val(downloadInfo.Inherit.Split(".")[1]) >= 14d; + var isNewVersion = NumberUtils.ParseDoubleOrZero(downloadInfo.Inherit.Split(".")[1]) >= 14d; var target = isNewVersion ? Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Code", downloadInfo.NameVersion + "_" + LauncherRuntime.GetUuid()) : Path.Combine(ModFolder.mcFolderSelected, "libraries", "optifine", "OptiFine", @@ -881,7 +881,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta var isCustomFolder = (mcFolder ?? "") != (ModFolder.mcFolderSelected ?? ""); var id = downloadInfo.NameVersion; var versionFolder = Path.Combine(mcFolder, "versions", id); - var isNewVersion = downloadInfo.Inherit.Contains("w") || LauncherText.Val(downloadInfo.Inherit.Split(".")[1]) >= 14d; + var isNewVersion = downloadInfo.Inherit.Contains("w") || NumberUtils.ParseDoubleOrZero(downloadInfo.Inherit.Split(".")[1]) >= 14d; var target = isNewVersion ? $"{ModMain.RequestTaskTempFolder()}OptiFine.jar" : $@"{mcFolder}libraries\optifine\OptiFine\{downloadInfo.NameFile.Replace("OptiFine_", "").Replace(".jar", "").Replace("preview_", "")}\{downloadInfo.NameFile.Replace("OptiFine_", "OptiFine-").Replace("preview_", "")}"; @@ -1749,7 +1749,7 @@ private static void ForgelikeInjector(string target, ModLoader.LoaderTask(); @@ -1975,7 +1975,7 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask(); - searchSource.Add(new SearchSource(entry.RawName, 1d)); + var searchSource = new List>(); + searchSource.Add(new KeyValuePair(entry.RawName, 1d)); if (entry.Description is not null && !string.IsNullOrEmpty(entry.Description)) - searchSource.Add(new SearchSource(entry.Description, 0.4d)); + searchSource.Add(new KeyValuePair(entry.Description, 0.4d)); if ((entry.TranslatedName ?? "") != (entry.RawName ?? "")) - searchSource.Add(new SearchSource(entry.TranslatedName, 1d)); - searchSource.Add(new SearchSource(string.Join("", entry.Tags), 0.2d)); - queryList.Add(new SearchEntry { item = Item, searchSource = searchSource }); + searchSource.Add(new KeyValuePair(entry.TranslatedName, 1d)); + searchSource.Add(new KeyValuePair(string.Join("", entry.Tags), 0.2d)); + queryList.Add(new SearchEntry(Item, searchSource)); } // 进行搜索 - searchResult = LauncherSearch.Search(queryList, PanSearchBox.Text, LauncherSearch.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); + searchResult = SimilaritySearch.Search(queryList, PanSearchBox.Text, SimilaritySearch.MaxLocalSearchDepth, 0.35d).Select(r => r.Item).ToList(); } RefreshContent(); diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.cs index 209041cf8..5c2fbc72e 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows.Controls; +using System.Windows.Controls; using System.Windows.Input; using PCL.Core.App.Localization; @@ -14,7 +14,7 @@ public void Refresh() // 强制刷新 public void RefreshButton_Click(object sender, EventArgs e) // 由边栏按钮匿名调用 { - Refresh((FormMain.PageSubType)LauncherText.Val(((MyIconButton)sender).Tag)); + Refresh((FormMain.PageSubType)NumberUtils.ParseDoubleOrZero(((MyIconButton)sender).Tag)); } public void Refresh(FormMain.PageSubType subType) @@ -240,7 +240,7 @@ public PageDownloadLeft() private void PageCheck(object sender, RouteEventArgs e) { if (sender is MyListItem { Tag: { } tag }) - PageChange((FormMain.PageSubType)LauncherText.Val(tag)); + PageChange((FormMain.PageSubType)NumberUtils.ParseDoubleOrZero(tag)); } public object PageGet(FormMain.PageSubType id) diff --git a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs index bca13218b..a95d9f343 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; @@ -649,9 +649,9 @@ private void Button_MouseSwipe(object sender, object e) var elements = ((StackPanel)Parent).Children; var index = elements.IndexOf(this); CurrentSwipe.Start = - (int)Math.Round(LauncherMath.Clamp(Math.Min(CurrentSwipe.Start, index), 0d, elements.Count - 1)); + (int)Math.Round(NumberUtils.Clamp(Math.Min(CurrentSwipe.Start, index), 0d, elements.Count - 1)); CurrentSwipe.End = - (int)Math.Round(LauncherMath.Clamp(Math.Max(CurrentSwipe.End, index), 0d, elements.Count - 1)); + (int)Math.Round(NumberUtils.Clamp(Math.Max(CurrentSwipe.End, index), 0d, elements.Count - 1)); // 勾选所有范围中的项 if (CurrentSwipe.Start == CurrentSwipe.End) return; diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs index 6b6d0185b..0421f4b69 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Text; using System.Windows; using System.Windows.Controls; @@ -2481,7 +2481,7 @@ public void Info_Click(object sender, EventArgs e) contentLines.Add(modEntry.Description + "\r\n"); if (modEntry.Authors is not null) contentLines.Add(Lang.Text("Instance.Resource.Item.Info.Author", modEntry.Authors)); - contentLines.Add(Lang.Text("Instance.Resource.Item.Info.File", modEntry.FileName, LauncherText.GetReadableFileSize(GetModFileInfo(modEntry.path).Length))); + contentLines.Add(Lang.Text("Instance.Resource.Item.Info.File", modEntry.FileName, ByteStream.GetReadableLength(GetModFileInfo(modEntry.path).Length, provider: Lang.Culture))); if (modEntry.Version is not null) contentLines.Add(Lang.Text("Instance.Resource.Item.Info.Version", modEntry.Version)); @@ -2648,7 +2648,7 @@ private void ShowSchematicInfoAsync(ModLocalComp.LocalCompFile modEntry) var contentLines = new List(); if (modEntry.Description is not null) contentLines.Add(modEntry.Description + "\r\n"); if (modEntry.Authors is not null) contentLines.Add(Lang.Text("Instance.Resource.Item.Info.Author", modEntry.Authors)); - contentLines.Add(Lang.Text("Instance.Resource.Item.Info.File", modEntry.FileName, LauncherText.GetReadableFileSize(GetModFileInfo(modEntry.path).Length))); + contentLines.Add(Lang.Text("Instance.Resource.Item.Info.File", modEntry.FileName, ByteStream.GetReadableLength(GetModFileInfo(modEntry.path).Length, provider: Lang.Culture))); if (modEntry.Version is not null) contentLines.Add(Lang.Text("Instance.Resource.Item.Info.Version", modEntry.Version)); if (modEntry.path.EndsWithF(".litematic", true)) ShowLitematicDetails(contentLines, modEntry); @@ -2905,29 +2905,28 @@ public void SearchRun(object sender, EventArgs e) var queryList = new List>(); foreach (var Entry in ModLocalComp.compResourceListLoader.output.AsReadOnly()) { - var searchSource = new List(); - searchSource.Add(new SearchSource(Entry.Name, 1d)); - searchSource.Add(new SearchSource(Entry.FileName, 1d)); - if (Entry.Version is not null) searchSource.Add(new SearchSource(Entry.Version, 0.2d)); + var searchSource = new List>(); + searchSource.Add(new KeyValuePair(Entry.Name, 1d)); + searchSource.Add(new KeyValuePair(Entry.FileName, 1d)); + if (Entry.Version is not null) searchSource.Add(new KeyValuePair(Entry.Version, 0.2d)); if (Entry.Description is not null && !string.IsNullOrEmpty(Entry.Description)) - searchSource.Add(new SearchSource(Entry.Description, 0.4d)); + searchSource.Add(new KeyValuePair(Entry.Description, 0.4d)); if (Entry.Comp is not null) { if ((Entry.Comp.RawName ?? "") != (Entry.Name ?? "")) - searchSource.Add(new SearchSource(Entry.Comp.RawName, 1d)); + searchSource.Add(new KeyValuePair(Entry.Comp.RawName, 1d)); if ((Entry.Comp.TranslatedName ?? "") != (Entry.Comp.RawName ?? "")) - searchSource.Add(new SearchSource(Entry.Comp.TranslatedName, 1d)); + searchSource.Add(new KeyValuePair(Entry.Comp.TranslatedName, 1d)); if ((Entry.Comp.Description ?? "") != (Entry.Description ?? "")) - searchSource.Add(new SearchSource(Entry.Comp.Description, 0.4d)); - searchSource.Add(new SearchSource(string.Join("", Entry.Comp.Tags), 0.2d)); + searchSource.Add(new KeyValuePair(Entry.Comp.Description, 0.4d)); + searchSource.Add(new KeyValuePair(string.Join("", Entry.Comp.Tags), 0.2d)); } - queryList.Add(new SearchEntry - { item = Entry, searchSource = searchSource }); + queryList.Add(new SearchEntry(Entry, searchSource )); } // 进行搜索 - return LauncherSearch.Search(queryList, query, LauncherSearch.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); + return SimilaritySearch.Search(queryList, query, SimilaritySearch.MaxLocalSearchDepth, 0.35d).Select(r => r.Item).ToList(); } #endregion diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs index a09c02746..13dfb8a37 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.IO.Compression; using System.Windows; using System.Windows.Controls; @@ -157,7 +157,7 @@ private void ReloadSubOptions(StackPanel panel, bool acceptCompressedFile, bool Tag = new ExportOption { Title = File.Name, DefaultChecked = true, - Rules = LauncherText.EscapeLikePattern($"{Folder}/{File.Name}") + Rules = TextUtils.EscapeLikePattern($"{Folder}/{File.Name}") } }); if (Folder == "shaderpacks") // 处理光影包的配置文件 @@ -172,7 +172,7 @@ private void ReloadSubOptions(StackPanel panel, bool acceptCompressedFile, bool { Title = $"{shaderConfig.Name}", DefaultChecked = true, Description = Lang.Text("Instance.Export.Config.ShaderConfigSuffix"), - Rules = LauncherText.EscapeLikePattern($"{Folder}/{shaderConfig.Name}") + Rules = TextUtils.EscapeLikePattern($"{Folder}/{shaderConfig.Name}") } }); } @@ -190,7 +190,7 @@ private void ReloadSubOptions(StackPanel panel, bool acceptCompressedFile, bool Tag = new ExportOption { Title = SubFolder.Name, DefaultChecked = true, - Rules = LauncherText.EscapeLikePattern($"{Folder}/{SubFolder.Name}/") + Rules = TextUtils.EscapeLikePattern($"{Folder}/{SubFolder.Name}/") } }; if (ReferenceEquals(panel, PanOptionsSaves)) @@ -209,7 +209,7 @@ private void ReloadSubOptions(StackPanel panel, bool acceptCompressedFile, bool { Title = $"{shaderConfig.Name}", DefaultChecked = true, Description = Lang.Text("Instance.Export.Config.ShaderConfigSuffix"), - Rules = LauncherText.EscapeLikePattern($"{Folder}/{shaderConfig.Name}") + Rules = TextUtils.EscapeLikePattern($"{Folder}/{shaderConfig.Name}") } }); } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.cs index 1d01455f5..9a0c8018e 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using PCL.Core.App; using PCL.Core.App.Localization; @@ -98,7 +98,7 @@ public void RefreshModDisabled() private void RefreshButton_Click(object sender, EventArgs e) // 由边栏按钮匿名调用 { - Refresh((FormMain.PageSubType)LauncherText.Val(((MyIconButton)sender).Tag)); + Refresh((FormMain.PageSubType)NumberUtils.ParseDoubleOrZero(((MyIconButton)sender).Tag)); } public void Refresh(FormMain.PageSubType subType) @@ -197,7 +197,7 @@ public void Reset(object sender, EventArgs e) private void PageCheck(object sender, RouteEventArgs e) { if (sender is MyListItem item && item.Tag is not null) - PageChange((FormMain.PageSubType)LauncherText.Val(item.Tag)); + PageChange((FormMain.PageSubType)NumberUtils.ParseDoubleOrZero(item.Tag)); } public object PageGet(FormMain.PageSubType id) diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs index c67f3372c..8f2eebdd9 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs @@ -1,4 +1,4 @@ -using System.Collections.Specialized; +using System.Collections.Specialized; using System.IO; using System.Windows; using System.Windows.Controls; @@ -191,7 +191,7 @@ private void RefreshUI() if (File.Exists(saveLogo)) { var target = - $@"{PageInstanceLeft.McInstance.PathInstance}PCL\ImgCache\{LauncherText.GetStringMd5(saveLogo)}.png"; + $@"{PageInstanceLeft.McInstance.PathInstance}PCL\ImgCache\{BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(saveLogo).AsSpan())}.png"; LegacyFileFacade.CopyFile(saveLogo, target); saveLogo = target; } @@ -523,12 +523,12 @@ private void PerformSearch() foreach (var saveFolder in saveFolders) { var folderName = GetFolderNameFromPath(saveFolder); - var searchSource = new List(); - searchSource.Add(new SearchSource(folderName, 1d)); - queryList.Add(new SearchEntry { item = saveFolder, searchSource = searchSource }); + var searchSource = new List>(); + searchSource.Add(new KeyValuePair(folderName, 1d)); + queryList.Add(new SearchEntry(saveFolder, searchSource)); } - _searchResult = LauncherSearch.Search(queryList, SearchBox.Text, LauncherSearch.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); + _searchResult = SimilaritySearch.Search(queryList, SearchBox.Text, SimilaritySearch.MaxLocalSearchDepth, 0.35d).Select(r => r.Item).ToList(); } else { diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs index 433cb2d2e..58ae7d408 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Text; using System.Windows; using System.Windows.Controls; @@ -1572,7 +1572,7 @@ public void Info_Click(object sender, EventArgs e) if (datapackEntry.Authors is not null) contentLines.Add(Lang.Text("Instance.Saves.Datapack.Info.Author") + datapackEntry.Authors); contentLines.Add(Lang.Text("Instance.Saves.Datapack.Info.File") + datapackEntry.FileName + "(" + - LauncherText.GetReadableFileSize(GetDatapackFileInfo(datapackEntry.path).Length) + ")"); + ByteStream.GetReadableLength(GetDatapackFileInfo(datapackEntry.path).Length, provider: Lang.Culture) + ")"); if (datapackEntry.Version is not null) contentLines.Add(Lang.Text("Instance.Saves.Datapack.Info.Version") + datapackEntry.Version); @@ -1657,30 +1657,29 @@ public void SearchRun(object sender, EventArgs e) var queryList = new List>(); foreach (var Entry in ModLocalComp.compResourceListLoader.output) { - var searchSource = new List(); - searchSource.Add(new SearchSource(Entry.Name, 1d)); - searchSource.Add(new SearchSource(Entry.FileName, 1d)); + var searchSource = new List>(); + searchSource.Add(new KeyValuePair(Entry.Name, 1d)); + searchSource.Add(new KeyValuePair(Entry.FileName, 1d)); if (Entry.Version is not null) - searchSource.Add(new SearchSource(Entry.Version, 0.2d)); + searchSource.Add(new KeyValuePair(Entry.Version, 0.2d)); if (Entry.Description is not null && !string.IsNullOrEmpty(Entry.Description)) - searchSource.Add(new SearchSource(Entry.Description, 0.4d)); + searchSource.Add(new KeyValuePair(Entry.Description, 0.4d)); if (Entry.Comp is not null) { if ((Entry.Comp.RawName ?? "") != (Entry.Name ?? "")) - searchSource.Add(new SearchSource(Entry.Comp.RawName, 1d)); + searchSource.Add(new KeyValuePair(Entry.Comp.RawName, 1d)); if ((Entry.Comp.TranslatedName ?? "") != (Entry.Comp.RawName ?? "")) - searchSource.Add(new SearchSource(Entry.Comp.TranslatedName, 1d)); + searchSource.Add(new KeyValuePair(Entry.Comp.TranslatedName, 1d)); if ((Entry.Comp.Description ?? "") != (Entry.Description ?? "")) - searchSource.Add(new SearchSource(Entry.Comp.Description, 0.4d)); - searchSource.Add(new SearchSource(string.Join("", Entry.Comp.Tags), 0.2d)); + searchSource.Add(new KeyValuePair(Entry.Comp.Description, 0.4d)); + searchSource.Add(new KeyValuePair(string.Join("", Entry.Comp.Tags), 0.2d)); } - queryList.Add(new SearchEntry - { item = Entry, searchSource = searchSource }); + queryList.Add(new SearchEntry(Entry, searchSource )); } // 进行搜索 - searchResult = LauncherSearch.Search(queryList, SearchBox.Text, LauncherSearch.MaxLocalSearchDepth, 0.35d).Select(r => r.item).ToList(); + searchResult = SimilaritySearch.Search(queryList, SearchBox.Text, SimilaritySearch.MaxLocalSearchDepth, 0.35d).Select(r => r.Item).ToList(); } RefreshUI(); diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesLeft.xaml.cs index 9c10cad22..20b2d3fb7 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesLeft.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using PCL.Core.App.Localization; @@ -47,7 +47,7 @@ public PageInstanceSavesLeft() private void PageCheck(object sender, RouteEventArgs e) { if (sender is MyListItem item && item.Tag is not null) - PageChange((FormMain.PageSubType)LauncherText.Val(item.Tag)); + PageChange((FormMain.PageSubType)NumberUtils.ParseDoubleOrZero(item.Tag)); } public object PageGet(FormMain.PageSubType id = FormMain.PageSubType.Default) @@ -129,7 +129,7 @@ private static void PageChangeRun(MyPageRight target) public void RefreshButton_Click(object sender, EventArgs e) // 由边栏按钮匿名调用 { - Refresh((FormMain.PageSubType)LauncherText.Val(((MyIconButton)sender).Tag)); + Refresh((FormMain.PageSubType)NumberUtils.ParseDoubleOrZero(((MyIconButton)sender).Tag)); } public void Refresh() diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs index 529dcc205..4757464be 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Text.Json; using System.Windows; using System.Windows.Controls; @@ -266,7 +266,7 @@ public void RefreshRam(bool showAnim) var ramAvailable = Math.Round((double)(phyRam.Available / 1024 / 1024 / 1024), 1); var ramGameActual = Math.Round(Math.Min(ramGame, ramAvailable), 5); var ramUsed = Math.Round(ramTotal - ramAvailable, 5); - var ramEmpty = Math.Round(LauncherMath.Clamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); + var ramEmpty = Math.Round(NumberUtils.Clamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); // 设置最大可用内存 if (ramTotal <= 1.5d) SliderRamCustom.MaxValue = (int)Math.Round(Math.Max(Math.Floor((ramTotal - 0.3d) / 0.1d), 1d)); diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs index 828868a2a..dbf41d4e7 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs @@ -439,7 +439,7 @@ public void LaunchingRefresh() hasLaunchDownloader = false; } - LabLaunchingDownload.Text = LauncherText.GetReadableFileSize(ModNet.NetManager.Speed) + "/s"; + LabLaunchingDownload.Text = ByteStream.GetReadableLength(ModNet.NetManager.Speed, provider: Lang.Culture) + "/s"; var shouldShowHint = Config.Preference.ShowLaunchingHint; // 进度改变动画 var animList = new List @@ -589,7 +589,7 @@ public void PageChangeToLaunching() LabLaunchingDownload.Visibility = Visibility.Visible; LabLaunchingProgressLeft.Opacity = 0.6d; LabLaunchingDownload.Visibility = Visibility.Visible; - LabLaunchingDownload.Text = LauncherText.GetReadableFileSize(0) + "/s"; + LabLaunchingDownload.Text = ByteStream.GetReadableLength(0, provider: Lang.Culture) + "/s"; LabLaunchingDownload.Opacity = 0d; LabLaunchingDownload.Visibility = Visibility.Collapsed; LabLaunchingDownloadLeft.Opacity = 0d; @@ -773,9 +773,9 @@ private object PageChange(PageType type, bool anim) { LauncherLog.Log( ex, - Lang.Text("Launch.Account.Error.SwitchPage", LauncherText.GetStringFromEnum(type)), + Lang.Text("Launch.Account.Error.SwitchPage", (type).ToString()), LauncherLogLevel.Feedback, - userSummary: Lang.Text("Launch.Account.Error.SwitchPage", LauncherText.GetStringFromEnum(type))); + userSummary: Lang.Text("Launch.Account.Error.SwitchPage", (type).ToString())); return pageNew; } } diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.cs index 5a93fb4e9..deba84ac4 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -226,7 +226,7 @@ public void RefreshRam(bool showAnim) var ramAvailable = Math.Round((double)phyRam.Available / 1024 / 1024 / 1024, 1); var ramGameActual = Math.Round(Math.Min(ramGame, ramAvailable), 5); var ramUsed = Math.Round(ramTotal - ramAvailable, 5); - var ramEmpty = Math.Round(LauncherMath.Clamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); + var ramEmpty = Math.Round(NumberUtils.Clamp(ramTotal - ramUsed - ramGame, 0d, 1000d), 1); // 设置最大可用内存 if (ramTotal <= 1.5d) SliderRamCustom.MaxValue = (int)Math.Round(Math.Max(Math.Floor((ramTotal - 0.3d) / 0.1d), 1d)); diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.cs index c18b164c5..f48a30b48 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using PCL.Core.App; using PCL.Core.App.Localization; @@ -72,7 +72,7 @@ private void PageOtherLeft_Unloaded(object sender, RoutedEventArgs e) public void Reset(object sender, EventArgs e) { - switch (LauncherText.Val(((MyIconButton)sender).Tag)) + switch (NumberUtils.ParseDoubleOrZero(((MyIconButton)sender).Tag)) { case (double)FormMain.PageSubType.SetupLaunch: { @@ -175,7 +175,7 @@ public static void TryFeedback() // Handles ItemFeedback.Click public void Refresh(object sender, EventArgs e) // 由边栏按钮匿名调用 { - switch (LauncherText.Val(((MyIconButton)sender).Tag)) + switch (NumberUtils.ParseDoubleOrZero(((MyIconButton)sender).Tag)) { case (double)FormMain.PageSubType.SetupFeedback: { @@ -244,7 +244,7 @@ private void PageCheck(object senderRaw, RouteEventArgs e) // 尚未初始化控件属性时,sender.Tag 为 Nothing,会跳过切换,且由于 PageID 默认为 0 而切换到第一个页面 // 若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False) if (sender.Tag is not null) - PageChange((FormMain.PageSubType)LauncherText.Val(sender.Tag)); + PageChange((FormMain.PageSubType)NumberUtils.ParseDoubleOrZero(sender.Tag)); } /// diff --git a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs index 7417748d5..216b4b7b5 100644 --- a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using System.Windows.Threading; using PCL.Network; @@ -61,7 +61,7 @@ private void Watcher() { // 无任务 LabProgress.Text = Lang.Number(1d, "P0"); - LabSpeed.Text = LauncherText.GetReadableFileSize(0) + "/s"; + LabSpeed.Text = ByteStream.GetReadableLength(0, provider: Lang.Culture) + "/s"; LabFile.Text = Lang.Number(0, "N0"); LabThread.Text = Lang.Number(0, "N0") + " / " + Lang.Number(ModNet.NetTaskThreadLimit, "N0"); } @@ -70,13 +70,13 @@ private void Watcher() // 有任务,输出基本信息 var tasks = ModLoader.loaderTaskbar.Where(l => l.show).ToList(); // 筛选掉启动 MC 的任务(#6270) var rawPercent = tasks.Any() - ? LauncherMath.Clamp( + ? NumberUtils.Clamp( tasks.Average(l => l.Progress), 0, 1) : 1d; var predictText = Lang.Number(rawPercent, "P2"); LabProgress.Text = rawPercent > 0.999999d ? Lang.Number(1d, "P0") : predictText; - LabSpeed.Text = LauncherText.GetReadableFileSize(ModNet.NetManager.Speed) + "/s"; + LabSpeed.Text = ByteStream.GetReadableLength(ModNet.NetManager.Speed, provider: Lang.Culture) + "/s"; LabFile.Text = ModNet.NetManager.FileRemain < 0 ? "0*" : Lang.Number(ModNet.NetManager.FileRemain, "N0"); LabThread.Text = Lang.Number(ModNet.NetManager.ThreadCount, "N0") + " / " + Lang.Number(ModNet.NetTaskThreadLimit, "N0"); @@ -124,7 +124,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) // 已有此卡片 Grid card = rightCards[loader.name]; var newValue = loader.Progress + (double)loader.State; - if (LauncherText.Val(card.Tag) == newValue) + if (NumberUtils.ParseDoubleOrZero(card.Tag) == newValue) return; card.Tag = newValue; if (card.Children.Count <= 3) @@ -273,7 +273,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) var cardXAML = $@" + Tag=""{loader.Progress + (double)loader.State}"" Title=""{TextUtils.EscapeXml(loader.name)}"" Margin=""0,0,0,15""> @@ -314,7 +314,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) } } - cardXAML += $""; + cardXAML += $""; row += 1; } diff --git a/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs b/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs index 21fc99e1c..ee2856f8e 100644 --- a/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageTools/PageToolsGameLink.xaml.cs @@ -1,4 +1,4 @@ -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Windows; using System.Windows.Input; @@ -997,7 +997,7 @@ public Subpages CurrentSubpage if (field == value) return; field = value; - LauncherLog.Log("[Link] 子页面更改为 " + LauncherText.GetStringFromEnum(value)); + LauncherLog.Log("[Link] 子页面更改为 " + (value).ToString()); PageOnContentExit(); } } = States.Link.LinkEula ? Subpages.PanSelect : Subpages.PanEula; diff --git a/Plain Craft Launcher 2/Pages/PageTools/PageToolsLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageTools/PageToolsLeft.xaml.cs index fa2e4c5c3..428850102 100644 --- a/Plain Craft Launcher 2/Pages/PageTools/PageToolsLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageTools/PageToolsLeft.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows; +using System.Windows; using System.Windows.Controls; using PCL.Core.App; @@ -55,7 +55,7 @@ public void Refresh(object sender, EventArgs e) var button = (MyIconButton)sender; if (button.Tag is null) return; - double id = LauncherText.Val(button.Tag); + double id = NumberUtils.ParseDoubleOrZero(button.Tag); switch (id) { case (double)FormMain.PageSubType.ToolsGameLink: @@ -85,7 +85,7 @@ private void PageCheck(object senderRaw, RouteEventArgs e) // 尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0 // 若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False) if (sender.Tag is not null) - PageChange((FormMain.PageSubType)LauncherText.Val(sender.Tag)); + PageChange((FormMain.PageSubType)NumberUtils.ParseDoubleOrZero(sender.Tag)); } public object PageGet(FormMain.PageSubType? id = null) diff --git a/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs b/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs index a0864956d..f74cece99 100644 --- a/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; @@ -545,7 +545,7 @@ private async void BtnAchievementSave_Click(object sender, MouseButtonEventArgs private async Task DownloadImageToLocalAsync(string imageUrl) { - var savePath = LauncherPaths.TempWithSlash + @"Download\" + LauncherText.GetHash(imageUrl) + ".png"; + var savePath = LauncherPaths.TempWithSlash + @"Download\" + LauncherStringHash.Compute(imageUrl) + ".png"; var client = NetworkService.GetClient(); try { From 23895e5e822285bf8408b1445db9112749b6615a Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Thu, 2 Jul 2026 16:41:53 +0800 Subject: [PATCH 10/16] =?UTF-8?q?=E5=88=A0=E9=99=A4=E3=80=81=E9=87=8D?= =?UTF-8?q?=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PCL.Core/IO/Directories.cs | 12 + Plain Craft Launcher 2/Controls/MyImage.cs | 2 +- Plain Craft Launcher 2/FormMain.xaml.cs | 44 +-- .../Infrastructure/LauncherFileSystem.cs | 66 +++++ ...{LegacyIniStore.cs => LauncherIniStore.cs} | 56 +++- .../Infrastructure/LauncherPaths.cs | 6 +- .../Infrastructure/LauncherProcess.cs | 36 +-- .../Infrastructure/LegacyFileFacade.cs | 250 ------------------ .../Modules/Base/ModSetup.cs | 4 +- .../Modules/Event/CustomEvent.cs | 4 +- .../Modules/Minecraft/McInstance.cs | 12 +- .../Modules/Minecraft/ModAssets.cs | 2 +- .../Modules/Minecraft/ModComp.cs | 10 +- .../Modules/Minecraft/ModDownload.cs | 6 +- .../Modules/Minecraft/ModFolder.cs | 7 +- .../Modules/Minecraft/ModInstanceList.cs | 22 +- .../Modules/Minecraft/ModJava.cs | 2 +- .../Modules/Minecraft/ModLaunch.cs | 78 +++--- .../Modules/Minecraft/ModLibrary.cs | 10 +- .../Modules/Minecraft/ModLocalComp.cs | 37 ++- .../Modules/Minecraft/ModModpack.cs | 73 +++-- .../Modules/Minecraft/ModProfile.cs | 12 +- .../Modules/Minecraft/ModSkin.cs | 6 +- Plain Craft Launcher 2/Modules/ModLink.cs | 3 +- Plain Craft Launcher 2/Modules/ModMain.cs | 10 +- Plain Craft Launcher 2/Modules/ModMusic.cs | 14 +- .../Network/Loaders/LoaderDownloadUnc.cs | 4 +- .../Modules/Network/Models/DownloadFile.cs | 2 +- .../Modules/Updates/UpdateManager.cs | 12 +- .../Modules/Updates/UpdatesMinioModel.cs | 14 +- .../Comp/PageDownloadCompDetail.xaml.cs | 10 +- .../Pages/PageDownload/ModDownloadLib.cs | 187 ++++++------- .../Pages/PageInstance/MyLocalModItem.xaml.cs | 6 +- .../PageInstanceCompResource.xaml.cs | 20 +- .../PageInstance/PageInstanceExport.xaml.cs | 35 ++- .../PageInstance/PageInstanceInstall.xaml.cs | 10 +- .../PageInstance/PageInstanceOverall.xaml.cs | 43 ++- .../PageInstance/PageInstanceSaves.xaml.cs | 4 +- .../PageInstanceSavesDatapack.xaml.cs | 18 +- .../Pages/PageLaunch/MySkin.xaml.cs | 16 +- .../Pages/PageLaunch/PageLaunchLeft.xaml.cs | 2 +- .../Pages/PageLaunch/PageLaunchRight.xaml.cs | 8 +- .../Pages/PageSelectLeft.xaml.cs | 12 +- .../Pages/PageSelectRight.xaml.cs | 6 +- .../Pages/PageSetup/PageSetupUI.xaml.cs | 18 +- .../Pages/PageTools/PageToolsTest.xaml.cs | 20 +- 46 files changed, 527 insertions(+), 704 deletions(-) create mode 100644 Plain Craft Launcher 2/Infrastructure/LauncherFileSystem.cs rename Plain Craft Launcher 2/Infrastructure/{LegacyIniStore.cs => LauncherIniStore.cs} (71%) delete mode 100644 Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs diff --git a/PCL.Core/IO/Directories.cs b/PCL.Core/IO/Directories.cs index 7f1afa882..fed390c9f 100644 --- a/PCL.Core/IO/Directories.cs +++ b/PCL.Core/IO/Directories.cs @@ -284,6 +284,18 @@ public static async Task> EnumerateFilesAsync(string? dire } } + /// + /// 异步遍历文件夹中的所有文件。目录不存在时返回空集合。 + /// + public static async Task> EnumerateFilesOrEmptyAsync( + string? directory, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory)) return []; + + return await EnumerateFilesAsync(directory, cancellationToken).ConfigureAwait(false); + } + /// /// 异步移动目录中的全部文件和子目录到目标目录。目标目录不存在时会自动创建。 /// diff --git a/Plain Craft Launcher 2/Controls/MyImage.cs b/Plain Craft Launcher 2/Controls/MyImage.cs index 5b8cf6805..294d698ed 100644 --- a/Plain Craft Launcher 2/Controls/MyImage.cs +++ b/Plain Craft Launcher 2/Controls/MyImage.cs @@ -141,7 +141,7 @@ private static async Task DownloadImageInternalAsync(string url) try { - Directory.CreateDirectory(LegacyFileFacade.GetPathFromFullPath(tempPath)); // 重新实现下载,以避免携带 Header(#5072) + Directory.CreateDirectory(PathUtils.GetDirectoryPart(tempPath)); // 重新实现下载,以避免携带 Header(#5072) using (var fs = new FileStream(tempDownloadingPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { using (var response = await HttpRequest.Create(url) diff --git a/Plain Craft Launcher 2/FormMain.xaml.cs b/Plain Craft Launcher 2/FormMain.xaml.cs index dad207c85..b46930afb 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.cs +++ b/Plain Craft Launcher 2/FormMain.xaml.cs @@ -37,7 +37,8 @@ private void ShowUpdateLog() var changelogFile = $"{LauncherPaths.TempWithSlash}CEUpdateLog.md"; string changelog; if (File.Exists(changelogFile)) - changelog = LegacyFileFacade.ReadText(changelogFile); + changelog = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(changelogFile)).GetAwaiter() + .GetResult(); else changelog = Lang.Text("Main.UpdateLog.Empty"); if (ModMain.MyMsgBoxMarkdown(changelog, @@ -1029,7 +1030,9 @@ private void FileDrag(IEnumerable filePathList) if (ModMain.MyMsgBox(Lang.Text("Main.FileDrag.HomepageExists"), Lang.Text("Main.FileDrag.OverwriteTitle"), Lang.Text("Common.Action.Overwrite"), Lang.Text("Common.Action.Cancel")) == 2) return; - LegacyFileFacade.CopyFile(filePath, LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Custom.xaml"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(filePath), + LauncherFileSystem.ResolvePath(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Custom.xaml")) + .GetAwaiter().GetResult(); UiThread.Post(() => { Config.Preference.Homepage.Type = 1; @@ -1063,7 +1066,7 @@ ModMain.frmInstanceSchematic is not null && case PageSubType.VersionWorld: { var destFolder = PageInstanceLeft.McInstance.PathIndie + @"saves\" + - LegacyFileFacade.GetFileNameWithoutExtensionFromPath(filePath); + PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(filePath); var destLevelDat = Path.Combine(destFolder, "level.dat"); if (Directory.Exists(destFolder)) { @@ -1075,7 +1078,7 @@ ModMain.frmInstanceSchematic is not null && LauncherRuntime.GetUuid().ToString()); try { - LegacyFileFacade.ExtractFile(filePath, extractFolder); + Files.ExtractFileAsync(filePath, extractFolder).GetAwaiter().GetResult(); var saveRoot = SaveImportHelper.GetSaveRootDirectory(extractFolder); if (saveRoot is null) { @@ -1083,11 +1086,11 @@ ModMain.frmInstanceSchematic is not null && return; } - LegacyFileFacade.CopyDirectory(saveRoot, destFolder); + Directories.CopyDirectoryAsync(saveRoot, destFolder).GetAwaiter().GetResult(); if (!File.Exists(destLevelDat)) { if (Directory.Exists(destFolder)) - LegacyFileFacade.DeleteDirectory(destFolder, true); + Directories.DeleteDirectoryAsync(destFolder, true).GetAwaiter().GetResult(); HintService.Hint(Lang.Text("Main.FileDrag.SaveInvalid"), HintType.Error); return; } @@ -1095,7 +1098,7 @@ ModMain.frmInstanceSchematic is not null && catch (Exception ex) { if (Directory.Exists(destFolder)) - LegacyFileFacade.DeleteDirectory(destFolder, true); + Directories.DeleteDirectoryAsync(destFolder, true).GetAwaiter().GetResult(); LauncherLog.Log( ex, Lang.Text("Main.FileDrag.SaveImportFailed"), @@ -1106,12 +1109,12 @@ ModMain.frmInstanceSchematic is not null && finally { if (Directory.Exists(extractFolder)) - LegacyFileFacade.DeleteDirectory(extractFolder, true); + Directories.DeleteDirectoryAsync(extractFolder, true).GetAwaiter().GetResult(); } HintService.Hint( Lang.Text("Main.FileDrag.Imported", - LegacyFileFacade.GetFileNameWithoutExtensionFromPath(filePath)), + PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(filePath)), HintType.Success); if (ModMain.frmInstanceSaves is not null) UiThread.Post(() => ModMain.frmInstanceSaves.Reload()); @@ -1120,16 +1123,17 @@ ModMain.frmInstanceSchematic is not null && case PageSubType.VersionResourcePack: { var destFile = PageInstanceLeft.McInstance.PathIndie + @"resourcepacks\" + - LegacyFileFacade.GetFileNameFromPath(filePath); + PathUtils.GetFileNameFromUrlOrPath(filePath); if (File.Exists(destFile)) { HintService.Hint(Lang.Text("Main.FileDrag.SameFileExists", destFile), HintType.Error); return; } - LegacyFileFacade.CopyFile(filePath, destFile); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(filePath), + LauncherFileSystem.ResolvePath(destFile)).GetAwaiter().GetResult(); HintService.Hint( - Lang.Text("Main.FileDrag.Imported", LegacyFileFacade.GetFileNameFromPath(filePath)), + Lang.Text("Main.FileDrag.Imported", PathUtils.GetFileNameFromUrlOrPath(filePath)), HintType.Success); if (ModMain.frmInstanceResourcePack is not null) UiThread.Post(() => ModMain.frmInstanceResourcePack.ReloadCompFileList()); @@ -1138,16 +1142,17 @@ ModMain.frmInstanceSchematic is not null && case PageSubType.VersionShader: { var destFile = PageInstanceLeft.McInstance.PathIndie + @"shaderpacks\" + - LegacyFileFacade.GetFileNameFromPath(filePath); + PathUtils.GetFileNameFromUrlOrPath(filePath); if (File.Exists(destFile)) { HintService.Hint(Lang.Text("Main.FileDrag.SameFileExists", destFile), HintType.Error); return; } - LegacyFileFacade.CopyFile(filePath, destFile); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(filePath), + LauncherFileSystem.ResolvePath(destFile)).GetAwaiter().GetResult(); HintService.Hint( - Lang.Text("Main.FileDrag.Imported", LegacyFileFacade.GetFileNameFromPath(filePath)), + Lang.Text("Main.FileDrag.Imported", PathUtils.GetFileNameFromUrlOrPath(filePath)), HintType.Success); if (ModMain.frmInstanceShader is not null) UiThread.Post(() => ModMain.frmInstanceShader.ReloadCompFileList()); @@ -1161,7 +1166,7 @@ ModMain.frmInstanceSchematic is not null && PageCurrentSub == PageSubType.VersionSchematic) { var destFile = PageInstanceLeft.McInstance.PathIndie + @"schematics\" + - LegacyFileFacade.GetFileNameFromPath(filePath); + PathUtils.GetFileNameFromUrlOrPath(filePath); if (File.Exists(destFile)) { HintService.Hint(Lang.Text("Main.FileDrag.SameFileExists", destFile), HintType.Error); @@ -1169,8 +1174,9 @@ ModMain.frmInstanceSchematic is not null && } Directory.CreateDirectory(PageInstanceLeft.McInstance.PathIndie + @"schematics\"); - LegacyFileFacade.CopyFile(filePath, destFile); - HintService.Hint(Lang.Text("Main.FileDrag.Imported", LegacyFileFacade.GetFileNameFromPath(filePath)), + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(filePath), LauncherFileSystem.ResolvePath(destFile)) + .GetAwaiter().GetResult(); + HintService.Hint(Lang.Text("Main.FileDrag.Imported", PathUtils.GetFileNameFromUrlOrPath(filePath)), HintType.Success); if (ModMain.frmInstanceSchematic is not null) UiThread.Post(() => ModMain.frmInstanceSchematic.ReloadCompFileList()); @@ -1501,7 +1507,7 @@ private string PageNameGet(PageStackData stack) case PageType.VersionSaves: { return Lang.Text("Main.Title.SaveManagement", - LegacyFileFacade.GetFolderNameFromPath(stack.additional.Value.SavePath)); + PathUtils.GetDirectoryNameLeaf(stack.additional.Value.SavePath)); } default: diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFileSystem.cs b/Plain Craft Launcher 2/Infrastructure/LauncherFileSystem.cs new file mode 100644 index 000000000..2ab404613 --- /dev/null +++ b/Plain Craft Launcher 2/Infrastructure/LauncherFileSystem.cs @@ -0,0 +1,66 @@ +using System.Diagnostics; +using System.IO; + +namespace PCL; + +/// +/// 专属文件系统行为。通用文件读写、复制、哈希、解压和目录操作请直接使用 PCL.Core.IO。 +/// +public static class LauncherFileSystem +{ + public static string ResolvePath(string filePath) + { + return LauncherPaths.ResolveLauncherFilePath(filePath); + } + + public static void WaitForFileReady( + string filePath, + int timeoutMs = 2000, + bool requireJson = false) + { + filePath = ResolvePath(filePath); + var start = Environment.TickCount; + long lastSize = -1; + while (Environment.TickCount - start < timeoutMs) + { + if (File.Exists(filePath)) + try + { + var info = new FileInfo(filePath); + var size = info.Length; + if (size <= 0) + continue; + if (!requireJson) + { + if (size == lastSize) + return; + lastSize = size; + } + else + { + var content = Files.ReadAllTextOrEmptyAsync(filePath).GetAwaiter().GetResult(); + if (!string.IsNullOrEmpty(content) && content.Trim().StartsWith("{")) + return; + } + } + catch (IOException) + { + } + + Thread.Sleep(50); + } + } + + public static void CreateSymbolicLinkByBundledLinkD(string linkPath, string targetPath, int flags) + { + using var cmdProcess = new Process(); + var linkDPath = ModLaunch.ExtractLinkD(); + var startInfo = cmdProcess.StartInfo; + startInfo.FileName = linkDPath; + startInfo.Arguments = $"\"{linkPath}\" \"{targetPath}\""; + startInfo.CreateNoWindow = true; + startInfo.UseShellExecute = false; + cmdProcess.Start(); + cmdProcess.WaitForExit(); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs b/Plain Craft Launcher 2/Infrastructure/LauncherIniStore.cs similarity index 71% rename from Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs rename to Plain Craft Launcher 2/Infrastructure/LauncherIniStore.cs index a48cd6d7c..1617d2c41 100644 --- a/Plain Craft Launcher 2/Infrastructure/LegacyIniStore.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherIniStore.cs @@ -1,41 +1,46 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.IO; using System.Text; namespace PCL; -public interface ILegacyKeyValueStore +public interface ILauncherKeyValueStore { string Read(string fileName, string key, string defaultValue = ""); + bool ContainsKey(string fileName, string key); + void Write(string fileName, string key, string? value); + void ClearCache(string fileName); } /// -/// PCL2 历史 “key:value” ini 文件格式的读写与缓存。 +/// PCL2 专属 “key:value” ini 文件格式的读写与缓存。 /// -public sealed class LegacyIniStore : ILegacyKeyValueStore +public sealed class LauncherIniStore : ILauncherKeyValueStore { private readonly ConcurrentDictionary> _cache = new(); private readonly object _writeLock = new(); - private LegacyIniStore() + private LauncherIniStore() { } - public static LegacyIniStore Shared { get; } = new(); + public static LauncherIniStore Shared { get; } = new(); public void ClearCache(string fileName) { - _cache.Remove(LauncherPaths.ResolveLegacyIniPath(fileName), out _); + _cache.Remove(LauncherPaths.ResolveLauncherIniPath(fileName), out _); } public string Read(string fileName, string key, string defaultValue = "") { var content = GetContent(fileName); + if (content is null || !content.TryGetValue(key, out var value)) return defaultValue; + return value; } @@ -51,26 +56,32 @@ public void Write(string fileName, string key, string? value) { if (key.Contains(':')) throw new Exception($"尝试写入 ini 文件 {fileName} 的键名中包含了冒号:{key}"); + key = key.Replace("\r", "").Replace("\n", ""); value = value?.Replace("\r", "").Replace("\n", ""); lock (_writeLock) { var content = GetContent(fileName) ?? new ConcurrentDictionary(); + if (value is null) { if (!content.ContainsKey(key)) return; + content.Remove(key, out _); } else { - if (content.TryGetValue(key, out var oldValue) && (oldValue ?? "") == (value ?? "")) + if (content.TryGetValue(key, out var oldValue) && + (oldValue ?? "") == (value ?? "")) return; + content[key] = value; } var fileContent = new StringBuilder(); + foreach (var pair in content) { fileContent.Append(pair.Key); @@ -79,12 +90,20 @@ public void Write(string fileName, string key, string? value) fileContent.Append("\r\n"); } - LegacyFileFacade.WriteText(LauncherPaths.ResolveLegacyIniPath(fileName), fileContent.ToString()); + Files + .WriteFileAsync( + LauncherPaths.ResolveLauncherIniPath(fileName), + fileContent.ToString()) + .GetAwaiter() + .GetResult(); } } catch (Exception ex) { - LauncherLog.Log(ex, $"写入文件失败({fileName} → {key}:{value})", LauncherLogLevel.Hint); + LauncherLog.Log( + ex, + $"写入文件失败({fileName} → {key}:{value})", + LauncherLogLevel.Hint); } } @@ -97,17 +116,24 @@ public void Delete(string fileName, string key) { try { - var resolvedPath = LauncherPaths.ResolveLegacyIniPath(fileName); + var resolvedPath = LauncherPaths.ResolveLauncherIniPath(fileName); + if (_cache.TryGetValue(resolvedPath, out var cached)) return cached; + if (!File.Exists(resolvedPath)) return null; var ini = new ConcurrentDictionary(); - foreach (var line in LegacyFileFacade.ReadText(resolvedPath) + + foreach (var line in Files + .ReadAllTextOrEmptyAsync(resolvedPath) + .GetAwaiter() + .GetResult() .Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries)) { var index = line.IndexOfF(":"); + if (index > 0) ini[line[..index]] = line[(index + 1)..]; } @@ -117,7 +143,11 @@ public void Delete(string fileName, string key) } catch (Exception ex) { - LauncherLog.Log(ex, $"生成 ini 文件缓存失败({fileName})", LauncherLogLevel.Hint); + LauncherLog.Log( + ex, + $"生成 ini 文件缓存失败({fileName})", + LauncherLogLevel.Hint); + return null; } } diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs b/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs index acb547c17..d94e5d36b 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs @@ -4,7 +4,7 @@ namespace PCL; /// -/// PCL2 历史路径与兼容路径解析。 +/// 路径解析。 /// public static class LauncherPaths { @@ -45,7 +45,7 @@ public static class LauncherPaths /// public static string PureAsciiDirectory { get; set; } = ResolvePureAsciiDirectory(); - public static string ResolveLegacyFilePath(string filePath) + public static string ResolveLauncherFilePath(string filePath) { if (string.IsNullOrEmpty(filePath)) return filePath; @@ -54,7 +54,7 @@ public static string ResolveLegacyFilePath(string filePath) : ExecutableDirectoryWithSlash + filePath; } - public static string ResolveLegacyIniPath(string fileName) + public static string ResolveLauncherIniPath(string fileName) { return IsWindowsAbsolutePath(fileName) ? fileName diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs index 55588daf4..9bee0275c 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs +++ b/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Windows; using PCL.Core.Logging; @@ -14,7 +14,7 @@ public static void ShellOnly(string fileName, string arguments = "") { try { - fileName = LegacyFileFacade.ShortenPath(fileName); + fileName = PathUtils.ShortenPath(fileName); using var program = new Process(); program.StartInfo.Arguments = arguments; @@ -115,9 +115,7 @@ public static void OpenExplorer(string location) { try { - location = LegacyFileFacade.ShortenPath( - location.Replace("/", @"\").Trim(' ', '"')); - + location = PathUtils.ShortenPath(location.Replace("/", @"\").Trim(' ', '"')); LauncherLog.Log($"[System] 正在打开资源管理器:{location}"); if (location.EndsWithF(@"\")) @@ -189,20 +187,20 @@ public static int PasteFileFromClipboard( var copiedFiles = 0; var copiedFolders = 0; - foreach (var fileOrFolder in files) + foreach (var i in files) { - if (copyFile && File.Exists(fileOrFolder)) + if (copyFile && File.Exists(i)) try { - var targetPath = dest + LegacyFileFacade.GetFileNameFromPath(fileOrFolder); + var thisDest = dest + PathUtils.GetFileNameFromUrlOrPath(i); - if (File.Exists(targetPath)) + if (File.Exists(thisDest)) { - LauncherLog.Log($"[System] 已存在同名文件:{targetPath}"); + LauncherLog.Log($"[System] 已存在同名文件:{thisDest}"); } else { - File.Copy(fileOrFolder, targetPath); + File.Copy(i, thisDest); copiedFiles += 1; } } @@ -212,24 +210,28 @@ public static int PasteFileFromClipboard( continue; } - if (copyDir && Directory.Exists(fileOrFolder)) + if (copyDir && Directory.Exists(i)) try { - var targetPath = dest + LegacyFileFacade.GetFolderNameFromPath(fileOrFolder); + var thisDest = dest + PathUtils.GetDirectoryNameLeaf(i); - if (Directory.Exists(targetPath)) + if (Directory.Exists(thisDest)) { - LauncherLog.Log($"[System] 已存在同名文件夹:{targetPath}"); + LauncherLog.Log($"[System] 已存在同名文件夹:{thisDest}"); } else { - LegacyFileFacade.CopyDirectory(fileOrFolder, targetPath); + Directories + .CopyDirectoryAsync(i, thisDest) + .GetAwaiter() + .GetResult(); + copiedFolders += 1; } } catch (Exception ex) { - LauncherLog.Log(ex, "[System] 复制文件夹时出错"); + LauncherLog.Log(ex, "[System] 复制文件时出错"); } } diff --git a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs b/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs deleted file mode 100644 index 3a442ebcb..000000000 --- a/Plain Craft Launcher 2/Infrastructure/LegacyFileFacade.cs +++ /dev/null @@ -1,250 +0,0 @@ -using System.Diagnostics; -using System.IO; -using System.Text; -using PCL.Core.Utils.Codecs; -using CoreDirectories = PCL.Core.IO.Directories; -using CoreFiles = PCL.Core.IO.Files; - -namespace PCL; - -/// -/// 历史文件 API 的同步兼容层。 -/// -public static class LegacyFileFacade -{ - public static string ResolvePath(string filePath) - { - return LauncherPaths.ResolveLegacyFilePath(filePath); - } - - public static string GetPathFromFullPath(string filePath) - { - return PathUtils.GetDirectoryPart(filePath); - } - - public static string GetFileNameFromPath(string filePath) - { - return PathUtils.GetFileNameFromUrlOrPath(filePath); - } - - public static string GetFileNameWithoutExtensionFromPath(string filePath) - { - return PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(filePath); - } - - public static string GetFolderNameFromPath(string folderPath) - { - return PathUtils.GetDirectoryNameLeaf(folderPath); - } - - public static void CopyFile(string fromPath, string toPath) - { - CoreFiles.CopyFileAsync(ResolvePath(fromPath), ResolvePath(toPath)).GetAwaiter().GetResult(); - } - - public static byte[] ReadBytes(string filePath, Encoding? encoding = null) - { - return CoreFiles.ReadAllBytesOrEmptyAsync(ResolvePath(filePath)).GetAwaiter().GetResult(); - } - - public static string ReadText(string filePath, Encoding? encoding = null) - { - return CoreFiles.ReadAllTextOrEmptyAsync(ResolvePath(filePath), encoding).GetAwaiter().GetResult(); - } - - public static string ReadText(Stream stream, Encoding? encoding = null) - { - return CoreFiles.ReadAllTextOrEmptyAsync(stream, encoding).GetAwaiter().GetResult(); - } - - - public static void WriteFile(string filePath, string text, bool append = false, Encoding? encoding = null) - { - WriteText(filePath, text, append, encoding); - } - - public static void WriteFile(string filePath, byte[] content, bool append = false) - { - WriteBytes(filePath, content, append); - } - - public static bool WriteFile(string filePath, Stream stream) - { - return WriteStream(filePath, stream); - } - - public static void WriteText(string filePath, string text, bool append = false, Encoding? encoding = null) - { - CoreFiles.WriteFileAsync(ResolvePath(filePath), text, append, encoding).GetAwaiter().GetResult(); - } - - public static void WriteBytes(string filePath, byte[] content, bool append = false) - { - CoreFiles.WriteFileAsync(ResolvePath(filePath), content, append).GetAwaiter().GetResult(); - } - - public static bool WriteStream(string filePath, Stream stream) - { - return CoreFiles.WriteFileAsync(ResolvePath(filePath), stream).GetAwaiter().GetResult(); - } - - public static string DecodeBytes(byte[] bytes) - { - return EncodingUtils.DecodeBytes(bytes); - } - - public static object GetHexString(Memory bytes) - { - return BinaryEncoding.ToHexLower(bytes.Span); - } - - public static string GetFileMd5(string filePath) - { - return CoreFiles.GetFileMD5Async(filePath).GetAwaiter().GetResult(); - } - - public static string GetFileSha512(string filePath) - { - return CoreFiles.GetFileSHA512Async(filePath).GetAwaiter().GetResult(); - } - - public static string GetFileSha256(string filePath) - { - return CoreFiles.GetFileSHA256Async(filePath).GetAwaiter().GetResult(); - } - - public static string GetFileSha1(string filePath) - { - return CoreFiles.GetFileSHA1Async(filePath).GetAwaiter().GetResult(); - } - - public static string GetStreamSha1(Stream inputStream) - { - try - { - return (string)GetHexString(SHA1Provider.Instance.ComputeHash(inputStream)); - } - catch (Exception ex) - { - LauncherLog.Log(ex, "获取流 SHA1 失败"); - return ""; - } - } - - public static string CheckFile( - string localPath, - long minSize, - long actualSize, - string hash, - bool isJson) - { - return CoreFiles.CheckAsync(localPath, minSize, actualSize, hash, isJson).GetAwaiter().GetResult(); - } - - public static void WaitForFileReady( - string filePath, - int timeoutMs = 2000, - bool requireJson = false) - { - filePath = ResolvePath(filePath); - var start = Environment.TickCount; - long lastSize = -1; - while (Environment.TickCount - start < timeoutMs) - { - if (File.Exists(filePath)) - try - { - var info = new FileInfo(filePath); - var size = info.Length; - if (size <= 0) - continue; - if (!requireJson) - { - if (size == lastSize) - return; - lastSize = size; - } - else - { - var content = ReadText(filePath); - if (!string.IsNullOrEmpty(content) && content.Trim().StartsWith("{")) - return; - } - } - catch (IOException) - { - } - - Thread.Sleep(50); - } - } - - public static void ExtractFile( - string compressFilePath, - string destDirectory, - Encoding? encode = null, - Action? progressIncrementHandler = null) - { - CoreFiles.ExtractFileAsync(compressFilePath, destDirectory, progressIncrementHandler).GetAwaiter().GetResult(); - } - - public static int DeleteDirectory(string path, bool ignoreIssue = false) - { - return CoreDirectories.DeleteDirectoryAsync(path, ignoreIssue).GetAwaiter().GetResult(); - } - - public static void CopyDirectory( - string fromPath, - string toPath, - Action? progressIncrementHandler = null) - { - CoreDirectories.CopyDirectoryAsync(fromPath, toPath, progressIncrementHandler).GetAwaiter().GetResult(); - } - - public static IEnumerable EnumerateFiles(string directory) - { - try - { - return CoreDirectories.EnumerateFilesAsync(ShortenPath(directory)).GetAwaiter().GetResult(); - } - catch (DirectoryNotFoundException) - { - return []; - } - } - - public static string ShortenPath(string longPath, int shortenThreshold = 247) - { - return PathUtils.ShortenPath(longPath, shortenThreshold); - } - - public static void MoveDirectory(string sourceDir, string targetDir) - { - CoreDirectories.MoveDirectoryAsync(sourceDir, targetDir).GetAwaiter().GetResult(); - } - - public static void CreateSymbolicLink(string linkPath, string targetPath, int flags) - { - var cmdProcess = new Process(); - var linkDPath = ModLaunch.ExtractLinkD(); - var startInfo = cmdProcess.StartInfo; - startInfo.FileName = linkDPath; - startInfo.Arguments = $"\"{linkPath}\" \"{targetPath}\""; - startInfo.CreateNoWindow = true; - startInfo.UseShellExecute = false; - cmdProcess.Start(); - while (!cmdProcess.HasExited) - { - } - } - - public static bool CheckPermission(string path) - { - return CoreDirectories.CheckPermissionAsync(path).GetAwaiter().GetResult(); - } - - public static void CheckPermissionWithException(string path) - { - CoreDirectories.CheckPermissionWithExceptionAsync(path).GetAwaiter().GetResult(); - } -} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Base/ModSetup.cs b/Plain Craft Launcher 2/Modules/Base/ModSetup.cs index 320bfecf6..b11d4ed13 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModSetup.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModSetup.cs @@ -172,7 +172,7 @@ public static void ApplyAll() public static void LaunchInstanceSelect(string value) { LauncherLog.Log($"[Setup] 当前选择的 Minecraft 版本:{value}"); - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", value); + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", value); } public static void LaunchFolderSelect(string value) @@ -666,7 +666,7 @@ public static void VersionServerLogin(int type) if (ModMain.frmInstanceSetup is null) return; // 为第三方登录清空缓存以更新描述 - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); if (PageInstanceLeft.McInstance is null) return; PageInstanceLeft.McInstance = new McInstance(PageInstanceLeft.McInstance.Name).Load(); diff --git a/Plain Craft Launcher 2/Modules/Event/CustomEvent.cs b/Plain Craft Launcher 2/Modules/Event/CustomEvent.cs index b17c23d43..5a007bdc2 100644 --- a/Plain Craft Launcher 2/Modules/Event/CustomEvent.cs +++ b/Plain Craft Launcher 2/Modules/Event/CustomEvent.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using PCL.Core.App; using PCL.Core.App.Configuration; using PCL.Core.App.Localization; @@ -273,7 +273,7 @@ private static void _DownloadFile(string arg, EventType _) try { PageToolsTest.StartCustomDownload(args[0], - args.Length >= 2 ? args[1] : LegacyFileFacade.GetFileNameFromPath(args[0]), + args.Length >= 2 ? args[1] : PathUtils.GetFileNameFromUrlOrPath(args[0]), args.Length >= 3 ? args[2] : null); } catch diff --git a/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs b/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs index 35b5d7a72..06194f71f 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/McInstance.cs @@ -122,7 +122,7 @@ public string Name get { if (field is null && !string.IsNullOrEmpty(PathInstance)) - field = LegacyFileFacade.GetFolderNameFromPath(PathInstance); + field = PathUtils.GetDirectoryNameLeaf(PathInstance); return field; } } @@ -400,7 +400,7 @@ bool FastJsonCheck(string json) } } - field = LegacyFileFacade.ReadText(jsonPath); + field = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(jsonPath)).GetAwaiter().GetResult(); // 如果 ReadFile 失败会返回空字符串;这可能是由于文件被临时占用,故延时后重试 if (!FastJsonCheck(field)) { @@ -408,14 +408,14 @@ bool FastJsonCheck(string json) { LauncherLog.Log($"[Minecraft] 实例 JSON 文件为空或有误,将进行短暂重试({jsonPath})", LauncherLogLevel.Debug); Thread.Sleep(200); - field = LegacyFileFacade.ReadText(jsonPath); + field = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(jsonPath)).GetAwaiter().GetResult(); } else { LauncherLog.Log($"[Minecraft] 实例 JSON 文件为空或有误,将在 2s 后重试读取({jsonPath})", LauncherLogLevel.Debug); Thread.Sleep(2000); - field = LegacyFileFacade.ReadText(jsonPath); + field = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(jsonPath)).GetAwaiter().GetResult(); } if (!FastJsonCheck(field)) JsonCompat.ParseNode(field); @@ -625,7 +625,7 @@ public bool Check() try { Directory.CreateDirectory(PathInstance + @"PCL\"); - LegacyFileFacade.CheckPermissionWithException(PathInstance + @"PCL\"); + Directories.CheckPermissionWithExceptionAsync(PathInstance + @"PCL\").GetAwaiter().GetResult(); } catch (Exception ex) { @@ -668,7 +668,7 @@ public bool Check() try { if (!string.IsNullOrEmpty(InheritInstanceName)) - if (!File.Exists(Path.Combine(LegacyFileFacade.GetPathFromFullPath(PathInstance), + if (!File.Exists(Path.Combine(PathUtils.GetDirectoryPart(PathInstance), InheritInstanceName, InheritInstanceName + ".json"))) { state = McInstanceState.Error; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs index 3014c0dae..dd6851d18 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModAssets.cs @@ -138,7 +138,7 @@ internal static List McAssetsListGet(McInstance mcInstance) Path.Combine(ModFolder.mcFolderSelected, "assets", "indexes", indexName + ".json")); var result = new List(); var json = (JsonObject)JsonCompat.ParseNode( - LegacyFileFacade.ReadText($@"{ModFolder.mcFolderSelected}assets\indexes\{indexName}.json")); + Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath($@"{ModFolder.mcFolderSelected}assets\indexes\{indexName}.json")).GetAwaiter().GetResult()); // 读取列表 foreach (var file in json["objects"].AsObject()) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs index c7f596243..6a855ff45 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs @@ -696,7 +696,7 @@ private static string InitializeModDbAndGetConnectionString() // 这里提取文件资源 trueDbFile.CopyTo(ms); ms.Seek(0L, SeekOrigin.Begin); - var fileHash = LegacyFileFacade.GetHexString(SHA1Provider.Instance.ComputeHash(ms)); + var fileHash = BinaryEncoding.ToHexLower(SHA1Provider.Instance.ComputeHash(ms)); var dbDir = Path.Combine(LauncherPaths.TempWithSlash, "Cache"); var dbPath = Path.Combine(dbDir, $"ModData{fileHash}.sqlite"); @@ -1447,7 +1447,7 @@ private async Task GetChineseDescriptionAsync() var descHash = $"{Id}{BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(Description).AsSpan())}"; var cacheFilePath = $@"{LauncherPaths.TempWithSlash}Cache\CompTranslation.ini"; - var cacheTranslation = LegacyIniStore.Shared.Read(cacheFilePath, descHash); + var cacheTranslation = LauncherIniStore.Shared.Read(cacheFilePath, descHash); if (!string.IsNullOrWhiteSpace(cacheTranslation)) { result = Base64Utils.DecodeToString(cacheTranslation); @@ -1461,7 +1461,7 @@ private async Task GetChineseDescriptionAsync() if (jsonObject.ContainsKey("translated")) { result = jsonObject["translated"].ToString(); - LegacyIniStore.Shared.Write(cacheFilePath, descHash, Base64Utils.EncodeString(result)); + LauncherIniStore.Shared.Write(cacheFilePath, descHash, Base64Utils.EncodeString(result)); } } catch (HttpRequestException ex) @@ -3540,7 +3540,7 @@ private static void _StartQuickDownload(CompFile file, string target) _ => Lang.Text("Download.Comp.Type.Mod") }; var loaderName = Lang.Text("Download.Comp.Detail.DownloadResource", desc, - LegacyFileFacade.GetFileNameWithoutExtensionFromPath(target)); + PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(target)); var loaders = new List { new LoaderDownload(Lang.Text("Download.Comp.Detail.DownloadFile"), @@ -3555,7 +3555,7 @@ private static void _StartQuickDownload(CompFile file, string target) var extractDir = Path.GetDirectoryName(target); loaders.Add(new ModLoader.LoaderTask( Lang.Text("Download.Comp.Detail.InstallWorld"), - _ => LegacyFileFacade.ExtractFile(target, extractDir, Encoding.UTF8)) + _ => Files.ExtractFileAsync(target, extractDir).GetAwaiter().GetResult()) { ProgressWeight = 0.1d, block = true diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs index 079604a2b..baa5cc5f8 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.cs @@ -159,7 +159,7 @@ public static DownloadFile DlClientAssetIndexGet(McInstance version) loadersAssetsUpdate.Add(new ModLoader.LoaderTask, string>( Lang.Text("Minecraft.Download.Stage.CopyAssetsIndex.Background"), task => { - LegacyFileFacade.CopyFile(tempAddress, realAddress); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(tempAddress), LauncherFileSystem.ResolvePath(realAddress)).GetAwaiter().GetResult(); ModLaunch.McLaunchLog("后台更新资源文件索引成功:" + tempAddress); })); var updater = new ModLoader.LoaderCombo( @@ -357,7 +357,7 @@ private static void DlClientListMojangMain(ModLoader.LoaderTask")[1]; try { - LegacyFileFacade.CheckPermissionWithException(path); + Directories.CheckPermissionWithExceptionAsync(path).GetAwaiter().GetResult(); cacheMcFolderList.Add(new McFolder { Name = name, Location = path, type = McFolder.Types.Custom }); } catch (Exception ex) @@ -219,8 +219,7 @@ public static void McFolderLauncherProfilesJsonCreate(string folder) ""selectedProfile"": ""PCL"", ""clientToken"": ""23323323323323323323323323323333"" }"; - LegacyFileFacade.WriteFile(Path.Combine(folder, "launcher_profiles.json"), resultJson, - encoding: Encoding.GetEncoding("GB18030")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(folder, "launcher_profiles.json")), resultJson, encoding: Encoding.GetEncoding("GB18030")).GetAwaiter().GetResult(); LauncherLog.Log($"[Minecraft] 已创建 launcher_profiles.json:{folder}"); } catch (Exception ex) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs index b75a50851..990e78250 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModInstanceList.cs @@ -84,7 +84,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) // 如果没有可用实例,清空缓存并跳过后续处理 if (!folderList.Any()) { - LegacyIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); + LauncherIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); McMcInstanceSelected = null; States.Game.SelectedInstance = ""; LauncherLog.Log("[Minecraft] 未找到可用 Minecraft 实例"); @@ -97,7 +97,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) // 尝试使用缓存 var useCache = !mcInstanceListForceRefresh && - NumberUtils.ParseDoubleOrZero(LegacyIniStore.Shared.Read(Path.Combine(path, "PCL.ini"), + NumberUtils.ParseDoubleOrZero(LauncherIniStore.Shared.Read(Path.Combine(path, "PCL.ini"), "InstanceCache")) == folderListCheck; @@ -115,7 +115,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) { mcInstanceListForceRefresh = false; LauncherLog.Log("[Minecraft] 文件夹列表变更或缓存无效,重载所有实例"); - LegacyIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", folderListCheck.ToString()); + LauncherIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", folderListCheck.ToString()); mcInstanceList = InitMcInstanceListWithoutCache(path); } @@ -125,7 +125,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) return; // 尝试读取已储存的选择 - var savedSelection = LegacyIniStore.Shared.Read(Path.Combine(path, "PCL.ini"), "Version"); + var savedSelection = LauncherIniStore.Shared.Read(Path.Combine(path, "PCL.ini"), "Version"); if (!string.IsNullOrEmpty(savedSelection)) foreach (var card in mcInstanceList) foreach (var instance in card.Value) @@ -165,7 +165,7 @@ private static void InitMcInstanceList(ModLoader.LoaderTask loader) } catch (Exception ex) { - LegacyIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); // 要求下次重新加载 + LauncherIniStore.Shared.Write(Path.Combine(path, "PCL.ini"), "InstanceCache", ""); // 要求下次重新加载 LauncherLog.Log( ex, Lang.Text("Select.Instance.Error.ListLoad"), @@ -180,18 +180,18 @@ private static Dictionary> InitMcInstanceLi var results = new Dictionary>(); try { - var cardCount = int.Parse(LegacyIniStore.Shared.Read(path + "PCL.ini", "CardCount", (-1).ToString())); + var cardCount = int.Parse(LauncherIniStore.Shared.Read(path + "PCL.ini", "CardCount", (-1).ToString())); if (cardCount == -1) return null; for (int i = 0, loopTo = cardCount - 1; i <= loopTo; i++) { var cardType = - (McInstanceCardType)int.Parse(LegacyIniStore.Shared.Read(path + "PCL.ini", "CardKey" + (i + 1), + (McInstanceCardType)int.Parse(LauncherIniStore.Shared.Read(path + "PCL.ini", "CardKey" + (i + 1), "0")); var instanceList = new List(); // 循环读取实例 - foreach (var folder in LegacyIniStore.Shared.Read(path + "PCL.ini", "CardValue" + (i + 1), ":") + foreach (var folder in LauncherIniStore.Shared.Read(path + "PCL.ini", "CardValue" + (i + 1), ":") .Split(":")) { if (string.IsNullOrEmpty(folder)) @@ -579,15 +579,15 @@ int getComponentCode(McInstance instance) #region 保存卡片缓存 - LegacyIniStore.Shared.Write(path + "PCL.ini", "CardCount", results.Count.ToString()); + LauncherIniStore.Shared.Write(path + "PCL.ini", "CardCount", results.Count.ToString()); for (int i = 0, loopTo = results.Count - 1; i <= loopTo; i++) { - LegacyIniStore.Shared.Write(path + "PCL.ini", "CardKey" + (i + 1), + LauncherIniStore.Shared.Write(path + "PCL.ini", "CardKey" + (i + 1), ((int)results.Keys.ElementAtOrDefault(i)).ToString()); var value = ""; foreach (var Instance in results.Values.ElementAtOrDefault(i)) value += Instance.Name + ":"; - LegacyIniStore.Shared.Write(path + "PCL.ini", "CardValue" + (i + 1), value); + LauncherIniStore.Shared.Write(path + "PCL.ini", "CardValue" + (i + 1), value); } #endregion diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs index 50a770428..2653ca423 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.cs @@ -379,7 +379,7 @@ public static ModLoader.LoaderCombo GetJavaDownloadLoader() $"[Java] 由于下载未完成,清理未下载完成的 Java 文件:{lastJavaBaseDir}", LauncherLogLevel.Debug); - LegacyFileFacade.DeleteDirectory(lastJavaBaseDir); + Directories.DeleteDirectoryAsync(lastJavaBaseDir).GetAwaiter().GetResult(); break; case LoadState.Finished: Javas.ScanJavaAsync().GetAwaiter().GetResult(); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs index 0f850bd87..e0407898b 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs @@ -2218,7 +2218,7 @@ public static string ExtractJavaWrapper() private static void WriteJavaWrapper(string path) { - LegacyFileFacade.WriteFile(path, Basics.GetResourceStream("Resources/java-wrapper.jar")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(path), Basics.GetResourceStream("Resources/java-wrapper.jar")).GetAwaiter().GetResult(); } /// @@ -2262,7 +2262,7 @@ public static string ExtractLinkD() private static void WriteLinkD(string path) { - LegacyFileFacade.WriteFile(path, Basics.GetResourceStream("Resources/linkd.exe")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(path), Basics.GetResourceStream("Resources/linkd.exe")).GetAwaiter().GetResult(); } /// @@ -2749,9 +2749,8 @@ private static string McLaunchArgumentsGameOld(McInstance version) " --tweakClass optifine.OptiFineForgeTweaker"; try { - LegacyFileFacade.WriteFile(Path.Combine(version.PathInstance, version.Name + ".json"), - LegacyFileFacade.ReadText(Path.Combine(version.PathInstance, version.Name + ".json")) - .Replace("optifine.OptiFineTweaker", "optifine.OptiFineForgeTweaker")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(version.PathInstance, version.Name + ".json")), Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(Path.Combine(version.PathInstance, version.Name + ".json"))).GetAwaiter().GetResult() + .Replace("optifine.OptiFineTweaker", "optifine.OptiFineForgeTweaker")).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -2840,9 +2839,8 @@ private static string McLaunchArgumentsGameNew(McInstance instance) " --tweakClass optifine.OptiFineForgeTweaker"; try { - LegacyFileFacade.WriteFile(Path.Combine(instance.PathInstance, instance.Name + ".json"), - LegacyFileFacade.ReadText(Path.Combine(instance.PathInstance, instance.Name + ".json")) - .Replace("optifine.OptiFineTweaker", "optifine.OptiFineForgeTweaker")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(instance.PathInstance, instance.Name + ".json")), Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(Path.Combine(instance.PathInstance, instance.Name + ".json"))).GetAwaiter().GetResult() + .Replace("optifine.OptiFineTweaker", "optifine.OptiFineForgeTweaker")).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -2862,11 +2860,11 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in // 基础参数 gameArguments.Add("${classpath_separator}", ";"); - gameArguments.Add("${natives_directory}", LegacyFileFacade.ShortenPath(GetNativesFolder())); + gameArguments.Add("${natives_directory}", PathUtils.ShortenPath(GetNativesFolder())); gameArguments.Add("${library_directory}", - LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected + "libraries")); + PathUtils.ShortenPath(ModFolder.mcFolderSelected + "libraries")); gameArguments.Add("${libraries_directory}", - LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected + "libraries")); + PathUtils.ShortenPath(ModFolder.mcFolderSelected + "libraries")); gameArguments.Add("${launcher_name}", "PCLCE"); gameArguments.Add("${launcher_version}", LauncherEnvironment.VersionCode.ToString()); gameArguments.Add("${version_name}", instance.Name); @@ -2876,8 +2874,8 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in ? Config.Launch.TypeInfo : argumentInfo); gameArguments.Add("${game_directory}", - LegacyFileFacade.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie[..^1])); - gameArguments.Add("${assets_root}", LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected + "assets")); + PathUtils.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie[..^1])); + gameArguments.Add("${assets_root}", PathUtils.ShortenPath(ModFolder.mcFolderSelected + "assets")); gameArguments.Add("${user_properties}", "{}"); gameArguments.Add("${auth_player_name}", mcLoginLoader.output.Name); gameArguments.Add("${auth_uuid}", mcLoginLoader.output.Uuid); @@ -2929,7 +2927,7 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in // Assets 相关参数 gameArguments.Add("${game_assets}", - LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected + + PathUtils.ShortenPath(ModFolder.mcFolderSelected + @"assets\virtual\legacy")); // 1.5.2 的 pre-1.6 资源索引应与 legacy 合并 gameArguments.Add("${assets_index_name}", ModAssets.McAssetsGetIndexName(instance)); @@ -2945,7 +2943,7 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in var legacyFixPath = Path.Combine(LauncherPaths.PureAsciiDirectory, "legacyfix.jar"); try { - LegacyFileFacade.WriteFile(legacyFixPath, Basics.GetResourceStream("Resources/legacyfix.jar")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(legacyFixPath), Basics.GetResourceStream("Resources/legacyfix.jar")).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -2959,7 +2957,7 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in var agentPath = Path.Combine(LauncherPaths.PureAsciiDirectory, "lwjgl-unsafe-agent.jar"); try { - LegacyFileFacade.WriteFile(agentPath, Basics.GetResourceStream("Resources/lwjgl-unsafe-agent.jar")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(agentPath), Basics.GetResourceStream("Resources/lwjgl-unsafe-agent.jar")).GetAwaiter().GetResult(); cpStrings.Add(agentPath); } catch (Exception ex) @@ -2993,7 +2991,7 @@ private static Dictionary McLaunchArgumentsReplace(McInstance in if (optiFineCp is not null) cpStrings.Insert(cpStrings.Count - 2, optiFineCp); // OptiFine 的总是需要放到倒数第二位 - gameArguments.Add("${classpath}", cpStrings.Select(c => LegacyFileFacade.ShortenPath(c)).Join(";")); + gameArguments.Add("${classpath}", cpStrings.Select(c => PathUtils.ShortenPath(c)).Join(";")); return gameArguments; } @@ -3059,7 +3057,7 @@ private static void McLaunchNatives(ModLoader.LoaderTask loader) $"{(mcLaunchJavaSelected.Installation.MajorVersion > 8 ? "chcp 65001>nul" + "\r\n" : "")}" + "@echo off" + "\r\n" + $"title 启动 - {ModInstanceList.McMcInstanceSelected.Name}" + "\r\n" + "echo 游戏正在启动,请稍候。" + "\r\n" + - $"cd /D \"{LegacyFileFacade.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie)}\"" + "\r\n" + + $"cd /D \"{PathUtils.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie)}\"" + "\r\n" + customCommandGlobal + "\r\n" + customCommandVersion + "\r\n" + $"\"{mcLaunchJavaSelected.Installation.JavaExePath}\" {mcLaunchArgument}" + "\r\n" + "echo 游戏已退出。" + "\r\n" + "pause"; - LegacyFileFacade.WriteFile( - currentLaunchOptions.SaveBatch ?? LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\LatestLaunch.bat", - McLogFilter.FilterAccessToken(cmdString, 'F'), - encoding: mcLaunchJavaSelected.Installation.MajorVersion > 8 ? Encoding.UTF8 : Encoding.Default); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(currentLaunchOptions.SaveBatch ?? LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\LatestLaunch.bat"), McLogFilter.FilterAccessToken(cmdString, 'F'), encoding: mcLaunchJavaSelected.Installation.MajorVersion > 8 ? Encoding.UTF8 : Encoding.Default).GetAwaiter().GetResult(); if (currentLaunchOptions.SaveBatch is not null) { McLaunchLog("导出启动脚本完成,强制结束启动过程"); @@ -3410,7 +3402,7 @@ private static void McLaunchCustom(ModLoader.LoaderTask loader) { customProcess.StartInfo.FileName = "cmd.exe"; customProcess.StartInfo.Arguments = "/c \"" + customCommandGlobal + "\""; - customProcess.StartInfo.WorkingDirectory = LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected); + customProcess.StartInfo.WorkingDirectory = PathUtils.ShortenPath(ModFolder.mcFolderSelected); customProcess.StartInfo.UseShellExecute = false; customProcess.StartInfo.CreateNoWindow = true; customProcess.Start(); @@ -3444,7 +3436,7 @@ private static void McLaunchCustom(ModLoader.LoaderTask loader) { customProcess.StartInfo.FileName = "cmd.exe"; customProcess.StartInfo.Arguments = "/c \"" + customCommandVersion + "\""; - customProcess.StartInfo.WorkingDirectory = LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected); + customProcess.StartInfo.WorkingDirectory = PathUtils.ShortenPath(ModFolder.mcFolderSelected); customProcess.StartInfo.UseShellExecute = false; customProcess.StartInfo.CreateNoWindow = true; customProcess.Start(); @@ -3484,12 +3476,12 @@ private static void McLaunchRun(ModLoader.LoaderTask loader) // 设置环境变量 var paths = new List(startInfo.EnvironmentVariables["Path"].Split(";")); - paths.Add(LegacyFileFacade.ShortenPath(mcLaunchJavaSelected.Installation.JavaFolder)); + paths.Add(PathUtils.ShortenPath(mcLaunchJavaSelected.Installation.JavaFolder)); startInfo.EnvironmentVariables["Path"] = paths.Distinct().ToList().Join(";"); - startInfo.EnvironmentVariables["appdata"] = LegacyFileFacade.ShortenPath(ModFolder.mcFolderSelected); + startInfo.EnvironmentVariables["appdata"] = PathUtils.ShortenPath(ModFolder.mcFolderSelected); // 设置其他参数 - startInfo.WorkingDirectory = LegacyFileFacade.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie); + startInfo.WorkingDirectory = PathUtils.ShortenPath(ModInstanceList.McMcInstanceSelected.PathIndie); startInfo.UseShellExecute = false; startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; @@ -3693,7 +3685,7 @@ string replacer(string s) if (escapeHandler is null) return s; if (s.Contains(@":\")) - s = LegacyFileFacade.ShortenPath(s); + s = PathUtils.ShortenPath(s); return escapeHandler(s); } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs index 87bd4f737..c93e6f4b1 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLibrary.cs @@ -362,7 +362,7 @@ public static List McLibListGetWithJson(JsonObject jsonObject, // D:\Minecraft\test\libraries\com\google\guava\guava\31.1-jre\guava-31.1-jre.jar string GetVersion(McLibToken token) { - return LegacyFileFacade.GetFolderNameFromPath(LegacyFileFacade.GetPathFromFullPath(token.LocalPath)); + return PathUtils.GetDirectoryNameLeaf(PathUtils.GetDirectoryPart(token.LocalPath)); } for (int i = 0, loopTo = basicArray.Count - 1; i <= loopTo; i++) @@ -484,9 +484,7 @@ public static List McLibNetFilesFromInstance(McInstance mcInstance { if (Directory.Exists(Path.Combine(mcInstance.PathInstance, "labymod-neo"))) Directory.Delete(Path.Combine(mcInstance.PathInstance, "labymod-neo"), true); - LegacyFileFacade.CreateSymbolicLink(Path.Combine(mcInstance.PathInstance, "labymod-neo"), - Path.Combine(ModFolder.mcFolderSelected, "labymod-neo"), - 0x2); + LauncherFileSystem.CreateSymbolicLinkByBundledLinkD(Path.Combine(mcInstance.PathInstance, "labymod-neo"), Path.Combine(ModFolder.mcFolderSelected, "labymod-neo"), 0x2); } try @@ -586,7 +584,7 @@ public static List McLibNetFilesFromTokens(List libs, { // Transformer 文件释放 if (!File.Exists(token.LocalPath)) - LegacyFileFacade.WriteFile(token.LocalPath, Basics.GetResourceStream("Resources/transformer.jar")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(token.LocalPath), Basics.GetResourceStream("Resources/transformer.jar")).GetAwaiter().GetResult(); LauncherLog.Log("[Download] 已自动释放 Transformer Discovery Service", LauncherLogLevel.Developer); continue; } @@ -596,7 +594,7 @@ public static List McLibNetFilesFromTokens(List libs, // OptiFine 主 Jar var optiFineBase = token.LocalPath.Replace(Path.Combine(customMcFolder, "libraries", "optifine", "OptiFine") + @"\", "").Split("_")[0] + "/" + - LegacyFileFacade.GetFileNameFromPath(token.LocalPath).Replace("-", "_"); + PathUtils.GetFileNameFromUrlOrPath(token.LocalPath).Replace("-", "_"); optiFineBase = "/maven/com/optifine/" + optiFineBase; if (optiFineBase.Contains("_pre")) optiFineBase = optiFineBase.Replace("com/optifine/", "com/optifine/preview_"); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs index 8c5cdc097..200ca8f94 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLocalComp.cs @@ -389,7 +389,7 @@ public LocalCompFile(string path) /// /// Mod 资源的完整路径,去除最后的 .disabled 和 .old。 /// - public string RawPath => LegacyFileFacade.GetPathFromFullPath(path) + RawFileName; + public string RawPath => PathUtils.GetDirectoryPart(path) + RawFileName; /// /// 资源的完整文件名。 @@ -400,7 +400,7 @@ public string FileName { if (IsFolder && !string.IsNullOrEmpty(Name)) return Name; - return LegacyFileFacade.GetFileNameFromPath(path); + return PathUtils.GetFileNameFromUrlOrPath(path); } } @@ -450,9 +450,9 @@ public string Name if (_Name is null) { if (IsFolder) - _Name = LegacyFileFacade.GetFolderNameFromPath(ActualPath); + _Name = PathUtils.GetDirectoryNameLeaf(ActualPath); else - _Name = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(path); + _Name = PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(path); } return _Name; @@ -965,7 +965,7 @@ public void LoadBasicInfo() if (path.EndsWithF(".litematic", true) || path.EndsWithF(".nbt", true) || path.EndsWithF(".schem", true) || path.EndsWithF(".schematic", true)) { - _Name = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(path); + _Name = PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(path); isLoaded = true; return; } @@ -1053,7 +1053,7 @@ public void Load(bool forceReload = false) { try { - _Name = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(path); + _Name = PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(path); // 根据文件类型加载数据 if (path.EndsWithF(".litematic", true)) { @@ -1127,7 +1127,7 @@ private void LookupMetadata(ZipArchive jar) string infoString = null; if (infoEntry is not null) { - infoString = LegacyFileFacade.ReadText(infoEntry.Open()); + infoString = Files.ReadAllTextOrEmptyAsync(infoEntry.Open()).GetAwaiter().GetResult(); if (infoString.Length < 15) infoString = null; } @@ -1167,7 +1167,7 @@ private void LookupMetadata(ZipArchive jar) Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { - LegacyFileFacade.WriteFile(Logo, entryStream); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Logo), entryStream).GetAwaiter().GetResult(); } } } @@ -1228,7 +1228,7 @@ private void LookupMetadata(ZipArchive jar) string fabricText = null; if (fabricEntry is not null) { - fabricText = LegacyFileFacade.ReadText(fabricEntry.Open(), Encoding.UTF8); + fabricText = Files.ReadAllTextOrEmptyAsync(fabricEntry.Open(), Encoding.UTF8).GetAwaiter().GetResult(); if (!fabricText.Contains("schemaVersion")) fabricText = null; } @@ -1260,7 +1260,7 @@ private void LookupMetadata(ZipArchive jar) Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { - LegacyFileFacade.WriteFile(Logo, entryStream); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Logo), entryStream).GetAwaiter().GetResult(); } } } @@ -1289,7 +1289,7 @@ private void LookupMetadata(ZipArchive jar) string quiltText = null; if (quiltEntry is not null) { - quiltText = LegacyFileFacade.ReadText(quiltEntry.Open(), Encoding.UTF8); + quiltText = Files.ReadAllTextOrEmptyAsync(quiltEntry.Open(), Encoding.UTF8).GetAwaiter().GetResult(); if (!quiltText.Contains("schema_version")) quiltText = null; } @@ -1325,7 +1325,7 @@ private void LookupMetadata(ZipArchive jar) Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = logoItem.Open()) { - LegacyFileFacade.WriteFile(Logo, entryStream); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Logo), entryStream).GetAwaiter().GetResult(); } } } @@ -1512,7 +1512,7 @@ private void LookupMetadata(ZipArchive jar) string fmlText = null; if (fmlEntry is not null) { - fmlText = LegacyFileFacade.ReadText(fmlEntry.Open(), Encoding.UTF8); + fmlText = Files.ReadAllTextOrEmptyAsync(fmlEntry.Open(), Encoding.UTF8).GetAwaiter().GetResult(); if (!fmlText.Contains("Lnet/minecraftforge/fml/common/Mod;")) fmlText = null; } @@ -1618,7 +1618,7 @@ private void LookupMetadata(ZipArchive jar) Logo = System.IO.Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Images", $"{md5}.png"); using (var entryStream = packPngEntry.Open()) { - LegacyFileFacade.WriteFile(Logo, entryStream); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Logo), entryStream).GetAwaiter().GetResult(); } LauncherLog.Log("成功提取资源包图标:" + path, LauncherLogLevel.Debug); @@ -1645,7 +1645,7 @@ private void LookupMetadata(ZipArchive jar) var metaEntry = jar.GetEntry("META-INF/MANIFEST.MF"); if (metaEntry is not null) { - var metaString = LegacyFileFacade.ReadText(metaEntry.Open()).Replace(" :", ":").Replace(": ", ":"); + var metaString = Files.ReadAllTextOrEmptyAsync(metaEntry.Open()).GetAwaiter().GetResult().Replace(" :", ":").Replace(": ", ":"); if (metaString.Contains("Implementation-Version:")) { metaString = metaString.Substring(metaString.IndexOfF("Implementation-Version:") + @@ -1924,7 +1924,7 @@ private static void CompResourceListLoad(LoaderTask lo cache[Entry.ModrinthHash + mcInstance + string.Join("", modLoaders)] = Entry.ToJson(); } - LegacyFileFacade.WriteFile(Path.Combine(LauncherPaths.TempWithSlash, "Cache", "LocalComp.json"), - cache.ToJsonString(LauncherRuntime.ModeDebug ? new JsonSerializerOptions(JsonCompat.SerializerOptions) { WriteIndented = true } : null)); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(LauncherPaths.TempWithSlash, "Cache", "LocalComp.json")), cache.ToJsonString(LauncherRuntime.ModeDebug ? new JsonSerializerOptions(JsonCompat.SerializerOptions) { WriteIndented = true } : null)).GetAwaiter().GetResult(); // 刷新 UI UiThread.Post(() => diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs index 3c3cf4aad..23cf155a0 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs @@ -96,8 +96,7 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam if (archive.GetEntry("manifest.json") is not null) { - var json = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(archive.GetEntry("manifest.json").Open(), - Encoding.UTF8)); + var json = (JsonObject)JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(archive.GetEntry("manifest.json").Open(), Encoding.UTF8).GetAwaiter().GetResult()); if (json["addons"] is null) { packType = 0; @@ -154,7 +153,7 @@ public static LoaderCombo ModpackInstall(string file, string instanceNam if (fullNames[1] == "manifest.json") { - var json = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(Entry.Open(), Encoding.UTF8)); + var json = (JsonObject)JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(Entry.Open(), Encoding.UTF8).GetAwaiter().GetResult()); if (json["addons"] is null) { packType = 0; @@ -261,11 +260,10 @@ private static void ExtractModpackFiles(string installTemp, string fileAddress, loader.Progress = initialProgress; // 删除旧目录 - LegacyFileFacade.DeleteDirectory(installTemp); + Directories.DeleteDirectoryAsync(installTemp).GetAwaiter().GetResult(); // 解压文件,ProgressIncrementHandler 通过 Lambda 更新进度 - LegacyFileFacade.ExtractFile(fileAddress, installTemp, encode, - delta => loader.Progress += delta * progressIncrement); + Files.ExtractFileAsync(fileAddress, installTemp, delta => loader.Progress += delta * progressIncrement).GetAwaiter().GetResult(); // 解压成功,更新进度并退出循环 loader.Progress = initialProgress + progressIncrement; @@ -311,8 +309,7 @@ private static void CopyOverrideDirectory(string overridesFolder, string version if (Directory.Exists(overridesFolder)) { LauncherLog.Log($"[ModPack] 处理整合包覆写文件夹:{overridesFolder} → {versionFolder}"); - LegacyFileFacade.CopyDirectory(overridesFolder, versionFolder, - delta => loader.Progress += delta * progressIncrement); + Directories.CopyDirectoryAsync(overridesFolder, versionFolder, delta => loader.Progress += delta * progressIncrement).GetAwaiter().GetResult(); } else { @@ -325,17 +322,17 @@ private static void CopyOverrideDirectory(string overridesFolder, string version var versionIni = $@"{versionFolder}PCL\Setup.ini"; if (File.Exists(overridesIni)) { - LegacyIniStore.Shared.Write(overridesIni, "VersionArgumentIndie", 1.ToString()); // 开启版本隔离 - LegacyIniStore.Shared.Write(overridesIni, "VersionArgumentIndieV2", true.ToString()); - LegacyFileFacade.CopyFile(overridesIni, versionIni); // 覆写已有的 ini + LauncherIniStore.Shared.Write(overridesIni, "VersionArgumentIndie", 1.ToString()); // 开启版本隔离 + LauncherIniStore.Shared.Write(overridesIni, "VersionArgumentIndieV2", true.ToString()); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(overridesIni), LauncherFileSystem.ResolvePath(versionIni)).GetAwaiter().GetResult(); // 覆写已有的 ini } else { - LegacyIniStore.Shared.Write(versionIni, "VersionArgumentIndie", 1.ToString()); // 开启版本隔离 - LegacyIniStore.Shared.Write(versionIni, "VersionArgumentIndieV2", true.ToString()); + LauncherIniStore.Shared.Write(versionIni, "VersionArgumentIndie", 1.ToString()); // 开启版本隔离 + LauncherIniStore.Shared.Write(versionIni, "VersionArgumentIndieV2", true.ToString()); } - LegacyIniStore.Shared.ClearCache(versionIni); // 重置缓存,避免被安装过程中写入的 ini 覆盖 + LauncherIniStore.Shared.ClearCache(versionIni); // 重置缓存,避免被安装过程中写入的 ini 覆盖 } #region CurseForge @@ -349,7 +346,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip try { json = (JsonObject)JsonCompat.ParseNode( - LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "manifest.json").Open())); + Files.ReadAllTextOrEmptyAsync(archive.GetEntry(archiveBaseFolder + "manifest.json").Open()).GetAwaiter().GetResult()); } catch (Exception ex) { @@ -611,7 +608,7 @@ private static LoaderCombo InstallPackCurseForge(string fileAddress, Zip File.Delete(Target); } - if (File.Exists(fileAddress) && LegacyFileFacade.GetFileNameWithoutExtensionFromPath(fileAddress) == "modpack") + if (File.Exists(fileAddress) && PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(fileAddress) == "modpack") { LauncherLog.Log("[ModPack] 删除安装整合包文件:" + fileAddress); File.Delete(fileAddress); @@ -672,7 +669,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr try { json = (JsonObject)JsonCompat.ParseNode( - LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "modrinth.index.json").Open())); + Files.ReadAllTextOrEmptyAsync(archive.GetEntry(archiveBaseFolder + "modrinth.index.json").Open()).GetAwaiter().GetResult()); } catch (Exception ex) { @@ -771,7 +768,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr { if (ModMain.MyMsgBox( Lang.Text("Minecraft.Download.Modpack.OptionalFile.Message", - LegacyFileFacade.GetFileNameFromPath(File["path"].ToString())), + PathUtils.GetFileNameFromUrlOrPath(File["path"].ToString())), Lang.Text("Minecraft.Download.Modpack.OptionalFile.Title"), Lang.Text("Minecraft.Download.Modpack.OptionalFile.Download"), Lang.Text("Minecraft.Download.Modpack.OptionalFile.Skip") @@ -850,7 +847,7 @@ private static LoaderCombo InstallPackModrinth(string fileAddress, ZipAr File.Delete(Target); } - if (File.Exists(fileAddress) && LegacyFileFacade.GetFileNameWithoutExtensionFromPath(fileAddress) == "modpack") + if (File.Exists(fileAddress) && PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(fileAddress) == "modpack") { LauncherLog.Log("[ModPack] 删除安装整合包文件:" + fileAddress); File.Delete(fileAddress); @@ -910,7 +907,7 @@ private static LoaderCombo InstallPackHMCL(string fileAddress, ZipArchiv try { json = (JsonObject)JsonCompat.ParseNode( - LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "modpack.json").Open(), Encoding.UTF8)); + Files.ReadAllTextOrEmptyAsync(archive.GetEntry(archiveBaseFolder + "modpack.json").Open(), Encoding.UTF8).GetAwaiter().GetResult()); } catch (Exception ex) { @@ -992,7 +989,7 @@ private static LoaderCombo InstallPackMCBBS(string fileAddress, ZipArchi archive.GetEntry(archiveBaseFolder + "manifest.json"); using (var stream = entry.Open()) { - json = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(stream, Encoding.UTF8)); + json = (JsonObject)JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(stream, Encoding.UTF8).GetAwaiter().GetResult()); } } catch (Exception ex) @@ -1183,7 +1180,7 @@ private static LoaderCombo InstallPackLauncherPack(string fileAddress, Z LauncherProcess.OpenExplorer(targetFolder); // 加入文件夹列表 - var instanceName = LegacyFileFacade.GetFolderNameFromPath(targetFolder); + var instanceName = PathUtils.GetDirectoryNameLeaf(targetFolder); Directory.CreateDirectory(Path.Combine(targetFolder, ".minecraft")); PageSelectLeft.AddFolder( Path.Combine(targetFolder, ".minecraft", archiveBaseFolder.Replace("/", @"\").TrimStart('\\')), instanceName, @@ -1251,7 +1248,7 @@ private static LoaderCombo InstallPackCompress(string fileAddress, ZipAr { ExtractModpackFiles(targetFolder, fileAddress, task, 0.95d); // 加入文件夹列表 - PageSelectLeft.AddFolder(Path.Combine(targetFolder, archiveBaseFolder), LegacyFileFacade.GetFolderNameFromPath(targetFolder), + PageSelectLeft.AddFolder(Path.Combine(targetFolder, archiveBaseFolder), PathUtils.GetDirectoryNameLeaf(targetFolder), false); Thread.Sleep(400); // 避免文件争用 UiThread.Post(() => ModMain.frmMain.PageChange(FormMain.PageType.InstanceSelect)); @@ -1296,8 +1293,8 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive try { packJson = (JsonObject)JsonCompat.ParseNode( - LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "mmc-pack.json").Open(), Encoding.UTF8)); - packInstance = LegacyFileFacade.ReadText(archive.GetEntry(archiveBaseFolder + "instance.cfg").Open(), Encoding.UTF8); + Files.ReadAllTextOrEmptyAsync(archive.GetEntry(archiveBaseFolder + "mmc-pack.json").Open(), Encoding.UTF8).GetAwaiter().GetResult()); + packInstance = Files.ReadAllTextOrEmptyAsync(archive.GetEntry(archiveBaseFolder + "instance.cfg").Open(), Encoding.UTF8).GetAwaiter().GetResult(); #region JSON Patches @@ -1315,8 +1312,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive foreach (var entry in archive.Entries) if (!entry.FullName.EndsWith("/") && entry.FullName.StartsWith(archiveBaseFolder + "patches/")) { - var patch = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText( - archive.GetEntry(entry.FullName).Open(), Encoding.UTF8)); + var patch = (JsonObject)JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(archive.GetEntry(entry.FullName).Open(), Encoding.UTF8).GetAwaiter().GetResult()); patches.Add(new KeyValuePair(patch, (int)(patch["order"] is not null ? patch["order"] : 0))); } @@ -1563,7 +1559,7 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive if (File.Exists(mMCSetupFile)) { List lines = []; - foreach (var Line in LegacyFileFacade.ReadText(mMCSetupFile).Split(new[] { "\r", "\n" }, + foreach (var Line in Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(mMCSetupFile)).GetAwaiter().GetResult().Split(new[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries)) { if (!Line.Contains("=")) @@ -1571,12 +1567,12 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive lines.Add(Line.BeforeFirst("=") + ":" + Line.AfterFirst("=")); } - LegacyFileFacade.WriteFile(mMCSetupFile, lines.Join("\r\n")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(mMCSetupFile), lines.Join("\r\n")).GetAwaiter().GetResult(); // 读取文件 - if (Convert.ToBoolean(LegacyIniStore.Shared.Read(mMCSetupFile, "OverrideCommands", + if (Convert.ToBoolean(LauncherIniStore.Shared.Read(mMCSetupFile, "OverrideCommands", false.ToString()))) { - var preLaunchCommand = LegacyIniStore.Shared.Read(mMCSetupFile, "PreLaunchCommand"); + var preLaunchCommand = LauncherIniStore.Shared.Read(mMCSetupFile, "PreLaunchCommand"); if (!string.IsNullOrEmpty(preLaunchCommand)) { preLaunchCommand = preLaunchCommand.Replace(@"\""", "\"") @@ -1589,37 +1585,36 @@ private static LoaderCombo InstallPackMMC(string fileAddress, ZipArchive } } - if (Convert.ToBoolean(LegacyIniStore.Shared.Read(mMCSetupFile, "JoinServerOnLaunch", + if (Convert.ToBoolean(LauncherIniStore.Shared.Read(mMCSetupFile, "JoinServerOnLaunch", false.ToString()))) { - var serverAddress = LegacyIniStore.Shared.Read(mMCSetupFile, "JoinServerOnLaunchAddress") + var serverAddress = LauncherIniStore.Shared.Read(mMCSetupFile, "JoinServerOnLaunchAddress") .Replace(@"\""", "\""); Config.Instance.ServerToEnter[versionFolder] = serverAddress; LauncherLog.Log("[ModPack] 迁移 MultiMC 实例独立设置:自动进入服务器:" + serverAddress); } - if (Convert.ToBoolean(LegacyIniStore.Shared.Read(mMCSetupFile, "IgnoreJavaCompatibility", + if (Convert.ToBoolean(LauncherIniStore.Shared.Read(mMCSetupFile, "IgnoreJavaCompatibility", false.ToString()))) { Config.Instance.IgnoreJavaCompatibility[versionFolder] = true; LauncherLog.Log("[ModPack] 迁移 MultiMC 实例独立设置:忽略 Java 兼容性警告"); } - var logo = Path.GetFileName(LegacyIniStore.Shared.Read(mMCSetupFile, "iconKey")); + var logo = Path.GetFileName(LauncherIniStore.Shared.Read(mMCSetupFile, "iconKey")); if (!string.IsNullOrEmpty(logo) && File.Exists($"{installTemp}{archiveBaseFolder}{logo}.png")) { States.Instance.IsLogoCustom[versionFolder] = true; States.Instance.LogoPath[versionFolder] = @"PCL\Logo.png"; - LegacyFileFacade.CopyFile($"{installTemp}{archiveBaseFolder}{logo}.png", - $@"{ModFolder.mcFolderSelected}versions\{instanceName}\PCL\Logo.png"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath($"{installTemp}{archiveBaseFolder}{logo}.png"), LauncherFileSystem.ResolvePath($@"{ModFolder.mcFolderSelected}versions\{instanceName}\PCL\Logo.png")).GetAwaiter().GetResult(); LauncherLog.Log($"[ModPack] 迁移 MultiMC 实例独立设置:实例图标({logo}.png)"); } // JVM 参数 - var jvmArgs = LegacyIniStore.Shared.Read(mMCSetupFile, "JvmArgs"); + var jvmArgs = LauncherIniStore.Shared.Read(mMCSetupFile, "JvmArgs"); if (!string.IsNullOrEmpty(jvmArgs)) { - if (Convert.ToBoolean(LegacyIniStore.Shared.Read(mMCSetupFile, "OverrideJavaArgs", + if (Convert.ToBoolean(LauncherIniStore.Shared.Read(mMCSetupFile, "OverrideJavaArgs", false.ToString()))) { Config.Instance.JvmArgs[versionFolder] = jvmArgs; diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs index 4dfed3227..46cf77e10 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs @@ -50,7 +50,7 @@ public static object McLoginMojangUuid(string name, bool throwOnNotFound) if (name.Trim().Length == 0) return TextUtils.LeftPadOrTrim("", "0", 32); // 从缓存获取 - var uuid = LegacyIniStore.Shared.Read(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini", name); + var uuid = LauncherIniStore.Shared.Read(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini", name); if ((uuid?.Length ?? 0) == 32) return uuid; // 从官网获取 @@ -91,7 +91,7 @@ public static object McLoginMojangUuid(string name, bool throwOnNotFound) // 写入缓存 if ((uuid?.Length ?? 0) != 32) throw new Exception("获取的正版 UUID 长度不足(" + uuid + ")"); - LegacyIniStore.Shared.Write(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini", name, uuid); + LauncherIniStore.Shared.Write(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini", name, uuid); return uuid; } @@ -184,10 +184,10 @@ public static void GetProfile() if (!File.Exists(profilePath)) { File.Create(profilePath).Close(); - LegacyFileFacade.WriteFile(profilePath, "{\"lastUsed\":0,\"profiles\":[]}"); // 创建档案列表文件 + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(profilePath), "{\"lastUsed\":0,\"profiles\":[]}").GetAwaiter().GetResult(); // 创建档案列表文件 } - var profileJobj = PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(profilePath)); + var profileJobj = PCL.Core.Utils.JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(profilePath)).GetAwaiter().GetResult()); lastUsedProfile = (int)profileJobj["lastUsed"]; var profileListJobj = (JsonArray)profileJobj["profiles"]; foreach (var Profile in profileListJobj) @@ -802,8 +802,8 @@ public static void ChangeSkinMs() { { new StringContent(skinInfo.IsSlim ? "slim" : "classic"), "variant" }, { - new ByteArrayContent(LegacyFileFacade.ReadBytes(skinInfo.LocalFile)), "file", - LegacyFileFacade.GetFileNameFromPath(skinInfo.LocalFile) + new ByteArrayContent(Files.ReadAllBytesOrEmptyAsync(LauncherFileSystem.ResolvePath(skinInfo.LocalFile)).GetAwaiter().GetResult()), "file", + PathUtils.GetFileNameFromUrlOrPath(skinInfo.LocalFile) } }; var res = Requester.Fetch("https://api.minecraftservices.com/minecraft/profile/skins", diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs index 222a4ccfd..45b37dd33 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModSkin.cs @@ -80,7 +80,7 @@ public static string McSkinGetAddress(string uuid, string type) // 尝试读取缓存 var cachePath = Path.Combine(LauncherPaths.TempWithSlash, $"Cache\\Skin\\Index{type}.ini"); - var cacheSkinAddress = LegacyIniStore.Shared.Read(cachePath, uuid); + var cacheSkinAddress = LauncherIniStore.Shared.Read(cachePath, uuid); if (!string.IsNullOrEmpty(cacheSkinAddress)) return cacheSkinAddress; @@ -132,7 +132,7 @@ public static string McSkinGetAddress(string uuid, string type) skinUrl = skinUrl.Contains("minecraft.net/") ? skinUrl.Replace("http://", "https://") : skinUrl; // 保存缓存 - LegacyIniStore.Shared.Write(cachePath, uuid, skinUrl); + LauncherIniStore.Shared.Write(cachePath, uuid, skinUrl); LauncherLog.Log($"[Skin] UUID {uuid} 对应的皮肤文件为 {skinUrl}"); return skinUrl; @@ -145,7 +145,7 @@ public static string McSkinGetAddress(string uuid, string type) /// public static string McSkinDownload(string address) { - var skinName = LegacyFileFacade.GetFileNameFromPath(address); + var skinName = PathUtils.GetFileNameFromUrlOrPath(address); var fileAddress = LauncherPaths.TempWithSlash + @"Cache\Skin\" + LauncherStringHash.Compute(address) + ".png"; lock (mcSkinDownloadLock) { diff --git a/Plain Craft Launcher 2/Modules/ModLink.cs b/Plain Craft Launcher 2/Modules/ModLink.cs index 7d4b24d28..c260bfd43 100644 --- a/Plain Craft Launcher 2/Modules/ModLink.cs +++ b/Plain Craft Launcher 2/Modules/ModLink.cs @@ -339,8 +339,7 @@ public static int DownloadEasyTier() // 2. Extract files loaders.Add(new ModLoader.LoaderTask(Lang.Text("Link.Mod.Task.ExtractFiles"), _ => - LegacyFileFacade.ExtractFile(dlTargetPath, - Path.Combine(Paths.SharedLocalData, "EasyTier", ETInfoProvider.ETVersion)) + Files.ExtractFileAsync(dlTargetPath, Path.Combine(Paths.SharedLocalData, "EasyTier", ETInfoProvider.ETVersion)).GetAwaiter().GetResult() ) { block = true }); // 3. Cleanup diff --git a/Plain Craft Launcher 2/Modules/ModMain.cs b/Plain Craft Launcher 2/Modules/ModMain.cs index ba230fe9f..c6aa857e3 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.cs +++ b/Plain Craft Launcher 2/Modules/ModMain.cs @@ -903,7 +903,7 @@ public static string ArgumentReplace(string text, Func escapeHan { if (s is null) return ""; if (escapeHandler is null) return s; - if (s.Contains(":\\")) s = LegacyFileFacade.ShortenPath(s); + if (s.Contains(":\\")) s = PathUtils.ShortenPath(s); return escapeHandler(s); }; @@ -1015,8 +1015,8 @@ public static void TryClearTaskTemp() try { LauncherLog.Log("[System] 开始清理任务缓存文件夹"); - LegacyFileFacade.DeleteDirectory(Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL", "TaskTemp")); - LegacyFileFacade.DeleteDirectory($@"{LauncherPaths.TempWithSlash}TaskTemp\"); + Directories.DeleteDirectoryAsync(Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL", "TaskTemp")).GetAwaiter().GetResult(); + Directories.DeleteDirectoryAsync($@"{LauncherPaths.TempWithSlash}TaskTemp\").GetAwaiter().GetResult(); LauncherLog.Log("[System] 已清理任务缓存文件夹"); } catch (Exception ex) @@ -1053,7 +1053,7 @@ public static string RequestTaskTempFolder(bool requireNonSpace = false) if (requireNonSpace && resultFolder.Contains(" ")) break; // 带空格 Directory.CreateDirectory(resultFolder); - LegacyFileFacade.CheckPermissionWithException(resultFolder); + Directories.CheckPermissionWithExceptionAsync(resultFolder).GetAwaiter().GetResult(); return resultFolder; } catch @@ -1065,7 +1065,7 @@ public static string RequestTaskTempFolder(bool requireNonSpace = false) resultFolder = Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL", "TaskTemp", $"{LauncherRuntime.GetUuid()}-{RandomUtils.NextInt(0, 1000000)}"); Directory.CreateDirectory(resultFolder); - LegacyFileFacade.CheckPermission(resultFolder); + Directories.CheckPermissionAsync(resultFolder).GetAwaiter().GetResult(); return resultFolder; } diff --git a/Plain Craft Launcher 2/Modules/ModMusic.cs b/Plain Craft Launcher 2/Modules/ModMusic.cs index 3c289bd5b..81e219948 100644 --- a/Plain Craft Launcher 2/Modules/ModMusic.cs +++ b/Plain Craft Launcher 2/Modules/ModMusic.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Windows.Controls; using NAudio; using NAudio.Wave; @@ -75,7 +75,7 @@ private static void MusicLoop(bool isFirstLoad = false) LauncherLog.Log(ex, $"播放音乐出现内部错误({musicCurrent})", LauncherLogLevel.Developer); // 错误处理:精准提示用户 - var fileName = LegacyFileFacade.GetFileNameFromPath(musicCurrent); + var fileName = PathUtils.GetFileNameFromUrlOrPath(musicCurrent); if (ex is MmException) { var msg = ex.Message; @@ -163,7 +163,7 @@ private static void MusicListInit(bool forceReload, string preventFirst = null) musicAllList = new List(); var musicDir = Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Musics"); Directory.CreateDirectory(musicDir); - foreach (var file in LegacyFileFacade.EnumerateFiles(musicDir)) + foreach (var file in Directories.EnumerateFilesOrEmptyAsync(PathUtils.ShortenPath(musicDir)).GetAwaiter().GetResult()) { var ext = file.Extension.ToLowerInvariant(); // 忽略非音频文件 @@ -237,7 +237,7 @@ private static void MusicRefreshUI() else { ModMain.frmMain.BtnExtraMusic.Show = true; - var fileName = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(musicCurrent); + var fileName = PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(musicCurrent); var isSingle = musicAllList.Count == 1; string tipText; if (MusicState == MusicStates.Pause) @@ -314,7 +314,7 @@ public static void MusicControlNext() if (musicAllList?.Count is { } arg2 && arg2 == 1) { MusicStartPlay(musicCurrent); - HintService.Hint(Lang.Text("Music.Hint.Replaying", LegacyFileFacade.GetFileNameFromPath(musicCurrent)), + HintService.Hint(Lang.Text("Music.Hint.Replaying", PathUtils.GetFileNameFromUrlOrPath(musicCurrent)), HintType.Success); } else @@ -327,7 +327,7 @@ public static void MusicControlNext() else { MusicStartPlay(addr); - HintService.Hint(Lang.Text("Music.Hint.Playing", LegacyFileFacade.GetFileNameFromPath(addr)), + HintService.Hint(Lang.Text("Music.Hint.Playing", PathUtils.GetFileNameFromUrlOrPath(addr)), HintType.Success); } } @@ -391,7 +391,7 @@ public static void MusicRefreshPlay(bool showHint, bool isFirstLoad = false) MusicStartPlay(addr, isFirstLoad); if (showHint) HintService.Hint( - Lang.Text("Music.Hint.Refreshed", LegacyFileFacade.GetFileNameFromPath(addr)), + Lang.Text("Music.Hint.Refreshed", PathUtils.GetFileNameFromUrlOrPath(addr)), HintType.Success, false); } diff --git a/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownloadUnc.cs b/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownloadUnc.cs index f03ea975b..0d91c6e8a 100644 --- a/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownloadUnc.cs +++ b/Plain Craft Launcher 2/Modules/Network/Loaders/LoaderDownloadUnc.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using PCL.Core.App; namespace PCL.Network.Loaders; @@ -41,7 +41,7 @@ private void Run(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Directory.CreateDirectory(Path.GetDirectoryName(savePath) ?? throw new IOException("下载路径无效")); - LegacyFileFacade.CopyFile(unc, savePath); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(unc), LauncherFileSystem.ResolvePath(savePath)).GetAwaiter().GetResult(); State = LoadState.Finished; } catch (OperationCanceledException) diff --git a/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs b/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs index bdf3a75e9..06069675c 100644 --- a/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs +++ b/Plain Craft Launcher 2/Modules/Network/Models/DownloadFile.cs @@ -48,7 +48,7 @@ public DownloadFile( { Urls = urls.Where(url => !string.IsNullOrWhiteSpace(url)).Distinct().ToList(); LocalPath = localPath; - LocalName = LegacyFileFacade.GetFileNameFromPath(localPath); + LocalName = PathUtils.GetFileNameFromUrlOrPath(localPath); Check = checker; UseBrowserUserAgent = useBrowserUserAgent; CustomUserAgent = customUserAgent; diff --git a/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs b/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs index c258b9a52..b07405c8c 100644 --- a/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs +++ b/Plain Craft Launcher 2/Modules/Updates/UpdateManager.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using System.Diagnostics; using System.IO; using PCL.Core.App; @@ -82,7 +82,7 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64 ); - LegacyFileFacade.WriteFile($"{LauncherPaths.TempWithSlash}CEUpdateLog.md", version.Changelog); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath($"{LauncherPaths.TempWithSlash}CEUpdateLog.md"), version.Changelog).GetAwaiter().GetResult(); LauncherLog.Log($"[Update] 远程最新版本: {version.VersionName}, 当前版本: {LauncherEnvironment.VersionBaseName}"); if (!(SemVer.Parse(version.VersionName) > SemVer.Parse(LauncherEnvironment.VersionBaseName))) return; @@ -109,7 +109,7 @@ public static void UpdateStart(UpdateEnums.UpdateType type, string receivedKey = SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64, dlTargetPath)); loaders.Add(new ModLoader.LoaderTask(Lang.Text("Update.Task.Check"), _ => { - var curHash = LegacyFileFacade.GetFileSha256(dlTargetPath); + var curHash = Files.GetFileSHA256Async(dlTargetPath).GetAwaiter().GetResult(); if ((curHash ?? "") != (version.Sha256 ?? "")) throw new Exception(Lang.Text("Update.Error.Sha256Mismatch", version.Sha256, curHash)); })); @@ -211,15 +211,15 @@ internal static void DownloadLatestPCL(ModLoader.LoaderBase loaderToSyncProgress SystemInfo.IsArm64System ? UpdateArch.arm64 : UpdateArch.x64); if (target is null) throw new Exception(Lang.Text("Update.Error.UnableToGetUpdate")); - if (File.Exists(latestPCLPath) && (LegacyFileFacade.GetFileSha256(latestPCLPath) ?? "") == (target.Sha256 ?? "")) + if (File.Exists(latestPCLPath) && (Files.GetFileSHA256Async(latestPCLPath).GetAwaiter().GetResult() ?? "") == (target.Sha256 ?? "")) { LauncherLog.Log("[System] 最新版 PCL 已存在,跳过下载"); return; } - if ((LegacyFileFacade.GetFileSha256(Basics.ExecutablePath) ?? "") == (target.Sha256 ?? "")) // 正在使用的版本符合要求,直接拿来用 + if ((Files.GetFileSHA256Async(Basics.ExecutablePath).GetAwaiter().GetResult() ?? "") == (target.Sha256 ?? "")) // 正在使用的版本符合要求,直接拿来用 { - LegacyFileFacade.CopyFile(Basics.ExecutablePath, latestPCLPath); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Basics.ExecutablePath), LauncherFileSystem.ResolvePath(latestPCLPath)).GetAwaiter().GetResult(); return; } diff --git a/Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs b/Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs index a94bf554e..6504a9b29 100644 --- a/Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs +++ b/Plain Craft Launcher 2/Modules/Updates/UpdatesMinioModel.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.IO.Compression; using System.Net.Http; using System.Text.Json.Serialization; @@ -82,7 +82,7 @@ public VersionAnnouncementDataModel GetAnnouncementList() ?.FirstOrDefault(); if (deJsonData is null) throw new Exception("No assets can download!"); - var selfSha256 = LegacyFileFacade.GetFileSha256(Basics.ExecutablePath); + var selfSha256 = Files.GetFileSHA256Async(Basics.ExecutablePath).GetAwaiter().GetResult(); var remoteUpdSha256 = deJsonData.Sha256; var patchFileName = $"{selfSha256}_{remoteUpdSha256}.patch"; if (deJsonData.Patches.Contains(patchFileName)) @@ -107,9 +107,9 @@ public VersionAnnouncementDataModel GetAnnouncementList() { var diff = new BsDiff(); var newFile = diff - .ApplyAsync(LegacyFileFacade.ReadBytes(Basics.ExecutablePath), LegacyFileFacade.ReadBytes(tempPath)) + .ApplyAsync(Files.ReadAllBytesOrEmptyAsync(LauncherFileSystem.ResolvePath(Basics.ExecutablePath)).GetAwaiter().GetResult(), Files.ReadAllBytesOrEmptyAsync(LauncherFileSystem.ResolvePath(tempPath)).GetAwaiter().GetResult()) .GetAwaiter().GetResult(); - LegacyFileFacade.WriteFile(output, newFile); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(output), newFile).GetAwaiter().GetResult(); } else { @@ -162,7 +162,7 @@ private JsonNode GetRemoteInfoByName(string name, string path = "") JsonNode jsonData; if (IsCacheValid($"{name}.json", _remoteCache[name])) { - jsonData = PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(localInfoFile)); + jsonData = PCL.Core.Utils.JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(localInfoFile)).GetAwaiter().GetResult()); } else { @@ -173,7 +173,7 @@ private JsonNode GetRemoteInfoByName(string name, string path = "") var content = response.AsString(); jsonData = PCL.Core.Utils.JsonCompat.ParseNode(content); - LegacyFileFacade.WriteFile(localInfoFile, content); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(localInfoFile), content).GetAwaiter().GetResult(); } return jsonData; @@ -190,7 +190,7 @@ private bool IsCacheValid(string path, string hash) var cacheFile = Path.Combine(LauncherPaths.TempWithSlash, "Cache", "Update", path); var fileInfo = new FileInfo(cacheFile); return fileInfo.Exists && (DateTime.Now - fileInfo.LastWriteTime).TotalHours < 1 && - (LegacyFileFacade.GetFileMd5(cacheFile) ?? "") == (hash ?? ""); + (Files.GetFileMD5Async(cacheFile).GetAwaiter().GetResult() ?? "") == (hash ?? ""); } private string GetChannelName(UpdateChannel channel, UpdateArch arch) diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.cs index 02c882f5a..32b57a283 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Collections.ObjectModel; using System.Diagnostics.Eventing.Reader; using System.IO; @@ -228,7 +228,7 @@ public void InstallWorld_Click(MyListItem sender, EventArgs e) loaders.Add(new LoaderDownload(Lang.Text("Download.Comp.Detail.DownloadWorldFile"), new List { file.ToNetFile(target) }) { ProgressWeight = 10d, block = true }); loaders.Add(new ModLoader.LoaderTask(Lang.Text("Download.Comp.Detail.InstallWorld"), - _ => LegacyFileFacade.ExtractFile(target, targetPath, Encoding.UTF8)) { ProgressWeight = 0.1d, block = true }); + _ => Files.ExtractFileAsync(target, targetPath).GetAwaiter().GetResult()) { ProgressWeight = 0.1d, block = true }); loaders.Add(new ModLoader.LoaderTask(Lang.Text("Download.Comp.Detail.CleanCache"), _ => System.IO.File.Delete(target))); @@ -389,7 +389,7 @@ public void Save_Click(object sender, EventArgs e) if (!target.Contains("\\")) return; // 记录缓存路径 - var targetDir = LegacyFileFacade.GetPathFromFullPath(target); + var targetDir = PathUtils.GetDirectoryPart(target); if (target != defaultFolder) { if (cachedFolder.ContainsKey(file.Type)) @@ -463,7 +463,7 @@ void DownloadDependencies() foreach (var (depFilename, downloadFile) in depDownloads) { var depLoaderName = Lang.Text("Download.Comp.Detail.DownloadResource", desc, - LegacyFileFacade.GetFileNameWithoutExtensionFromPath(depFilename)); + PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(depFilename)); var depLoaders = new List { new LoaderDownload(Lang.Text("Download.Comp.Detail.DownloadFile"), @@ -532,7 +532,7 @@ void DownloadDependencies() // 构造下载任务 var loaderName = Lang.Text("Download.Comp.Detail.DownloadResource", desc, - LegacyFileFacade.GetFileNameWithoutExtensionFromPath(target)); + PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(target)); var loaders = new List { new LoaderDownload(Lang.Text("Download.Comp.Detail.DownloadFile"), diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs index 3a9705dfa..eb01a9b59 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.cs @@ -230,17 +230,17 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa Lang.Text("Minecraft.Download.Stage.AnalyzeVanillaLibraries.Side"), task => { var jsonPath = Path.Combine(instanceFolder, instanceName + ".json"); - LegacyFileFacade.WaitForFileReady(jsonPath); + LauncherFileSystem.WaitForFileReady(jsonPath); LauncherLog.Log("[Download] 开始分析原版支持库文件:" + instanceFolder); if (id == "1.16.5" && Config.Download.FixAuthLib) // 1.16.5 Authlib 修复 try { - var json = LegacyFileFacade.ReadText(jsonPath); + var json = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(jsonPath)).GetAwaiter().GetResult(); json = json.Replace("2.1.28/authlib-2.1.28.jar", "2.3.31/authlib-2.3.31.jar") .Replace("com.mojang:authlib:2.1.28", "com.mojang:authlib:2.3.31") .Replace("ad54da276bf59983d02d5ed16fc14541354c71fd", "bbd00ca33b052f73a6312254780fc580d2da3535") .Replace("76328", "87662"); - LegacyFileFacade.WriteFile(jsonPath, json); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(jsonPath), json).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -264,7 +264,7 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa loadersAssets.Add(new ModLoader.LoaderTask>( Lang.Text("Minecraft.Download.Stage.AnalyzeAssetsIndex.Side"), task => { - LegacyFileFacade.WaitForFileReady(Path.Combine(instanceFolder, instanceName + ".json")); + LauncherFileSystem.WaitForFileReady(Path.Combine(instanceFolder, instanceName + ".json")); try { var assetIndex = new McInstance(instanceFolder); @@ -278,9 +278,9 @@ public static void McDownloadClientCore(string id, string jsonUrl, NetPreDownloa // 顺手添加 Json 项目 try { - var versionJson = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(Path.Combine(instanceFolder, instanceName + ".json"))); + var versionJson = (JsonObject)JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(Path.Combine(instanceFolder, instanceName + ".json"))).GetAwaiter().GetResult()); versionJson.Add("clientVersion", id); - LegacyFileFacade.WriteFile(Path.Combine(instanceFolder, instanceName + ".json"), versionJson.ToString()); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(instanceFolder, instanceName + ".json")), versionJson.ToString()).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -495,8 +495,7 @@ @echo off echo {Lang.Text("Minecraft.Download.ServerBatch.ServerStopped")} pause """; - LegacyFileFacade.WriteFile(Path.Combine(versionFolder, "Launch Server.bat"), bat.Replace("\n", "\r\n"), - encoding: Encoding.Default.Equals(Encoding.UTF8) ? Encoding.UTF8 : Encoding.GetEncoding("GB18030")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(versionFolder, "Launch Server.bat")), bat.Replace("\n", "\r\n"), encoding: Encoding.Default.Equals(Encoding.UTF8) ? Encoding.UTF8 : Encoding.GetEncoding("GB18030")).GetAwaiter().GetResult(); // 删除实例 JSON File.Delete(Path.Combine(versionFolder, id + ".json")); }) @@ -764,7 +763,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta CreateNoWindow = true, RedirectStandardError = true, RedirectStandardOutput = true, - WorkingDirectory = LegacyFileFacade.ShortenPath(baseMcFolderHome) + WorkingDirectory = PathUtils.ShortenPath(baseMcFolderHome) }; if (info.EnvironmentVariables.ContainsKey("appdata")) info.EnvironmentVariables["appdata"] = baseMcFolderHome; @@ -970,14 +969,12 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta return; lock (vanillaSyncLock) { - var clientName = LegacyFileFacade.GetFolderNameFromPath(clientFolder); + var clientName = PathUtils.GetDirectoryNameLeaf(clientFolder); Directory.CreateDirectory(Path.Combine(mcFolder, "versions", downloadInfo.Inherit)); if (!File.Exists(Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".json"))) - LegacyFileFacade.CopyFile($"{clientFolder}{clientName}.json", - $@"{mcFolder}versions\{downloadInfo.Inherit}\{downloadInfo.Inherit}.json"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath($"{clientFolder}{clientName}.json"), LauncherFileSystem.ResolvePath($@"{mcFolder}versions\{downloadInfo.Inherit}\{downloadInfo.Inherit}.json")).GetAwaiter().GetResult(); if (!File.Exists(Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar"))) - LegacyFileFacade.CopyFile($"{clientFolder}{clientName}.jar", - $@"{mcFolder}versions\{downloadInfo.Inherit}\{downloadInfo.Inherit}.jar"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath($"{clientFolder}{clientName}.jar"), LauncherFileSystem.ResolvePath($@"{mcFolder}versions\{downloadInfo.Inherit}\{downloadInfo.Inherit}.jar")).GetAwaiter().GetResult(); } }) { @@ -998,15 +995,11 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta { // 准备安装环境 if (Directory.Exists(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit))) - LegacyFileFacade.DeleteDirectory(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit)); + Directories.DeleteDirectoryAsync(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit)).GetAwaiter().GetResult(); Directory.CreateDirectory(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit)); ModFolder.McFolderLauncherProfilesJsonCreate(baseMcFolder); - LegacyFileFacade.CopyFile( - Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".json"), - Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".json")); - LegacyFileFacade.CopyFile( - Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar"), - Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar")); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".json")), LauncherFileSystem.ResolvePath(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".json"))).GetAwaiter().GetResult(); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar")), LauncherFileSystem.ResolvePath(Path.Combine(baseMcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar"))).GetAwaiter().GetResult(); task.Progress = 0.06d; // 进行安装 var useJavaWrapper = EncodingUtils.IsDefaultEncodingUtf8(); @@ -1031,11 +1024,11 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta task.Progress = 0.96d; // 复制文件 File.Delete(Path.Combine(baseMcFolder, "launcher_profiles.json")); - LegacyFileFacade.CopyDirectory(baseMcFolder, mcFolder); + Directories.CopyDirectoryAsync(baseMcFolder, mcFolder).GetAwaiter().GetResult(); task.Progress = 0.98d; // 清理文件 File.Delete(target); - LegacyFileFacade.DeleteDirectory(baseMcFolderHome); + Directories.DeleteDirectoryAsync(baseMcFolderHome).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -1060,9 +1053,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta Directory.CreateDirectory(versionFolder); task.Progress = 0.1d; if (File.Exists(Path.Combine(versionFolder, id + ".jar"))) File.Delete(Path.Combine(versionFolder, id + ".jar")); - LegacyFileFacade.CopyFile( - Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar"), - Path.Combine(versionFolder, id + ".jar")); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(mcFolder, "versions", downloadInfo.Inherit, downloadInfo.Inherit + ".jar")), LauncherFileSystem.ResolvePath(Path.Combine(versionFolder, id + ".jar"))).GetAwaiter().GetResult(); task.Progress = 0.7d; var inheritInstance = new McInstance(Path.Combine(mcFolder, "versions", downloadInfo.Inherit)); @@ -1103,7 +1094,7 @@ private static void McDownloadOptiFineInstall(string baseMcFolderHome, string ta ] } }"; - LegacyFileFacade.WriteFile(Path.Combine(versionFolder, id + ".json"), json); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(versionFolder, id + ".json")), json).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -1489,7 +1480,7 @@ private static void McDownloadLiteLoaderSave(ModDownload.DlLiteLoaderListEntry d versionJson.Add("minimumLauncherVersion", 18); versionJson.Add("inheritsFrom", downloadInfo.Inherit); versionJson.Add("jar", downloadInfo.Inherit); - LegacyFileFacade.WriteFile(Path.Combine(versionFolder, versionName + ".json"), versionJson.ToString()); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(versionFolder, versionName + ".json")), versionJson.ToString()).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -2076,12 +2067,12 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask { - LegacyFileFacade.WaitForFileReady(installerAddress); + LauncherFileSystem.WaitForFileReady(installerAddress); var installer = new ZipArchive(new FileStream(installerAddress, FileMode.Open)); try { @@ -2232,7 +2221,7 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask {versionFolder}{targetVersion}.json"); } @@ -2333,11 +2320,11 @@ private static void ForgelikeInjectorLine(string content, ModLoader.LoaderTask>( Lang.Text("Minecraft.Download.Stage.AnalyzeVanillaAndLabyModLibrariesSide"), task => { - LegacyFileFacade.WaitForFileReady(Path.Combine(versionFolder, versionName + ".json")); + LauncherFileSystem.WaitForFileReady(Path.Combine(versionFolder, versionName + ".json")); LauncherLog.Log("[Download] 开始分析原版与 LabyMod 支持库文件:" + versionFolder); task.output = ModLibrary.McLibNetFilesFromInstance(new McInstance(versionFolder)); }) @@ -3574,9 +3560,9 @@ public static void McDownloadLabyModSnapshotLoaderSave() // 顺手添加 Json 项目 try { - var versionJson = (JsonObject)JsonCompat.ParseNode(LegacyFileFacade.ReadText(Path.Combine(versionFolder, versionName + ".json"))); + var versionJson = (JsonObject)JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(Path.Combine(versionFolder, versionName + ".json"))).GetAwaiter().GetResult()); versionJson.Add("clientVersion", id); - LegacyFileFacade.WriteFile(Path.Combine(versionFolder, versionName + ".json"), versionJson.ToString()); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(versionFolder, versionName + ".json")), versionJson.ToString()).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -3834,13 +3820,13 @@ public static void McInstallState(object loaderObj) if (Config.Download.AutoSelectInstance) { var versionName = loader.name; - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", versionName.Remove(versionName.Length - 3, 3)); } - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 清空缓存(合并安装会先生成文件夹,这会在刷新时误判为可以使用缓存) - LegacyFileFacade.DeleteDirectory($"{combo.input}PCLInstallBackups\\"); + Directories.DeleteDirectoryAsync($"{combo.input}PCLInstallBackups\\").GetAwaiter().GetResult(); HintService.Hint($"{loader.name}{Lang.Text("Common.Status.Success")}", HintType.Success); break; @@ -3867,12 +3853,9 @@ public static void McInstallState(object loaderObj) Directory.Exists( $"{combo.input}PCLInstallBackups\\")) // 实例修改失败回滚 { - LegacyFileFacade.CopyDirectory( - $"{combo.input}PCLInstallBackups\\", - (string)combo.input); + Directories.CopyDirectoryAsync($"{combo.input}PCLInstallBackups\\", (string)combo.input).GetAwaiter().GetResult(); File.Delete($"{combo.input}.pclignore"); - LegacyFileFacade.DeleteDirectory( - $"{combo.input}PCLInstallBackups\\"); + Directories.DeleteDirectoryAsync($"{combo.input}PCLInstallBackups\\").GetAwaiter().GetResult(); } else { @@ -3895,7 +3878,7 @@ public static void McInstallFailedClearFolder(object loader) LauncherLog.Log($"[Download] 由于下载失败或取消,清理实例文件夹:{((ModLoader.LoaderCombo)loader).input}", LauncherLogLevel.Developer); var instancePath = (string)((ModLoader.LoaderCombo)loader).input; ((DynamicCacheConfigStorage)ConfigService.GetProvider(ConfigSource.GameInstance)).InvalidateCache(instancePath); - LegacyFileFacade.DeleteDirectory(instancePath); + Directories.DeleteDirectoryAsync(instancePath).GetAwaiter().GetResult(); } } catch (Exception ex) @@ -3948,7 +3931,7 @@ public static bool McInstall(McInstallRequest request, string type = mcInstallDe { ((DynamicCacheConfigStorage)ConfigService.GetProvider(ConfigSource.GameInstance)) .InvalidateCache(request.targetInstanceFolder); - LegacyFileFacade.DeleteDirectory(request.targetInstanceFolder); + Directories.DeleteDirectoryAsync(request.targetInstanceFolder).GetAwaiter().GetResult(); } } } @@ -3975,7 +3958,7 @@ request.forgeEntry is not null || // 获取参数 var instanceFolder = Path.Combine(ModFolder.mcFolderSelected, "versions", request.targetInstanceName); if (Directory.Exists(tempMcFolder)) - LegacyFileFacade.DeleteDirectory(tempMcFolder); + Directories.DeleteDirectoryAsync(tempMcFolder).GetAwaiter().GetResult(); string optiFineFolder = null; if (request.optiFineVersion is not null) { @@ -4076,7 +4059,7 @@ request.forgeEntry is not null || request.neoForgeEntry is not null || var loaderList = new List(); // 添加忽略标识 loaderList.Add(new ModLoader.LoaderTask(Lang.Text("Minecraft.Download.Stage.AddIgnoreFlag"), - _ => LegacyFileFacade.WriteFile(Path.Combine(instanceFolder, ".pclignore"), "用于临时地在 PCL 的实例列表中屏蔽此实例。")) + _ => Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(instanceFolder, ".pclignore")), "用于临时地在 PCL 的实例列表中屏蔽此实例。").GetAwaiter().GetResult()) { show = false, block = false }); // Fabric API if (request.fabricApi is not null) @@ -4242,13 +4225,13 @@ request.neoForgeEntry is null task.Progress = 0.2d; // 迁移文件 if (Directory.Exists(Path.Combine(tempMcFolder, "libraries"))) - LegacyFileFacade.CopyDirectory(Path.Combine(tempMcFolder, "libraries"), Path.Combine(ModFolder.mcFolderSelected, "libraries")); + Directories.CopyDirectoryAsync(Path.Combine(tempMcFolder, "libraries"), Path.Combine(ModFolder.mcFolderSelected, "libraries")).GetAwaiter().GetResult(); task.Progress = 0.8d; // 创建 Mod 和资源包文件夹 var modsFolder = Path.Combine(new McInstance(instanceFolder).PathIndie, "mods"); // 版本隔离信息在此时被决定 if (Directory.Exists(modsTempFolder)) { - LegacyFileFacade.CopyDirectory(modsTempFolder, modsFolder); + Directories.CopyDirectoryAsync(modsTempFolder, modsFolder).GetAwaiter().GetResult(); } else if (modable) { @@ -4374,13 +4357,13 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (!outputFolder.EndsWithF(@"\")) outputFolder += @"\"; - outputName = LegacyFileFacade.GetFolderNameFromPath(outputFolder); + outputName = PathUtils.GetDirectoryNameLeaf(outputFolder); outputJsonPath = Path.Combine(outputFolder, outputName + ".json"); outputJar = Path.Combine(outputFolder, outputName + ".jar"); if (!minecraftFolder.EndsWithF(@"\")) minecraftFolder += @"\"; - minecraftName = LegacyFileFacade.GetFolderNameFromPath(minecraftFolder); + minecraftName = PathUtils.GetDirectoryNameLeaf(minecraftFolder); minecraftJsonPath = Path.Combine(minecraftFolder, minecraftName + ".json"); minecraftJar = Path.Combine(minecraftFolder, minecraftName + ".jar"); @@ -4388,7 +4371,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!optiFineFolder.EndsWithF(@"\")) optiFineFolder += @"\"; - optiFineName = LegacyFileFacade.GetFolderNameFromPath(optiFineFolder); + optiFineName = PathUtils.GetDirectoryNameLeaf(optiFineFolder); optiFineJsonPath = Path.Combine(optiFineFolder, optiFineName + ".json"); } @@ -4396,7 +4379,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!forgeFolder.EndsWithF(@"\")) forgeFolder += @"\"; - forgeName = LegacyFileFacade.GetFolderNameFromPath(forgeFolder); + forgeName = PathUtils.GetDirectoryNameLeaf(forgeFolder); forgeJsonPath = Path.Combine(forgeFolder, forgeName + ".json"); } @@ -4404,7 +4387,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!neoForgeFolder.EndsWithF(@"\")) neoForgeFolder += @"\"; - neoForgeName = LegacyFileFacade.GetFolderNameFromPath(neoForgeFolder); + neoForgeName = PathUtils.GetDirectoryNameLeaf(neoForgeFolder); neoForgeJsonPath = Path.Combine(neoForgeFolder, neoForgeName + ".json"); } @@ -4412,7 +4395,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!cleanroomFolder.EndsWithF(@"\")) cleanroomFolder += @"\"; - cleanroomName = LegacyFileFacade.GetFolderNameFromPath(cleanroomFolder); + cleanroomName = PathUtils.GetDirectoryNameLeaf(cleanroomFolder); cleanroomJsonPath = Path.Combine(cleanroomFolder, cleanroomName + ".json"); } @@ -4420,7 +4403,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!liteLoaderFolder.EndsWithF(@"\")) liteLoaderFolder += @"\"; - liteLoaderName = LegacyFileFacade.GetFolderNameFromPath(liteLoaderFolder); + liteLoaderName = PathUtils.GetDirectoryNameLeaf(liteLoaderFolder); liteLoaderJsonPath = Path.Combine(liteLoaderFolder, liteLoaderName + ".json"); } @@ -4428,7 +4411,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!fabricFolder.EndsWithF(@"\")) fabricFolder += @"\"; - fabricName = LegacyFileFacade.GetFolderNameFromPath(fabricFolder); + fabricName = PathUtils.GetDirectoryNameLeaf(fabricFolder); fabricJsonPath = Path.Combine(fabricFolder, fabricName + ".json"); } @@ -4436,7 +4419,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!legacyFabricFolder.EndsWithF(@"\")) legacyFabricFolder += @"\"; - legacyFabricName = LegacyFileFacade.GetFolderNameFromPath(legacyFabricFolder); + legacyFabricName = PathUtils.GetDirectoryNameLeaf(legacyFabricFolder); legacyFabricJsonPath = Path.Combine(legacyFabricFolder, legacyFabricName + ".json"); } @@ -4444,7 +4427,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!quiltFolder.EndsWithF(@"\")) quiltFolder += @"\"; - quiltName = LegacyFileFacade.GetFolderNameFromPath(quiltFolder); + quiltName = PathUtils.GetDirectoryNameLeaf(quiltFolder); quiltJsonPath = Path.Combine(quiltFolder, quiltName + ".json"); } @@ -4452,7 +4435,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin { if (!labyModFolder.EndsWithF(@"\")) labyModFolder += @"\"; - labyModName = LegacyFileFacade.GetFolderNameFromPath(labyModFolder); + labyModName = PathUtils.GetDirectoryNameLeaf(labyModFolder); labyModJsonPath = Path.Combine(labyModFolder, labyModName + ".json"); } @@ -4472,7 +4455,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin #region 读取文件并检查文件是否合规 - var minecraftJsonText = LegacyFileFacade.ReadText(minecraftJsonPath); + var minecraftJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(minecraftJsonPath)).GetAwaiter().GetResult(); if (!hasLabyMod) { if (!minecraftJsonText.StartsWithF("{")) @@ -4483,7 +4466,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasOptiFine) { - var optiFineJsonText = LegacyFileFacade.ReadText(optiFineJsonPath); + var optiFineJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(optiFineJsonPath)).GetAwaiter().GetResult(); if (!optiFineJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "OptiFine", optiFineJsonPath, optiFineJsonText.Substring(0, Math.Min(optiFineJsonText.Length, 1000)))); @@ -4492,7 +4475,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasForge) { - var forgeJsonText = LegacyFileFacade.ReadText(forgeJsonPath); + var forgeJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(forgeJsonPath)).GetAwaiter().GetResult(); if (!forgeJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Forge", forgeJsonPath, forgeJsonText.Substring(0, Math.Min(forgeJsonText.Length, 1000)))); @@ -4501,7 +4484,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasNeoForge) { - var neoForgeJsonText = LegacyFileFacade.ReadText(neoForgeJsonPath); + var neoForgeJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(neoForgeJsonPath)).GetAwaiter().GetResult(); if (!neoForgeJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "NeoForge", neoForgeJsonPath, neoForgeJsonText.Substring(0, Math.Min(neoForgeJsonText.Length, 1000)))); @@ -4510,7 +4493,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasCleanroom) { - var cleanroomJsonText = LegacyFileFacade.ReadText(cleanroomJsonPath); + var cleanroomJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(cleanroomJsonPath)).GetAwaiter().GetResult(); if (!cleanroomJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Cleanroom", cleanroomJsonPath, cleanroomJsonText.Substring(0, Math.Min(cleanroomJsonText.Length, 1000)))); @@ -4519,7 +4502,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasLiteLoader) { - var liteLoaderJsonText = LegacyFileFacade.ReadText(liteLoaderJsonPath); + var liteLoaderJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(liteLoaderJsonPath)).GetAwaiter().GetResult(); if (!liteLoaderJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "LiteLoader", liteLoaderJsonPath, liteLoaderJsonText.Substring(0, Math.Min(liteLoaderJsonText.Length, 1000)))); @@ -4528,7 +4511,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasFabric) { - var fabricJsonText = LegacyFileFacade.ReadText(fabricJsonPath); + var fabricJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(fabricJsonPath)).GetAwaiter().GetResult(); if (!fabricJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Fabric", fabricJsonPath, fabricJsonText.Substring(0, Math.Min(fabricJsonText.Length, 1000)))); @@ -4537,7 +4520,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasLegacyFabric) { - var legacyFabricJsonText = LegacyFileFacade.ReadText(legacyFabricJsonPath); + var legacyFabricJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(legacyFabricJsonPath)).GetAwaiter().GetResult(); if (!legacyFabricJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Legacy Fabric", fabricJsonPath, legacyFabricJsonText.Substring(0, Math.Min(legacyFabricJsonText.Length, 1000)))); @@ -4546,7 +4529,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasQuilt) { - var quiltJsonText = LegacyFileFacade.ReadText(quiltJsonPath); + var quiltJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(quiltJsonPath)).GetAwaiter().GetResult(); if (!quiltJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "Quilt", quiltJsonPath, quiltJsonText.Substring(0, Math.Min(quiltJsonText.Length, 1000)))); @@ -4555,7 +4538,7 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin if (hasLabyMod) { - var labyModJsonText = LegacyFileFacade.ReadText(labyModJsonPath); + var labyModJsonText = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(labyModJsonPath)).GetAwaiter().GetResult(); if (!labyModJsonText.StartsWithF("{")) throw new Exception(Lang.Text("Minecraft.Download.Error.JsonInvalid", "LabyMod", labyModJsonPath, labyModJsonText.Substring(0, Math.Min(labyModJsonText.Length, 1000)))); @@ -4773,12 +4756,12 @@ private static void MergeJson(string outputFolder, string minecraftFolder, strin #region 保存 - LegacyFileFacade.WriteFile(outputJsonPath, outputJson.ToString()); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(outputJsonPath), outputJson.ToString()).GetAwaiter().GetResult(); if ((minecraftJar ?? "") != (outputJar ?? "")) // 可能是同一个文件 { if (File.Exists(outputJar)) File.Delete(outputJar); - LegacyFileFacade.CopyFile(minecraftJar, outputJar); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(minecraftJar), LauncherFileSystem.ResolvePath(outputJar)).GetAwaiter().GetResult(); } LauncherLog.Log("[Download] 实例合并 " + outputName + " 完成"); diff --git a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs index a95d9f343..5170f4d59 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.cs @@ -65,20 +65,20 @@ public void Refresh() { case ModLocalComp.LocalCompFile.LocalFileStatus.Fine: { - descFileName = LegacyFileFacade.GetFileNameWithoutExtensionFromPath(Entry.path); + descFileName = PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(Entry.path); break; } case ModLocalComp.LocalCompFile.LocalFileStatus.Disabled: { descFileName = - LegacyFileFacade.GetFileNameWithoutExtensionFromPath(Entry.path.Replace(".disabled", "") + PathUtils.GetFileNameWithoutExtensionFromUrlOrPath(Entry.path.Replace(".disabled", "") .Replace(".old", "")); // McMod.McModState.Unavailable break; } default: { - descFileName = LegacyFileFacade.GetFileNameFromPath(Entry.path); + descFileName = PathUtils.GetFileNameFromUrlOrPath(Entry.path); break; } } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs index 0421f4b69..12de739ba 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceCompResource.xaml.cs @@ -1086,19 +1086,19 @@ private static void ExecuteModInstallation(McInstance targetMcInstance, IEnumera { foreach (var modFile in filePathList) { - var fileName = LegacyFileFacade.GetFileNameFromPath(modFile) + var fileName = PathUtils.GetFileNameFromUrlOrPath(modFile) .Replace(".disabled", "") .Replace(".old", ""); if (!fileName.Contains(".")) fileName += ".jar"; // Ensure extension (#4227) - LegacyFileFacade.CopyFile(modFile, Path.Combine(modFolder, fileName)); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(modFile), LauncherFileSystem.ResolvePath(Path.Combine(modFolder, fileName))).GetAwaiter().GetResult(); } // Success hint if (filePathList.Count() == 1) { - var installedName = LegacyFileFacade.GetFileNameFromPath(filePathList.First()).Replace(".disabled", "") + var installedName = PathUtils.GetFileNameFromUrlOrPath(filePathList.First()).Replace(".disabled", "") .Replace(".old", ""); HintWrapper.Show(Lang.Text("Instance.Resource.Install.SuccessSingle", installedName), HintTheme.Success); } @@ -1256,7 +1256,7 @@ public static void InstallCompFiles(IEnumerable filePathList, ModComp.Co Directory.CreateDirectory(compFolder); foreach (var FilePath in filePathList) { - var newFileName = LegacyFileFacade.GetFileNameFromPath(FilePath); + var newFileName = PathUtils.GetFileNameFromUrlOrPath(FilePath); if (compType == ModComp.CompType.Mod) { newFileName = newFileName.Replace(".disabled", "").Replace(".old", ""); @@ -1269,11 +1269,11 @@ public static void InstallCompFiles(IEnumerable filePathList, ModComp.Co if (ModMain.MyMsgBox(Lang.Text("Instance.Resource.Install.OverwriteConfirm.Message", newFileName), Lang.Text("Instance.Resource.Install.OverwriteConfirm.Title"), Lang.Text("Common.Action.Overwrite"), Lang.Text("Common.Action.Cancel")) != 1) continue; - LegacyFileFacade.CopyFile(FilePath, destFile); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(FilePath), LauncherFileSystem.ResolvePath(destFile)).GetAwaiter().GetResult(); } if (filePathList.Count() == 1) - HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessSingle", LegacyFileFacade.GetFileNameFromPath(filePathList.First())), HintType.Success); + HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessSingle", PathUtils.GetFileNameFromUrlOrPath(filePathList.First())), HintType.Success); else HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessMultiple", filePathList.Count(), compTypeName), HintType.Success); @@ -1900,7 +1900,7 @@ private void EDMods(IEnumerable modList, bool isEnab if (File.Exists(modEntity.path)) { // 同时存在两个名称的 Mod - if ((LegacyFileFacade.GetFileMd5(modEntity.path) ?? "") != (LegacyFileFacade.GetFileMd5(newPath) ?? "")) + if ((Files.GetFileMD5Async(modEntity.path).GetAwaiter().GetResult() ?? "") != (Files.GetFileMD5Async(newPath).GetAwaiter().GetResult() ?? "")) { ModMain.MyMsgBox( Lang.Text("Instance.Resource.Ed.FileConflict.Message", newPath, modEntity.path), @@ -2067,7 +2067,7 @@ public void UpdateResource(IEnumerable modList) // 添加到下载列表 var tempAddress = LauncherPaths.TempWithSlash + @"DownloadedComp\" + Entry.FileName.Replace(currentReplaceName, newestReplaceName); - var realAddress = LegacyFileFacade.GetPathFromFullPath(Entry.path) + + var realAddress = PathUtils.GetDirectoryPart(Entry.path) + Entry.FileName.Replace(currentReplaceName, newestReplaceName); fileList.Add(file.ToNetFile(tempAddress)); fileCopyList[tempAddress] = realAddress; @@ -2099,10 +2099,10 @@ public void UpdateResource(IEnumerable modList) LauncherLog.Log($"[Mod] 更新后的资源文件已存在,将会把它放入回收站:{Entry.Value}", LauncherLogLevel.Debug); } - if (Directory.Exists(LegacyFileFacade.GetPathFromFullPath(Entry.Value))) + if (Directory.Exists(PathUtils.GetDirectoryPart(Entry.Value))) { File.Move(Entry.Key, Entry.Value); - finishedFileNames.Add(LegacyFileFacade.GetFileNameFromPath(Entry.Value)); + finishedFileNames.Add(PathUtils.GetFileNameFromUrlOrPath(Entry.Value)); } else { diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs index 13dfb8a37..5dedad439 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.cs @@ -542,7 +542,7 @@ private void ExportConfig(object sender, MouseButtonEventArgs e) configLines.Add(sperator); configLines.AddRange(GetExtraFileLines()); // 结束 - LegacyFileFacade.WriteFile(configPath, configLines.Join("\r\n")); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(configPath), configLines.Join("\r\n")).GetAwaiter().GetResult(); HintService.Hint(Lang.Text("Instance.Export.SaveSuccess", configPath), HintType.Success); LauncherProcess.OpenExplorer(configPath); } @@ -569,7 +569,7 @@ private void ReadConfigFile(string configPath) // 保存配置文件路径到缓存 States.System.ExportConfigPath = configPath; - var fileContent = LegacyFileFacade.ReadText(configPath); + var fileContent = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(configPath)).GetAwaiter().GetResult(); var segments = fileContent.Split(sperator); if (segments.Length == 0) @@ -735,7 +735,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) !configPackPath.EndsWithF("/")) try { - Directory.CreateDirectory(LegacyFileFacade.GetPathFromFullPath(configPackPath)); + Directory.CreateDirectory(PathUtils.GetDirectoryPart(configPackPath)); packPath = configPackPath; LauncherLog.Log($"[Export] 使用配置文件中指定的导出路径:{configPackPath}"); } @@ -789,8 +789,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) loader => { UpdateManager.DownloadLatestPCL(loader); - LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.TempWithSlash, "CE-Latest.exe"), - Path.Combine(cacheFolder, "Plain Craft Launcher.exe")); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(LauncherPaths.TempWithSlash, "CE-Latest.exe")), LauncherFileSystem.ResolvePath(Path.Combine(cacheFolder, "Plain Craft Launcher.exe"))).GetAwaiter().GetResult(); }) { ProgressWeight = 0.5d, @@ -840,7 +839,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) if (!shouldKeep) continue; var targetPath = Path.Combine(overridesFolder, relativePath); - LegacyFileFacade.CopyFile(Entry.FullName, targetPath); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Entry.FullName), LauncherFileSystem.ResolvePath(targetPath)).GetAwaiter().GetResult(); // 若为压缩包,考虑联网获取路径 if (checkHostedAssets && new[] { ".zip", ".rar", ".jar", ".disabled", ".old" }.Contains(Entry.Extension.ToLower()) && @@ -870,13 +869,13 @@ private void StartExport(object sender, MouseButtonEventArgs e) if (Line.EndsWithF(@"\") || Line.EndsWithF("/")) { if (Directory.Exists(Line)) - LegacyFileFacade.CopyDirectory(Line, Path.Combine(baseFolder, LegacyFileFacade.GetFolderNameFromPath(Line)) + @"\"); + Directories.CopyDirectoryAsync(Line, Path.Combine(baseFolder, PathUtils.GetDirectoryNameLeaf(Line)) + @"\").GetAwaiter().GetResult(); else HintService.Hint(Lang.Text("Instance.Export.Config.FolderNotFound", Line), HintType.Error); } else if (File.Exists(Line)) { - LegacyFileFacade.CopyFile(Line, Path.Combine(baseFolder, LegacyFileFacade.GetFileNameFromPath(Line))); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Line), LauncherFileSystem.ResolvePath(Path.Combine(baseFolder, PathUtils.GetFileNameFromUrlOrPath(Line)))).GetAwaiter().GetResult(); } else { @@ -885,26 +884,26 @@ private void StartExport(object sender, MouseButtonEventArgs e) loader.Progress = 0.97d; // 复制 PCL 实例设置 - LegacyFileFacade.CopyDirectory(Path.Combine(mcInstance.PathInstance, "PCL"), Path.Combine(overridesFolder, "PCL")); + Directories.CopyDirectoryAsync(Path.Combine(mcInstance.PathInstance, "PCL"), Path.Combine(overridesFolder, "PCL")).GetAwaiter().GetResult(); #if RELEASE // 复制 PCL 本体 - if (includePCL) LegacyFileFacade.CopyFile(Basics.ExecutablePath, Path.Combine(cacheFolder, Basics.ExecutableName)); + if (includePCL) Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Basics.ExecutablePath), LauncherFileSystem.ResolvePath(Path.Combine(cacheFolder, Basics.ExecutableName))).GetAwaiter().GetResult(); #endif // 复制 PCL 个性化内容 if (includePCLCustom) { if (Directory.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Pictures"))) - LegacyFileFacade.CopyDirectory(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Pictures"), Path.Combine(cacheFolder, "PCL", "Pictures")); + Directories.CopyDirectoryAsync(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Pictures"), Path.Combine(cacheFolder, "PCL", "Pictures")).GetAwaiter().GetResult(); if (Directory.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Musics"))) - LegacyFileFacade.CopyDirectory(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Musics"), Path.Combine(cacheFolder, "PCL", "Musics")); + Directories.CopyDirectoryAsync(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Musics"), Path.Combine(cacheFolder, "PCL", "Musics")).GetAwaiter().GetResult(); if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Custom.xaml"))) - LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Custom.xaml"), Path.Combine(cacheFolder, "PCL", "Custom.xaml")); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Custom.xaml")), LauncherFileSystem.ResolvePath(Path.Combine(cacheFolder, "PCL", "Custom.xaml"))).GetAwaiter().GetResult(); if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Setup.ini"))) - LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Setup.ini"), Path.Combine(cacheFolder, "PCL", "Setup.ini")); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Setup.ini")), LauncherFileSystem.ResolvePath(Path.Combine(cacheFolder, "PCL", "Setup.ini"))).GetAwaiter().GetResult(); if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "hints.txt"))) - LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "hints.txt"), Path.Combine(cacheFolder, "PCL", "hints.txt")); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "hints.txt")), LauncherFileSystem.ResolvePath(Path.Combine(cacheFolder, "PCL", "hints.txt"))).GetAwaiter().GetResult(); if (File.Exists(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Logo.png"))) - LegacyFileFacade.CopyFile(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Logo.png"), Path.Combine(cacheFolder, "PCL", "Logo.png")); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Logo.png")), LauncherFileSystem.ResolvePath(Path.Combine(cacheFolder, "PCL", "Logo.png"))).GetAwaiter().GetResult(); } }) { @@ -1063,7 +1062,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) "hashes", new JsonObject { - { "sha1", modFile.ModrinthHash }, { "sha512", LegacyFileFacade.GetFileSha512(modFile.path) } + { "sha1", modFile.ModrinthHash }, { "sha512", Files.GetFileSHA512Async(modFile.path).GetAwaiter().GetResult() } } }, { "downloads", new JsonArray(Pair.Value.OrderByDescending(u => u.Contains("modrinth.com")).Select(s => (JsonNode)s).ToArray()) }, @@ -1089,7 +1088,7 @@ private void StartExport(object sender, MouseButtonEventArgs e) File.WriteAllText(Path.Combine(cacheFolder, "modpack", "modrinth.index.json"), resultJson.ToJsonString(new JsonSerializerOptions(JsonCompat.SerializerOptions) { WriteIndented = true })); // 打包 - Directory.CreateDirectory(LegacyFileFacade.GetPathFromFullPath(packPath)); + Directory.CreateDirectory(PathUtils.GetDirectoryPart(packPath)); if (File.Exists(packPath)) File.Delete(packPath); if (includePCL) diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs index 4eed53f45..c304a5963 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceInstall.xaml.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.IO; using System.Windows; using System.Windows.Controls; @@ -126,12 +126,10 @@ private void BtnSelectStart_Click(object sender, MouseButtonEventArgs mouseButto PageInstanceLeft.McInstance.Info.HasLabyMod) Directory.Delete(System.IO.Path.Combine(PageInstanceLeft.McInstance.PathIndie, "labymod-neo"), true); // 备份实例核心文件 - LegacyFileFacade.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json", - PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + ".json"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json"), LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + ".json")).GetAwaiter().GetResult(); if (File.Exists(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar")) - LegacyFileFacade.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar", - PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + - ".jar"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar"), LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + + ".jar")).GetAwaiter().GetResult(); // 确认独立 API (如 Fabric API 等) 是否需要被修改 if (selectedFabricApi?.Equals(_currentFabricApi) == true) selectedFabricApi = null; diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.cs index e02e0d25b..7a96a949f 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.cs @@ -1,4 +1,4 @@ -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.IO; using System.Windows; using System.Windows.Controls; @@ -241,7 +241,7 @@ private void ComboDisplayType_SelectionChanged(object sender, SelectionChangedEv PageInstanceLeft.McInstance.displayType = (McInstanceCardType)States.Instance.CardType[PageInstanceLeft.McInstance.PathInstance]; ModMain.frmInstanceLeft.RefreshModDisabled(); - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); } @@ -275,7 +275,7 @@ private void ComboDisplayType_SelectionChanged(object sender, SelectionChangedEv States.Instance.CardType[PageInstanceLeft.McInstance.PathInstance] = (int)McInstanceCardType.Hidden; - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); } @@ -337,8 +337,8 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) JsonObject jsonObject; try { - jsonObject = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(LegacyFileFacade.ReadText(PageInstanceLeft.McInstance.PathInstance + - PageInstanceLeft.McInstance.Name + ".json")); + jsonObject = (JsonObject)PCL.Core.Utils.JsonCompat.ParseNode(Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + + PageInstanceLeft.McInstance.Name + ".json")).GetAwaiter().GetResult()); } catch (Exception ex) { @@ -350,7 +350,7 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) FileSystem.RenameDirectory(oldPath, tempName); FileSystem.RenameDirectory(tempPath, newName); // 清理 ini 缓存 - LegacyIniStore.Shared.ClearCache(Path.Combine(PageInstanceLeft.McInstance.PathIndie, "options.txt")); + LauncherIniStore.Shared.ClearCache(Path.Combine(PageInstanceLeft.McInstance.PathIndie, "options.txt")); // 重命名 Jar 文件与 natives 文件夹 // 不能进行遍历重命名,否则在实例名很短的时候容易误伤其他文件(Meloong-Git/#6443) if (Directory.Exists(Path.Combine(newPath, $"{oldName}-natives"))) @@ -362,7 +362,7 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) } else { - LegacyFileFacade.DeleteDirectory(Path.Combine(newPath, $"{newName}-natives")); + Directories.DeleteDirectoryAsync(Path.Combine(newPath, $"{newName}-natives")).GetAwaiter().GetResult(); FileSystem.RenameDirectory(Path.Combine(newPath, $"{oldName}-natives"), $"{newName}-natives"); } } @@ -383,16 +383,15 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) // 替换实例设置文件中的路径 if (File.Exists(Path.Combine(newPath, "PCL", "Setup.ini"))) - LegacyFileFacade.WriteFile(Path.Combine(newPath, "PCL", "Setup.ini"), - LegacyFileFacade.ReadText(Path.Combine(newPath, "PCL", "Setup.ini")).Replace(oldPath, newPath)); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(newPath, "PCL", "Setup.ini")), Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(Path.Combine(newPath, "PCL", "Setup.ini"))).GetAwaiter().GetResult().Replace(oldPath, newPath)).GetAwaiter().GetResult(); // 更改已选中的实例 - if ((LegacyIniStore.Shared.Read(ModFolder.mcFolderSelected + "PCL.ini", "Version") ?? "") == (oldName ?? "")) - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", newName); + if ((LauncherIniStore.Shared.Read(ModFolder.mcFolderSelected + "PCL.ini", "Version") ?? "") == (oldName ?? "")) + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", newName); // 写入实例 Json,并删除旧的 Json try { jsonObject["id"] = newName; - LegacyFileFacade.WriteFile(Path.Combine(newPath, $"{newName}.json"), jsonObject.ToString()); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(Path.Combine(newPath, $"{newName}.json")), jsonObject.ToString()).GetAwaiter().GetResult(); if (!isCaseChangedOnly) File.Delete(Path.Combine(newPath, $"{oldName}.json")); } @@ -406,7 +405,7 @@ private void BtnDisplayRename_Click(object sender, MouseButtonEventArgs e) PageInstanceLeft.McInstance = new McInstance(newName).Load(); if (ModInstanceList.McMcInstanceSelected is not null && ModInstanceList.McMcInstanceSelected.Equals(PageInstanceLeft.McInstance)) - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", newName); + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "Version", newName); Reload(); ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); @@ -438,7 +437,7 @@ private void ComboDisplayLogo_SelectionChanged(object sender, SelectionChangedEv return; } - LegacyFileFacade.CopyFile(fileName, PageInstanceLeft.McInstance.PathInstance + @"PCL\Logo.png"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(fileName), LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + @"PCL\Logo.png")).GetAwaiter().GetResult(); } else { @@ -461,7 +460,7 @@ private void ComboDisplayLogo_SelectionChanged(object sender, SelectionChangedEv States.Instance.LogoPath[PageInstanceLeft.McInstance.PathInstance] = newLogo; States.Instance.IsLogoCustom[PageInstanceLeft.McInstance.PathInstance] = !string.IsNullOrEmpty(newLogo); // 刷新显示 - LegacyIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 + LauncherIniStore.Shared.Write(ModFolder.mcFolderSelected + "PCL.ini", "InstanceCache", ""); // 要求刷新缓存 PageInstanceLeft.McInstance = new McInstance(PageInstanceLeft.McInstance.Name).Load(); Reload(); ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, @@ -656,12 +655,10 @@ private void BtnManageRestore_Click(object sender, MouseButtonEventArgs e) return; // 备份实例核心文件 - LegacyFileFacade.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json", - PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + - ".json"); - LegacyFileFacade.CopyFile(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar", - PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + - ".jar"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".json"), LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + + ".json")).GetAwaiter().GetResult(); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + PageInstanceLeft.McInstance.Name + ".jar"), LauncherFileSystem.ResolvePath(PageInstanceLeft.McInstance.PathInstance + @"PCLInstallBackups\" + PageInstanceLeft.McInstance.Name + + ".jar")).GetAwaiter().GetResult(); // 提交安装申请 var request = new ModDownloadLib.McInstallRequest { @@ -760,12 +757,12 @@ private void BtnManageDelete_Click(object sender, MouseButtonEventArgs e) { var instancePath = PageInstanceLeft.McInstance.PathInstance; var instanceName = PageInstanceLeft.McInstance.Name; - LegacyIniStore.Shared.ClearCache(Path.Combine(PageInstanceLeft.McInstance.PathIndie, "options.txt")); + LauncherIniStore.Shared.ClearCache(Path.Combine(PageInstanceLeft.McInstance.PathIndie, "options.txt")); ((DynamicCacheConfigStorage)ConfigService.GetProvider(ConfigSource.GameInstance)).InvalidateCache( instancePath); if (isShiftPressed) { - LegacyFileFacade.DeleteDirectory(instancePath); + Directories.DeleteDirectoryAsync(instancePath).GetAwaiter().GetResult(); HintService.Hint(Lang.Text("Instance.Overall.Delete.PermanentSuccess", instanceName), HintType.Success); } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs index 8f2eebdd9..3d115e788 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves.xaml.cs @@ -192,7 +192,7 @@ private void RefreshUI() { var target = $@"{PageInstanceLeft.McInstance.PathInstance}PCL\ImgCache\{BinaryEncoding.ToHexLower(MD5Provider.Instance.ComputeHash(saveLogo).AsSpan())}.png"; - LegacyFileFacade.CopyFile(saveLogo, target); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(saveLogo), LauncherFileSystem.ResolvePath(target)).GetAwaiter().GetResult(); saveLogo = target; } else @@ -404,7 +404,7 @@ private void BtnPaste_Click(object sender, MouseButtonEventArgs e) } else { - LegacyFileFacade.CopyDirectory(i, worldPath + GetFolderNameFromPath(i)); + Directories.CopyDirectoryAsync(i, worldPath + GetFolderNameFromPath(i)).GetAwaiter().GetResult(); copied += 1; } } diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs index 58ae7d408..5f2b2dbca 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSaves/PageInstanceSavesDatapack.xaml.cs @@ -627,18 +627,18 @@ public static void InstallDatapackFiles(IEnumerable filePathList) foreach (var FilePath in filePathList) { - var newFileName = LegacyFileFacade.GetFileNameFromPath(FilePath); + var newFileName = PathUtils.GetFileNameFromUrlOrPath(FilePath); var destFile = datapackFolder + newFileName; if (File.Exists(destFile)) if (ModMain.MyMsgBox(Lang.Text("Instance.Resource.Install.OverwriteConfirm.Message", newFileName), Lang.Text("Instance.Resource.Install.OverwriteConfirm.Title"), Lang.Text("Common.Action.Overwrite"), Lang.Text("Common.Action.Cancel")) != 1) continue; - LegacyFileFacade.CopyFile(FilePath, destFile); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(FilePath), LauncherFileSystem.ResolvePath(destFile)).GetAwaiter().GetResult(); } if (filePathList.Count() == 1) - HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessSingle", LegacyFileFacade.GetFileNameFromPath(filePathList.First())), HintType.Success); + HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessSingle", PathUtils.GetFileNameFromUrlOrPath(filePathList.First())), HintType.Success); else HintService.Hint(Lang.Text("Instance.Resource.Install.SuccessMultiple", filePathList.Count(), Lang.Text("Download.Comp.Type.DataPack")), HintType.Success); @@ -707,7 +707,7 @@ void ExportText(string content, string fileName) foreach (var DatapackEntity in ModLocalComp.compResourceListLoader.output) exportContent.Add(DatapackEntity.FileName); ExportText(exportContent.Join("\r\n"), - LegacyFileFacade.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave) + "的数据包信息.txt"); + PathUtils.GetDirectoryNameLeaf(PageInstanceSavesLeft.currentSave) + "的数据包信息.txt"); break; } @@ -719,7 +719,7 @@ void ExportText(string content, string fileName) exportContent.Add( $"{DatapackEntity.FileName},{DatapackEntity.Comp?.TranslatedName},{DatapackEntity.Version},{DatapackEntity.compFile?.ReleaseDate},{DatapackEntity.Comp?.Id},{GetDatapackFileInfo(DatapackEntity.path).Length},{DatapackEntity.path}"); ExportText(exportContent.Join("\r\n"), - LegacyFileFacade.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave) + "的数据包信息.csv"); + PathUtils.GetDirectoryNameLeaf(PageInstanceSavesLeft.currentSave) + "的数据包信息.csv"); break; } } @@ -1092,7 +1092,7 @@ private void ToggleDatapacks(IEnumerable datapackLis { if (File.Exists(newPath)) { - ModMain.MyMsgBox(Lang.Text("Instance.Saves.Datapack.Replace.FileNameConflict", LegacyFileFacade.GetFileNameFromPath(newPath))); + ModMain.MyMsgBox(Lang.Text("Instance.Saves.Datapack.Replace.FileNameConflict", PathUtils.GetFileNameFromUrlOrPath(newPath))); continue; } @@ -1292,10 +1292,10 @@ public void UpdateResource(IEnumerable datapackList) LauncherLog.Log($"[Datapack] 更新后的数据包文件已存在,将会把它放入回收站:{Entry.Value}", LauncherLogLevel.Debug); } - if (Directory.Exists(LegacyFileFacade.GetPathFromFullPath(Entry.Value))) + if (Directory.Exists(PathUtils.GetDirectoryPart(Entry.Value))) { File.Move(Entry.Key, Entry.Value); - finishedFileNames.Add(LegacyFileFacade.GetFileNameFromPath(Entry.Value)); + finishedFileNames.Add(PathUtils.GetFileNameFromUrlOrPath(Entry.Value)); } else { @@ -1312,7 +1312,7 @@ public void UpdateResource(IEnumerable datapackList) // 结束处理 var loader = new ModLoader.LoaderCombo>( Lang.Text("Instance.Saves.Datapack.Update.Task.Title", - LegacyFileFacade.GetFolderNameFromPath(PageInstanceSavesLeft.currentSave)), installLoaders); + PathUtils.GetDirectoryNameLeaf(PageInstanceSavesLeft.currentSave)), installLoaders); var pathDatapacks = Path.Combine(PageInstanceSavesLeft.currentSave, "datapacks"); loader.OnStateChanged = _ => diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs index 76c49d9c6..05050d1a3 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.cs @@ -111,7 +111,7 @@ public static void Save(ModLoader.LoaderTask, string> lo try { var fileAddress = SystemDialogs.SelectSaveFile(Lang.Text("Launch.Skin.SaveDialog.Title"), - LegacyFileFacade.GetFileNameFromPath(address), + PathUtils.GetFileNameFromUrlOrPath(address), Lang.Text("Launch.Skin.SaveDialog.Filter")); if (!fileAddress.Contains(@"\")) return; File.Delete(fileAddress); @@ -122,7 +122,7 @@ public static void Save(ModLoader.LoaderTask, string> lo } else { - LegacyFileFacade.CopyFile(address, fileAddress); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(address), LauncherFileSystem.ResolvePath(fileAddress)).GetAwaiter().GetResult(); } HintService.Hint(Lang.Text("Launch.Skin.SaveSuccess"), HintType.Success); @@ -297,12 +297,12 @@ public static void RefreshCache(ModLoader.LoaderTask, st HintService.Hint(Lang.Text("Launch.Skin.Refreshing")); LauncherLog.Log("[Skin] 正在清空皮肤缓存"); if (Directory.Exists(LauncherPaths.TempWithSlash + @"Cache\Skin")) - LegacyFileFacade.DeleteDirectory(LauncherPaths.TempWithSlash + @"Cache\Skin"); + Directories.DeleteDirectoryAsync(LauncherPaths.TempWithSlash + @"Cache\Skin").GetAwaiter().GetResult(); if (Directory.Exists(LauncherPaths.TempWithSlash + @"Cache\Uuid")) - LegacyFileFacade.DeleteDirectory(LauncherPaths.TempWithSlash + @"Cache\Uuid"); - LegacyIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexMs.ini"); - LegacyIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexAuth.ini"); - LegacyIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini"); + Directories.DeleteDirectoryAsync(LauncherPaths.TempWithSlash + @"Cache\Uuid").GetAwaiter().GetResult(); + LauncherIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexMs.ini"); + LauncherIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexAuth.ini"); + LauncherIniStore.Shared.ClearCache(LauncherPaths.TempWithSlash + @"Cache\Uuid\Mojang.ini"); foreach (var SkinLoader in sender is not null ? new[] { sender } : new[] { PageLaunchLeft.skinLegacy, PageLaunchLeft.skinMs }) @@ -333,7 +333,7 @@ public static void ReloadCache(string skinAddress) { try { - LegacyIniStore.Shared.Write(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexMs.ini", ModProfile.selectedProfile.Uuid, + LauncherIniStore.Shared.Write(LauncherPaths.TempWithSlash + @"Cache\Skin\IndexMs.ini", ModProfile.selectedProfile.Uuid, skinAddress); LauncherLog.Log($"[Skin] 已写入皮肤地址缓存 {ModProfile.selectedProfile.Uuid} -> {skinAddress}"); foreach (var SkinLoader in new[] { PageLaunchLeft.skinMs, PageLaunchLeft.skinLegacy }) diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs index dbf41d4e7..4e92d0d1c 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs @@ -102,7 +102,7 @@ public void PageLaunchLeft_Loaded(object sender, RoutedEventArgs e) } PageSelectLeft.AddFolder(LauncherPaths.ExecutableDirectoryWithSlash + @".minecraft\", - LegacyFileFacade.GetFolderNameFromPath(LauncherPaths.ExecutableDirectoryWithSlash), false); + PathUtils.GetDirectoryNameLeaf(LauncherPaths.ExecutableDirectoryWithSlash), false); ModFolder.mcFolderListLoader.WaitForExit(); } diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs index a2a0df753..b375d3bd8 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Globalization; using System.Reflection; using System.Windows; @@ -101,7 +101,7 @@ private void RefreshReal() { // 本地文件 LogWrapper.Info("[Page] 主页自定义数据来源:本地文件"); - content = LegacyFileFacade.ReadText(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Custom.xaml")); + content = Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(Path.Combine(LauncherPaths.ExecutableDirectoryWithSlash, "PCL", "Custom.xaml"))).GetAwaiter().GetResult(); } else if (uiCustomType == 2) { @@ -240,7 +240,7 @@ private string LoadFromNetwork(string url) LogWrapper.Info("[Page] 主页自定义数据来源:联网缓存文件"); // 后台更新缓存 onlineLoader.Start(url); - return LegacyFileFacade.ReadText(cachePath); + return Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(cachePath)).GetAwaiter().GetResult(); } LogWrapper.Info("[Page] 主页自定义数据来源:联网全新下载"); @@ -374,7 +374,7 @@ private void OnlineLoaderSub(ModLoader.LoaderTask task) LauncherLog.Log($"[Page] 已联网下载主页,内容长度:{fileContent.Length},来源:{address}"); States.UI.SavedHomepageUrl = address; States.UI.SavedHomepageVersion = version; - LegacyFileFacade.WriteFile(LauncherPaths.TempWithSlash + @"Cache\Custom.xaml", fileContent); + Files.WriteFileAsync(LauncherFileSystem.ResolvePath(LauncherPaths.TempWithSlash + @"Cache\Custom.xaml"), fileContent).GetAwaiter().GetResult(); } // 要求刷新 diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.cs index bbdf50a44..ce1fa2d31 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; @@ -415,16 +415,16 @@ public static void AddFolder(string folderPath, string displayName, bool showHin try { if (!folderPath.EndsWith(@"\")) folderPath += @"\"; - if (!LegacyFileFacade.CheckPermission(folderPath)) + if (!Directories.CheckPermissionAsync(folderPath).GetAwaiter().GetResult()) { if (!showHint) throw new Exception("PCL 没有访问文件夹的权限:" + folderPath); HintService.Hint(Lang.Text("Select.Folder.AccessDenied"), HintType.Error); return; } - if (!LegacyFileFacade.CheckPermission(folderPath + @"versions\")) + if (!Directories.CheckPermissionAsync(folderPath + @"versions\").GetAwaiter().GetResult()) foreach (var Folder in new DirectoryInfo(folderPath).GetDirectories()) - if (LegacyFileFacade.CheckPermission(Path.Combine(Folder.FullName, "versions"))) + if (Directories.CheckPermissionAsync(Path.Combine(Folder.FullName, "versions")).GetAwaiter().GetResult()) { folderPath = Folder.FullName + @"\"; break; @@ -626,7 +626,7 @@ folder.type is ModFolder.McFolder.Types.Original or ModFolder.McFolder.Types.Ren try { HintService.Hint(inProgress); - LegacyFileFacade.DeleteDirectory(folder.Location); + Directories.DeleteDirectoryAsync(folder.Location).GetAwaiter().GetResult(); if (isClearing) Directory.CreateDirectory(folder.Location); HintService.Hint(success, HintType.Success); @@ -666,7 +666,7 @@ public void RefreshCurrent() public static void RefreshCurrent(string folder) { - LegacyIniStore.Shared.Write(Path.Combine(folder, "PCL.ini"), "InstanceCache", ""); + LauncherIniStore.Shared.Write(Path.Combine(folder, "PCL.ini"), "InstanceCache", ""); if (folder == ModFolder.mcFolderSelected) ModLoader.LoaderFolderRun(ModInstanceList.mcInstanceListLoader, ModFolder.mcFolderSelected, ModLoader.LoaderFolderRunType.ForceRun, 1, @"versions\"); diff --git a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.cs b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.cs index 818a6b0d2..c240cdfac 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.IO; using System.Windows; using System.Windows.Controls; @@ -543,12 +543,12 @@ public static void DeleteVersion(MyListItem item, McInstance mcInstance) { case 1: { - LegacyIniStore.Shared.ClearCache(Path.Combine(mcInstance.PathIndie, "options.txt")); + LauncherIniStore.Shared.ClearCache(Path.Combine(mcInstance.PathIndie, "options.txt")); ((DynamicCacheConfigStorage)ConfigService.GetProvider(ConfigSource.GameInstance)).InvalidateCache( mcInstance.PathInstance); if (isShiftPressed) { - LegacyFileFacade.DeleteDirectory(mcInstance.PathInstance); + Directories.DeleteDirectoryAsync(mcInstance.PathInstance).GetAwaiter().GetResult(); HintService.Hint(Lang.Text("Select.Instance.Delete.PermanentSuccess", mcInstance.Name), HintType.Success); } diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs index 1bf706d7f..f549698fb 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -289,7 +289,7 @@ private void BtnBackgroundClear_Click(object sender, MouseButtonEventArgs e) Lang.Text("Common.Dialog.Warning"), button2: Lang.Text("Common.Action.Cancel"), isWarn: true) == 1) { - LegacyFileFacade.DeleteDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures"); + Directories.DeleteDirectoryAsync(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures").GetAwaiter().GetResult(); BackgroundRefresh(false, true); HintService.Hint(Lang.Text("Setup.Ui.Background.Clear.Success"), HintType.Success); } @@ -306,7 +306,7 @@ public static void BackgroundRefresh(bool isHint, bool refresh) { // 获取可用的图片文件 Directory.CreateDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures\"); - var pic = LegacyFileFacade.EnumerateFiles(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures\").Where(file => + var pic = Directories.EnumerateFilesOrEmptyAsync(PathUtils.ShortenPath(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Pictures\")).GetAwaiter().GetResult().Where(file => !(file.Extension.Equals(".ini", StringComparison.OrdinalIgnoreCase) || file.Extension.Equals(".db", StringComparison.OrdinalIgnoreCase))).Select(file => file.FullName) .ToList(); @@ -380,7 +380,7 @@ 你可以尝试使用视频转码工具打开视频文件并设定目标格式 _ = Config.Preference.Background.WallpaperSuitMode; ModMain.frmMain.ImgBack.Visibility = Visibility.Visible; if (isHint) - HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", LegacyFileFacade.GetFileNameFromPath(address)), HintType.Success, + HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", PathUtils.GetFileNameFromUrlOrPath(address)), HintType.Success, false); } catch (Exception ex) @@ -395,7 +395,7 @@ 你可以尝试使用视频转码工具打开视频文件并设定目标格式 ModMain.frmMain.VideoBack.Source = new Uri(address, UriKind.Absolute); ModVideoBack.VideoPlay(); if (isHint) - HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", LegacyFileFacade.GetFileNameFromPath(address)), HintType.Success, + HintService.Hint(Lang.Text("Setup.Ui.Background.Refresh.Success", PathUtils.GetFileNameFromUrlOrPath(address)), HintType.Success, false); } catch (Exception playEx) @@ -432,7 +432,7 @@ private void BtnLogoChange_Click(object sender, MouseButtonEventArgs e) { // 拷贝文件 File.Delete(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); - LegacyFileFacade.CopyFile(fileName, LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(fileName), LauncherFileSystem.ResolvePath(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png")).GetAwaiter().GetResult(); // 设置当前显示 ModMain.frmMain.ImageTitleLogo.Source = null; // 防止因为 Source 属性前后的值相同而不更新 (#5628) ModMain.frmMain.ImageTitleLogo.Source = LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"; @@ -519,7 +519,7 @@ private void RadioLogoType3_Check(object sender, RouteEventArgs e) { // 拷贝文件 File.Delete(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); - LegacyFileFacade.CopyFile(fileName, LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png"); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(fileName), LauncherFileSystem.ResolvePath(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Logo.png")).GetAwaiter().GetResult(); goto Refresh; } catch (Exception ex) @@ -571,7 +571,7 @@ public void MusicRefreshUI() PanMusicVolume.Visibility = Visibility.Visible; PanMusicDetail.Visibility = Visibility.Visible; BtnMusicClear.Visibility = Visibility.Visible; - CardMusic.Title = Lang.Text("Setup.Ui.Music.TitleWithCount", LegacyFileFacade.EnumerateFiles(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics\").Count()); + CardMusic.Title = Lang.Text("Setup.Ui.Music.TitleWithCount", Directories.EnumerateFilesOrEmptyAsync(PathUtils.ShortenPath(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics\")).GetAwaiter().GetResult().Count()); } else { @@ -600,7 +600,7 @@ private void BtnMusicClear_Click(object sender, MouseButtonEventArgs e) // 删除文件 try { - LegacyFileFacade.DeleteDirectory(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics"); + Directories.DeleteDirectoryAsync(LauncherPaths.ExecutableDirectoryWithSlash + @"PCL\Musics").GetAwaiter().GetResult(); // DisableSMTCSupport() HintService.Hint(Lang.Text("Setup.Ui.Music.Delete.Success"), HintType.Success); } diff --git a/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs b/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs index f74cece99..359196ae9 100644 --- a/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageTools/PageToolsTest.xaml.cs @@ -134,7 +134,7 @@ public static void StartCustomDownload(string url, string fileName, string folde try { Directory.CreateDirectory(folder); - LegacyFileFacade.CheckPermissionWithException(folder); + Directories.CheckPermissionWithExceptionAsync(folder).GetAwaiter().GetResult(); } catch (Exception ex) { @@ -247,10 +247,8 @@ public static void RubbishClear() foreach (var dirInfo in cleanMcFolderList) { - num += LegacyFileFacade.DeleteDirectory( - dirInfo.FullName + (dirInfo.FullName.EndsWith(@"\") ? "" : @"\") + @"crash-reports\", true); - num += LegacyFileFacade.DeleteDirectory( - dirInfo.FullName + (dirInfo.FullName.EndsWith(@"\") ? "" : @"\") + @"logs\", true); + num += Directories.DeleteDirectoryAsync(dirInfo.FullName + (dirInfo.FullName.EndsWith(@"\") ? "" : @"\") + @"crash-reports\", true).GetAwaiter().GetResult(); + num += Directories.DeleteDirectoryAsync(dirInfo.FullName + (dirInfo.FullName.EndsWith(@"\") ? "" : @"\") + @"logs\", true).GetAwaiter().GetResult(); foreach (var fileInfo in dirInfo.EnumerateFiles("*")) if (fileInfo.Name.StartsWith("hs_err_pid") || fileInfo.Name.EndsWith(".log") || fileInfo.Name == "WailaErrorOutput.txt") @@ -262,11 +260,11 @@ public static void RubbishClear() foreach (var dirInfo2 in dirInfo.EnumerateDirectories()) if ((dirInfo2.Name ?? "") == (dirInfo2.Name + "-natives" ?? "") || dirInfo2.Name == "natives-windows-x86_64") - num += LegacyFileFacade.DeleteDirectory(dirInfo2.FullName, true); + num += Directories.DeleteDirectoryAsync(dirInfo2.FullName, true).GetAwaiter().GetResult(); } - num += LegacyFileFacade.DeleteDirectory(LauncherPaths.TempWithSlash, true); - num += LegacyFileFacade.DeleteDirectory(Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL"), true); + num += Directories.DeleteDirectoryAsync(LauncherPaths.TempWithSlash, true).GetAwaiter().GetResult(); + num += Directories.DeleteDirectoryAsync(Path.Combine(SystemPaths.DriveLetter, "ProgramData", "PCL"), true).GetAwaiter().GetResult(); if (num != 0) { ModMain.MyMsgBox(Lang.Text("Tools.Test.Clean.ClearedMessage", num), @@ -323,7 +321,7 @@ private void TextDownloadUrl_TextChanged(object sender, TextChangedEventArgs e) try { if (!string.IsNullOrEmpty(TextDownloadName.Text) || string.IsNullOrEmpty(TextDownloadUrl.Text)) return; - TextDownloadName.Text = LegacyFileFacade.GetFileNameFromPath(WebUtility.UrlDecode(TextDownloadUrl.Text)); + TextDownloadName.Text = PathUtils.GetFileNameFromUrlOrPath(WebUtility.UrlDecode(TextDownloadUrl.Text)); } catch { @@ -403,7 +401,7 @@ private void BtnSkinSave_Click(object sender, MouseButtonEventArgs e) UiThread.Post(() => { var path = SystemDialogs.SelectSaveFile(Lang.Text("Tools.Test.Skin.Save"), $"{id}.png", Lang.Text("Tools.Test.Skin.FileFilter")); - LegacyFileFacade.CopyFile(result, path); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(result), LauncherFileSystem.ResolvePath(path)).GetAwaiter().GetResult(); HintService.Hint(Lang.Text("Tools.Test.Skin.Saved", id), HintType.Success); }); } @@ -570,7 +568,7 @@ private async Task DownloadImageToLocalAsync(string imageUrl) return; } - LegacyFileFacade.CopyFile(savePath, path); + Files.CopyFileAsync(LauncherFileSystem.ResolvePath(savePath), LauncherFileSystem.ResolvePath(path)).GetAwaiter().GetResult(); File.Delete(savePath); HintService.Hint(Lang.Text("Tools.Test.Achievement.Saved"), HintType.Success); } From 2a5d402ebc93bf410c09f199dc210c797eec5dec Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Thu, 2 Jul 2026 23:11:33 +0800 Subject: [PATCH 11/16] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E3=80=81=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PCL.Core.Test/IO/DirectoriesTest.cs | 42 +++++ PCL.Core.Test/Utils/NumberUtilsTest.cs | 15 +- PCL.Core.Test/Utils/TextUtilsTest.cs | 7 + PCL.Core/IO/Directories.cs | 151 ++++++++---------- PCL.Core/Utils/NumberUtils.cs | 80 +++++++--- PCL.Core/Utils/TextUtils.cs | 13 +- .../Infrastructure/CustomXamlLoader.cs | 0 .../Infrastructure/LauncherEnvironment.cs | 0 .../Infrastructure/LauncherExitCode.cs | 0 .../Infrastructure/LauncherFeedbackService.cs | 0 .../Infrastructure/LauncherFileSystem.cs | 0 .../Infrastructure/LauncherFontService.cs | 0 .../Infrastructure/LauncherIniStore.cs | 0 .../Infrastructure/LauncherLog.cs | 0 .../Infrastructure/LauncherLogLevel.cs | 0 .../Infrastructure/LauncherPaths.cs | 17 +- .../Infrastructure/LauncherProcess.cs | 4 +- .../Infrastructure/LauncherRuntime.cs | 0 .../Infrastructure/LauncherStringHash.cs | 0 .../{ => Modules}/Infrastructure/UiThread.cs | 0 .../Pages/PageSpeedLeft.xaml.cs | 8 +- 21 files changed, 221 insertions(+), 116 deletions(-) create mode 100644 PCL.Core.Test/IO/DirectoriesTest.cs rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/CustomXamlLoader.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherEnvironment.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherExitCode.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherFeedbackService.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherFileSystem.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherFontService.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherIniStore.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherLog.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherLogLevel.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherPaths.cs (83%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherProcess.cs (98%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherRuntime.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/LauncherStringHash.cs (100%) rename Plain Craft Launcher 2/{ => Modules}/Infrastructure/UiThread.cs (100%) diff --git a/PCL.Core.Test/IO/DirectoriesTest.cs b/PCL.Core.Test/IO/DirectoriesTest.cs new file mode 100644 index 000000000..12d0bfecf --- /dev/null +++ b/PCL.Core.Test/IO/DirectoriesTest.cs @@ -0,0 +1,42 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.IO; + +namespace PCL.Core.Test.IO; + +[TestClass] +public class DirectoriesTest +{ + private string _tempDir = null!; + + [TestInitialize] + public void SetUp() + { + _tempDir = Path.Combine(Path.GetTempPath(), "PCLCoreDirectoriesTest", Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(_tempDir); + } + + [TestCleanup] + public void TearDown() + { + if (Directory.Exists(_tempDir)) + Directory.Delete(_tempDir, true); + } + + [TestMethod] + public async Task CheckPermissionAsyncUsesRealProbeFile() + { + Assert.IsTrue(await Directories.CheckPermissionAsync(_tempDir)); + Assert.AreEqual(0, Directory.EnumerateFiles(_tempDir, ".pcl-permission-*.tmp").Count()); + } + + [TestMethod] + public async Task CheckPermissionAsyncReturnsFalseForMissingDirectory() + { + var missing = Path.Combine(_tempDir, "missing"); + Assert.IsFalse(await Directories.CheckPermissionAsync(missing)); + } +} \ No newline at end of file diff --git a/PCL.Core.Test/Utils/NumberUtilsTest.cs b/PCL.Core.Test/Utils/NumberUtilsTest.cs index be687930d..3037d8c4d 100644 --- a/PCL.Core.Test/Utils/NumberUtilsTest.cs +++ b/PCL.Core.Test/Utils/NumberUtilsTest.cs @@ -25,11 +25,24 @@ public void LerpRoundsToSixDigits() [TestMethod] [DataRow("12.5", 12.5d)] + [DataRow("123abc", 123d)] + [DataRow("1.20.4", 1.2d)] + [DataRow("1e3xxx", 1000d)] [DataRow("not-a-number", 0d)] [DataRow("&", 0d)] [DataRow(null, 0d)] - public void ParseDoubleOrZeroUsesExplicitParsing(string? value, double expected) + public void ParseDoubleOrZeroKeepsLeadingNumberParsing(string? value, double expected) { Assert.AreEqual(expected, NumberUtils.ParseDoubleOrZero(value)); } + + [TestMethod] + [DataRow(".5", 0.5d)] + [DataRow("-.5abc", -0.5d)] + [DataRow("+42px", 42d)] + [DataRow("1e", 1d)] + public void ParseLeadingDoubleOrZeroHandlesPartialLiterals(string value, double expected) + { + Assert.AreEqual(expected, NumberUtils.ParseLeadingDoubleOrZero(value)); + } } \ No newline at end of file diff --git a/PCL.Core.Test/Utils/TextUtilsTest.cs b/PCL.Core.Test/Utils/TextUtilsTest.cs index edb789ef3..5293e53e4 100644 --- a/PCL.Core.Test/Utils/TextUtilsTest.cs +++ b/PCL.Core.Test/Utils/TextUtilsTest.cs @@ -20,6 +20,13 @@ public void EscapesLikePattern() Assert.AreEqual("a[*][?][#][[]b[]]", TextUtils.EscapeLikePattern("a*?#[b]")); } + [TestMethod] + public void EscapesXamlAttributeTextWithMarkupExtensionPrefix() + { + Assert.AreEqual("{}{Binding Name}", TextUtils.EscapeXamlAttributeText("{Binding Name}")); + Assert.AreEqual("a&b"c", TextUtils.EscapeXamlAttributeText("a&b\"c")); + } + [TestMethod] public void StringSliceExtensionsKeepUnmatchedText() { diff --git a/PCL.Core/IO/Directories.cs b/PCL.Core/IO/Directories.cs index fed390c9f..e1611c954 100644 --- a/PCL.Core/IO/Directories.cs +++ b/PCL.Core/IO/Directories.cs @@ -1,5 +1,3 @@ -using System.Security.AccessControl; - namespace PCL.Core.IO; using System; @@ -10,77 +8,39 @@ namespace PCL.Core.IO; using System.Threading.Tasks; using Logging; -public static class Directories { +public static class Directories +{ /// - /// 异步检查是否拥有对指定文件夹的读写权限。 - /// 如果文件夹不存在或没有权限,返回 false,不修改文件系统。 + /// 异步检查是否拥有对指定文件夹的实际写入权限。 + /// 通过创建并删除临时探测文件确认真实 I/O 能力,避免仅靠 ACL 推断造成误判。 /// /// 要检查的文件夹路径。 /// 取消操作的令牌。 - /// 如果拥有读写权限且文件夹存在,返回 true;否则返回 false。 - public static async Task CheckPermissionAsync(string? path, CancellationToken cancellationToken = default) { - try { - if (string.IsNullOrWhiteSpace(path)) { - return false; - } - - // 排除特殊系统文件夹 - if (IsSystemProtectedFolder(path)) { - return false; - } - - // 检查文件夹是否存在 - if (!Directory.Exists(path)) { - return false; - } - - // 检查目录访问权限 - var directoryInfo = new DirectoryInfo(path); - var security = await Task.Run(() => directoryInfo.GetAccessControl(), cancellationToken); - var rules = security.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)); - - // 检查当前用户是否有读写权限,优先考虑拒绝规则 - var currentUser = System.Security.Principal.WindowsIdentity.GetCurrent(); - var principal = new System.Security.Principal.WindowsPrincipal(currentUser); - - var isDenied = false; - var isAllowed = false; - - foreach (FileSystemAccessRule rule in rules) { - if (!rule.FileSystemRights.HasFlag(FileSystemRights.Write)) - continue; - - // 检查规则是否适用于当前用户或其组 - if (principal.IsInRole(rule.IdentityReference.Value)) { - if (rule.AccessControlType == AccessControlType.Deny) { - isDenied = true; - break; // 拒绝优先,直接返回 - } - if (rule.AccessControlType == AccessControlType.Allow) { - isAllowed = true; - } - } - } - - if (isDenied || !isAllowed) { - return false; - } - - // 尝试枚举目录内容以确认实际访问能力 - await Task.Run(() => Directory.EnumerateFiles(path, "*", SearchOption.TopDirectoryOnly).Any(), cancellationToken); + /// 如果文件夹存在且可实际写入,返回 true;否则返回 false。 + public static async Task CheckPermissionAsync( + string? path, + CancellationToken cancellationToken = default) + { + try + { + await CheckPermissionWithExceptionAsync(path, cancellationToken).ConfigureAwait(false); return true; - } catch (OperationCanceledException) { + } + catch (OperationCanceledException) + { LogWrapper.Warn("权限检查被取消"); return false; - } catch (Exception ex) { + } + catch (Exception ex) + { LogWrapper.Warn(ex, $"没有对文件夹 {path} 的权限,请尝试以管理员权限运行。"); return false; } } /// - /// 异步检查文件夹权限,若无权限或文件夹不存在则抛出异常。 - /// 不修改文件系统。 + /// 异步检查文件夹权限,若无权限或文件夹不存在则抛出异常。 + /// 通过创建并删除临时探测文件确认真实 I/O 能力。 /// /// 要检查的文件夹路径。 /// 取消操作的令牌。 @@ -88,40 +48,59 @@ public static async Task CheckPermissionAsync(string? path, CancellationTo /// 文件夹不存在。 /// 无访问权限。 /// 操作被取消。 - public static async Task CheckPermissionWithExceptionAsync(string? path, CancellationToken cancellationToken = default) { - if (string.IsNullOrWhiteSpace(path)) { + public static async Task CheckPermissionWithExceptionAsync( + string? path, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path), "文件夹路径不能为空!"); - } - if (IsSystemProtectedFolder(path)) { + if (IsSystemProtectedFolder(path)) throw new UnauthorizedAccessException($"无法访问受保护的系统文件夹:{path}"); - } - if (!Directory.Exists(path)) { + if (!Directory.Exists(path)) throw new DirectoryNotFoundException($"文件夹不存在:{path}"); - } - - try { - var directoryInfo = new DirectoryInfo(path); - var security = await Task.Run(() => directoryInfo.GetAccessControl(), cancellationToken); - var rules = security.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)); - - var hasAccess = rules.Cast() - .Any(rule => rule.FileSystemRights.HasFlag(FileSystemRights.Write) && - rule.AccessControlType == AccessControlType.Allow); - - if (!hasAccess) { - throw new UnauthorizedAccessException($"没有对文件夹 {path} 的写权限"); - } - // 确认实际访问能力 - await Task.Run(() => Directory.EnumerateFiles(path, "*", SearchOption.TopDirectoryOnly).Any(), cancellationToken); - } catch (UnauthorizedAccessException) { + var probePath = Path.Combine(path, $".pcl-permission-{Guid.NewGuid():N}.tmp"); + try + { + await File.WriteAllBytesAsync(probePath, [], cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + _TryDeleteProbeFileBestEffort(probePath); throw; - } catch (OperationCanceledException) { + } + catch (UnauthorizedAccessException) + { + _TryDeleteProbeFileBestEffort(probePath); throw; - } catch (Exception ex) { - throw new UnauthorizedAccessException($"无法访问文件夹 {path}:{ex.Message}", ex); + } + catch (Exception ex) + { + _TryDeleteProbeFileBestEffort(probePath); + throw new UnauthorizedAccessException($"无法写入文件夹 {path}:{ex.Message}", ex); + } + + try + { + if (File.Exists(probePath)) File.Delete(probePath); + } + catch (Exception ex) + { + throw new UnauthorizedAccessException($"无法删除文件夹 {path} 中的权限检查临时文件:{ex.Message}", ex); + } + } + + private static void _TryDeleteProbeFileBestEffort(string probePath) + { + try + { + if (File.Exists(probePath)) File.Delete(probePath); + } + catch + { + // 权限检查失败后的兜底清理,不覆盖原始异常。 } } diff --git a/PCL.Core/Utils/NumberUtils.cs b/PCL.Core/Utils/NumberUtils.cs index 863f1a681..b786f52ac 100644 --- a/PCL.Core/Utils/NumberUtils.cs +++ b/PCL.Core/Utils/NumberUtils.cs @@ -41,7 +41,8 @@ public static double Lerp( } /// - /// 使用明确的数值解析规则将对象转换为 double;解析失败时返回 0。 + /// 将对象转换为 double;解析失败时返回 0。 + /// 对字符串保留旧 VB Val 风格的“读取开头数值片段”语义,例如“123abc”解析为 123。 /// public static double ParseDoubleOrZero(object? value) { @@ -68,24 +69,65 @@ public static double ParseDoubleOrZero(object? value) break; } - var text = Convert.ToString(value, CultureInfo.InvariantCulture); - if (string.IsNullOrWhiteSpace(text) || text == "&") return 0d; - - text = text.Trim(); - if (double.TryParse( - text, - NumberStyles.Float, - CultureInfo.InvariantCulture, - out var invariantResult)) - return invariantResult; - if (double.TryParse( - text, - NumberStyles.Float, - CultureInfo.CurrentCulture, - out var currentResult)) - return currentResult; - - return 0d; + return ParseLeadingDoubleOrZero(Convert.ToString(value, CultureInfo.InvariantCulture)); + } + + /// + /// 从字符串开头读取一个使用英文句点作为小数点的浮点数字面量;无法读取时返回 0。 + /// 该方法用于替代历史 VB Val 调用点,不会要求整个字符串都必须是数字。 + /// + public static double ParseLeadingDoubleOrZero(string? text) + { + if (string.IsNullOrWhiteSpace(text)) return 0d; + + text = text.TrimStart(); + if (text.Length == 0 || text[0] == '&') return 0d; + + var index = 0; + if (text[index] is '+' or '-') index++; + + var hasDigit = false; + while (index < text.Length && char.IsDigit(text[index])) + { + hasDigit = true; + index++; + } + + if (index < text.Length && text[index] == '.') + { + index++; + while (index < text.Length && char.IsDigit(text[index])) + { + hasDigit = true; + index++; + } + } + + if (!hasDigit) return 0d; + + var exponentEnd = _TryReadExponent(text, index); + if (exponentEnd > index) index = exponentEnd; + + return double.TryParse( + text[..index], + NumberStyles.Float, + CultureInfo.InvariantCulture, + out var result) + ? result + : 0d; + } + + private static int _TryReadExponent(string text, int index) + { + if (index >= text.Length || text[index] is not ('e' or 'E')) return index; + + var cursor = index + 1; + if (cursor < text.Length && text[cursor] is '+' or '-') cursor++; + + var digitStart = cursor; + while (cursor < text.Length && char.IsDigit(text[cursor])) cursor++; + + return cursor > digitStart ? cursor : index; } /// diff --git a/PCL.Core/Utils/TextUtils.cs b/PCL.Core/Utils/TextUtils.cs index cf008f527..cda165bb8 100644 --- a/PCL.Core/Utils/TextUtils.cs +++ b/PCL.Core/Utils/TextUtils.cs @@ -51,7 +51,7 @@ public static string TrimDisplayName(string value, bool removeQuote = true) /// /// 对 XML 特殊字符进行转义。 /// - public static string EscapeXml(string value) + public static string EscapeXml(string? value) { if (string.IsNullOrEmpty(value)) return string.Empty; return value @@ -63,6 +63,17 @@ public static string EscapeXml(string value) .Replace("\r\n", " "); } + /// + /// 对将被拼入 XAML 属性值的文本进行转义。 + /// 以“{”开头的值会被 WPF 解析为 MarkupExtension,因此需要用“{}”前缀显式声明普通文本。 + /// + public static string EscapeXamlAttributeText(string? value) + { + if (string.IsNullOrEmpty(value)) return string.Empty; + if (value.StartsWith('{')) value = "{}" + value; + return EscapeXml(value); + } + /// /// 为 Access/VB Like 风格通配字符添加方括号转义。 /// diff --git a/Plain Craft Launcher 2/Infrastructure/CustomXamlLoader.cs b/Plain Craft Launcher 2/Modules/Infrastructure/CustomXamlLoader.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/CustomXamlLoader.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/CustomXamlLoader.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherEnvironment.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherEnvironment.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherEnvironment.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherEnvironment.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherExitCode.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherExitCode.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherExitCode.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherFeedbackService.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherFeedbackService.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherFeedbackService.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFileSystem.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherFileSystem.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherFileSystem.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherFileSystem.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherFontService.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherFontService.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherFontService.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherIniStore.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherIniStore.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherIniStore.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherIniStore.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherLog.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherLog.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherLog.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherLog.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherLogLevel.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherLogLevel.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherLogLevel.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherLogLevel.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherPaths.cs similarity index 83% rename from Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherPaths.cs index d94e5d36b..033ff63f1 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherPaths.cs +++ b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherPaths.cs @@ -49,14 +49,14 @@ public static string ResolveLauncherFilePath(string filePath) { if (string.IsNullOrEmpty(filePath)) return filePath; - return IsWindowsAbsolutePath(filePath) + return IsAbsolutePath(filePath) ? filePath : ExecutableDirectoryWithSlash + filePath; } public static string ResolveLauncherIniPath(string fileName) { - return IsWindowsAbsolutePath(fileName) + return IsAbsolutePath(fileName) ? fileName : $@"{ExecutableDirectoryWithSlash}PCL\{fileName}.ini"; } @@ -70,9 +70,18 @@ public static string EnsureTrailingSlash(string path) : path + DirectorySeparator; } - public static bool IsWindowsAbsolutePath(string path) + public static bool IsAbsolutePath(string path) { - return !string.IsNullOrEmpty(path) && path.Contains(@":\", StringComparison.Ordinal); + if (string.IsNullOrWhiteSpace(path)) return false; + + if (path.StartsWith(@"\\", StringComparison.Ordinal)) return true; + if (path.StartsWith('/') || path.StartsWith('\\')) return true; + if (path.Length >= 3 && + char.IsLetter(path[0]) && + path[1] == ':' && + path[2] is '\\' or '/') return true; + + return Path.IsPathFullyQualified(path) || Path.IsPathRooted(path); } private static string ResolvePureAsciiDirectory() diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherProcess.cs similarity index 98% rename from Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherProcess.cs index 9bee0275c..efe705c42 100644 --- a/Plain Craft Launcher 2/Infrastructure/LauncherProcess.cs +++ b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherProcess.cs @@ -142,7 +142,7 @@ public static void ClipboardSet(string text, bool showSuccessHint = true) for (var attempt = 0; attempt <= 5; attempt++) try { - UiThread.Post(() => Clipboard.SetText(text)); + UiThread.Invoke(() => Clipboard.SetText(text)); success = true; break; } @@ -176,7 +176,7 @@ public static int PasteFileFromClipboard( try { - var files = Clipboard.GetFileDropList(); + var files = UiThread.Invoke(() => Clipboard.GetFileDropList()); if (files.Count.Equals(0)) { diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherRuntime.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherRuntime.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherRuntime.cs diff --git a/Plain Craft Launcher 2/Infrastructure/LauncherStringHash.cs b/Plain Craft Launcher 2/Modules/Infrastructure/LauncherStringHash.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/LauncherStringHash.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/LauncherStringHash.cs diff --git a/Plain Craft Launcher 2/Infrastructure/UiThread.cs b/Plain Craft Launcher 2/Modules/Infrastructure/UiThread.cs similarity index 100% rename from Plain Craft Launcher 2/Infrastructure/UiThread.cs rename to Plain Craft Launcher 2/Modules/Infrastructure/UiThread.cs diff --git a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs index 216b4b7b5..df9d1f26f 100644 --- a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.cs @@ -273,7 +273,7 @@ public void TaskRefresh(ModLoader.LoaderBase loader) var cardXAML = $@" + Tag=""{loader.Progress + (double)loader.State}"" Title=""{TextUtils.EscapeXamlAttributeText(loader.name)}"" Margin=""0,0,0,15""> @@ -296,7 +296,8 @@ public void TaskRefresh(ModLoader.LoaderBase loader) } case LoadState.Loading: { - cardXAML += $""; + cardXAML += + $""; break; } case LoadState.Finished: @@ -314,7 +315,8 @@ public void TaskRefresh(ModLoader.LoaderBase loader) } } - cardXAML += $""; + cardXAML += + $""; row += 1; } From 400e7fe3df0546e3df858f918f86baf14a53a024 Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 8 Jul 2026 00:59:35 +0800 Subject: [PATCH 12/16] =?UTF-8?q?=E9=80=80=E5=9B=9E=20NColor=20=E8=BF=81?= =?UTF-8?q?=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PCL.Core.Test/UI/NColorTest.cs | 53 --- PCL.Core/UI/NColor.cs | 159 --------- .../Controls/AnimatedBackgroundGrid.cs | 2 +- .../Controls/MyHint.xaml.cs | 8 +- .../Controls/MyIconButton.xaml.cs | 52 +-- .../Controls/MyIconTextButton.xaml.cs | 2 +- .../Controls/MyMsg/MyMsgInput.xaml.cs | 6 +- .../Controls/MyMsg/MyMsgMarkdown.xaml.cs | 6 +- .../Controls/MyMsg/MyMsgSelect.xaml.cs | 6 +- .../Controls/MyMsg/MyMsgText.xaml.cs | 6 +- .../Controls/MyRadioButton.xaml.cs | 38 +-- .../Controls/MyToast.xaml.cs | 2 +- .../Controls/SvgIconControlHelper.cs | 4 +- .../Modules/Base/ModAnimation.cs | 24 +- .../Modules/Minecraft/ModStyle.cs | 2 +- .../Modules/UI/Theme/MyColor.cs | 307 ++++++++++++++++++ .../Modules/UI/Theme/ThemeManager.cs | 16 +- .../Pages/PageLaunch/MyMsgLogin.xaml.cs | 6 +- 18 files changed, 397 insertions(+), 302 deletions(-) delete mode 100644 PCL.Core.Test/UI/NColorTest.cs create mode 100644 Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs diff --git a/PCL.Core.Test/UI/NColorTest.cs b/PCL.Core.Test/UI/NColorTest.cs deleted file mode 100644 index 3ce027ad1..000000000 --- a/PCL.Core.Test/UI/NColorTest.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Windows.Media; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using PCL.Core.UI; - -namespace PCL.Core.Test.UI; - -[TestClass] -public class NColorTest -{ - [TestMethod] - public void FromArgbUsesAlphaFirstOrder() - { - var color = NColor.FromArgb(10d, 20d, 30d, 40d); - - Assert.AreEqual(10f, color.A); - Assert.AreEqual(20f, color.R); - Assert.AreEqual(30f, color.G); - Assert.AreEqual(40f, color.B); - } - - [TestMethod] - public void WithAlphaKeepsRgbChannels() - { - var color = new NColor(20d, 30d, 40d).WithAlpha(128d); - - Assert.AreEqual(128f, color.A); - Assert.AreEqual(20f, color.R); - Assert.AreEqual(30f, color.G); - Assert.AreEqual(40f, color.B); - } - - [TestMethod] - public void LerpInterpolatesAndRoundsChannels() - { - var color = NColor.Lerp(new NColor(0d, 0d, 0d), new NColor(10d, 20d, 30d), 0.5d); - - Assert.AreEqual(5f, color.R); - Assert.AreEqual(10f, color.G); - Assert.AreEqual(15f, color.B); - Assert.AreEqual(255f, color.A); - } - - [TestMethod] - public void ObjectConstructorAcceptsWpfBrush() - { - var color = new NColor(new SolidColorBrush(Color.FromArgb(8, 1, 2, 3))); - - Assert.AreEqual(8f, color.A); - Assert.AreEqual(1f, color.R); - Assert.AreEqual(2f, color.G); - Assert.AreEqual(3f, color.B); - } -} \ No newline at end of file diff --git a/PCL.Core/UI/NColor.cs b/PCL.Core/UI/NColor.cs index b60a7bda2..dbba4022b 100644 --- a/PCL.Core/UI/NColor.cs +++ b/PCL.Core/UI/NColor.cs @@ -53,11 +53,6 @@ public NColor(float r, float g, float b, float a = 255f) _color = new Vector4(r, g, b, a); } - public NColor(double r, double g, double b, double a = 255d) - : this((float)r, (float)g, (float)b, (float)a) - { - } - public NColor(Color color) : this(color.R, color.G, color.B, color.A) { } @@ -134,60 +129,10 @@ public NColor(string str) _color = new Vector4(r, g, b, a); } - public NColor(object? obj) - { - switch (obj) - { - case null: - _color = new Vector4(255f, 255f, 255f, 255f); - break; - case NColor color: - _color = color._color; - break; - case Color color: - _color = new Vector4(color.R, color.G, color.B, color.A); - break; - case System.Drawing.Color color: - _color = new Vector4(color.R, color.G, color.B, color.A); - break; - case SolidColorBrush brush: - var brushColor = brush.Color; - _color = new Vector4(brushColor.R, brushColor.G, brushColor.B, brushColor.A); - break; - case Brush brush: - var solidBrush = (SolidColorBrush)brush; - var solidBrushColor = solidBrush.Color; - _color = new Vector4(solidBrushColor.R, solidBrushColor.G, solidBrushColor.B, solidBrushColor.A); - break; - case string str: - _color = new NColor(str)._color; - break; - default: - _color = new Vector4( - Convert.ToSingle(((dynamic)obj).R), - Convert.ToSingle(((dynamic)obj).G), - Convert.ToSingle(((dynamic)obj).B), - Convert.ToSingle(((dynamic)obj).A)); - break; - } - } - public NColor(float a, NColor color) : this(color.R, color.G, color.B, a) { } - public NColor(double a, NColor color) : this(color.R, color.G, color.B, (float)a) - { - } - - public NColor(double a, Brush brush) : this(a, (NColor)brush) - { - } - - public NColor(double a, SolidColorBrush brush) : this(a, (NColor)brush) - { - } - public NColor(float r, float g, float b) : this(r, g, b, 255f) { } @@ -205,33 +150,6 @@ private NColor(Vector4 v) _color = v; } - public static NColor FromArgb(double a, double r, double g, double b) - { - return new NColor(r, g, b, a); - } - - public NColor WithAlpha(double value) - { - var color = this; - color.A = (float)value; - return color; - } - - public static NColor Lerp(NColor from, NColor to, double progress) - { - var p = (float)progress; - return Round(from * (1f - p) + to * p, 6); - } - - public static NColor Round(NColor color, int digits = 0) - { - return new NColor( - Math.Round(color.R, digits), - Math.Round(color.G, digits), - Math.Round(color.B, digits), - Math.Round(color.A, digits)); - } - #endregion #region 运算符重载 @@ -251,31 +169,11 @@ public static NColor Round(NColor color, int digits = 0) return new NColor(a._color * b); } - public static NColor operator *(NColor a, double b) - { - return new NColor(a._color * (float)b); - } - - public static NColor operator *(float a, NColor b) - { - return new NColor(b._color * a); - } - - public static NColor operator *(double a, NColor b) - { - return new NColor(b._color * (float)a); - } - public static NColor operator /(NColor a, float b) { return b == 0 ? throw new DivideByZeroException("除数不能为零。") : new NColor(a._color / b); } - public static NColor operator /(NColor a, double b) - { - return b == 0 ? throw new DivideByZeroException("除数不能为零。") : new NColor(a._color / (float)b); - } - public static bool operator ==(NColor a, NColor b) { return a._color == b._color; @@ -342,39 +240,6 @@ public static NColor FromHsl(double sH, double sS, double sL) return color; } - private static readonly double[] _PerceptualCenterOffsets = - [ - +0.10d, -0.06d, -0.30d, -0.19d, - -0.15d, -0.24d, -0.32d, -0.09d, - +0.18d, +0.05d, -0.12d, -0.02d, - +0.10d - ]; - - public static NColor FromPerceptualHsl(double hue, double saturation, double lightness) - { - if (saturation == 0d) - return FromHsl(hue, saturation, lightness); - - hue %= 360d; - if (hue < 0d) - hue += 360d; - - var segmentPosition = hue / 30d; - var segmentIndex = (int)segmentPosition; - var segmentBlend = segmentPosition - segmentIndex; - - var centerOffset = _PerceptualCenterOffsets[segmentIndex] + - (_PerceptualCenterOffsets[segmentIndex + 1] - _PerceptualCenterOffsets[segmentIndex]) * - segmentBlend; - - var visualCenter = 50d - centerOffset * saturation; - var adjustedLightness = lightness < visualCenter - ? lightness / visualCenter * 50d - : (1d + (lightness - visualCenter) / (100d - visualCenter)) * 50d; - - return FromHsl(hue, saturation, adjustedLightness); - } - private static double _Hue(double v1, double v2, double vH) { if (vH < 0) vH += 1; @@ -390,11 +255,6 @@ private static double _Hue(double v1, double v2, double vH) #endregion - public override string ToString() - { - return $"({A},{R},{G},{B})"; - } - #region 隐式转换 public static implicit operator Color(NColor color) @@ -406,15 +266,6 @@ public static implicit operator Color(NColor color) (byte)Math.Clamp(color.B, 0, 255)); } - public static implicit operator System.Drawing.Color(NColor color) - { - return System.Drawing.Color.FromArgb( - (byte)Math.Clamp(color.A, 0, 255), - (byte)Math.Clamp(color.R, 0, 255), - (byte)Math.Clamp(color.G, 0, 255), - (byte)Math.Clamp(color.B, 0, 255)); - } - public static implicit operator Brush(NColor color) { return new SolidColorBrush(color); @@ -430,16 +281,6 @@ public static implicit operator NColor(Color color) return new NColor(color); } - public static implicit operator NColor(System.Drawing.Color color) - { - return new NColor(color); - } - - public static implicit operator NColor(string value) - { - return new NColor(value); - } - public static implicit operator NColor(Brush brush) { return new NColor(brush); diff --git a/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs b/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs index 9fdfbc608..a0a9f2bd0 100644 --- a/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs +++ b/Plain Craft Launcher 2/Controls/AnimatedBackgroundGrid.cs @@ -61,7 +61,7 @@ private static void _BackgroundBrushChanged(DependencyObject d, DependencyProper new[] { ModAnimation.AaColor(grid.AnimatableElement, grid._animatableBrushProperty, - new NColor(brush) - grid.AnimatableBrush, 300) + new MyColor(brush) - grid.AnimatableBrush, 300) }, "MyCard Theme " + grid.uuid); await Task.Delay(300); grid.AnimatableBrush = brush; diff --git a/Plain Craft Launcher 2/Controls/MyHint.xaml.cs b/Plain Craft Launcher 2/Controls/MyHint.xaml.cs index dc80f66ea..6099cb540 100644 --- a/Plain Craft Launcher 2/Controls/MyHint.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyHint.xaml.cs @@ -127,10 +127,10 @@ private void UpdateUI() } var s = ThemeService.CurrentTone; - Background = NColor.FromPerceptualHsl(hue, 90, s.L7 * 100); - BorderBrush = NColor.FromPerceptualHsl(hue, 90, s.L2 * 100); - LabText.Foreground = NColor.FromPerceptualHsl(hue, 90, s.L2 * 100); - BtnClose.Foreground = NColor.FromPerceptualHsl(hue, 90, s.L2 * 100); + Background = new MyColor().FromHsl2(hue, 90, s.L7 * 100); + BorderBrush = new MyColor().FromHsl2(hue, 90, s.L2 * 100); + LabText.Foreground = new MyColor().FromHsl2(hue, 90, s.L2 * 100); + BtnClose.Foreground = new MyColor().FromHsl2(hue, 90, s.L2 * 100); // 根据提示气泡对齐方向刷新边框 // 此处依赖 HasBorder 的副作用进行范围检查 diff --git a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs index 082496039..0de5aa7a8 100644 --- a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.cs @@ -117,21 +117,21 @@ public SolidColorBrush Foreground // 自定义事件 public event ClickEventHandler? Click; - private static NColor _GetTransparentBackground() + private static MyColor _GetTransparentBackground() { - return NColor.FromArgb(0d, 255d, 255d, 255d); + return new MyColor(0d, 255d, 255d, 255d); } - private NColor? GetBaseFillColor() + private MyColor? GetBaseFillColor() { return Theme switch { - Themes.Red => NColor.FromArgb(160d, 255d, 76d, 76d), + Themes.Red => new MyColor(160d, 255d, 76d, 76d), Themes.Black => ThemeManager.IsDarkMode - ? NColor.FromArgb(160d, 255d, 255d, 255d) - : NColor.FromArgb(160d, 0d, 0d, 0d), - Themes.Custom => new NColor(160d, Foreground), - _ => new NColor() + ? new MyColor(160d, 255d, 255d, 255d) + : new MyColor(160d, 0d, 0d, 0d), + Themes.Custom => new MyColor(160d, Foreground), + _ => null }; } @@ -140,7 +140,7 @@ private void EnsureBaseBrushes() PanBack.Background ??= _GetTransparentBackground(); var baseFill = GetBaseFillColor(); if (baseFill is not null && !IsUsingSvgIcon) - Path.Fill ??= baseFill.Value; + Path.Fill ??= baseFill; } private void AnimateActiveSvgIconBrush(string resourceKey, int duration) @@ -149,7 +149,7 @@ private void AnimateActiveSvgIconBrush(string resourceKey, int duration) SvgIconControlHelper.AnimateSvgIconBrushTo(ShapeSvgIcon, resourceKey, duration, ColorAnimationKey); } - private void AnimateActiveSvgIconBrush(NColor color, int duration) + private void AnimateActiveSvgIconBrush(MyColor color, int duration) { if (IsUsingSvgIcon) SvgIconControlHelper.AnimateSvgIconBrushTo(ShapeSvgIcon, color, duration, ColorAnimationKey); @@ -188,7 +188,7 @@ private void SetActiveIconBrush(Brush brush) animations.Add(ModAnimation.AaColor( PanBack, BackgroundProperty, - NColor.FromArgb(50d, 255d, 255d, 255d) - PanBack.Background, + new MyColor(50d, 255d, 255d, 255d) - PanBack.Background, animationColorIn)); break; } @@ -196,21 +196,21 @@ private void SetActiveIconBrush(Brush brush) { if (IsUsingSvgIcon) AnimateActiveSvgIconBrush( - new NColor(255d, 76d, 76d), + new MyColor(255d, 76d, 76d), animationColorIn); else animations.Add(ModAnimation.AaColor( Path, Shape.FillProperty, - new NColor(255d, 76d, 76d) - Path.Fill, + new MyColor(255d, 76d, 76d) - Path.Fill, animationColorIn)); break; } case Themes.Black: { var blackHoverColor = ThemeManager.IsDarkMode - ? NColor.FromArgb(230d, 255d, 255d, 255d) - : NColor.FromArgb(230d, 0d, 0d, 0d); + ? new MyColor(230d, 255d, 255d, 255d) + : new MyColor(230d, 0d, 0d, 0d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(blackHoverColor, animationColorIn); else @@ -223,7 +223,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.Custom: { - var customHoverColor = new NColor(255d, Foreground); + var customHoverColor = new MyColor(255d, Foreground); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(customHoverColor, animationColorIn); else @@ -260,7 +260,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.White: { - var whiteNormalColor = new NColor(234d, 242d, 254d); + var whiteNormalColor = new MyColor(234d, 242d, 254d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(whiteNormalColor, animationColorOut); else @@ -279,7 +279,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.Red: { - var redNormalColor = NColor.FromArgb(160d, 255d, 76d, 76d); + var redNormalColor = new MyColor(160d, 255d, 76d, 76d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(redNormalColor, animationColorOut); else @@ -295,8 +295,8 @@ private void SetActiveIconBrush(Brush brush) case Themes.Black: { var blackNormalColor = ThemeManager.IsDarkMode - ? NColor.FromArgb(160d, 255d, 255d, 255d) - : NColor.FromArgb(160d, 0d, 0d, 0d); + ? new MyColor(160d, 255d, 255d, 255d) + : new MyColor(160d, 0d, 0d, 0d); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(blackNormalColor, animationColorOut); else @@ -311,7 +311,7 @@ private void SetActiveIconBrush(Brush brush) } case Themes.Custom: { - var customNormalColor = new NColor(160d, Foreground); + var customNormalColor = new MyColor(160d, Foreground); if (IsUsingSvgIcon) AnimateActiveSvgIconBrush(customNormalColor, animationColorOut); else @@ -337,18 +337,18 @@ private void ApplyNonAnimatedTheme() SetActiveIconResource("ColorBrush4"); break; case Themes.White: - SetActiveIconBrush(new NColor(234d, 242d, 254d)); + SetActiveIconBrush(new MyColor(234d, 242d, 254d)); break; case Themes.Red: - SetActiveIconBrush(NColor.FromArgb(160d, 255d, 76d, 76d)); + SetActiveIconBrush(new MyColor(160d, 255d, 76d, 76d)); break; case Themes.Black: SetActiveIconBrush(ThemeManager.IsDarkMode - ? NColor.FromArgb(160d, 255d, 255d, 255d) - : NColor.FromArgb(160d, 0d, 0d, 0d)); + ? new MyColor(160d, 255d, 255d, 255d) + : new MyColor(160d, 0d, 0d, 0d)); break; case Themes.Custom: - SetActiveIconBrush(new NColor(160d, Foreground)); + SetActiveIconBrush(new MyColor(160d, Foreground)); break; } diff --git a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs index accd12c5d..f63fd202c 100644 --- a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.cs @@ -199,7 +199,7 @@ private void StartBackgroundAnimation(string resourceKey, int duration) ModAnimation.AniStart(ModAnimation.AaColor(this, BackgroundProperty, resourceKey, duration), ColorAnimationKey); } - private void StartBackgroundAnimation(NColor delta, int duration) + private void StartBackgroundAnimation(MyColor delta, int duration) { ModAnimation.AniStart(ModAnimation.AaColor(this, BackgroundProperty, delta, duration), ColorAnimationKey); } diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs index fe76f68a0..155927f28 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.cs @@ -78,8 +78,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? NColor.FromArgb(140d, 80d, 0d, 0d) - : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -118,7 +118,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs index 2a45c0706..bd1032e51 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgMarkdown.xaml.cs @@ -76,8 +76,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? NColor.FromArgb(140d, 80d, 0d, 0d) - : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -117,7 +117,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs index d3d700518..0df63d3ed 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs @@ -109,8 +109,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? NColor.FromArgb(140d, 80d, 0d, 0d) - : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -149,7 +149,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs index cb6112c4f..1c491f27e 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.cs @@ -75,8 +75,8 @@ private void Load(object sender, RoutedEventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? NColor.FromArgb(140d, 80d, 0d, 0d) - : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -116,7 +116,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs index c12abb0f8..c0f4da34d 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.cs @@ -327,7 +327,7 @@ private void RefreshColor(object obj = null, object e = null) if (Checked) { // 勾选 - var color3 = new NColor(ThemeManager.AppResources["ColorObject3"]); + var color3 = new MyColor(ThemeManager.AppResources["ColorObject3"]); ModAnimation.AniStart( new[] { @@ -338,7 +338,7 @@ private void RefreshColor(object obj = null, object e = null) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new NColor(255d, 255d, 255d) - Background, animationTimeOfCheck), + new MyColor(255d, 255d, 255d) - Background, animationTimeOfCheck), "MyRadioButton Color " + Uuid); } else if (isMouseDown) @@ -346,8 +346,8 @@ private void RefreshColor(object obj = null, object e = null) // 按下 ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new NColor(120d, - new NColor(ThemeManager.AppResources["ColorObject8"])) - Background, 60), + new MyColor(120d, + new MyColor(ThemeManager.AppResources["ColorObject8"])) - Background, 60), "MyRadioButton Color " + Uuid); } else if (IsMouseOver) @@ -357,15 +357,15 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new NColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseIn), + new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseIn), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new NColor(255d, 255d, 255d) - LabText.Foreground, + new MyColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfMouseIn) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new NColor(50d, - new NColor(ThemeManager.AppResources["ColorObject8"])) - Background, + new MyColor(50d, + new MyColor(ThemeManager.AppResources["ColorObject8"])) - Background, animationTimeOfMouseIn), "MyRadioButton Color " + Uuid); } else @@ -375,15 +375,15 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new NColor(255d, 255d, 255d) - ShapeLogo.Fill, + new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfMouseOut), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new NColor(255d, 255d, 255d) - LabText.Foreground, + new MyColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfMouseOut) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new NColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - + new MyColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - Background, animationTimeOfMouseOut), "MyRadioButton Color " + Uuid); } @@ -398,9 +398,9 @@ private void RefreshColor(object obj = null, object e = null) new[] { ModAnimation.AaColor(ShapeLogo, Shape.FillProperty, - new NColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfCheck), + new MyColor(255d, 255d, 255d) - ShapeLogo.Fill, animationTimeOfCheck), ModAnimation.AaColor(LabText, TextBlock.ForegroundProperty, - new NColor(255d, 255d, 255d) - LabText.Foreground, + new MyColor(255d, 255d, 255d) - LabText.Foreground, animationTimeOfCheck) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( @@ -442,7 +442,7 @@ private void RefreshColor(object obj = null, object e = null) }, "MyRadioButton Checked " + Uuid); ModAnimation.AniStart( ModAnimation.AaColor(this, BackgroundProperty, - new NColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - + new MyColor(ThemeManager.AppResources["ColorBrushSemiTransparent"]) - Background, animationTimeOfMouseOut), "MyRadioButton Color " + Uuid); } @@ -462,15 +462,15 @@ private void RefreshColor(object obj = null, object e = null) { if (Checked) { - Background = new NColor(255d, 255d, 255d); + Background = new MyColor(255d, 255d, 255d); ShapeLogo.SetResourceReference(Shape.FillProperty, "ColorBrush3"); LabText.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush3"); } else { Background = (Brush)ThemeManager.AppResources["ColorBrushSemiTransparent"]; - ShapeLogo.Fill = new NColor(255d, 255d, 255d); - LabText.Foreground = new NColor(255d, 255d, 255d); + ShapeLogo.Fill = new MyColor(255d, 255d, 255d); + LabText.Foreground = new MyColor(255d, 255d, 255d); } break; @@ -480,8 +480,8 @@ private void RefreshColor(object obj = null, object e = null) if (Checked) { SetResourceReference(BackgroundProperty, "ColorBrush3"); - ShapeLogo.Fill = new NColor(255d, 255d, 255d); - LabText.Foreground = new NColor(255d, 255d, 255d); + ShapeLogo.Fill = new MyColor(255d, 255d, 255d); + LabText.Foreground = new MyColor(255d, 255d, 255d); } else { diff --git a/Plain Craft Launcher 2/Controls/MyToast.xaml.cs b/Plain Craft Launcher 2/Controls/MyToast.xaml.cs index ebeffbb43..ee06953aa 100644 --- a/Plain Craft Launcher 2/Controls/MyToast.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyToast.xaml.cs @@ -210,7 +210,7 @@ private void UpdateColors() _ => 210d }; var res = System.Windows.Application.Current.Resources; - var accent = NColor.FromPerceptualHsl(baseHue, 75, 60); + var accent = new MyColor().FromHsl2(baseHue, 75, 60); var bg = ThemeService.IsDarkMode ? new SolidColorBrush(LabColor.FromLch(0.35)) : (Brush)res["ColorBrushBackground"]; diff --git a/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs b/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs index 23384bee0..fb567f363 100644 --- a/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs +++ b/Plain Craft Launcher 2/Controls/SvgIconControlHelper.cs @@ -59,13 +59,13 @@ internal static void AnimateSvgIconBrushTo( internal static void AnimateSvgIconBrushTo( SvgIcon svgIcon, - NColor color, + MyColor color, int duration, string? animationKey = null) { if (svgIcon.Visibility == Visibility.Visible) svgIcon.AnimateIconBrushTo( - color, + new NColor((Color)color), TimeSpan.FromMilliseconds(duration), animationKey: animationKey); } diff --git a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs index 1b069402f..c029b79b2 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs +++ b/Plain Craft Launcher 2/Modules/Base/ModAnimation.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Collections.Concurrent; using System.Text; using System.Windows; @@ -316,16 +316,16 @@ private static AniData AniRun(AniData ani) case AniType.Color: { // 利用 Last 记录了余下的小数值 - var delta = NColor.Lerp( - NColor.FromArgb(0d, 0d, 0d, 0d), - (NColor)ani.value, + var delta = MyColor.Lerp( + new MyColor(0d, 0d, 0d, 0d), + (MyColor)ani.value, ani.ease.GetDelta(ani.timeFinished / (double)ani.timeTotal, ani.timePercent)) - + (NColor)ani.valueLast; + + (MyColor)ani.valueLast; var obj = (FrameworkElement)((dynamic)ani.obj)[0]; var prop = (DependencyProperty)((dynamic)ani.obj)[1]; - var newColor = new NColor(obj.GetValue(prop)) + delta; + var newColor = new MyColor(obj.GetValue(prop)) + delta; obj.SetValue(prop, prop.PropertyType.Name == "Color" ? (Color)newColor : (SolidColorBrush)newColor); - ani.valueLast = newColor - new NColor(obj.GetValue(prop)); + ani.valueLast = newColor - new MyColor(obj.GetValue(prop)); break; } @@ -964,7 +964,7 @@ public static AniData AaDouble(ParameterizedThreadStart lambda, double value, in public static AniData AaColor( FrameworkElement obj, DependencyProperty prop, - NColor value, + MyColor value, int time = 400, int delay = 0, AniEase ease = null, @@ -974,7 +974,7 @@ public static AniData AaColor( { typeMain = AniType.Color, timeTotal = time, ease = ease ?? new AniEaseLinear(), obj = new object[] { obj, prop, "" }, value = value, isAfter = after, timeFinished = -delay, - valueLast = NColor.FromArgb(0d, 0d, 0d, 0d) + valueLast = new MyColor(0d, 0d, 0d, 0d) }; } @@ -1003,9 +1003,9 @@ public static AniData AaColor( { typeMain = AniType.Color, timeTotal = time, ease = ease ?? new AniEaseLinear(), obj = new object[] { obj, prop, res }, - value = new NColor(System.Windows.Application.Current.FindResource(res)) - - new NColor(obj.GetValue(prop)), - isAfter = after, timeFinished = -delay, valueLast = NColor.FromArgb(0d, 0d, 0d, 0d) + value = new MyColor(System.Windows.Application.Current.FindResource(res)) + - new MyColor(obj.GetValue(prop)), + isAfter = after, timeFinished = -delay, valueLast = new MyColor(0d, 0d, 0d, 0d) }; } diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs index 9cac9bbfe..9adb61469 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModStyle.cs @@ -258,7 +258,7 @@ public static void SetColorfulTextLab(string text, TextBlock lab, bool isDarkMod lab.Inlines.Add(curRun); } - curRun.Foreground = new SolidColorBrush(new NColor(color)); + curRun.Foreground = new SolidColorBrush(new MyColor(color)); curRun.FontWeight = hasBlodProperty ? FontWeights.Bold : FontWeights.Normal; curRun.FontStyle = hasItalicProperty ? FontStyles.Italic : FontStyles.Normal; curRun.TextDecorations = hasStrickThroughProperty ? TextDecorations.Strikethrough : null; diff --git a/Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs b/Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs new file mode 100644 index 000000000..40e31a3a8 --- /dev/null +++ b/Plain Craft Launcher 2/Modules/UI/Theme/MyColor.cs @@ -0,0 +1,307 @@ +using System.Windows.Media; + +namespace PCL; + +/// +/// 支持小数与常见类型隐式转换的颜色。 +/// +public class MyColor +{ + public double a = 255d; + public double b; + public double g; + public double r; + + // 构造函数 + public MyColor() + { + } + + public MyColor(Color col) + { + a = col.A; + r = col.R; + g = col.G; + b = col.B; + } + + public MyColor(string hexString) + { + var stringColor = (Color)ColorConverter.ConvertFromString(hexString); + a = stringColor.A; + r = stringColor.R; + g = stringColor.G; + b = stringColor.B; + } + + public MyColor(double newA, MyColor col) + { + a = newA; + r = col.r; + g = col.g; + b = col.b; + } + + public MyColor(double newR, double newG, double newB) + { + a = 255d; + r = newR; + g = newG; + b = newB; + } + + public MyColor(double newA, double newR, double newG, double newB) + { + a = newA; + r = newR; + g = newG; + b = newB; + } + + public MyColor(Brush brush) + { + var color = ((SolidColorBrush)brush).Color; + a = color.A; + r = color.R; + g = color.G; + b = color.B; + } + + public MyColor(SolidColorBrush brush) + { + var color = brush.Color; + a = color.A; + r = color.R; + g = color.G; + b = color.B; + } + + public MyColor(object obj) + { + if (obj is null) + { + a = 255d; + r = 255d; + g = 255d; + b = 255d; + } + else if (obj is SolidColorBrush brush) + { + // 避免反复获取 Color 对象造成性能下降 + var color = brush.Color; + a = color.A; + r = color.R; + g = color.G; + b = color.B; + } + else + { + a = Convert.ToDouble(((dynamic)obj).A); + r = Convert.ToDouble(((dynamic)obj).R); + g = Convert.ToDouble(((dynamic)obj).G); + b = Convert.ToDouble(((dynamic)obj).B); + } + } + + private static byte ClampToByte(double value) + { + return (byte)Math.Clamp(Math.Round(value), 0d, 255d); + } + + public static MyColor Lerp(MyColor from, MyColor to, double progress) + { + return Round(from * (1d - progress) + to * progress, 6); + } + + public static MyColor Round(MyColor color, int digits = 0) + { + return new MyColor + { + a = Math.Round(color.a, digits), + r = Math.Round(color.r, digits), + g = Math.Round(color.g, digits), + b = Math.Round(color.b, digits) + }; + } + + // 类型转换 + public static implicit operator MyColor(string str) + { + return new MyColor(str); + } + + public static implicit operator MyColor(Color col) + { + return new MyColor(col); + } + + public static implicit operator Color(MyColor conv) + { + return Color.FromArgb(ClampToByte(conv.a), ClampToByte(conv.r), ClampToByte(conv.g), ClampToByte(conv.b)); + } + + public static implicit operator System.Drawing.Color(MyColor conv) + { + return System.Drawing.Color.FromArgb(ClampToByte(conv.a), ClampToByte(conv.r), ClampToByte(conv.g), + ClampToByte(conv.b)); + } + + public static implicit operator MyColor(SolidColorBrush bru) + { + return new MyColor(bru.Color); + } + + public static implicit operator SolidColorBrush(MyColor conv) + { + return new SolidColorBrush(Color.FromArgb(ClampToByte(conv.a), ClampToByte(conv.r), ClampToByte(conv.g), + ClampToByte(conv.b))); + } + + public static implicit operator MyColor(Brush bru) + { + return new MyColor(bru); + } + + public static implicit operator Brush(MyColor conv) + { + return new SolidColorBrush(Color.FromArgb(ClampToByte(conv.a), ClampToByte(conv.r), ClampToByte(conv.g), + ClampToByte(conv.b))); + } + + // 颜色运算 + public static MyColor operator +(MyColor a, MyColor b) + { + return new MyColor { a = a.a + b.a, b = a.b + b.b, g = a.g + b.g, r = a.r + b.r }; + } + + public static MyColor operator -(MyColor a, MyColor b) + { + return new MyColor { a = a.a - b.a, b = a.b - b.b, g = a.g - b.g, r = a.r - b.r }; + } + + public static MyColor operator *(MyColor a, double b) + { + return new MyColor { a = a.a * b, b = a.b * b, g = a.g * b, r = a.r * b }; + } + + public static MyColor operator /(MyColor a, double b) + { + return new MyColor { a = a.a / b, b = a.b / b, g = a.g / b, r = a.r / b }; + } + + public static bool operator ==(MyColor a, MyColor b) + { + if (a is null && b is null) + return true; + if (a is null || b is null) + return false; + return a.a == b.a && a.r == b.r && a.g == b.g && a.b == b.b; + } + + public static bool operator !=(MyColor a, MyColor b) + { + if (a is null && b is null) + return false; + if (a is null || b is null) + return true; + return !(a.a == b.a && a.r == b.r && a.g == b.g && a.b == b.b); + } + + // HSL + public double Hue(double v1, double v2, double vH) + { + if (vH < 0d) + vH += 1d; + if (vH > 1d) + vH -= 1d; + + return vH switch + { + < 0.16667d => v1 + (v2 - v1) * 6d * vH, + < 0.5d => v2, + < 0.66667d => v1 + (v2 - v1) * (4d - vH * 6d), + _ => v1 + }; + } + + public MyColor FromHsl(double sH, double sS, double sL) + { + if (sS == 0d) + { + r = sL * 2.55d; + g = r; + b = r; + } + else + { + var h = sH / 360d; + var s = sS / 100d; + var l = sL / 100d; + s = l < 0.5d ? s * l + l : s * (1.0d - l) + l; + l = 2d * l - s; + r = 255d * Hue(l, s, h + 1d / 3d); + g = 255d * Hue(l, s, h); + b = 255d * Hue(l, s, h - 1d / 3d); + } + + a = 255d; + return this; + } + + public MyColor FromHsl2(double sH, double sS, double sL) + { + if (sS == 0d) + { + r = sL * 2.55d; + g = r; + b = r; + } + else + { + // 初始化 + sH = (sH + 3600000d) % 360d; + var cent = new[] + { + +0.1d, -0.06d, -0.3d, -0.19d, -0.15d, -0.24d, -0.32d, -0.09d, +0.18d, +0.05d, -0.12d, -0.02d, +0.1d, + -0.06d + }; // 0, 30, 60 + // 90, 120, 150 + // 180, 210, 240 + // 270, 300, 330 + // 最后两位与前两位一致,加是变亮,减是变暗 + // 计算色调对应的亮度片区 + var center = sH / 30.0d; + var intCenter = (int)Math.Round(Math.Floor(center)); // 亮度片区编号 + center = 50d - + ((1d - center + intCenter) * cent[intCenter] + (center - intCenter) * cent[intCenter + 1]) * + sS; + // center = 50 + (cent(intCenter) + (center - intCenter) * (cent(intCenter + 1) - cent(intCenter))) * sS + sL = (sL < center ? sL / center : 1d + (sL - center) / (100d - center)) * 50d; + FromHsl(sH, sS, sL); + } + + a = 255d; + return this; + } + + public MyColor Alpha(double sA) + { + a = sA; + return this; + } + + public override string ToString() + { + return "(" + a + "," + r + "," + g + "," + b + ")"; + } + + public override bool Equals(object obj) + { + return obj is MyColor other && a == other.a && r == other.r && g == other.g && b == other.b; + } + + public override int GetHashCode() + { + return HashCode.Combine(a, r, g, b); + } +} \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs b/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs index 75fe1dacc..0570c3ada 100644 --- a/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs +++ b/Plain Craft Launcher 2/Modules/UI/Theme/ThemeManager.cs @@ -14,17 +14,17 @@ public static class ThemeManager public static ResourceDictionary AppResources => System.Windows.Application.Current.Resources; - public static NColor colorGray1 = new(AppResources["ColorObjectGray1"]); - public static NColor colorGray4 = new(AppResources["ColorObjectGray4"]); - public static NColor colorGray5 = new(AppResources["ColorObjectGray5"]); - public static NColor colorSemiTransparent = new(AppResources["ColorBrushSemiTransparent"]); + public static MyColor colorGray1 = new(AppResources["ColorObjectGray1"]); + public static MyColor colorGray4 = new(AppResources["ColorObjectGray4"]); + public static MyColor colorGray5 = new(AppResources["ColorObjectGray5"]); + public static MyColor colorSemiTransparent = new(AppResources["ColorBrushSemiTransparent"]); public static void ThemeRefresh(int newTheme = -1) { - colorGray1 = new NColor(AppResources["ColorObjectGray1"]); - colorGray4 = new NColor(AppResources["ColorObjectGray4"]); - colorGray5 = new NColor(AppResources["ColorObjectGray5"]); - colorSemiTransparent = new NColor(AppResources["ColorBrushSemiTransparent"]); + colorGray1 = new MyColor(AppResources["ColorObjectGray1"]); + colorGray4 = new MyColor(AppResources["ColorObjectGray4"]); + colorGray5 = new MyColor(AppResources["ColorObjectGray5"]); + colorSemiTransparent = new MyColor(AppResources["ColorBrushSemiTransparent"]); ThemeRefreshMain(); } diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs index a88c2aad5..e872e4135 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.cs @@ -172,8 +172,8 @@ private void Load(object sender, EventArgs e) ModAnimation.AniStart( ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, (myConverter.IsWarn - ? NColor.FromArgb(140d, 80d, 0d, 0d) - : NColor.FromArgb(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), + ? new MyColor(140d, 80d, 0d, 0d) + : new MyColor(90d, 0d, 0d, 0d)) - ModMain.frmMain.PanMsgBackground.Background, 200), "PanMsgBackground Background"); ModAnimation.AniStart( new[] @@ -208,7 +208,7 @@ private void Close() if (!ModMain.WaitingMyMsgBox.Any()) ModAnimation.AniStart(ModAnimation.AaColor(ModMain.frmMain.PanMsgBackground, BlurBorder.BackgroundProperty, - NColor.FromArgb(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, + new MyColor(0d, 0d, 0d, 0d) - ModMain.frmMain.PanMsgBackground.Background, 200, ease: new ModAnimation.AniEaseOutFluent(ModAnimation.AniEasePower.Weak))); }, 30), ModAnimation.AaOpacity(this, -Opacity, 80, 20), From 788cd35247ba70329b8b1f46116ba0f20766a055 Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 8 Jul 2026 01:36:35 +0800 Subject: [PATCH 13/16] =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E4=B8=BA=20UiThread?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plain Craft Launcher 2/Controls/MyTextBox.cs | 2 +- Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs | 2 +- .../Pages/PageDownload/PageDownloadCompFavorites.xaml.cs | 2 +- .../Pages/PageDownload/PageDownloadInstall.xaml.cs | 2 +- Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Plain Craft Launcher 2/Controls/MyTextBox.cs b/Plain Craft Launcher 2/Controls/MyTextBox.cs index cc48e162d..c396eb805 100644 --- a/Plain Craft Launcher 2/Controls/MyTextBox.cs +++ b/Plain Craft Launcher 2/Controls/MyTextBox.cs @@ -380,7 +380,7 @@ private void RefreshColor() private void RefreshTextColor() { var newColor = IsEnabled ? ThemeManager.colorGray1 : ThemeManager.colorGray4; - if (((SolidColorBrush)Foreground).Color.R == newColor.R) + if (((SolidColorBrush)Foreground).Color.R == newColor.r) return; if (IsLoaded && ModAnimation.AniControlEnabled == 0 && !string.IsNullOrEmpty(Text)) { diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs index d18c4394c..fc5e87637 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModProfile.cs @@ -470,7 +470,7 @@ public static void EditProfileId() lastUsedProfile = profileList.Count - 1; // 本方法在后台线程执行(阻塞网络请求),下面操作 WPF 控件,必须切回 UI 线程, // 否则触发线程亲和性异常——与本文件其他从后台线程刷新界面处一样用 RunInUi 包裹。 - ModBase.RunInUi(() => + UiThread.Post(() => { // 改名成功后正处于档案页(ProfileSkin),此时 RefreshPage 因目标页与当前页相同会提前 // 返回、不刷新显示的玩家 ID,需显式 Reload 当前档案页,使新 ID 立即生效。 diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs index 7424a3a45..cc63f90be 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompFavorites.xaml.cs @@ -44,7 +44,7 @@ public PageDownloadCompFavorites() PanSearchBox.TextChanged += SearchRun; WeakLanguageChanged.Add(this, OnLanguageChanged); } - private static void OnLanguageChanged(PageDownloadCompFavorites page) => ModBase.RunInUi(page._RefreshCategoryTitles); + private static void OnLanguageChanged(PageDownloadCompFavorites page) => UiThread.Post(page._RefreshCategoryTitles); private ModComp.CompFavorites.FavData CurrentFavTarget { diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.cs b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.cs index c75f569b6..06d3b2517 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.cs @@ -1055,7 +1055,7 @@ private void _RebuildVersionCards(JsonArray versions) _AddCategoryCards(dict, categoryOrder); } - private void _OnLanguageChanged() => ModBase.RunInUi(() => + private void _OnLanguageChanged() => UiThread.Post(() => { LoadMinecraft.Text = Lang.Text("Download.Version.LoadingList"); if (ModDownload.dlClientListLoader.output.Value?["versions"] is JsonArray versions) diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs index c47f11193..3eec21ee8 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.cs @@ -58,7 +58,7 @@ public PageLaunchLeft() PanLaunchingInfo.SizeChanged += PanLaunchingInfo_SizeChangedW; PanLaunchingInfo.SizeChanged += PanLaunchingInfo_SizeChangedH; } - private static void OnLanguageChanged(PageLaunchLeft page) => ModBase.RunInUi(page.RefreshButtonsUI); + private static void OnLanguageChanged(PageLaunchLeft page) => UiThread.Post(page.RefreshButtonsUI); public void PageLaunchLeft_Loaded(object sender, RoutedEventArgs e) { From ded03161e78ef1a3484161bc1d18dfff8ca028c6 Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 8 Jul 2026 20:38:49 +0800 Subject: [PATCH 14/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PCL.Core.Test/IO/DirectoriesTest.cs | 26 ++++- PCL.Core.Test/IO/FilesTest.cs | 61 ++++++++++++ PCL.Core.Test/Utils/PathUtilsTest.cs | 3 + PCL.Core/IO/Directories.cs | 7 +- PCL.Core/IO/Files.cs | 99 ++++++++++++------- PCL.Core/IO/PathUtils.cs | 24 +++-- .../Modules/Minecraft/ModLaunch.cs | 18 ++-- .../Modules/Minecraft/ModModpack.cs | 8 +- 8 files changed, 190 insertions(+), 56 deletions(-) create mode 100644 PCL.Core.Test/IO/FilesTest.cs diff --git a/PCL.Core.Test/IO/DirectoriesTest.cs b/PCL.Core.Test/IO/DirectoriesTest.cs index 12d0bfecf..dff538269 100644 --- a/PCL.Core.Test/IO/DirectoriesTest.cs +++ b/PCL.Core.Test/IO/DirectoriesTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -12,6 +13,8 @@ public class DirectoriesTest { private string _tempDir = null!; + public required TestContext TestContext { get; set; } + [TestInitialize] public void SetUp() { @@ -29,7 +32,7 @@ public void TearDown() [TestMethod] public async Task CheckPermissionAsyncUsesRealProbeFile() { - Assert.IsTrue(await Directories.CheckPermissionAsync(_tempDir)); + Assert.IsTrue(await Directories.CheckPermissionAsync(_tempDir, TestContext.CancellationToken)); Assert.AreEqual(0, Directory.EnumerateFiles(_tempDir, ".pcl-permission-*.tmp").Count()); } @@ -37,6 +40,25 @@ public async Task CheckPermissionAsyncUsesRealProbeFile() public async Task CheckPermissionAsyncReturnsFalseForMissingDirectory() { var missing = Path.Combine(_tempDir, "missing"); - Assert.IsFalse(await Directories.CheckPermissionAsync(missing)); + Assert.IsFalse(await Directories.CheckPermissionAsync(missing, TestContext.CancellationToken)); + } + + [TestMethod] + public async Task CopyDirectoryAsyncReportsIncrementalProgress() + { + var source = Path.Combine(_tempDir, "source"); + var target = Path.Combine(_tempDir, "target"); + Directory.CreateDirectory(source); + await File.WriteAllTextAsync(Path.Combine(source, "one.txt"), "1", TestContext.CancellationToken); + await File.WriteAllTextAsync(Path.Combine(source, "two.txt"), "2", TestContext.CancellationToken); + + var progress = new List(); + await Directories.CopyDirectoryAsync(source, target, progress.Add, TestContext.CancellationToken); + + Assert.HasCount(2, progress); + Assert.AreEqual(0.5d, progress[0], 0.0000001d); + Assert.AreEqual(0.5d, progress[1], 0.0000001d); + Assert.IsTrue(File.Exists(Path.Combine(target, "one.txt"))); + Assert.IsTrue(File.Exists(Path.Combine(target, "two.txt"))); } } \ No newline at end of file diff --git a/PCL.Core.Test/IO/FilesTest.cs b/PCL.Core.Test/IO/FilesTest.cs new file mode 100644 index 000000000..fa13677d8 --- /dev/null +++ b/PCL.Core.Test/IO/FilesTest.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PCL.Core.IO; + +namespace PCL.Core.Test.IO; + +[TestClass] +public class FilesTest +{ + private string _tempDir = null!; + + public required TestContext TestContext { get; set; } + + [TestInitialize] + public void SetUp() + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + _tempDir = Path.Combine(Path.GetTempPath(), "PCLCoreFilesTest", Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(_tempDir); + } + + [TestCleanup] + public void TearDown() + { + if (Directory.Exists(_tempDir)) + Directory.Delete(_tempDir, true); + } + + [TestMethod] + public async Task ExtractFileAsyncTreatsMrpackAsZipAndUsesArchiveEncoding() + { + var archivePath = Path.Combine(_tempDir, "pack.mrpack"); + var outputPath = Path.Combine(_tempDir, "out"); + var encoding = Encoding.GetEncoding("GB18030"); + + await using (var archive = await ZipFile.OpenAsync( + archivePath, + ZipArchiveMode.Create, + encoding, TestContext.CancellationToken)) + { + var entry = archive.CreateEntry("overrides/中文.txt"); + await using var stream = await entry.OpenAsync(TestContext.CancellationToken); + await using var writer = new StreamWriter(stream, Encoding.UTF8); + await writer.WriteAsync("ok"); + } + + var progress = new List(); + await Files.ExtractFileAsync(archivePath, outputPath, progress.Add, encoding, TestContext.CancellationToken); + + var extractedFile = Path.Combine(outputPath, "overrides", "中文.txt"); + Assert.IsTrue(File.Exists(extractedFile)); + Assert.AreEqual("ok", await File.ReadAllTextAsync(extractedFile, TestContext.CancellationToken)); + Assert.HasCount(1, progress); + Assert.AreEqual(1d, progress[0], 0.0000001d); + } +} \ No newline at end of file diff --git a/PCL.Core.Test/Utils/PathUtilsTest.cs b/PCL.Core.Test/Utils/PathUtilsTest.cs index 3d68ef092..8135381d6 100644 --- a/PCL.Core.Test/Utils/PathUtilsTest.cs +++ b/PCL.Core.Test/Utils/PathUtilsTest.cs @@ -8,8 +8,11 @@ public class PathUtilsTest { [TestMethod] [DataRow("https://example.com/files/core.jar?download=1", "core.jar")] + [DataRow("https://example.com/files/foo%231.jar?download=1", "foo#1.jar")] [DataRow(@"C:\\Games\\Minecraft\\core.jar", "core.jar")] + [DataRow(@"C:\Games\Minecraft\foo#1.jar", "foo#1.jar")] [DataRow("/tmp/a/b/core.jar", "core.jar")] + [DataRow("/tmp/a/b/foo#1.jar", "foo#1.jar")] public void GetsFileNameFromUrlOrPath(string path, string expected) { Assert.AreEqual(expected, PathUtils.GetFileNameFromUrlOrPath(path)); diff --git a/PCL.Core/IO/Directories.cs b/PCL.Core/IO/Directories.cs index e1611c954..9d256b579 100644 --- a/PCL.Core/IO/Directories.cs +++ b/PCL.Core/IO/Directories.cs @@ -193,7 +193,7 @@ public static async Task DeleteDirectoryAsync(string? path, bool ignoreIssu /// /// 源文件夹路径。 /// 目标文件夹路径。 - /// 进度更新回调,接收 0 到 1 的进度值。 + /// 进度增量回调,每复制一个文件传入本次增加的进度值。 /// 取消操作的令牌。 /// 源或目标文件夹路径为空。 /// 操作被取消。 @@ -212,7 +212,7 @@ public static async Task CopyDirectoryAsync(string? fromPath, string? toPath, Ac var allFiles = (await EnumerateFilesAsync(fromPath, cancellationToken).ConfigureAwait(false)).ToList(); var totalFiles = allFiles.Count; - long copiedFiles = 0; + var progressStep = totalFiles > 0 ? 1d / totalFiles : 1d; foreach (var file in allFiles) { cancellationToken.ThrowIfCancellationRequested(); @@ -226,8 +226,7 @@ public static async Task CopyDirectoryAsync(string? fromPath, string? toPath, Ac for (var attempt = 0; attempt < 2; attempt++) { try { await FileCopyAsync(file.FullName, destFilePath, overwrite: true, cancellationToken).ConfigureAwait(false); - copiedFiles++; - progressIncrementHandler?.Invoke((double)copiedFiles / totalFiles); + progressIncrementHandler?.Invoke(progressStep); break; } catch (Exception ex) when (attempt == 0) { LogWrapper.Error(ex, $"复制文件失败,将在 0.3s 后重试({file.FullName} 到 {destFilePath})"); diff --git a/PCL.Core/IO/Files.cs b/PCL.Core/IO/Files.cs index 5fc072e01..08219a2d5 100644 --- a/PCL.Core/IO/Files.cs +++ b/PCL.Core/IO/Files.cs @@ -12,6 +12,8 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; +using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; @@ -20,6 +22,7 @@ using System.Threading.Tasks; using System.Windows; using PCL.Core.App; +using ZipFile = System.IO.Compression.ZipFile; namespace PCL.Core.IO; @@ -356,43 +359,61 @@ public static async Task WriteFileAsync(string filePath, Stream? stream, C #region 文件解压 /// - /// 尝试根据文件后缀名判断文件种类并解压,支持 zip、gz、tar、tar.gz 和 bzip2。 - /// 会尝试将 jar 文件以 zip 方式解压。不会清空目标目录,但会创建不存在的目录。 + /// 尝试根据文件后缀名判断文件种类并解压,支持 zip、jar、mrpack、gz、tar、tar.gz 和 bzip2。 + /// 会尝试将 jar 与 mrpack 文件以 zip 方式解压。不会清空目标目录,但会创建不存在的目录。 /// /// 压缩文件路径 /// 目标解压目录 - /// 进度更新回调,接收 0.0 到 1.0 的进度值 + /// 进度增量回调,接收本次解压增加的进度值 + /// 归档文件名编码;为空时使用 GB18030 作为兼容回退。 /// 取消操作的令牌 /// 异步任务。 - /// 为 null 或空时抛出 + /// + /// 当 为 + /// null 或空时抛出 + /// /// 当文件格式不受支持时抛出 - public static async Task ExtractFileAsync(string? compressFilePath, string? destDirectory, Action? progressIncrementHandler = null, - CancellationToken cancellationToken = default) { - if (string.IsNullOrEmpty(compressFilePath)) { + public static async Task ExtractFileAsync( + string? compressFilePath, + string? destDirectory, + Action? progressIncrementHandler = null, + Encoding? archiveEncoding = null, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(compressFilePath)) + { LogWrapper.Error(new ArgumentNullException(nameof(compressFilePath)), "压缩文件路径为空"); return; } - if (string.IsNullOrEmpty(destDirectory)) { + if (string.IsNullOrEmpty(destDirectory)) + { LogWrapper.Error(new ArgumentNullException(nameof(destDirectory)), "目标目录路径为空"); return; } - try { + try + { Directory.CreateDirectory(destDirectory); // 创建目标目录(同步操作,因为通常很快且无异步版本) - if (compressFilePath.EndsWithF(".gz") || compressFilePath.EndsWithF(".tgz")) { - await _ExtractGZipAsync(compressFilePath, destDirectory, progressIncrementHandler, cancellationToken).ConfigureAwait(false); - } else if (compressFilePath.EndsWithF(".bz2")) { - await _ExtractBZip2Async(compressFilePath, destDirectory, progressIncrementHandler, cancellationToken).ConfigureAwait(false); - } else if (compressFilePath.EndsWithF(".tar")) { - await _ExtractTarAsync(compressFilePath, destDirectory, progressIncrementHandler, cancellationToken).ConfigureAwait(false); - } else if (compressFilePath.EndsWithF(".zip") || compressFilePath.EndsWithF(".jar")) { - await _ExtractZipAsync(compressFilePath, destDirectory, progressIncrementHandler, cancellationToken).ConfigureAwait(false); - } else { + if (compressFilePath.EndsWithF(".gz") || compressFilePath.EndsWithF(".tgz")) + await _ExtractGZipAsync(compressFilePath, destDirectory, progressIncrementHandler, archiveEncoding, + cancellationToken).ConfigureAwait(false); + else if (compressFilePath.EndsWithF(".bz2")) + await _ExtractBZip2Async(compressFilePath, destDirectory, progressIncrementHandler, cancellationToken) + .ConfigureAwait(false); + else if (compressFilePath.EndsWithF(".tar")) + await _ExtractTarAsync(compressFilePath, destDirectory, progressIncrementHandler, archiveEncoding, + cancellationToken).ConfigureAwait(false); + else if (compressFilePath.EndsWithF(".zip") || compressFilePath.EndsWithF(".jar") || + compressFilePath.EndsWithF(".mrpack")) + await _ExtractZipAsync(compressFilePath, destDirectory, progressIncrementHandler, archiveEncoding, + cancellationToken).ConfigureAwait(false); + else throw new NotSupportedException("不支持的压缩文件格式"); - } - } catch (Exception ex) { + } + catch (Exception ex) + { LogWrapper.Error(ex, $"解压文件 {compressFilePath} 失败"); throw; } @@ -405,6 +426,7 @@ private static async Task _ExtractGZipAsync( string compressFilePath, string destDirectory, Action? progressIncrementHandler, + Encoding? archiveEncoding, CancellationToken cancellationToken) { var outputFileName = Path.GetFileName(compressFilePath).ToLower(); @@ -424,7 +446,7 @@ private static async Task _ExtractGZipAsync( if (isTarGZip) { // 处理 .tgz / .tar.gz 文件 - await using TarInputStream tarStream = new(gzipStream, Encoding.UTF8); + await using TarInputStream tarStream = new(gzipStream, archiveEncoding ?? Encoding.GetEncoding("GB18030")); await _ExtractTarStreamAsync( tarStream, @@ -479,10 +501,11 @@ private static async Task _ExtractTarAsync( string compressFilePath, string destDirectory, Action? progressIncrementHandler, + Encoding? archiveEncoding, CancellationToken cancellationToken) { await using FileStream compressedFile = new(compressFilePath, FileMode.Open, FileAccess.Read); - await using TarInputStream tarStream = new(compressedFile, Encoding.UTF8); + await using TarInputStream tarStream = new(compressedFile, archiveEncoding ?? Encoding.GetEncoding("GB18030")); await _ExtractTarStreamAsync( tarStream, @@ -606,24 +629,33 @@ await Task } /// - /// 异步解压 Zip 文件(包括 .zip 和 .jar)。 + /// 异步解压 Zip 文件(包括 .zip、.jar 和 .mrpack)。 /// private static async Task _ExtractZipAsync( string compressFilePath, string destDirectory, Action? progressIncrementHandler, + Encoding? archiveEncoding, CancellationToken cancellationToken) { - using ZipFile zipFile = new(compressFilePath); - - var totalEntries = zipFile.Count; - long currentEntry = 0; - - foreach (ZipEntry entry in zipFile) + await using var archive = await ZipFile.OpenAsync( + compressFilePath, + ZipArchiveMode.Read, + archiveEncoding ?? Encoding.GetEncoding("GB18030"), + cancellationToken); + + var fileEntries = archive.Entries + .Where(entry => !entry.FullName.EndsWith('/') && !entry.FullName.EndsWith('\\')) + .ToList(); + var progressStep = fileEntries.Count > 0 ? 1d / fileEntries.Count : 1d; + + foreach (var entry in archive.Entries) { - var destinationPath = _GetSafePath(destDirectory, entry.Name); + cancellationToken.ThrowIfCancellationRequested(); + + var destinationPath = _GetSafePath(destDirectory, entry.FullName); - if (entry.IsDirectory) + if (entry.FullName.EndsWith('/') || entry.FullName.EndsWith('\\')) { Directory.CreateDirectory(destinationPath); continue; @@ -631,15 +663,14 @@ private static async Task _ExtractZipAsync( Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)!); - await using var zipStream = zipFile.GetInputStream(entry); + await using var zipStream = await entry.OpenAsync(cancellationToken); await using FileStream outputStream = new(destinationPath, FileMode.Create, FileAccess.Write); await zipStream .CopyToAsync(outputStream, cancellationToken) .ConfigureAwait(false); - currentEntry++; - progressIncrementHandler?.Invoke((double)currentEntry / totalEntries); + progressIncrementHandler?.Invoke(progressStep); } } diff --git a/PCL.Core/IO/PathUtils.cs b/PCL.Core/IO/PathUtils.cs index cae8212ee..6b544eb92 100644 --- a/PCL.Core/IO/PathUtils.cs +++ b/PCL.Core/IO/PathUtils.cs @@ -42,22 +42,15 @@ public static string GetDirectoryPart(string path) } /// - /// 从本地路径或 URL 中提取文件名,URL 查询字符串与片段会被忽略。 + /// 从本地路径或 URL 中提取文件名;只有远程 URL 的查询字符串与片段会被忽略。 /// public static string GetFileNameFromUrlOrPath(string path) { ArgumentException.ThrowIfNullOrEmpty(path); path = path.Trim(' ', '"'); - if (Uri.TryCreate(path, UriKind.Absolute, out var uri) && !string.IsNullOrEmpty(uri.LocalPath)) - { + if (_TryCreateRemoteUri(path, out var uri) && !string.IsNullOrEmpty(uri.LocalPath)) path = Uri.UnescapeDataString(uri.LocalPath); - } - else - { - var queryIndex = path.IndexOfAny(['?', '#']); - if (queryIndex >= 0) path = path[..queryIndex]; - } if (_EndsWithDirectorySeparator(path)) throw new ArgumentException($"不包含文件名:{path}", nameof(path)); @@ -73,6 +66,19 @@ public static string GetFileNameFromUrlOrPath(string path) }; } + private static bool _TryCreateRemoteUri(string path, out Uri uri) + { + if (!Uri.TryCreate(path, UriKind.Absolute, out uri!)) + return false; + + if (uri.IsFile || uri.Scheme.Length <= 1) + return false; + + return uri.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) + || uri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) + || uri.Scheme.Equals(Uri.UriSchemeFtp, StringComparison.OrdinalIgnoreCase); + } + public static string GetFileNameWithoutExtensionFromUrlOrPath(string path) { return Path.GetFileNameWithoutExtension(GetFileNameFromUrlOrPath(path)); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs index d58e02e1d..29f306979 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs @@ -3187,9 +3187,12 @@ private static void McLaunchPrerun() }"; var replaceJson = (JsonObject)JsonCompat.ParseNode(replaceJsonString); // 更新文件 - var profiles = - (JsonObject)JsonCompat.ParseNode( - Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(ModFolder.mcFolderSelected + "launcher_profiles.json")).GetAwaiter().GetResult()); + var profiles = (JsonObject)JsonCompat.ParseNode( + Files.ReadAllTextOrEmptyAsync( + LauncherFileSystem.ResolvePath(ModFolder.mcFolderSelected + "launcher_profiles.json"), + Encoding.GetEncoding("GB18030")) + .GetAwaiter() + .GetResult()); profiles.Merge(replaceJson); Files.WriteFileAsync(LauncherFileSystem.ResolvePath(ModFolder.mcFolderSelected + "launcher_profiles.json"), profiles.ToString(), encoding: Encoding.GetEncoding("GB18030")).GetAwaiter().GetResult(); McLaunchLog("已更新 launcher_profiles.json"); @@ -3222,9 +3225,12 @@ private static void McLaunchPrerun() }"; var replaceJson = (JsonObject)JsonCompat.ParseNode(replaceJsonString); // 更新文件 - var profiles = - (JsonObject)JsonCompat.ParseNode( - Files.ReadAllTextOrEmptyAsync(LauncherFileSystem.ResolvePath(ModFolder.mcFolderSelected + "launcher_profiles.json")).GetAwaiter().GetResult()); + var profiles = (JsonObject)JsonCompat.ParseNode( + Files.ReadAllTextOrEmptyAsync( + LauncherFileSystem.ResolvePath(ModFolder.mcFolderSelected + "launcher_profiles.json"), + Encoding.GetEncoding("GB18030")) + .GetAwaiter() + .GetResult()); profiles.Merge(replaceJson); Files.WriteFileAsync(LauncherFileSystem.ResolvePath(ModFolder.mcFolderSelected + "launcher_profiles.json"), profiles.ToString(), encoding: Encoding.GetEncoding("GB18030")).GetAwaiter().GetResult(); McLaunchLog("已在删除后更新 launcher_profiles.json"); diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs index 23cf155a0..7807fd71a 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.cs @@ -263,7 +263,13 @@ private static void ExtractModpackFiles(string installTemp, string fileAddress, Directories.DeleteDirectoryAsync(installTemp).GetAwaiter().GetResult(); // 解压文件,ProgressIncrementHandler 通过 Lambda 更新进度 - Files.ExtractFileAsync(fileAddress, installTemp, delta => loader.Progress += delta * progressIncrement).GetAwaiter().GetResult(); + Files.ExtractFileAsync( + fileAddress, + installTemp, + delta => loader.Progress += delta * progressIncrement, + encode) + .GetAwaiter() + .GetResult(); // 解压成功,更新进度并退出循环 loader.Progress = initialProgress + progressIncrement; From 7b46b905d997e15a21b0b87f3ceb40367f9266ee Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 8 Jul 2026 20:53:09 +0800 Subject: [PATCH 15/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=AD=BB=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PCL.Core/IO/Files.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/PCL.Core/IO/Files.cs b/PCL.Core/IO/Files.cs index 08219a2d5..c439caa4a 100644 --- a/PCL.Core/IO/Files.cs +++ b/PCL.Core/IO/Files.cs @@ -204,7 +204,7 @@ public static async Task ReadAllBytesOrEmptyAsync(string filePath, Cance var fullPath = GetFullPath(filePath); if (File.Exists(fullPath)) { // 使用 ReadAllBytesAsync - return await File.ReadAllBytesAsync(fullPath, cancelToken); + return await File.ReadAllBytesAsync(fullPath, cancelToken).ConfigureAwait(false); } throw new FileNotFoundException(fullPath); } catch (Exception ex) { @@ -224,8 +224,8 @@ public static async Task ReadAllTextOrEmptyAsync(string filePath, Encodi try { var fullPath = GetFullPath(filePath); if (!File.Exists(fullPath)) throw new FileNotFoundException(fullPath); - if (encoding is null) return await File.ReadAllTextAsync(fullPath, cancelToken); - return await File.ReadAllTextAsync(fullPath, encoding, cancelToken); + if (encoding is null) return await File.ReadAllTextAsync(fullPath, cancelToken).ConfigureAwait(false); + return await File.ReadAllTextAsync(fullPath, encoding, cancelToken).ConfigureAwait(false); } catch (Exception ex) { LogWrapper.Warn(ex, $"读取文件出错:{filePath}"); return ""; @@ -243,7 +243,7 @@ public static async Task ReadAllTextOrEmptyAsync(Stream stream, Encoding try { ArgumentNullException.ThrowIfNull(stream); using var memoryStream = new MemoryStream(); - await stream.CopyToAsync(memoryStream, cancelToken); + await stream.CopyToAsync(memoryStream, cancelToken).ConfigureAwait(false); // 使用 MemoryStream 的内部 buffer 避免再分配一次完整的 byte 数组以节省内存 // 注:内部 buffer 长度可能大于实际数据长度 var buffer = memoryStream.GetBuffer(); @@ -269,7 +269,7 @@ public static async Task ReadFileToStreamOrEmptyAsync(string fileP await using var fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true); var memoryStream = new MemoryStream(); - await fileStream.CopyToAsync(memoryStream, cancelToken); + await fileStream.CopyToAsync(memoryStream, cancelToken).ConfigureAwait(false); memoryStream.Position = 0; // 重置流位置以便后续读取 return memoryStream; } catch (Exception ex) { @@ -299,10 +299,10 @@ public static async Task WriteFileAsync(string filePath, string text, bool appen await using (var fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) encoding ??= EncodingDetector.DetectEncoding(fileStream); // 注:从此处开始,编码检测使用的 stream 已经销毁 - await File.AppendAllTextAsync(fullPath, text, encoding, cancelToken); + await File.AppendAllTextAsync(fullPath, text, encoding, cancelToken).ConfigureAwait(false); } else { encoding ??= new UTF8Encoding(false); // 无 BOM 的 UTF-8 - await File.WriteAllTextAsync(fullPath, text, encoding, cancelToken); + await File.WriteAllTextAsync(fullPath, text, encoding, cancelToken).ConfigureAwait(false); } } @@ -324,7 +324,7 @@ public static async Task WriteFileAsync(string filePath, byte[] content, bool ap var fileMode = append ? FileMode.Append : FileMode.Create; await using var fileStream = new FileStream(fullPath, fileMode, FileAccess.Write, FileShare.Read); - await fileStream.WriteAsync(content.AsMemory(), cancelToken); + await fileStream.WriteAsync(content.AsMemory(), cancelToken).ConfigureAwait(false); } /// From bbb06ba48133a0ea4e1fd8c5b3771835cf245f1d Mon Sep 17 00:00:00 2001 From: ClovenBugle Date: Wed, 8 Jul 2026 21:35:00 +0800 Subject: [PATCH 16/16] =?UTF-8?q?=E5=90=8E=E7=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PCL.Core.Test/IO/FilesTest.cs | 29 +++++++++++++++++++++++++++++ PCL.Core/IO/Files.cs | 10 +++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/PCL.Core.Test/IO/FilesTest.cs b/PCL.Core.Test/IO/FilesTest.cs index fa13677d8..59315a34c 100644 --- a/PCL.Core.Test/IO/FilesTest.cs +++ b/PCL.Core.Test/IO/FilesTest.cs @@ -58,4 +58,33 @@ public async Task ExtractFileAsyncTreatsMrpackAsZipAndUsesArchiveEncoding() Assert.HasCount(1, progress); Assert.AreEqual(1d, progress[0], 0.0000001d); } + + [TestMethod] + public async Task ExtractFileAsyncAcceptsZipArchiveExtensionsCaseInsensitively() + { + var encoding = Encoding.GetEncoding("GB18030"); + + foreach (var fileName in new[] { "PACK.ZIP", "foo.JAR", "pack.MRPACK" }) + { + var archivePath = Path.Combine(_tempDir, fileName); + var outputPath = Path.Combine(_tempDir, Path.GetFileNameWithoutExtension(fileName) + "-out"); + + await using (var archive = await ZipFile.OpenAsync( + archivePath, + ZipArchiveMode.Create, + encoding, TestContext.CancellationToken)) + { + var entry = archive.CreateEntry("overrides/uppercase-extension.txt"); + await using var stream = await entry.OpenAsync(TestContext.CancellationToken); + await using var writer = new StreamWriter(stream, Encoding.UTF8); + await writer.WriteAsync("ok"); + } + + await Files.ExtractFileAsync(archivePath, outputPath, null, encoding, TestContext.CancellationToken); + + var extractedFile = Path.Combine(outputPath, "overrides", "uppercase-extension.txt"); + Assert.IsTrue(File.Exists(extractedFile), $"Failed to extract {fileName}"); + Assert.AreEqual("ok", await File.ReadAllTextAsync(extractedFile, TestContext.CancellationToken)); + } + } } \ No newline at end of file diff --git a/PCL.Core/IO/Files.cs b/PCL.Core/IO/Files.cs index c439caa4a..7f7fadc4f 100644 --- a/PCL.Core/IO/Files.cs +++ b/PCL.Core/IO/Files.cs @@ -396,17 +396,17 @@ public static async Task ExtractFileAsync( { Directory.CreateDirectory(destDirectory); // 创建目标目录(同步操作,因为通常很快且无异步版本) - if (compressFilePath.EndsWithF(".gz") || compressFilePath.EndsWithF(".tgz")) + if (compressFilePath.EndsWithF(".gz", true) || compressFilePath.EndsWithF(".tgz", true)) await _ExtractGZipAsync(compressFilePath, destDirectory, progressIncrementHandler, archiveEncoding, cancellationToken).ConfigureAwait(false); - else if (compressFilePath.EndsWithF(".bz2")) + else if (compressFilePath.EndsWithF(".bz2", true)) await _ExtractBZip2Async(compressFilePath, destDirectory, progressIncrementHandler, cancellationToken) .ConfigureAwait(false); - else if (compressFilePath.EndsWithF(".tar")) + else if (compressFilePath.EndsWithF(".tar", true)) await _ExtractTarAsync(compressFilePath, destDirectory, progressIncrementHandler, archiveEncoding, cancellationToken).ConfigureAwait(false); - else if (compressFilePath.EndsWithF(".zip") || compressFilePath.EndsWithF(".jar") || - compressFilePath.EndsWithF(".mrpack")) + else if (compressFilePath.EndsWithF(".zip", true) || compressFilePath.EndsWithF(".jar", true) || + compressFilePath.EndsWithF(".mrpack", true)) await _ExtractZipAsync(compressFilePath, destDirectory, progressIncrementHandler, archiveEncoding, cancellationToken).ConfigureAwait(false); else