LTCat 2 ماه پیش
والد
کامیت
7fb6e5d68e
61فایلهای تغییر یافته به همراه1184 افزوده شده و 929 حذف شده
  1. 1 1
      MeloongCore
  2. 246 0
      PCLCS/.editorconfig
  3. 15 6
      PCLCS/Configs.cs
  4. 5 4
      PCLCS/Constants.cs
  5. 64 30
      PCLCS/Java.cs
  6. 0 0
      PCLCS/Launch/JavaWrapper.jar
  7. 30 0
      PCLCS/Launch/LaunchUtils.cs
  8. 0 0
      PCLCS/Launch/LwjglUnsafeAgent.jar
  9. 2 1
      PCLCS/PCLCS.csproj
  10. 0 2
      PCLCS/Resource/Resource.cs
  11. 119 119
      PCLCS/Resource/WikiEntries.txt
  12. 0 31
      Plain Craft Launcher 2/Application.xaml
  13. 4 17
      Plain Craft Launcher 2/Application.xaml.vb
  14. 1 2
      Plain Craft Launcher 2/Controls/MyLoading.xaml.vb
  15. 0 3
      Plain Craft Launcher 2/Controls/MyScrollViewer.vb
  16. 2 2
      Plain Craft Launcher 2/FormMain.xaml
  17. 25 12
      Plain Craft Launcher 2/FormMain.xaml.vb
  18. BIN
      Plain Craft Launcher 2/Images/Heads/HerobrineXia.png
  19. 3 3
      Plain Craft Launcher 2/Modules/Base/ModAnimation.vb
  20. 9 58
      Plain Craft Launcher 2/Modules/Base/ModBase.vb
  21. 4 4
      Plain Craft Launcher 2/Modules/Base/ModNet.vb
  22. 11 8
      Plain Craft Launcher 2/Modules/Base/ModValidate.vb
  23. 4 3
      Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
  24. 25 19
      Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
  25. 48 50
      Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
  26. 35 11
      Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
  27. 3 3
      Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
  28. 24 43
      Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
  29. 7 3
      Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb
  30. 28 22
      Plain Craft Launcher 2/Modules/ModEvent.vb
  31. 17 19
      Plain Craft Launcher 2/Modules/ModMain.vb
  32. 1 3
      Plain Craft Launcher 2/Modules/Resource/ResourceProject.vb
  33. 0 5
      Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb
  34. 1 1
      Plain Craft Launcher 2/Modules/Resource/ResourceVersion.vb
  35. 2 2
      Plain Craft Launcher 2/My Project/AssemblyInfo.vb
  36. 5 25
      Plain Craft Launcher 2/My Project/Resources.Designer.vb
  37. 3 6
      Plain Craft Launcher 2/My Project/Resources.resx
  38. 2 37
      Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
  39. 1 1
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
  40. 2 5
      Plain Craft Launcher 2/Pages/PageDownload/Resource/PageDownloadCompDetail.xaml.vb
  41. 1 1
      Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml
  42. 13 1
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml
  43. 19 5
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.vb
  44. 4 1
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceMod.xaml.vb
  45. 6 12
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml
  46. 14 3
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.vb
  47. 3 3
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.vb
  48. 6 0
      Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
  49. 1 1
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml
  50. 1 1
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb
  51. 6 2
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml
  52. 1 1
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml
  53. 2 2
      Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb
  54. 313 312
      Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
  55. 3 0
      Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml.vb
  56. 4 1
      Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb
  57. 0 3
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml
  58. 2 0
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml
  59. 17 5
      Plain Craft Launcher 2/Pages/PageSetup/Settings.vb
  60. 14 14
      Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb
  61. 5 0
      Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj

+ 1 - 1
MeloongCore

@@ -1 +1 @@
-Subproject commit e5c8e65e2b4c4c7de5a6a6f56508edf2c0175aff
+Subproject commit 8bfb4f709f78a528a40e0bd48e6f77bef0e07e24

+ 246 - 0
PCLCS/.editorconfig

@@ -0,0 +1,246 @@
+# 如果要从更高级别的目录继承 .editorconfig 设置,请删除以下行
+root = true
+
+# c# 文件
+[*.cs]
+
+#### Core EditorConfig 选项 ####
+
+# 缩进和间距
+indent_size = 4
+indent_style = space
+tab_width = 4
+
+# 新行首选项
+end_of_line = crlf
+insert_final_newline = false
+
+#### .NET 代码操作 ####
+
+# 类型成员
+dotnet_hide_advanced_members = false
+dotnet_member_insertion_location = with_other_members_of_the_same_kind
+dotnet_property_generation_behavior = prefer_throwing_properties
+
+# 符号搜索
+dotnet_search_reference_assemblies = true
+
+#### .NET 编码约定 ####
+
+# 组织 Using
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = false
+file_header_template = unset
+
+# this. 和 Me. 首选项
+dotnet_style_qualification_for_event = false
+dotnet_style_qualification_for_field = false
+dotnet_style_qualification_for_method = false
+dotnet_style_qualification_for_property = false
+
+# 语言关键字与 bcl 类型首选项
+dotnet_style_predefined_type_for_locals_parameters_members = true
+dotnet_style_predefined_type_for_member_access = true
+
+# 括号首选项
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
+
+# 修饰符首选项
+dotnet_style_require_accessibility_modifiers = for_non_interface_members
+
+# 表达式级首选项
+dotnet_prefer_system_hash_code = true
+dotnet_style_coalesce_expression = true
+dotnet_style_collection_initializer = true
+dotnet_style_explicit_tuple_names = true
+dotnet_style_namespace_match_folder = true
+dotnet_style_null_propagation = true
+dotnet_style_object_initializer = true
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true:suggestion
+dotnet_style_prefer_collection_expression = when_types_loosely_match
+dotnet_style_prefer_compound_assignment = true
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
+dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
+dotnet_style_prefer_inferred_anonymous_type_member_names = true
+dotnet_style_prefer_inferred_tuple_names = true
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true
+dotnet_style_prefer_simplified_boolean_expressions = true
+dotnet_style_prefer_simplified_interpolation = true
+
+# 字段首选项
+dotnet_style_readonly_field = true
+
+# 参数首选项
+dotnet_code_quality_unused_parameters = all
+
+# 禁止显示首选项
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+# 新行首选项
+dotnet_style_allow_multiple_blank_lines_experimental = true
+dotnet_style_allow_statement_immediately_after_block_experimental = true
+
+#### c# 编码约定 ####
+
+# var 首选项
+csharp_style_var_elsewhere = false
+csharp_style_var_for_built_in_types = false
+csharp_style_var_when_type_is_apparent = false
+
+# Expression-bodied 成员
+csharp_style_expression_bodied_accessors = true
+csharp_style_expression_bodied_constructors = false
+csharp_style_expression_bodied_indexers = true
+csharp_style_expression_bodied_lambdas = true
+csharp_style_expression_bodied_local_functions = false
+csharp_style_expression_bodied_methods = false
+csharp_style_expression_bodied_operators = false
+csharp_style_expression_bodied_properties = true
+
+# 模式匹配首选项
+csharp_style_pattern_matching_over_as_with_null_check = true
+csharp_style_pattern_matching_over_is_with_cast_check = true
+csharp_style_prefer_extended_property_pattern = true
+csharp_style_prefer_not_pattern = true
+csharp_style_prefer_pattern_matching = true:suggestion
+csharp_style_prefer_switch_expression = true
+
+# Null 检查首选项
+csharp_style_conditional_delegate_call = true
+
+# 修饰符首选项
+csharp_prefer_static_anonymous_function = true
+csharp_prefer_static_local_function = true
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
+csharp_style_prefer_readonly_struct = true
+csharp_style_prefer_readonly_struct_member = true
+
+# 代码块首选项
+csharp_prefer_braces = true
+csharp_prefer_simple_using_statement = true
+csharp_prefer_system_threading_lock = true
+csharp_style_namespace_declarations = file_scoped:suggestion
+csharp_style_prefer_method_group_conversion = true
+csharp_style_prefer_primary_constructors = true
+csharp_style_prefer_top_level_statements = true
+
+# 表达式级首选项
+csharp_prefer_simple_default_expression = true
+csharp_style_deconstructed_variable_declaration = true
+csharp_style_implicit_object_creation_when_type_is_apparent = true
+csharp_style_inlined_variable_declaration = true
+csharp_style_prefer_implicitly_typed_lambda_expression = true
+csharp_style_prefer_index_operator = true
+csharp_style_prefer_local_over_anonymous_function = true
+csharp_style_prefer_null_check_over_type_check = true
+csharp_style_prefer_range_operator = true
+csharp_style_prefer_tuple_swap = true
+csharp_style_prefer_unbound_generic_type_in_nameof = true
+csharp_style_prefer_utf8_string_literals = true
+csharp_style_throw_expression = true
+csharp_style_unused_value_assignment_preference = discard_variable
+csharp_style_unused_value_expression_statement_preference = discard_variable
+
+# "using" 指令首选项
+csharp_using_directive_placement = outside_namespace
+
+# 新行首选项
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
+csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
+csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
+csharp_style_allow_embedded_statements_on_same_line_experimental = true
+
+#### C# 格式规则 ####
+
+# 新行首选项
+csharp_new_line_before_catch = false
+csharp_new_line_before_else = false
+csharp_new_line_before_finally = false
+csharp_new_line_before_members_in_anonymous_types = false
+csharp_new_line_before_members_in_object_initializers = false
+csharp_new_line_before_open_brace = none
+csharp_new_line_between_query_expression_clauses = false
+
+# 缩进首选项
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = false
+csharp_indent_labels = flush_left
+csharp_indent_switch_labels = false
+
+# 空格键首选项
+csharp_space_after_cast = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = ignore
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# 包装首选项
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+#### 命名样式 ####
+
+# 命名规则
+
+dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
+dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
+dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
+
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
+dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
+
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
+dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
+
+# 符号规范
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers = 
+
+dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.类型.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.类型.required_modifiers = 
+
+dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
+dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.非字段成员.required_modifiers = 
+
+# 命名样式
+
+dotnet_naming_style.帕斯卡拼写法.required_prefix = 
+dotnet_naming_style.帕斯卡拼写法.required_suffix = 
+dotnet_naming_style.帕斯卡拼写法.word_separator = 
+dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
+
+dotnet_naming_style.以_i_开始.required_prefix = I
+dotnet_naming_style.以_i_开始.required_suffix = 
+dotnet_naming_style.以_i_开始.word_separator = 
+dotnet_naming_style.以_i_开始.capitalization = pascal_case

+ 15 - 6
PCLCS/Configs.cs

@@ -2,10 +2,19 @@ namespace PCLCS;
 public static class Configs {
 
     /// <summary>当前 Java 相关配置的版本。0 代表尚未从老的 Settings 系统中迁移。</summary>
-    public static readonly ConfigEntry<int> JavaConfigVersion = new(nameof(JavaConfigVersion), 0);
-    public static readonly ConfigEntry<ConcurrentList<Java>> JavaList = new(nameof(JavaList), []);
-    public static readonly ConfigEntry<List<string>> JavaRemovedList = new(nameof(JavaRemovedList), []);
-    public static readonly ConfigEntry<bool> InstanceMigratedJava = new(nameof(InstanceMigratedJava), false);
-    public static readonly ConfigEntry<Java> InstanceForcedJava = new(nameof(InstanceForcedJava), null);
+    public static readonly ConfigEntry<int> JavaConfigVersion = new("JavaConfigVersion", 0);
+    public static readonly ConfigEntry<ConcurrentList<Java>> JavaList = new("JavaList", []);
+    public static readonly ConfigEntry<List<string>> JavaRemovedList = new("JavaRemovedList", []);
+    public static readonly DynamicConfigEntry<bool> JavaMigrated = new("InstanceMigratedJava", false);
+    public static readonly DynamicConfigEntry<Java> JavaForced = new("InstanceForcedJava", null);
 
-}
+    static Configs() {
+        /// 当 JavaForced 获取到一个不在 JavaList 中的值时,将其重置为 null。
+        JavaForced.PreviewGet += (args, provider) => {
+            if (args.Value is not null && !JavaList.Get()!.Contains(args.Value)) {
+                args.Value = null;
+                JavaForced.Reset(provider);
+            }
+        };
+    }
+}

+ 5 - 4
PCLCS/Constants.cs

@@ -17,10 +17,12 @@ public enum ResourceTypes {
     DataPack = 16,
     /// <summary>服务端插件。</summary>
     Plugin = 32,
+    /// <summary>地图。</summary>
+    Map = 64,
     /// <summary>同时包含数据包以及 Mod。</summary>
     ModOrDataPack = Mod | DataPack,
     /// <summary>允许任意种类,或种类未知。</summary>
-    Any = Mod | ModPack | ResourcePack | Shader | DataPack | Plugin,
+    Any = Mod | ModPack | ResourcePack | Shader | DataPack | Plugin | Map,
 }
 
 /// <summary>
@@ -42,9 +44,8 @@ public enum ModLoaders {
     Forge = 1,
     LiteLoader = 2,
     Fabric = 4,
-    Quilt = 8,
     NeoForge = 16,
-    All = Forge | LiteLoader | Fabric | Quilt | NeoForge,
+    All = Forge | LiteLoader | Fabric | NeoForge,
 }
 
 /// <summary>
@@ -67,7 +68,7 @@ public static class Versions {
     /// <summary>
     /// 版本管理中 Mod 信息缓存的版本号。
     /// </summary>
-    public const int LocalModCacheVersion = 17;
+    public const int LocalModCacheVersion = 18;
     /// <summary>
     /// Minecraft 本地实例信息缓存的版本号。
     /// </summary>

+ 64 - 30
PCLCS/Java.cs

@@ -19,6 +19,13 @@ namespace PCLCS;
     /// <para/> 若为 null,则还需要调用 <see cref="CheckAsync"/> 以获取版本号。
     /// </summary>
     public Version? Version = version;
+    /// <summary>Java 的默认字符编码。</summary>
+    [JsonIgnore] public string? FileEncodingName;
+    /// <summary>
+    /// Java 根据系统环境确定的本地字符编码,仅 Java 17+ 可用。
+    /// <para/>若系统开启了 UTF-8,部分 Java 会错误地返回 JDK,因此不能使用 <see cref="Encoding.Default"/>。
+    /// </summary>
+    [JsonIgnore] public string? NativeEncodingName;
 
     /// <summary>
     /// 检查该 Java 是否存在问题,并获取其版本号。
@@ -31,12 +38,12 @@ namespace PCLCS;
             if (!FileUtils.Exists(JavaExePath)) throw new FileNotFoundException("未找到 java.exe 文件", JavaExePath);
 
             // 运行 -version
-            output = (await TaskUtils.RunProgramAsync(JavaExePath, "-version", 15000, cancellationToken: cancellationToken).NoCapture()).Output.Lower();
+            output = (await TaskUtils.RunProgramAsync(JavaExePath, "-XshowSettings:properties -version", 15000, cancellationToken: cancellationToken).NoCapture()).Output.Lower();
             if (output == "") throw new InvalidOperationException("尝试运行该 Java 失败");
             Logger.Trace($"Java 检查输出:{JavaExePath}{Environment.NewLine}{output}");
             if (output.Contains("/lib/ext exists")) throw new InvalidOperationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试");
             if (output.Contains("a fatal error") || output.Contains("error: ")) throw new InvalidOperationException("无法运行该 Java,该 Java 或系统存在问题");
-
+           
             // 获取版本号
             var versionString = (output.RegexSeek(@"(?<=version "")[^""]+") ?? output.RegexSeek("(?<=openjdk )[0-9]+"))?.Replace("_", ".").Replace("+", ".").BeforeFirst("-");
             if (string.IsNullOrEmpty(versionString)) throw new InvalidOperationException($"未找到该 Java 的版本号{(output.Length < 500 ? $"\n原始输出为:\n{output}" : "")}");
@@ -46,7 +53,16 @@ namespace PCLCS;
             Version = new Version(segments.Take(4).Join("."));
             if (Version.Major is <= 4 or >= 100) throw new InvalidOperationException($"分析详细信息失败,获取的版本为 {Version}{(output.Length < 500 ? $"\n原始输出为:\n{output}" : "")}");
 
+            // 获取 Java 的相关属性
             if (!output.Contains("64-bit")) throw new InvalidOperationException("该 Java 为 32 位版本,请安装 64 位的 Java");
+            string? GetProperty(string name) {
+                string prefix = name + " = ";
+                string? line = output.Split('\n').Select(l => l.Trim()).FirstOrDefault(l => l.StartsWithF(prefix));
+                return line?[prefix.Length..].Trim();
+            }
+            FileEncodingName = GetProperty("file.encoding");
+            NativeEncodingName = GetProperty("native.encoding") ?? FileEncodingName; // 旧版本没有 native.encoding
+
             Logger.Info($"检查 Java 成功:{this}");
             available = true;
         } catch (Exception ex) {
@@ -59,6 +75,12 @@ namespace PCLCS;
         }
         return available!.Value;
     }
+
+    public void InvalidateChecked() {
+        isChecked = 0;
+        available = null;
+    }
+
     [JsonIgnore] private int isChecked = 0;
     /// <summary>若已进行过检查,表示该检查是否成功。若未检查,则为 null。</summary>
     [JsonIgnore] internal bool? available = null;
@@ -95,8 +117,8 @@ public static class JavaUtils {
         javas = await JavaUtils.CheckAllAsync(javas, cancellationToken, progress).NoCapture();
         javas.Sort((left, right) => {
             // 优先使用带完整 Java 的文件夹列表中的 Java
-            var isLeftInCandidateFolder = JavaUtils.CandidateFolders.Any(folder => PathUtils.IsParentOf(folder, left.Folder));
-            var isRightInCandidateFolder = JavaUtils.CandidateFolders.Any(folder => PathUtils.IsParentOf(folder, right.Folder));
+            var isLeftInCandidateFolder = JavaUtils.CandidateFolders.Value.Any(folder => PathUtils.IsParentOf(folder, left.Folder));
+            var isRightInCandidateFolder = JavaUtils.CandidateFolders.Value.Any(folder => PathUtils.IsParentOf(folder, right.Folder));
             if (isLeftInCandidateFolder != isRightInCandidateFolder) return isLeftInCandidateFolder ? -1 : 1;
             // 其次优先使用主版本号接近 21 的 Java
             var leftDistance = left.Version is null ? int.MaxValue : Math.Abs(left.Version.Major - 21);
@@ -111,36 +133,47 @@ public static class JavaUtils {
     /// <summary>
     /// 存在完整 Java 的文件夹列表。
     /// </summary>
-    internal static readonly List<string> CandidateFolders = [
-        Paths.AppData + @".minecraft\runtime\", // 这也是 PCL 下载 Java 的路径
-        Paths.AppData + @".hmcl\java\",
-        Paths.AppData + @"ATLauncher\runtimes\minecraft\",
-        Paths.AppData + @"ModrinthApp\meta\java_versions\",
-        Paths.AppData + @"PrismLauncher\java\",
-        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\curseforge\minecraft\Install\runtime\",
-        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\.jdks\",
-        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\.sdkman\candidates\java\",
-        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\.ftba\bin\runtime\",
-        Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Packages\Microsoft.4297127D64EC6_8wekyb3d8bbwe\LocalCache\Local\runtime\",
-        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Minecraft Launcher\runtime\",
-        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Minecraft\runtime\",
-        Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Curse\Minecraft\Install\runtime\",
-        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Java\",
-        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Eclipse Adoptium\",
-        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Amazon Corretto\",
-        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Zulu\",
-        ..DirectoryUtils.EnumerateDirectories(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Microsoft\", searchPattern: "jdk-*"),
-        // 环境变量
-        ..(Environment.GetEnvironmentVariable("JDK_HOME") + ";" + Environment.GetEnvironmentVariable("JAVA_HOME")).
-            Split(";", true).Select(path => path.Trim(' ', '"'))
-    ];
+    internal static readonly Lazy<List<string>> CandidateFolders = new(() => {
+        List<string> folders = [
+            Paths.AppData + @".minecraft\runtime\", // 这也是 PCL 下载 Java 的路径
+            Paths.AppData + @".hmcl\java\",
+            Paths.AppData + @"ATLauncher\runtimes\minecraft\",
+            Paths.AppData + @"ModrinthApp\meta\java_versions\",
+            Paths.AppData + @"PrismLauncher\java\",
+            Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\curseforge\minecraft\Install\runtime\",
+            Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\.jdks\",
+            Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\.sdkman\candidates\java\",
+            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\.ftba\bin\runtime\",
+            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Packages\Microsoft.4297127D64EC6_8wekyb3d8bbwe\LocalCache\Local\runtime\",
+            Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Minecraft Launcher\runtime\",
+            Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Minecraft\runtime\",
+            Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Curse\Minecraft\Install\runtime\",
+            Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Java\",
+            Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Eclipse Adoptium\",
+            Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Amazon Corretto\",
+            Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Zulu\",
+            ..DirectoryUtils.EnumerateDirectories(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\Microsoft\", searchPattern: "jdk-*"),
+            // 环境变量
+            ..(Environment.GetEnvironmentVariable("JDK_HOME") + ";" + Environment.GetEnvironmentVariable("JAVA_HOME")).
+                Split(";", true).Select(path => path.Trim(' ', '"'))
+        ];
+        return folders.Select(f => {
+            try {
+                return PathUtils.ForCompare(f);
+            } catch (Exception ex) {
+                Logger.Warn(ex, $"Java 候选文件夹路径无效({f})");
+                return null;
+            }
+        }).Where(f => f is not null).Cast<string>().ToList();
+    });
+    
 
     /// <summary>
     /// 从常见文件夹和环境变量中搜索 Java,并将搜索结果写入设置。
     /// </summary>
     public static async Task RefreshListAsync(CancellationToken c = default, ProgressProvider? p = null) {
         // 搜索
-        List<Java> javaList = await SearchFoldersAsync(true, CandidateFolders, c, p?.SplitTo(0.5)).NoCapture();
+        List<Java> javaList = await SearchFoldersAsync(true, CandidateFolders.Value, c, p?.SplitTo(0.5)).NoCapture();
         // 将新发现的 Java 排在最前,原有列表保留既有顺序排在后面
         var oldJavaList = Configs.JavaList.Get()!;
         oldJavaList = await JavaUtils.CheckAllAsync(oldJavaList, c, p?.SplitTo(0.9)).NoCapture(); // 检查原有列表中的 Java
@@ -169,6 +202,7 @@ public static class JavaUtils {
                         string targetFolder = PathUtils.AddSlashSuffix(PathUtils.ForCompare(PathUtils.RemoveLastPart(file)));
                         // 判断文件夹是否包含重解析点(例如符号链接)
                         static bool HasReparsePoint(FileSystemInfo info) {
+                            if (PathUtils.IsParentOf(Paths.AppData + @".minecraft\runtime\", info.FullName)) return false; // 不筛查 PCL 的下载路径(#8928)
                             do {
                                 if (info.Attributes.HasFlag(FileAttributes.ReparsePoint)) return true;
                                 info = info is FileInfo fileInfo ? fileInfo.Directory : ((DirectoryInfo) info).Parent;
@@ -194,14 +228,14 @@ public static class JavaUtils {
         if (results.All(r => r.HasReparsePoint)) {
             Logger.Warn("找到的所有 Java 都包含重解析点,保留全部结果");
         } else if (results.Any(r => r.HasReparsePoint)) {
-            Logger.Info($"找到以下的 Java 包含重解析点,将它们从列表中排除:{results.Where(r => r.HasReparsePoint).Select(r => r.Folder).Join('、')}");
+            Logger.Warn($"找到的以下 Java 包含重解析点,将它们从列表中排除:{results.Where(r => r.HasReparsePoint).Select(r => r.Folder).Join('、')}");
             results = [..results.Where(r => !r.HasReparsePoint)];
         }
         // 筛除特殊路径
         if (results.All(r => r.IsSpecialPath)) {
             Logger.Warn("找到的所有 Java 都包含特殊路径,保留全部结果");
         } else if (results.Any(r => r.IsSpecialPath)) {
-            Logger.Info($"找到以下的 Java 包含特殊路径,将它们从列表中排除:{results.Where(r => r.IsSpecialPath).Select(r => r.Folder).Join('、')}");
+            Logger.Warn($"找到的以下 Java 包含特殊路径,将它们从列表中排除:{results.Where(r => r.IsSpecialPath).Select(r => r.Folder).Join('、')}");
             results = [..results.Where(r => !r.IsSpecialPath)];
         }
 

+ 0 - 0
Plain Craft Launcher 2/Resources/java-wrapper.jar → PCLCS/Launch/JavaWrapper.jar


+ 30 - 0
PCLCS/Launch/LaunchUtils.cs

@@ -0,0 +1,30 @@
+namespace PCLCS;
+
+public static class LaunchUtils {
+
+    /// <summary>
+    /// 释放补丁文件并返回完整文件路径。
+    /// </summary>
+    /// <param name="patchFilePath">补丁文件路径
+    /// <param name="outputDirectory">补丁文件的释放目录。</param>
+    public static string ExtractPatch(string patchFilePath, string outputDirectory) {
+        Logger.Info($"选定的资源 {patchFilePath} 输出路径:{outputDirectory}");
+        lock (ExtractPatchLock) { // 避免 OptiFine 和 Forge 安装时同时释放导致冲突
+            try {
+                FileUtils.ExtractResources(patchFilePath, Path.Combine(outputDirectory, PathUtils.GetLastPart(patchFilePath)), typeof(LaunchUtils));
+            } catch (Exception ex) {
+                if (!FileUtils.Exists(outputDirectory)) throw new FileNotFoundException($"释放 {patchFilePath} 失败", ex);
+                Logger.Warn(ex, $"{patchFilePath} 文件重新释放失败,将尝试更换文件名重新生成");
+                patchFilePath = Path.Combine(outputDirectory, $"{PathUtils.GetFileNameWithoutExtension(patchFilePath)}2.{PathUtils.GetExtension(patchFilePath)}");
+                try {
+                    FileUtils.ExtractResources(patchFilePath, Path.Combine(outputDirectory, PathUtils.GetLastPart(patchFilePath)), typeof(LaunchUtils));
+                } catch (Exception ex2) {
+                    throw new FileNotFoundException($"释放 {patchFilePath} 最终尝试失败", ex2);
+                }
+            }
+        }
+        return Path.Combine(outputDirectory, PathUtils.GetLastPart(patchFilePath));
+    }
+    private static readonly object ExtractPatchLock = new();
+
+}

+ 0 - 0
Plain Craft Launcher 2/Resources/lwjgl-unsafe-agent.jar → PCLCS/Launch/LwjglUnsafeAgent.jar


+ 2 - 1
PCLCS/PCLCS.csproj

@@ -55,7 +55,8 @@
 
 	<!-- 内嵌的资源 -->
 	<ItemGroup>
-		<None Remove="Resource\WikiEntries.txt" />
+		<EmbeddedResource Include="Launch\JavaWrapper.jar" LogicalName="Launch\JavaWrapper.jar" />
+		<EmbeddedResource Include="Launch\LwjglUnsafeAgent.jar" LogicalName="Launch\LwjglUnsafeAgent.jar" />
 		<EmbeddedResource Include="Resource\WikiEntries.txt" LogicalName="Resource\WikiEntries.txt" />
 	</ItemGroup>
 	<ItemGroup>

+ 0 - 2
PCLCS/Resource/Resource.cs

@@ -9,7 +9,6 @@ public static class Resource {
         1 => ModLoaders.Forge,
         3 => ModLoaders.LiteLoader,
         4 => ModLoaders.Fabric,
-        5 => ModLoaders.Quilt,
         6 => ModLoaders.NeoForge,
         _ => ModLoaders.None,
     };
@@ -24,7 +23,6 @@ public static class Resource {
             ModLoaders.Forge => 1,
             ModLoaders.LiteLoader => 3,
             ModLoaders.Fabric => 4,
-            ModLoaders.Quilt => 5,
             ModLoaders.NeoForge => 6,
             _ => 0,
         };

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 119 - 119
PCLCS/Resource/WikiEntries.txt


+ 0 - 31
Plain Craft Launcher 2/Application.xaml

@@ -132,37 +132,6 @@
                 <Setter Property="FontFamily" Value="Resources/#PCL English, Microsoft YaHei UI" />
             </Style>
 
-            <!-- ToolTip -->
-            <Style TargetType="ToolTip">
-                <EventSetter Event="Opened" Handler="OnTooltipOpened" />
-                <EventSetter Event="Closed" Handler="OnTooltipClosed" />
-                <Setter Property="Template">
-                    <Setter.Value>
-                        <ControlTemplate>
-                            <Border BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1.5" CornerRadius="4" MaxWidth="500" Background="#E5FFFFFF" Margin="0,0,4,4" SnapsToDevicePixels="True">
-                                <Border.Effect>
-                                    <DropShadowEffect Opacity="0.3" BlurRadius="4" ShadowDepth="2" Color="{DynamicResource ColorObject1}" />
-                                </Border.Effect>
-                                <TextBlock Text="{TemplateBinding ContentControl.Content}" TextWrapping="Wrap" Foreground="{DynamicResource ColorBrush1}" Margin="7,5" FontSize="12"/>
-                            </Border>
-                        </ControlTemplate>
-                    </Setter.Value>
-                </Setter>
-            </Style>
-            <Style x:Key="ExtendTextToolTip" TargetType="ToolTip">
-                <EventSetter Event="Opened" Handler="OnTooltipOpened" />
-                <EventSetter Event="Closed" Handler="OnTooltipClosed" />
-                <Setter Property="Template">
-                    <Setter.Value>
-                        <ControlTemplate>
-                            <Border BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1" CornerRadius="3" Background="White" Margin="0,0,4,4" SnapsToDevicePixels="True">
-                                <TextBlock Text="{TemplateBinding ContentControl.Content}" TextWrapping="Wrap" Foreground="{DynamicResource ColorBrush1}" Margin="7,5" FontSize="12"/>
-                            </Border>
-                        </ControlTemplate>
-                    </Setter.Value>
-                </Setter>
-            </Style>
-            
             <!-- ScrollViewer -->
             <Style x:Key="MyThumb" TargetType="Thumb">
                 <Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>

+ 4 - 17
Plain Craft Launcher 2/Application.xaml.vb

@@ -1,6 +1,5 @@
 Imports System.Reflection
 Imports System.Windows.Threading
-Imports Microsoft.Win32
 
 Public Class Application
 
@@ -23,9 +22,7 @@ Public Class Application
             End If
             '检查 .NET Framework 版本
             Try
-                Using ndpKey As RegistryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\")
-                    If ndpKey?.GetValue("Release") IsNot Nothing AndAlso CInt(ndpKey.GetValue("Release")) < 528040 Then OldEnvironmentAssert()
-                End Using
+                If CInt(RegistryUtils.TryRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full", "Release", 999999)) < 528040 Then OldEnvironmentAssert()
             Catch ex As Exception
                 Logger.Warn(ex, "检查 .NET Framework 版本失败")
             End Try
@@ -218,7 +215,7 @@ RetryCacheCheck:
 
     '动态 DLL 加载
     Private Sub New() '这里必须尽早调用,且不能使用任何库,否则加载 MeloongCore 就会导致崩溃
-        Static Prefixes As String() = {"NAudio", "Newtonsoft.Json", "Ookii.Dialogs.Wpf", "Imazen.WebP", "CacheCow.Common", "CacheCow.Client.FileStore", "CacheCow.Client", "ThrottleDebounce", "System.Net.Http.Formatting", "PCLCS", "MeloongCore.Wpf", "MeloongCore"}
+        Static Prefixes As String() = {"NAudio", "Newtonsoft.Json", "Ookii.Dialogs.Wpf", "Imazen.WebP", "CacheCow.Common", "CacheCow.Client.FileStore", "CacheCow.Client", "ThrottleDebounce", "System.Net.Http.Formatting", "Microsoft.Win32.Registry", "PCLCS", "MeloongCore.Wpf", "MeloongCore"}
         Static LoadedAssemblies As New ConcurrentDictionary(Of String, Lazy(Of Assembly))(StringComparer.Ordinal) '缓存
         AddHandler AppDomain.CurrentDomain.AssemblyResolve,
         Function(sender As Object, Args As ResolveEventArgs) As Assembly
@@ -234,17 +231,15 @@ RetryCacheCheck:
         End Function
     End Sub
     Private Shared Sub ExtractLibwebp() '这个方法会调用 ModBase,进而调用 MeloongCore,所以不能放在 New 里
-        SetDllDirectory(PathPure.TrimEnd("\"c))
+        SetDllDirectory(PathPure.Value.TrimEnd("\"c))
         Try
-            ExtractResources(PathPure & "libwebp.dll", "libwebp64")
+            ExtractResources(PathPure.Value & "libwebp.dll", "libwebp64")
         Catch ex As Exception
             Logger.Warn(ex, "写入 libwebp.dll 失败") '防止同时加载多个图片时,同时写入文件导致文件占用,进而导致崩溃
         End Try
     End Sub
     Private Declare Function SetDllDirectory Lib "kernel32" Alias "SetDllDirectoryA" (lpPathName As String) As Boolean
 
-    '切换窗口
-
     '控件模板事件
     Private Sub MyIconButton_Click(sender As Object, e As EventArgs)
         Select Case Settings.Get(Of McLoginType)("LoginType")
@@ -290,12 +285,4 @@ RetryCacheCheck:
         End Select
     End Sub
 
-    Public Shared ShowingTooltips As New List(Of ToolTip)
-    Private Sub OnTooltipOpened(sender As ToolTip, e As RoutedEventArgs)
-        ShowingTooltips.Add(sender)
-    End Sub
-    Private Sub OnTooltipClosed(sender As ToolTip, e As RoutedEventArgs)
-        ShowingTooltips.Remove(sender)
-    End Sub
-
 End Class

+ 1 - 2
Plain Craft Launcher 2/Controls/MyLoading.xaml.vb

@@ -76,8 +76,7 @@ Public Class MyLoading
                     If Ex Is Nothing Then
                         LabText.Text = "未知错误"
                     Else
-                        Ex = Ex.RootException()
-                        LabText.Text = If(Ex.IsBadNetwork(), "网络环境不佳,请稍后再试,或使用 VPN 改善网络环境", Ex.Message)
+                        LabText.Text = Ex.GetDisplay(False)
                     End If
                 Else
                     LabText.Text = TextError

+ 0 - 3
Plain Craft Launcher 2/Controls/MyScrollViewer.vb

@@ -18,9 +18,6 @@ Public Class MyScrollViewer
         End If
         e.Handled = True
         PerformVerticalOffsetDelta(-e.Delta)
-        '关闭 Tooltip (#2552)
-        '通过 IsOpen 关闭 Tooltip 而不是降低 Border 不透明度 (#5744)
-        Application.ShowingTooltips.ForEach(Sub(tooltip) tooltip.IsOpen = False)
     End Sub
     Public Sub PerformVerticalOffsetDelta(Delta As Double)
         AniStart(

+ 2 - 2
Plain Craft Launcher 2/FormMain.xaml

@@ -169,8 +169,8 @@
                 <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Grid.Row="1" Margin="15">
                     <local:MyExtraButton x:Name="BtnExtraBack" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="返回顶部" Visibility="Collapsed"
                                        Logo="M858.496 188.9024 173.1072 188.9024c-30.2848 0-54.8352-24.5504-54.8352-54.8352L118.272 106.6496c0-30.2848 24.5504-54.8352 54.8352-54.8352l685.3888 0c30.2848 0 54.8352 24.5504 54.8352 54.8352l0 27.4176C913.3312 164.352 888.7808 188.9024 858.496 188.9024L858.496 188.9024zM150.6048 550.8608c0 0 300.0064-240.3584 303.0272-243.328 13.9776-13.5936 31.1808-21.8624 48.8192-24.7552 1.7152-0.3072 3.4304-0.5888 5.1456-0.768 2.7392-0.3072 5.4528-0.3584 8.192-0.3328 2.7392-0.0256 5.4272 0.0256 8.1664 0.3328 1.7408 0.1792 3.4304 0.4864 5.1456 0.768 17.664 2.8928 34.8672 11.1616 48.8192 24.7552 3.0464 2.944 303.0016 243.328 303.0016 243.328 32.384 31.5136 29.6192 63.9744-2.7392 95.5136-32.3328 31.5392-75.648 2.9696-108.0064-28.544l-185.8816-147.1232 0 485.8368c0 30.3104-24.5248 54.8608-54.8352 54.8608l-27.392 0c-30.2848 0-54.8352-24.5504-54.8352-54.8608L447.232 470.7072l-185.8304 147.0976c-32.3584 31.5392-75.6992 60.1344-108.032 28.5696C121.0368 614.8352 118.272 582.3744 150.6048 550.8608L150.6048 550.8608zM150.6048 550.8608" />
-                    <local:MyExtraButton x:Name="BtnExtraDownload" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="下载管理" Visibility="Collapsed"
-                                       Logo="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
+                    <local:MyExtraButton x:Name="BtnExtraDownload" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="任务管理" Visibility="Collapsed"
+                                       LogoScale="1.1" Logo="M484.693 225.28 314.027 389.12l-68.267-68.267c-13.653-13.653-40.96-13.653-47.787 0-13.653 13.654-13.653 34.134 0 47.787l95.574 95.573c13.653 13.654 34.133 13.654 47.786 0L532.48 273.067c13.653-13.654 13.653-34.134 0-47.787s-34.133-13.653-47.787 0M819.2 341.333H614.4c-20.48 0-34.133 13.654-34.133 34.134S593.92 409.6 614.4 409.6h204.8c20.48 0 34.133-13.653 34.133-34.133s-13.653-34.134-34.133-34.134m0 341.334H614.4c-20.48 0-34.133 13.653-34.133 34.133s13.653 34.133 34.133 34.133h204.8c20.48 0 34.133-13.653 34.133-34.133s-13.653-34.133-34.133-34.133m-477.867-102.4c-75.093 0-136.533 61.44-136.533 136.533s61.44 136.533 136.533 136.533 136.534-61.44 136.534-136.533-61.44-136.533-136.534-136.533m0 204.8c-40.96 0-68.266-27.307-68.266-68.267s27.306-68.267 68.266-68.267S409.6 675.84 409.6 716.8s-27.307 68.267-68.267 68.267" />
                     <local:MyExtraButton x:Name="BtnExtraApril" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="投降" Visibility="Collapsed"
                                        Logo="M124.96 32c-28.64 0-60.064 23.2-60.064 51.904v856.192c0 28.576 30.688 51.904 59.296 51.904s60.064-23.328 60.064-51.904V83.904C184.256 55.2 153.536 32 124.96 32z m616.352 71.264c-168.416 0-168.416-69.024-336.8-69.024-97.216 0-172.256 45.344-172.256 45.344l-0.736 516.736s75.776-45.28 172.96-45.28c168.416 0 168.416 69.024 336.8 69.024 105.344 0 211.168-55.328 211.168-55.328V48.064c0.032 0-105.792 55.2-211.136 55.2z m0 0" />
                     <local:MyExtraButton x:Name="BtnExtraShutdown" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="关闭 Minecraft" Visibility="Collapsed"

+ 25 - 12
Plain Craft Launcher 2/FormMain.xaml.vb

@@ -11,6 +11,12 @@ Public Class FormMain
         Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
         '统计更新日志条目
         If BuildType = BuildTypes.Release Then
+            If LastVersion < 408 Then 'Release 2.13.1.0
+                FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:版本设置中,添加打开截图文件夹的快捷方式"))
+                FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:导出整合包时,可以勾选导出光影设置文件"))
+                FeatureCount += 21
+                BugCount += 22
+            End If
             If LastVersion < 406 Then 'Release 2.13.0.1
                 FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增:重做 Java 管理与相关设置,允许调整 Java 优先级、指定 Java 版本范围等"))
                 FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:导出整合包时允许自动导出版本文件夹中的 Java"))
@@ -87,6 +93,12 @@ Public Class FormMain
             '3:BUG+ IMP* FEAT-
             '2:BUG* IMP-
             '1:BUG-
+            If LastVersion < 409 Then 'Snapshot 2.13.1.0
+                FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:版本设置中,添加打开截图文件夹的快捷方式"))
+                FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:导出整合包时,可以勾选导出光影设置文件"))
+                FeatureCount += 21
+                BugCount += 22
+            End If
             If LastVersion < 407 Then 'Snapshot 2.13.0.1
                 If LastVersion = 405 Then
                     FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:使用部分主页预设时崩溃"))
@@ -150,7 +162,7 @@ Public Class FormMain
             If LastVersion < 385 Then 'Snapshot 2.12.5
                 FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法下载 NeoForge 26.1"))
                 If LastVersion = 384 Then
-                    FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:下载可能失败,提示下载管理刷新线程出错"))
+                    FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:下载可能失败,提示任务管理刷新线程出错"))
                     FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法保存选择的 Minecraft 文件夹"))
                     FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:使用中文搜索 Mod 时,部分结果会忽略筛选条件"))
                 End If
@@ -1029,6 +1041,7 @@ Public Class FormMain
                 Logger.Info("文件为压缩包,尝试作为整合包安装")
                 Try
                     ModpackInstall(FilePath)
+                    RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.TaskManager))
                     Return
                 Catch ex As Exception
                     If ex.IsCanceled Then Return
@@ -1157,9 +1170,9 @@ Public Class FormMain
         ''' </summary>
         InstanceSelect = 5
         ''' <summary>
-        ''' 下载管理。这是一个副页面。
+        ''' 任务管理。这是一个副页面。
         ''' </summary>
-        DownloadManager = 6
+        TaskManager = 6
         ''' <summary>
         ''' 版本设置。这是一个副页面。
         ''' </summary>
@@ -1206,8 +1219,8 @@ Public Class FormMain
         Select Case Stack.Page
             Case PageType.InstanceSelect
                 Return "版本选择"
-            Case PageType.DownloadManager
-                Return "下载管理"
+            Case PageType.TaskManager
+                Return "任务管理"
             Case PageType.InstanceSetup
                 Return "版本设置 - " & If(PageInstanceLeft.Instance Is Nothing, "未知版本", PageInstanceLeft.Instance.Name)
             Case PageType.ResourceDetail
@@ -1429,7 +1442,7 @@ Public Class FormMain
                     If FrmSelectLeft Is Nothing Then FrmSelectLeft = New PageSelectLeft
                     If FrmSelectRight Is Nothing Then FrmSelectRight = New PageSelectRight
                     PageChangeAnim(FrmSelectLeft, FrmSelectRight)
-                Case PageType.DownloadManager '下载管理
+                Case PageType.TaskManager '任务管理
                     If FrmSpeedLeft Is Nothing Then FrmSpeedLeft = New PageSpeedLeft
                     If FrmSpeedRight Is Nothing Then FrmSpeedRight = New PageSpeedRight
                     PageChangeAnim(FrmSpeedLeft, FrmSpeedRight)
@@ -1449,7 +1462,7 @@ Public Class FormMain
             BtnExtraApril.ShowRefresh()
 #End Region
 
-            Logger.Info($"切换主要页面:{Stack}, {SubType}")
+            Logger.Info($"切换主要页面:{Stack.Page}, {SubType}")
         Catch ex As Exception
             Logger.Error(ex, $"切换主要页面失败(ID {PageCurrent.Page})")
         Finally
@@ -1461,8 +1474,8 @@ Public Class FormMain
         AniStop("PageLeft PageChange") '停止左边栏变更导致的右页面切换动画,防止它与本动画一起触发多次 PageOnEnter
         AniControlEnabled += 1
         '清除新页面关联性
-        If Not IsNothing(TargetLeft.Parent) Then TargetLeft.SetValue(ContentPresenter.ContentProperty, Nothing)
-        If Not IsNothing(TargetRight) AndAlso Not IsNothing(TargetRight.Parent) Then TargetRight.SetValue(ContentPresenter.ContentProperty, Nothing)
+        If TargetLeft.Parent IsNot Nothing Then TargetLeft.SetValue(ContentPresenter.ContentProperty, Nothing)
+        If TargetRight IsNot Nothing AndAlso TargetRight.Parent IsNot Nothing Then TargetRight.SetValue(ContentPresenter.ContentProperty, Nothing)
         PageLeft = TargetLeft
         PageRight = TargetRight
         '触发页面通用动画
@@ -1603,12 +1616,12 @@ Public Class FormMain
         MusicControlNext()
     End Sub
 
-    '下载管理
+    '任务管理
     Private Sub BtnExtraDownload_Click(sender As Object, e As EventArgs) Handles BtnExtraDownload.Click
-        PageChange(PageType.DownloadManager)
+        PageChange(PageType.TaskManager)
     End Sub
     Private Function BtnExtraDownload_ShowCheck() As Boolean
-        Return HasDownloadingTask() AndAlso Not PageCurrent = PageType.DownloadManager
+        Return HasDownloadingTask() AndAlso Not PageCurrent = PageType.TaskManager
     End Function
 
     '投降

BIN
Plain Craft Launcher 2/Images/Heads/HerobrineXia.png


+ 3 - 3
Plain Craft Launcher 2/Modules/Base/ModAnimation.vb

@@ -79,7 +79,7 @@ Public Module ModAnimation
         ''' 已经执行的动画长度。如果为负数则为延迟。
         ''' </summary>
         ''' <remarks></remarks>
-        Public TimeFinished As Integer
+        Public TimeFinished As Double
         ''' <summary>
         ''' 已经完成的百分比。
         ''' </summary>
@@ -853,9 +853,8 @@ Sleeper:
     ''' <summary>
     ''' 动画定时器事件。
     ''' </summary>
-    Public Sub AniTimer(DeltaTick As Integer)
+    Public Sub AniTimer(DeltaTick As Double)
         Try
-
             If DeltaTick / AniSpeed > 100 Then Logger.Info($"两个动画帧间隔 {DeltaTick} ms")
             Dim i As Integer = -1
             '循环每个动画组
@@ -1034,6 +1033,7 @@ NextAni:
                     End If
 
                 Case AniType.Code
+                    Ani.TimeFinished = Ani.TimeTotal
                     CType(Ani.Value, ThreadStart)()
 
                 Case AniType.ScaleTransform

+ 9 - 58
Plain Craft Launcher 2/Modules/Base/ModBase.vb

@@ -6,12 +6,12 @@ Public Module ModBase
 #Region "声明"
 
     '下列版本信息由更新器自动修改
-    Public Const VersionBaseName As String = "2.13.0.1" '显示用版本名
+    Public Const VersionBaseName As String = "2.13.1.0" '显示用版本名
     Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
 #If RELEASE Then
-    Public Const VersionCode As Integer = 406 '正式版
+    Public Const VersionCode As Integer = 408 '正式版
 #Else
-    Public Const VersionCode As Integer = 407 '快照版
+    Public Const VersionCode As Integer = 409 '快照版
 #End If
 
     '版本信息
@@ -465,57 +465,7 @@ Public Module ModBase
 
 #Region "文件"
 
-    '=============================
-    '  注册表
-    '=============================
-
-    ''' <summary>
-    ''' 读取注册表键。如果失败则返回默认值。
-    ''' </summary>
-    Public Function ReadReg(Key As String, Optional DefaultValue As String = "") As String
-        Try
-            Return If(My.Computer.Registry.CurrentUser.OpenSubKey("Software\" & RegFolder, False)?.GetValue(Key), DefaultValue)
-        Catch ex As Exception
-            Logger.Error(ex, $"读取注册表出错:{Key}", LogBehavior.Toast)
-            Return DefaultValue
-        End Try
-    End Function
-    ''' <summary>
-    ''' 写入注册表键。
-    ''' </summary>
-    Public Sub WriteReg(Key As String, Value As String, Optional ThrowException As Boolean = False)
-        Try
-            Dim SubKey As Microsoft.Win32.RegistryKey = My.Computer.Registry.CurrentUser.OpenSubKey("Software\" & RegFolder, True)
-            If SubKey Is Nothing Then SubKey = My.Computer.Registry.CurrentUser.CreateSubKey("Software\" & RegFolder) '如果不存在就创建  
-            SubKey.SetValue(Key, Value)
-        Catch ex As Exception
-            Logger.Warn(ex, $"写入注册表出错:{Key}", If(ThrowException, LogBehavior.Toast, LogBehavior.ToastIfDebug))
-            If ThrowException Then Throw
-        End Try
-    End Sub
-    ''' <summary>
-    ''' 是否存在某个注册表键。
-    ''' </summary>
-    Public Function HasReg(Key As String) As Boolean
-        Return ReadReg(Key, Nothing) IsNot Nothing
-    End Function
-    ''' <summary>
-    ''' 删除注册表键。
-    ''' </summary>
-    Public Sub DeleteReg(Key As String, Optional ThrowException As Boolean = False)
-        Try
-            Dim SubKey As Microsoft.Win32.RegistryKey = My.Computer.Registry.CurrentUser.OpenSubKey("Software\" & RegFolder, True)
-            If SubKey?.GetValue(Key) Is Nothing Then Return
-            SubKey.DeleteValue(Key)
-        Catch ex As Exception
-            Logger.Warn(ex, $"删除注册表出错:{Key}", If(ThrowException, LogBehavior.Toast, LogBehavior.ToastIfDebug))
-            If ThrowException Then Throw
-        End Try
-    End Sub
-
-    '=============================
-    '  ini
-    '=============================
+    'ini
 
     Private ReadOnly IniCache As New ConcurrentDictionary(Of String, ConcurrentDictionary(Of String, String))
     ''' <summary>
@@ -617,7 +567,8 @@ Public Module ModBase
         End Try
     End Sub
 
-    '文件校验
+    '权限检查
+
     ''' <summary>
     ''' 检查是否拥有某一文件夹的 I/O 权限。如果文件夹不存在,会返回 False。
     ''' </summary>
@@ -837,8 +788,8 @@ Public Module ModBase
     ''' <summary>
     ''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。
     ''' </summary>
-    Public PathPure As String = GetPureASCIIDir()
-    Private Function GetPureASCIIDir() As String
+    Public PathPure As Lazy(Of String) = New Lazy(Of String)(
+    Function()
         If Paths.Base.IsAsciiOnly() Then
             Return Paths.Base & "PCL\"
         ElseIf Paths.AppDataThenName.IsAsciiOnly() Then
@@ -848,7 +799,7 @@ Public Module ModBase
         Else
             Return OsDrive & "ProgramData\PCL\"
         End If
-    End Function
+    End Function)
 
     ''' <summary>
     ''' 指示接取到这个异常的函数进行重试。

+ 4 - 4
Plain Craft Launcher 2/Modules/Base/ModNet.vb

@@ -288,7 +288,7 @@ Retry:
         Catch ex As TimeoutException
             Throw New WebException($"连接服务器超时,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout)
         Catch ex As Exception
-            ex.ThrowIfCanceled()
+            If TypeOf ex IsNot TaskCanceledException Then ex.ThrowIfCanceled() 'GetResultWithTimeout 会抛出 TaskCanceledException
             RecordIPReliability(HostIp, -1)
             If ex.IsBadNetwork Then
                 Throw New WebException($"网络请求失败,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout)
@@ -1423,8 +1423,8 @@ Retry:
             End Get
             Set(value As Integer)
                 _FailCount = value
-                If State = LoadState.Loading AndAlso value >= Math.Min(10000, Math.Max(FileRemain * 5.5, NetTaskThreadLimit * 5.5 + 3)) Then
-                    Logger.Warn($"由于同加载器中失败次数过多引发强制失败:连续失败了 {value} 次")
+                If State = LoadState.Loading AndAlso value >= Math.Min(10000, Math.Max(FileRemain * 8, NetTaskThreadLimit * 8 + 3)) Then
+                    Logger.Error($"由于同加载器中失败次数过多引发强制失败:连续失败了 {value} 次", LogBehavior.ToastIfDebug)
                     On Error Resume Next
                     Dim ExList As New List(Of Exception)
                     For Each File In Files
@@ -1917,7 +1917,7 @@ FinishExCatch:
     End Class
 
     ''' <summary>
-    ''' 是否有正在进行中、需要在下载管理页面显示的下载任务?
+    ''' 是否有正在进行中、需要在任务管理页面显示的下载任务?
     ''' </summary>
     Public Function HasDownloadingTask(Optional IgnoreCustomDownload As Boolean = False) As Boolean
         Return LoaderTaskbar.Any(

+ 11 - 8
Plain Craft Launcher 2/Modules/Base/ModValidate.vb

@@ -260,16 +260,16 @@ Public Class ValidateFolderName
     Inherits Validate
     Public Property Folder As String
     Public Property UseMinecraftCharCheck As Boolean = True
-    Public Property IgnoreCase As Boolean = True
     Private ReadOnly PathIgnore As IEnumerable(Of String)
+    Private ReadOnly IgnoreList As List(Of String)
     Public Sub New()
     End Sub
-    Public Sub New(Folder As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True)
+    Public Sub New(Folder As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreList As List(Of String) = Nothing)
         Me.Folder = Folder
-        Me.IgnoreCase = IgnoreCase
         Me.UseMinecraftCharCheck = UseMinecraftCharCheck
         On Error Resume Next
         PathIgnore = DirectoryUtils.EnumerateDirectories(Folder)
+        Me.IgnoreList = IgnoreList
     End Sub
     Public Overrides Function Validate(Str As String) As String
         Try
@@ -291,15 +291,17 @@ Public Class ValidateFolderName
             Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!", True).Validate(Str)
             If InvalidStrCheck <> "" Then Return InvalidStrCheck
             '检查 NTFS 8.3 文件名(#4505)
-            If Str.RegexCheck(".{2,}~\d") Then Return "文件夹名不可包含这一特殊格式!"
+            If Str.RegexCheck(".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!"
             '检查文件夹重名
             Dim Arr As New List(Of String)
+            Dim folderName As String
             If PathIgnore IsNot Nothing Then
                 For Each FolderPath In PathIgnore
-                    Arr.Add(PathUtils.GetLastPart(FolderPath))
+                    folderName = PathUtils.GetLastPart(FolderPath)
+                    If IgnoreList Is Nothing OrElse Not IgnoreList.Contains(folderName, StringComparer.OrdinalIgnoreCase) Then Arr.Add(folderName)
                 Next
             End If
-            Dim SameNameCheck = New ValidateExceptSame(Arr, "不可与现有文件夹重名!", IgnoreCase).Validate(Str)
+            Dim SameNameCheck = New ValidateExceptSame(Arr, "不可与现有文件夹重名!", True).Validate(Str)
             If Not SameNameCheck = "" Then Return SameNameCheck
             Return ""
         Catch ex As Exception
@@ -387,6 +389,9 @@ Public Class ValidateFolderPath
         '检查长度
         LengthCheck = New ValidateLength(1, 254).Validate(Str)
         If LengthCheck <> "" Then Return LengthCheck
+        '检查 NTFS 8.3 文件名(#4505)
+        Dim Match = Str.RegexSeek(".{2,}~\d")
+        If Match IsNot Nothing Then Return $"文件夹名不能包含 {Match} 这一特殊格式!"
         '检查开头
         If Str.StartsWithF("\\Mac\") Then GoTo Fin
         For Each Drive In Environment.GetLogicalDrives().Where(Function(p) DirectoryUtils.Exists(p))
@@ -413,8 +418,6 @@ Fin:
             '检查特殊字符串
             Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(SubStr)
             If Not InvalidStrCheck = "" Then Return InvalidStrCheck
-            '检查 NTFS 8.3 文件名(#4505)
-            If SubStr.RegexCheck(".{2,}~\d") Then Return "文件夹名不可包含这一特殊格式!"
         Next
         Return ""
     End Function

+ 4 - 3
Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb

@@ -514,7 +514,6 @@ Done:
             If LogMc.Contains("signer information does not match signer information of other classes in the same package") Then AppendReason(CrashReason.文件或内容校验失败, If(LogMc.RegexSeek("(?<=class "")[^']+(?=""'s signer information)"), "").TrimEnd(vbCrLf))
             If LogMc.Contains("Maybe try a lower resolution resourcepack?") Then AppendReason(CrashReason.材质过大或显卡配置不足)
             If LogMc.Contains("java.lang.NoSuchMethodError: net.minecraft.world.server.ChunkManager$ProxyTicketManager.shouldForceTicks(J)Z") AndAlso LogMc.Contains("OptiFine") Then AppendReason(CrashReason.OptiFine导致无法加载世界)
-            If LogMc.Contains("Unsupported class file major version") Then AppendReason(CrashReason.Java版本不兼容)
             If LogMc.Contains("com.electronwill.nightconfig.core.io.ParsingException: Not enough data available") AndAlso Not CrashReasons.ContainsKey(CrashReason.Mod配置文件导致游戏崩溃) Then AppendReason(CrashReason.NightConfig的Bug)
             If LogMc.Contains("Cannot find launch target fmlclient, unable to launch") Then AppendReason(CrashReason.Forge安装不完整)
             If LogMc.Contains("Invalid paths argument, contained no existing paths") AndAlso LogMc.Contains("libraries\net\minecraftforge\fmlcore") Then AppendReason(CrashReason.Forge安装不完整)
@@ -522,7 +521,9 @@ Done:
             If LogMc.Contains("has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to") Then AppendReason(CrashReason.Mod需要Java11)
             If LogMc.Contains("java.lang.RuntimeException: java.lang.NoSuchMethodException: no such method: sun.misc.Unsafe.defineAnonymousClass(Class,byte[],Object[])Class/invokeVirtual") Then AppendReason(CrashReason.Mod需要Java11)
             If LogMc.Contains("java.lang.IllegalArgumentException: The requested compatibility level JAVA_11 could not be set. Level is not supported by the active JRE or ASM version") Then AppendReason(CrashReason.Mod需要Java11)
+            If LogMc.Contains("Unsupported class file major version") Then AppendReason(CrashReason.Java版本不兼容)
             If LogMc.Contains("Unsupported major.minor version") Then AppendReason(CrashReason.Java版本不兼容)
+            If LogMc.Contains("Level is not supported by the active JRE or ASM version") Then AppendReason(CrashReason.Java版本不兼容)
             If LogMc.Contains("Invalid maximum heap size") Then AppendReason(CrashReason.使用32位Java导致JVM无法分配足够多的内存)
             If LogMc.Contains("Could not reserve enough space") Then
                 If LogMc.Contains("for 1048576KB object heap") Then
@@ -543,8 +544,8 @@ Done:
             End If
             If LogMc.Contains("Missing or unsupported mandatory dependencies:") Then
                 AppendReason(CrashReason.Mod缺少前置或MC版本错误,
-                    LogMc.RegexSearch("(?<=Missing or unsupported mandatory dependencies:)([\n\r]+\t(.*))+", RegularExpressions.RegexOptions.IgnoreCase).
-                    Select(Function(s) s.Trim((vbCrLf & vbTab & " ").ToCharArray)).Distinct().ToList())
+                LogMc.RegexSearch("(?<=Missing or unsupported mandatory dependencies:)([\n\r]+\t(.*))+", RegularExpressions.RegexOptions.IgnoreCase).
+                Select(Function(s) s.Trim((vbCrLf & vbTab & " ").ToCharArray)).Distinct().ToList())
             End If
         End If
 

+ 25 - 19
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb

@@ -65,7 +65,7 @@ Public Module ModDownload
 
 #Region "下载资源文件"
         If ShouldIgnoreFileCheck(Instance) Then
-            Logger.Info("已跳过所有 Assets 检查")
+            Logger.Warn("设置要求跳过所有 Assets 检查,文件可能不是最新的", LogBehavior.None)
         Else
             Dim LoadersAssets As New List(Of LoaderBase)
             '获取资源文件索引地址
@@ -78,13 +78,23 @@ Public Module ModDownload
                     If IndexFile Is Nothing Then
                         Task.Output = New List(Of NetFile)
                         Logger.Warn($"未找到版本 {Instance.Name} 的合适的资源索引下载地址,游戏 assets 可能缺失")
-                    ElseIf DownloadAssetIndexInBackground Then
+                        Return
+                    End If
+                    Dim IndexBackgroundFile = PathTemp & "Cache\" & IndexFile.LocalName & "_background"
+                    If FileUtils.Exists(IndexBackgroundFile) AndAlso
+                       FileUtils.GetInfo(IndexBackgroundFile).LastWriteTime.Date > FileUtils.GetInfo(IndexFile.LocalPath).LastWriteTime.Date Then
+                        Logger.Info($"发现后台更新的资源索引缓存文件:{IndexBackgroundFile}")
+                        FileUtils.Move(IndexBackgroundFile, IndexFile.LocalPath)
+                    End If
+                    If DownloadAssetIndexInBackground Then
+                        '允许后台更新索引
                         If IndexFile.Check.Check(IndexFile.LocalPath) Is Nothing Then
                             Task.Output = New List(Of NetFile)
                         Else
                             Task.Output = New List(Of NetFile) From {IndexFile}
                         End If
-                    Else '强制要求重新下载
+                    Else
+                        '强制要求重新下载
                         RealAddressMain = IndexFile.LocalPath
                         TempAddressMain = PathTemp & "Cache\" & IndexFile.LocalName
                         IndexFile.LocalPath = TempAddressMain
@@ -114,28 +124,24 @@ Public Module ModDownload
                 Dim LoadersAssetsUpdate As New List(Of LoaderBase)
                 LoadersAssetsUpdate.Add(New LoaderTask(Of String, List(Of NetFile))("后台分析资源文件索引地址",
                 Sub(Task As LoaderTask(Of String, List(Of NetFile)))
-                    Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Instance)
-                    If BackAssetsFile Is Nothing Then
+                    Dim IndexFile As NetFile = DlClientAssetIndexGet(Instance)
+                    If IndexFile Is Nothing Then
                         Logger.Warn($"未找到版本 {Instance.Name} 的合适的资源索引下载地址,游戏 assets 可能缺失")
                         Task.Cancel()
                         Throw New OperationCanceledException
                     End If
-                    RealAddressBg = BackAssetsFile.LocalPath
-                    TempAddressBg = PathTemp & "Cache\" & BackAssetsFile.LocalName & "_background"
-                    BackAssetsFile.LocalPath = TempAddressBg
-                    Task.Output = New List(Of NetFile) From {BackAssetsFile}
+                    RealAddressBg = IndexFile.LocalPath
+                    TempAddressBg = PathTemp & "Cache\" & IndexFile.LocalName & "_background"
+                    IndexFile.LocalPath = TempAddressBg
+                    Task.Output = New List(Of NetFile) From {IndexFile}
                     '检查是否需要更新:每天只更新一次
-                    If FileUtils.Exists(RealAddressBg) AndAlso Math.Abs((FileUtils.GetInfo(RealAddressBg).LastWriteTime.Date - Now.Date).TotalDays) < 1 Then
-                        Logger.Info("无需更新资源文件索引,取消")
+                    Dim LastUpdate As Date = FileUtils.GetInfo(RealAddressBg).LastWriteTime.Date
+                    If FileUtils.Exists(RealAddressBg) AndAlso Math.Abs((LastUpdate - Now.Date).TotalDays) < 1 Then
+                        Logger.Info($"无需更新资源文件索引,上次更新于 {LastUpdate}")
                         Task.Cancel()
                     End If
                 End Sub))
                 LoadersAssetsUpdate.Add(New LoaderDownload("后台下载资源文件索引", New List(Of NetFile)))
-                LoadersAssetsUpdate.Add(New LoaderTask(Of List(Of NetFile), String)("后台复制资源文件索引",
-                Sub(Task As LoaderTask(Of List(Of NetFile), String))
-                    FileUtils.Move(TempAddressBg, RealAddressBg)
-                    McLaunchLog("后台更新资源文件索引成功:" & TempAddressBg)
-                End Sub))
                 Dim Updater As New LoaderCombo(Of String)("后台更新资源文件索引", LoadersAssetsUpdate)
                 Logger.Info("开始后台检查资源文件索引")
                 Updater.Start()
@@ -1193,15 +1199,15 @@ Public Module ModDownload
             Urls.Add((Url, If(Url.Contains("modrinth"), 20, 10)))
             Urls.Add((Url, 30))
         End If
-        Dim Exs As String = ""
+        Dim Errors As New List(Of Exception)
         For Each Source In Urls
             Try
                 Return NetRequestByClient(Source.Url, Method, Content, ContentType, Timeout:=Source.Timeout * 1000, Encoding:=Encoding.UTF8, RequireJson:=True).DeserializeJson()
             Catch ex As Exception
-                Exs += ex.Message + vbCrLf
+                Errors.Add(ex)
             End Try
         Next
-        Throw New Exception(Exs)
+        Throw New AggregateException(Errors)
     End Function
 
 #End Region

+ 48 - 50
Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb

@@ -101,11 +101,12 @@ Public Module ModJava
     End Sub
 
     ''' <summary>
-    ''' 手动触发搜索 Java。
+    ''' 手动触发搜索 Java,强制检查所有 Java。
     ''' </summary>
     Public Sub ManuallySearchJava(Optional CancellationToken As CancellationToken = Nothing)
         RunInThread(
         Sub()
+            Configs.JavaList.Get().ForAll(Sub(java) java.InvalidateChecked()) '重置已检查的状态
             JavaListRefreshWorker.Start(cancellationToken:=CancellationToken)
             JavaListRefreshWorker.WaitIfRunningAsync(cancellationToken:=CancellationToken).Run() 'worker 开始/结束时会自动重载 UI
             If Configs.JavaList.Get().Any Then
@@ -142,7 +143,10 @@ Public Module ModJava
         Dim AddConstraint =
         Sub(Constraint As ValueRange(Of Version))
             JavaRange = JavaRange?.Intersect(Constraint)
-            If JavaRange.IsEmpty Then Logger.Warn($"Java 版本要求冲突(当前追加的要求为 {Constraint},版本为 {Instance.VersionDisplayName})")
+            If JavaRange.IsEmpty Then
+                Logger.Warn($"Java 版本要求冲突,若启动失败请在版本设置手动指定 Java:当前追加的要求为 {Constraint},游戏版本为 {Instance.VersionDisplayName}", LogBehavior.Toast)
+                JavaRange = Constraint
+            End If
         End Sub
 
         '原版 26-:通过版本号判断
@@ -294,7 +298,7 @@ Public Module ModJava
 
                 Case 3 '=============================== 强制指定特定 Java ===============================
 
-                    Dim ChosenJava = Configs.InstanceForcedJava.Get(Instance.Config)
+                    Dim ChosenJava = Configs.JavaForced.Get(Instance.Config)
                     Logger.Info($"版本设置中强制指定的 Java:{Instance.PathVersion} → {ChosenJava}")
                     If ChosenJava Is Nothing Then
                         If TryFixOrHint Then
@@ -305,7 +309,7 @@ Public Module ModJava
                         p?.Skip() : Return Nothing '<==== 设置中未指定 Java
                     End If
                     If Not Configs.JavaList.Get().Contains(ChosenJava) Then
-                        Configs.InstanceForcedJava.Reset(Instance.Config)
+                        Configs.JavaForced.Reset(Instance.Config)
                         UpdateJavaLists()
                         If TryFixOrHint Then
                             SwitchToInstanceSetup(Instance)
@@ -314,7 +318,7 @@ Public Module ModJava
                         p?.Skip() : Return Nothing '<==== 设置中指定的 Java 不在列表中
                     End If
                     If Not ChosenJava.CheckAsync(c).Run() Then
-                        Configs.InstanceForcedJava.Reset(Instance.Config)
+                        Configs.JavaForced.Reset(Instance.Config)
                         UpdateJavaLists()
                         If TryFixOrHint Then
                             SwitchToInstanceSetup(Instance)
@@ -365,9 +369,41 @@ Public Module ModJava
 
                         '电脑中没有合适的 Java,获取 Mojang 提供的 Java 下载列表
                         Logger.Warn($"电脑中没有合适的 Java,开始获取 Mojang 提供的 Java 下载列表")
-                        Dim Components = DownloadJavaList()
-                        c.ThrowIfCancellationRequested()
-                        p?.Set(0.4)
+                        Static DownloadListWorker As New RedoableWorker(Of List(Of JavaDownloadInfo))(
+                        Function(cancellationToken)
+                            '下载 Mojang 提供的 Java 列表
+                            Dim IndexFileStr As String = NetRequestByLoader(DlVersionListOrder(
+                                {"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
+                                {"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"}
+                            ), IsJson:=True)
+                            cancellationToken?.ThrowIfCancellationRequested()
+                            '解析 Java 列表
+                            Dim Results = New List(Of JavaDownloadInfo)
+                            For Each Prop As JProperty In IndexFileStr.DeserializeJson(Of JObject)()("windows-x64")
+                                cancellationToken?.ThrowIfCancellationRequested()
+                                If Prop.Name = "minecraft-java-exe" Then Continue For '不是完整 Java
+                                Try
+                                    Dim Entry = Prop.Value.FirstOrDefault
+                                    If Entry Is Nothing Then Continue For
+                                    Dim JavaName = Entry("version")("name").ToString '可能的名称格式:"12"、"8u51-cacert462b08"、"17.0.8.1"、"17.0.1.12.1"、"21.0.7"
+                                    If JavaName.Contains(".") Then
+                                        Dim Parts As String() = JavaName.Split(".")
+                                        Results.Add(New JavaDownloadInfo With {.ComponentName = Prop.Name, .Java = Entry, .JavaVersion = New Version(Val(Parts(0)), Val(Parts(1)), If(Parts.Length >= 3, Val(Parts(2)), 0), If(Parts.Length >= 4, Val(Parts(3)), 0))})
+                                    ElseIf JavaName.StartsWithF("8u51-") Then
+                                        Results.Add(New JavaDownloadInfo With {.ComponentName = Prop.Name, .Java = Entry, .JavaVersion = New Version(8, 0, 51, 0)})
+                                    Else
+                                        Results.Add(New JavaDownloadInfo With {.ComponentName = Prop.Name, .Java = Entry, .JavaVersion = New Version(Val(JavaName.BeforeFirstOfAny({"u", "."})), 0, 0, 0)})
+                                    End If
+                                Catch ex As Exception
+                                    Logger.Warn(ex, $"解析 Mojang 提供的 Java 列表项失败,已跳过({Prop.Name})")
+                                End Try
+                            Next
+                            Return Results
+                        End Function)
+                        If Not DownloadListWorker.HasSucceeded Then DownloadListWorker.Start(c, p?.SplitTo(0.4))
+                        DownloadListWorker.WaitIfRunning(cancellationToken:=c)
+                        p?.Set(0.4, skiped:=True)
+                        Dim Components = DownloadListWorker.LastResult
 
                         '确定要下载的目标 Java
                         Dim JavaToDownload As JavaDownloadInfo = If(
@@ -443,7 +479,7 @@ Public Module ModJava
     ''' 从老版本 PCL 迁移版本独立的 Java 设置。
     ''' </summary>
     Private Sub MigrateInstanceJavaSettings(Instance As McInstance, Optional c As CancellationToken = Nothing, Optional p As ProgressProvider = Nothing)
-        If Configs.InstanceMigratedJava.Get(Instance.Config) Then p?.Skip() : Return
+        If Configs.JavaMigrated.Get(Instance.Config) Then p?.Skip() : Return
         If FrmInstanceSetup IsNot Nothing Then RunInUiWait(Sub() FrmInstanceSetup.ComboArgumentJava.IsEnabled = False)
         Try
             Logger.Info($"正在尝试迁移版本独立的 Java 设置({Instance.Name})")
@@ -462,10 +498,10 @@ Public Module ModJava
                 Configs.JavaList.Edit(Sub(ByRef List) List.Add(ForcedJava)) '加入列表底部
                 Logger.Info($"已将强制指定的 Java 加入 Java 列表底部:{ForcedJava}")
             End If
-            Configs.InstanceForcedJava.Set(ForcedJava, Instance.Config)
+            Configs.JavaForced.Set(ForcedJava, Instance.Config)
             Settings.Set("VersionArgumentJavaV2", 3, Instance)
             UpdateJavaLists()
-            Configs.InstanceMigratedJava.Set(True, Instance.Config) '完成
+            Configs.JavaMigrated.Set(True, Instance.Config) '完成
             p?.Finish() : Return
 NoForcedJava:
             Dim JavaFound = JavaUtils.SearchFoldersAsync(True, {Instance.PathVersion}, c, p?.SplitTo(1)).Run()
@@ -478,7 +514,7 @@ NoForcedJava:
                 Logger.Info("没有需要迁移的内容,自动选择 Java")
                 Settings.Set("VersionArgumentJavaV2", 0, Instance)
             End If
-            Configs.InstanceMigratedJava.Set(True, Instance.Config) '完成
+            Configs.JavaMigrated.Set(True, Instance.Config) '完成
         Finally
             If FrmInstanceSetup IsNot Nothing Then RunInUiWait(
             Sub()
@@ -499,44 +535,6 @@ NoForcedJava:
         Public Property JavaVersion As Version
     End Class
 
-    ''' <summary>
-    ''' 下载 Mojang 提供的 Java 列表。
-    ''' <para/> 若本次打开程序已经下载过,则会直接返回缓存的结果。
-    ''' </summary>
-    Private Function DownloadJavaList() As List(Of JavaDownloadInfo)
-        'TODO: 写一个更简单的 Lazy,允许重置缓存
-        Static Components As New Lazy(Of List(Of JavaDownloadInfo))(
-        Function()
-            '下载 Mojang 提供的 Java 列表
-            Dim IndexFileStr As String = NetRequestByLoader(DlVersionListOrder(
-                {"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
-                {"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"}
-            ), IsJson:=True)
-            '解析 Java 列表
-            Dim Results = New List(Of JavaDownloadInfo)
-            For Each Prop As JProperty In IndexFileStr.DeserializeJson(Of JObject)()("windows-x64")
-                If Prop.Name = "minecraft-java-exe" Then Continue For '不是完整 Java
-                Try
-                    Dim Entry = Prop.Value.FirstOrDefault
-                    If Entry Is Nothing Then Continue For
-                    Dim JavaName = Entry("version")("name").ToString '可能的名称格式:"12"、"8u51-cacert462b08"、"17.0.8.1"、"17.0.1.12.1"、"21.0.7"
-                    If JavaName.Contains(".") Then
-                        Dim Parts As String() = JavaName.Split(".")
-                        Results.Add(New JavaDownloadInfo With {.ComponentName = Prop.Name, .Java = Entry, .JavaVersion = New Version(Val(Parts(0)), Val(Parts(1)), If(Parts.Length >= 3, Val(Parts(2)), 0), If(Parts.Length >= 4, Val(Parts(3)), 0))})
-                    ElseIf JavaName.StartsWithF("8u51-") Then
-                        Results.Add(New JavaDownloadInfo With {.ComponentName = Prop.Name, .Java = Entry, .JavaVersion = New Version(8, 0, 51, 0)})
-                    Else
-                        Results.Add(New JavaDownloadInfo With {.ComponentName = Prop.Name, .Java = Entry, .JavaVersion = New Version(Val(JavaName.BeforeFirstOfAny({"u", "."})), 0, 0, 0)})
-                    End If
-                Catch ex As Exception
-                    Logger.Warn(ex, $"解析 Mojang 提供的 Java 列表项失败,已跳过({Prop.Name})")
-                End Try
-            Next
-            Return Results
-        End Function)
-        Return Components.Value
-    End Function
-
     ''' <summary>
     ''' 构建下载指定 Java 的加载器。
     ''' </summary>

+ 35 - 11
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb

@@ -463,7 +463,8 @@ NextInner:
     End Function
 
     '登录主模块加载器
-    Public McLoginLoader As New LoaderTask(Of McLoginData, McLoginResult)("登录", AddressOf McLoginStart, AddressOf McLoginInput, ThreadPriority.BelowNormal) With {.ReloadTimeout = 1, .ProgressWeight = 15, .Block = False}
+    Public McLoginLoader As New LoaderTask(Of McLoginData, McLoginResult)("登录", AddressOf McLoginStart, AddressOf McLoginInput, ThreadPriority.BelowNormal) With
+        {.ReloadTimeout = 1, .ProgressWeight = 15, .Block = False}
     Public Function McLoginInput() As McLoginData
         Dim LoginData As McLoginData = Nothing
         Dim LoginType = Settings.Get(Of McLoginType)("LoginType")
@@ -1175,6 +1176,7 @@ Retry:
 
 #Region "启动参数"
     Private McLaunchArgument As String
+    Private McLaunchEncoding As Encoding
 
     '主方法
     Private Sub McLaunchArgumentMain(Loader As LoaderTask(Of String, Integer))
@@ -1296,8 +1298,8 @@ NextInstance:
         'LUA
         Dim UseLUA As Boolean =
             Not Settings.Get(Of Boolean)("LaunchAdvanceDisableLUA") AndAlso Not Settings.Get(Of Boolean)("VersionAdvanceDisableLUA", McInstanceSelected) AndAlso
-            McLibListGet(McInstanceSelected, False).Any(Function(e) e.OriginalName = "org.lwjgl:lwjgl:3.4.1")
-        If UseLUA Then Args.Add($"-javaagent:""{ExtractPatch("LUA")}""")
+            McLibListGet(McInstanceSelected, False).Select(Function(e) e.OriginalName).Contains("org.lwjgl:lwjgl:3.4.1")
+        If UseLUA Then Args.Add($"-javaagent:""{LaunchUtils.ExtractPatch("Launch\LwjglUnsafeAgent.jar", PathPure.Value)}""")
         McLaunchLog("使用 LUA:" & UseLUA)
 
 #Region "内存管理"
@@ -1361,14 +1363,34 @@ NextInstance:
         'Log4j 漏洞防御参数
         Args.Add("-Dlog4j2.formatMsgNoLookups=true")
 
-        '编码(#4700、#5892、#5909)
-        If McLaunchJavaSelected.Version.Major > 8 AndAlso Not Args.Any(Function(a) a.StartsWithF("-Dstdout.encoding=")) Then Args.Add("-Dstdout.encoding=UTF-8")
-        If McLaunchJavaSelected.Version.Major > 8 AndAlso Not Args.Any(Function(a) a.StartsWithF("-Dstderr.encoding=")) Then Args.Add("-Dstderr.encoding=UTF-8")
-        If McLaunchJavaSelected.Version.Major >= 18 AndAlso Not Args.Any(Function(a) a.StartsWithF("-Dfile.encoding=")) Then Args.Add("-Dfile.encoding=COMPAT") 'Dfile.encoding 需要放在 Dstdout.encoding 后面(#6934)
+        '编码(#4700、#5892、#5909、#6934、#8950)
+        Dim EncodingName As String
+        Select Case McLaunchJavaSelected.Version.Major
+            Case Is >= 21 'Java 21+ 会固定使用 UTF-8
+                EncodingName = "UTF-8"
+            Case Is >= 18 'Java 18~20 时,启动 MC 时会添加 COMPAT 参数,因此 Java 会回退到 native.encoding
+                EncodingName = McLaunchJavaSelected.NativeEncodingName
+            Case Else 'Java 17- 时,直接使用 file.encoding
+                EncodingName = McLaunchJavaSelected.FileEncodingName
+        End Select
+        Try
+            McLaunchEncoding = Encoding.GetEncoding(If(EncodingName.Equals("GBK", StringComparison.OrdinalIgnoreCase), "GB18030", EncodingName))
+        Catch ex As Exception
+            Dim FallbackEncoding = Encoding.GetEncoding(Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage) '老版本 Java 的编码选择行为
+            McLaunchLog($"无法识别 Java 编码 {If(EncodingName, "Nothing")},已回退为 {FallbackEncoding.WebName}", LogLevel.Warn)
+            McLaunchEncoding = FallbackEncoding
+        End Try
+        McLaunchLog($"使用编码:{McLaunchEncoding.WebName}")
+        Dim LaunchEncodingName = If(McLaunchEncoding.CodePage = 54936, "GBK", McLaunchEncoding.WebName)
+        Dim StdoutArgName = If(McLaunchJavaSelected.Version.Major < 19, "sun.stdout.encoding", "stdout.encoding") '老版本 Java 应该设置 sun.std
+        Dim StderrArgName = If(McLaunchJavaSelected.Version.Major < 19, "sun.stderr.encoding", "stderr.encoding")
+        If Not Args.Any(Function(a) a.StartsWithF($"-D{StdoutArgName}=")) Then Args.Add($"-D{StdoutArgName}={LaunchEncodingName}")
+        If Not Args.Any(Function(a) a.StartsWithF($"-D{StderrArgName}=")) Then Args.Add($"-D{StderrArgName}={LaunchEncodingName}")
+        If McLaunchJavaSelected.Version.Major >= 18 AndAlso McLaunchJavaSelected.Version.Major < 21 Then Args.Add("-Dfile.encoding=COMPAT") '使用 COMPAT 防止部分 Mod 配置文件不兼容 UTF-8
 
         '为 JLW 添加 -jar,它必须放在最后
         If UseJLW Then
-            Args.Add("-jar") : Args.Add(ExtractPatch("JavaWrapper"))
+            Args.Add("-jar") : Args.Add(LaunchUtils.ExtractPatch("Launch\JavaWrapper.jar", PathPure.Value))
         End If
 
         '再次去重并输出
@@ -1482,7 +1504,7 @@ NextInstance:
         Yield ("${natives_directory}", GetNativesFolder().TrimEnd("\"c))
         Yield ("${library_directory}", PathUtils.ToShortPath(McFolderSelected & "libraries"))
         Yield ("${libraries_directory}", PathUtils.ToShortPath(McFolderSelected & "libraries"))
-        Yield ("${pure_directory}", PathPure.TrimEnd("\"c)) '由 PCL 添加,这会允许在分割参数并去重后再替换路径,防止路径中的特殊字符影响参数分割和去重
+        Yield ("${pure_directory}", PathPure.Value.TrimEnd("\"c)) '由 PCL 添加,这会允许在分割参数并去重后再替换路径,防止路径中的特殊字符影响参数分割和去重
         Yield ("${launcher_name}", "PCL")
         Yield ("${launcher_version}", VersionCode)
         Yield ("${version_name}", McInstanceSelected.Name)
@@ -1997,7 +2019,7 @@ IgnoreCustomSkin:
         '输出 bat
         Try
             Dim CmdString As String =
-                $"{If(McLaunchJavaSelected.Version.Major > 8, "chcp 65001>nul" & vbCrLf, "")}" &
+                $"chcp {If(McLaunchEncoding.CodePage = 54936 AndAlso IsGBKEncoding, 936, McLaunchEncoding.CodePage)}>nul" & vbCrLf &
                 "@echo off" & vbCrLf &
                 $"title 启动 - {McInstanceSelected.Name}" & vbCrLf &
                 "echo 游戏正在启动,请稍候。" & vbCrLf &
@@ -2010,7 +2032,7 @@ IgnoreCustomSkin:
             FileUtils.Write(
                 filePath:=If(CurrentLaunchOptions.SaveBatch, Paths.Base & "PCL\LatestLaunch.bat"),
                 text:=FilterAccessToken(CmdString, "F").Replace("%", "%%"),
-                encoding:=If(McLaunchJavaSelected.Version.Major > 8, Encoding.UTF8, Encoding.Default))
+                encoding:=McLaunchEncoding)
             If CurrentLaunchOptions.SaveBatch IsNot Nothing Then
                 McLaunchLog("导出启动脚本完成,强制结束启动过程")
                 CanceledHint = "导出启动脚本成功!"
@@ -2092,6 +2114,8 @@ IgnoreCustomSkin:
         '设置其他参数
         StartInfo.WorkingDirectory = McInstanceSelected.PathIndie
         StartInfo.UseShellExecute = False
+        StartInfo.StandardOutputEncoding = McLaunchEncoding
+        StartInfo.StandardErrorEncoding = McLaunchEncoding
         StartInfo.RedirectStandardOutput = True
         StartInfo.RedirectStandardError = True
         StartInfo.CreateNoWindow = True

+ 3 - 3
Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb

@@ -484,7 +484,7 @@ VersionSearchFinish:
             Return JsonPath
         End Function
         ''' <summary>
-        ''' 该版本的 Json 文本。
+        ''' 该版本的 Json 文本。会抛出异常。
         ''' </summary>
         Public Property JsonText As String
             Get
@@ -2073,7 +2073,7 @@ OnLoaded:
 
         '统一通行证文件
         If Settings.Get(Of Integer)("VersionServerLogin", Instance:=Instance) = 3 Then
-            Dim TargetFile As String = PathPure & "nide8auth.jar"
+            Dim TargetFile As String = PathPure.Value & "nide8auth.jar"
             Try
                 '测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/
                 Logger.Info("开始获取统一通行证下载信息")
@@ -2093,7 +2093,7 @@ OnLoaded:
 
         'Authlib-Injector 文件
         If Settings.Get(Of Integer)("VersionServerLogin", Instance:=Instance) = 4 Then
-            Dim TargetFile = PathPure & "authlib-injector.jar"
+            Dim TargetFile = PathPure.Value & "authlib-injector.jar"
             Try
                 Logger.Info("开始获取 Authlib-Injector 下载信息")
                 Dim DownloadInfo As JObject = NetRequestByClientRetry(

+ 24 - 43
Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb

@@ -109,29 +109,10 @@ Public Module ModModpack
         End Try
     End Function
 
-    Private Sub ExtractModpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase, ProgressIncrement As Double)
-        '解压文件
-        Dim RetryCount As Integer = 1
-        Dim InitialProgress = Loader.Progress
-Retry:
-        Try
-            Loader.Progress = InitialProgress
-            DirectoryUtils.Delete(InstallTemp)
-            Dim RawProgress As Double = Loader.Progress
-            FileUtils.ExtractToDirectory(FileAddress, InstallTemp, progressHandler:=Sub(Percentage) Loader.Progress = RawProgress + Percentage * ProgressIncrement)
-        Catch ex As Exception
-            Logger.Warn(ex, $"第 {RetryCount} 次解压尝试失败")
-            '完全不知道为啥会出现文件正在被另一进程使用的问题,总之加个重试
-            If RetryCount < 5 Then
-                Thread.Sleep(RetryCount * 2000)
-                If Loader IsNot Nothing AndAlso Loader.LoadingState <> MyLoading.MyLoadingState.Run Then Return
-                RetryCount += 1
-                GoTo Retry
-            Else
-                Throw New Exception("解压整合包文件失败", ex)
-            End If
-        End Try
-        Loader.Progress = InitialProgress + ProgressIncrement
+    Private Sub ExtractModpackFiles(InstallTemp As String, FileAddress As String, Optional c As CancellationToken = Nothing, Optional p As ProgressProvider = Nothing)
+        DirectoryUtils.Delete(InstallTemp)
+        c.ThrowIfCancellationRequested()
+        FileUtils.ExtractToDirectory(FileAddress, InstallTemp, c, p)
     End Sub
     ''' <summary>
     ''' 从整合包的 override 目录复制文件,同时设置 PCL 的配置文件与版本隔离。
@@ -213,7 +194,6 @@ Retry:
                 Logger.Info($"整合包 Fabric 版本:{Id}")
                 TargetVersion.Fabric = Id.Replace("fabric-", "")
             Else
-                'ElseIf Id.StartsWithF("quilt-") Then
                 NotifyIncompatibleLoader(Id)
             End If
         Next
@@ -224,7 +204,7 @@ Retry:
         If OverrideHome <> "" Then
             InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
             Sub(Task As LoaderTask(Of String, Integer))
-                ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
+                ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.6))
                 CopyOverrideDirectory(
                     InstallTemp & ArchiveBaseFolder & If(OverrideHome = "." OrElse OverrideHome = "./", "", OverrideHome), '#5613
                     $"{McFolderSelected}versions\{InstanceName}", Task)
@@ -296,13 +276,15 @@ Retry:
                     Dim TargetFolder As String, Type As ResourceTypes
                     If ModJson("modules").Any Then 'modules 可能返回 null(#1006)
                         Dim ModuleNames = CType(ModJson("modules"), JArray).Select(Function(l) l("name").ToString).ToList
-                        If ModuleNames.Contains("META-INF") OrElse ModuleNames.Contains("mcmod.info") OrElse
-                           ModJson?("FileName")?.ToString.EndsWithF(".jar", True) Then
+                        If ModuleNames.Contains("META-INF") OrElse ModuleNames.Contains("mcmod.info") OrElse ModuleNames.Contains("fabric.mod.json") OrElse
+                            ModJson?("FileName")?.ToString.EndsWithF(".jar", True) Then
                             TargetFolder = "mods" : Type = ResourceTypes.Mod
                         ElseIf ModuleNames.Contains("pack.mcmeta") Then
                             TargetFolder = "resourcepacks" : Type = ResourceTypes.ResourcePack
-                        Else
+                        ElseIf ModuleNames.Contains("shaders") Then
                             TargetFolder = "shaderpacks" : Type = ResourceTypes.Shader
+                        Else
+                            TargetFolder = "saves" : Type = ResourceTypes.Map
                         End If
                     Else
                         TargetFolder = "mods" : Type = ResourceTypes.Mod
@@ -348,6 +330,12 @@ Retry:
                 WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
                 Logger.Info($"已设置整合包 Logo:{Logo}")
             End If
+            '解压地图文件
+            Dim SaveFolder As String = $"{VersionFolder}saves\"
+            For Each MapFile In DirectoryUtils.EnumerateFiles(SaveFolder, searchPattern:="*.zip")
+                FileUtils.ExtractToDirectory(MapFile, SaveFolder, Task.CreateCancellationToken())
+                FileUtils.Delete(MapFile)
+            Next
             '删除原始整合包文件
             For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
                 If FileUtils.Exists(Target) Then
@@ -373,7 +361,6 @@ Retry:
         Loader.Start(Request.VersionFolder)
         LoaderTaskbarAdd(Loader)
         FrmMain.BtnExtraDownload.ShowRefresh()
-        RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
         Return Loader
     End Function
 
@@ -404,7 +391,6 @@ Retry:
                     TargetVersion.Fabric = Entry.Value.ToString
                     Logger.Info($"整合包 Fabric 版本:{TargetVersion.Fabric}")
                 Case Else
-                    'Case "quilt-loader" 'eg. 1.0.0
                     NotifyIncompatibleLoader(Entry.Name)
             End Select
         Next
@@ -421,7 +407,7 @@ Retry:
         Dim InstallLoaders As New List(Of LoaderBase)
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         Sub(Task As LoaderTask(Of String, Integer))
-            ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.5)
+            ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.5))
             CopyOverrideDirectory(
                 InstallTemp & ArchiveBaseFolder & "overrides",
                 McFolderSelected & "versions\" & InstanceName, Task)
@@ -456,7 +442,7 @@ Retry:
                 Throw New OperationCanceledException
             End If
             FileList.Add(New NetFile(Urls, TargetPath,
-                New FileChecker With {.ActualSize = File("fileSize").ToObject(Of Long), .Hash = File("hashes")("sha1").ToString}, True))
+                New FileChecker With {.Hash = File("hashes")("sha1").ToString}, True)) 'Modrinth 整合包不应校验文件大小(他们官方自己说的)
         Next
         If FileList.Any Then
             InstallLoaders.Add(New LoaderDownload("下载额外文件", FileList) With {.ProgressWeight = FileList.Count * 1.5}) '每个 Mod 需要 1.5s
@@ -511,7 +497,6 @@ Retry:
         Loader.Start(Request.VersionFolder)
         LoaderTaskbarAdd(Loader)
         FrmMain.BtnExtraDownload.ShowRefresh()
-        RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
         Return Loader
     End Function
 
@@ -535,7 +520,7 @@ Retry:
         Dim InstallLoaders As New List(Of LoaderBase)
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         Sub(Task As LoaderTask(Of String, Integer))
-            ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
+            ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.6))
             CopyOverrideDirectory(
                 InstallTemp & ArchiveBaseFolder & "minecraft",
                 McFolderSelected & "versions\" & InstanceName, Task)
@@ -564,7 +549,6 @@ Retry:
         Loader.Start(Request.VersionFolder)
         LoaderTaskbarAdd(Loader)
         FrmMain.BtnExtraDownload.ShowRefresh()
-        RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
         Return Loader
     End Function
 
@@ -590,7 +574,7 @@ Retry:
         Dim InstallLoaders As New List(Of LoaderBase)
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         Sub(Task As LoaderTask(Of String, Integer))
-            ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.55)
+            ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.55))
             CopyOverrideDirectory(
                 InstallTemp & ArchiveBaseFolder & ".minecraft",
                 McFolderSelected & "versions\" & InstanceName, Task)
@@ -662,7 +646,6 @@ Retry:
                     Request.NeoForgeVersion = Component("version")
                 Case "net.fabricmc.fabric-loader"
                     Request.FabricVersion = Component("version")
-                    'Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
                 Case Else
                     If UID.StartsWithF("org.lwjgl") Then '#8210
                         Logger.Info($"已跳过 LWJGL 项:{UID}")
@@ -690,7 +673,6 @@ Retry:
         Loader.Start(Request.VersionFolder)
         LoaderTaskbarAdd(Loader)
         FrmMain.BtnExtraDownload.ShowRefresh()
-        RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
         Return Loader
     End Function
 
@@ -719,7 +701,7 @@ Retry:
         Dim InstallLoaders As New List(Of LoaderBase)
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         Sub(Task As LoaderTask(Of String, Integer))
-            ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
+            ExtractModpackFiles(InstallTemp, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.6))
             CopyOverrideDirectory(
                 InstallTemp & ArchiveBaseFolder & "overrides",
                 McFolderSelected & "versions\" & InstanceName, Task)
@@ -738,7 +720,7 @@ Retry:
         Next
         If Not Addons.ContainsKey("game") Then Throw New Exception("该 MCBBS 整合包未提供游戏版本信息,无法安装!")
         If Addons.ContainsKey("quilt") Then
-            Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Red)
+            Hint("PCL 不支持安装 Quilt 整合包!", HintType.Red)
             Throw New OperationCanceledException
         End If
         Dim Request As New McInstallRequest With {
@@ -769,7 +751,6 @@ Retry:
         Loader.Start(Request.VersionFolder)
         LoaderTaskbarAdd(Loader)
         FrmMain.BtnExtraDownload.ShowRefresh()
-        RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
         Return Loader
     End Function
 
@@ -784,7 +765,7 @@ Retry:
         Dim Loader As New LoaderCombo(Of String)("解压压缩包", {
             New LoaderTask(Of String, Integer)("解压压缩包",
             Sub(Task As LoaderTask(Of String, Integer))
-                ExtractModpackFiles(TargetFolder, FileAddress, Task, 0.9)
+                ExtractModpackFiles(TargetFolder, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.9))
                 OpenExplorer(TargetFolder)
                 Thread.Sleep(400) '避免文件争用
                 '查找解压后的 exe 文件
@@ -860,7 +841,7 @@ Retry:
         Dim Loader As New LoaderCombo(Of String)("解压压缩包", {
             New LoaderTask(Of String, Integer)("解压压缩包",
             Sub(Task As LoaderTask(Of String, Integer))
-                ExtractModpackFiles(TargetFolder, FileAddress, Task, 0.95)
+                ExtractModpackFiles(TargetFolder, FileAddress, Task.CreateCancellationToken(), Task.CreateSyncProgressProvider(ToPercentage:=0.95))
                 '加入文件夹列表
                 PageSelectLeft.AddFolder(TargetFolder & ArchiveBaseFolder, PathUtils.GetLastPart(TargetFolder), False)
                 Thread.Sleep(400) '避免文件争用

+ 7 - 3
Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb

@@ -8,7 +8,8 @@ Public Module ModWatcher
         Dim IsRunning As Boolean = False
         Dim TriggerLauncherShutdown As Boolean = True
         For Each Watcher In McWatcherList
-            If Watcher.State = Watcher.MinecraftState.Loading OrElse Watcher.State = Watcher.MinecraftState.Running Then
+            If Watcher.State = Watcher.MinecraftState.Loading OrElse Watcher.State = Watcher.MinecraftState.Running OrElse
+               (Watcher.State = Watcher.MinecraftState.Crashed AndAlso Not Watcher.GameProcess.HasExited) Then
                 IsRunning = True
                 Exit For
             ElseIf Watcher.State = Watcher.MinecraftState.Crashed OrElse Watcher.State = Watcher.MinecraftState.Canceled Then
@@ -91,7 +92,9 @@ Public Module ModWatcher
             RunInNewThread(
             Sub()
                 Try
-                    Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse State = MinecraftState.Canceled OrElse Loader.State = LoadState.Canceled
+                    Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Canceled OrElse
+                             (Loader.State = LoadState.Canceled AndAlso State <> MinecraftState.Crashed) OrElse
+                             (State = MinecraftState.Crashed AndAlso GameProcess.HasExited)
                         TimerWindow()
                         TimerLog()
                         '设置窗口标题
@@ -103,6 +106,7 @@ Public Module ModWatcher
                             Thread.Sleep(64)
                         Next
                     Loop
+                    If State = MinecraftState.Crashed Then WatcherStateChanged()
                     WatcherLog("Minecraft 日志监控已退出")
                 Catch ex As Exception
                     Logger.Error(ex, "Minecraft 日志监控主循环出错")
@@ -314,7 +318,7 @@ Public Module ModWatcher
                     Dim str As New StringBuilder(512)
                     GetClassName(hwnd, str, str.Capacity)
                     Dim ClassName As String = str.ToString
-                    If Not (ClassName = "GLFW30" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Return
+                    If Not (ClassName = "GLFW30" OrElse ClassName = "SDL_app" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Return
                     '获取窗口标题名
                     str = New StringBuilder(512)
                     GetWindowText(hwnd, str, str.Capacity)

+ 28 - 22
Plain Craft Launcher 2/Modules/ModEvent.vb

@@ -178,6 +178,8 @@ Public Class CustomEvent
         Logger.Info($"执行自定义事件:{Type}, {Arg}")
         If Arg Is Nothing Then Arg = ""
         Dim Args As String() = Arg.Split("|")
+        Dim Arg0 As String = Arg.BeforeFirst("|")
+        Dim Arg1 As String = Arg.AfterFirst("|")
         Try
             Select Case Type
                 Case EventType.打开网页
@@ -194,16 +196,16 @@ Public Class CustomEvent
                     Sub()
                         Try
                             '确认实际路径
-                            Dim ActualPaths = GetAbsoluteUrls(Args(0), Type)
+                            Dim ActualPaths = GetAbsoluteUrls(Arg0, Type)
                             Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1)
                             Logger.Info($"打开类自定义事件实际路径:{Location},工作目录:{WorkingDir}")
                             '执行
                             If Type = EventType.打开帮助 Then
                                 PageOtherHelp.EnterHelpPage(Location)
                             Else
-                                If Not EventSafetyConfirm("即将执行:" & Location & If(Args.Length >= 2, " " & Args(1), "")) Then Return
+                                If Not EventSafetyConfirm("即将执行:" & Location & If(Args.Length >= 2, " " & Arg1, "")) Then Return
                                 Dim Info As New ProcessStartInfo With {
-                                    .Arguments = If(Args.Length >= 2, Args(1), ""),
+                                    .Arguments = If(Args.Length >= 2, Arg1, ""),
                                     .FileName = Location,
                                     .WorkingDirectory = WorkingDir
                                 }
@@ -215,19 +217,19 @@ Public Class CustomEvent
                     End Sub)
 
                 Case EventType.启动游戏
-                    If Args(0) = "\current" Then
+                    If Arg0 = "\current" Then
                         If McInstanceSelected Is Nothing Then
                             Hint("请先选择一个 Minecraft 版本!", HintType.Red)
                             Return
                         Else
-                            Args(0) = McInstanceSelected.Name
+                            Arg0 = McInstanceSelected.Name
                         End If
                     End If
                     RunInUi(
                     Sub()
                         If McLaunchStart(New McLaunchOptions With
-                                {.ServerIp = If(Args.Length >= 2, Args(1), Nothing), .Instance = New McInstance(Args(0))}) Then
-                            Hint($"正在启动 {Args(0)}……")
+                                {.ServerIp = If(Args.Length >= 2, Args(1), Nothing), .Instance = New McInstance(Arg0)}) Then
+                            Hint($"正在启动 {Arg0}……")
                         End If
                     End Sub)
 
@@ -264,51 +266,55 @@ Public Class CustomEvent
 
                 Case EventType.弹出窗口
                     If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 弹窗标题|弹窗内容")
-                    MyMsgBox(Args(1).Replace("\n", vbCrLf), Args(0).Replace("\n", vbCrLf), If(Args.Length > 2, Args(2), "确定"))
+                    MyMsgBox(Arg1.BeforeLast("|").Replace("\n", vbCrLf), Arg0.Replace("\n", vbCrLf), If(Args.Length > 2, Arg1.AfterLast("|"), "确定"))
 
                 Case EventType.弹出提示
-                    Hint(Args(0).Replace("\n", vbCrLf), If(Args.Length = 1, HintType.Blue, EnumUtils.FromString(Of HintType)(Args(1))))
+                    Hint(Arg0.Replace("\n", vbCrLf), If(Args.Length = 1, HintType.Blue, EnumUtils.FromString(Of HintType)(Arg1)))
 
                 Case EventType.切换页面
                     RunInUi(Sub() FrmMain.PageChange(
-                                EnumUtils.FromString(Of FormMain.PageType)(Args(0)),
-                                If(Args.Length = 1, FormMain.PageSubType.Default, EnumUtils.FromString(Of FormMain.PageSubType)(Args(1)))))
+                                EnumUtils.FromString(Of FormMain.PageType)(Arg0),
+                                If(Args.Length = 1, FormMain.PageSubType.Default, EnumUtils.FromString(Of FormMain.PageSubType)(Arg1))))
 
                 Case EventType.导入整合包, EventType.安装整合包
                     RunInUi(Sub() ModpackInstall())
 
                 Case EventType.下载文件
-                    Args(0) = Args(0).Replace("\", "/")
-                    If Not (Args(0).StartsWithF("http://", True) OrElse Args(0).StartsWithF("https://", True)) Then
+                    Arg0 = Arg0.Replace("\", "/")
+                    If Not (Arg0.StartsWithF("http://", True) OrElse Arg0.StartsWithF("https://", True)) Then
                         MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL 不支持其他乱七八糟的下载协议。", "事件执行失败")
                         Return
                     End If
-                    If Not EventSafetyConfirm("即将从该网址下载文件:" & vbCrLf & Args(0)) Then Return
+                    If Not EventSafetyConfirm("即将从该网址下载文件:" & vbCrLf & Arg0) Then Return
                     RunInUi(
                     Sub()
                         Try
                             Select Case Args.Length
                                 Case 1
-                                    PageOtherTest.StartCustomDownload(Args(0), PathUtils.GetLastPart(Args(0)))
+                                    PageOtherTest.StartCustomDownload(Arg0, PathUtils.GetLastPart(Arg0))
                                 Case 2
-                                    PageOtherTest.StartCustomDownload(Args(0), Args(1))
+                                    PageOtherTest.StartCustomDownload(Arg0, Arg1)
                                 Case Else
-                                    PageOtherTest.StartCustomDownload(Args(0), Args(1), Args(2))
+                                    PageOtherTest.StartCustomDownload(Arg0, Arg(1), Args(2))
                             End Select
                         Catch
-                            PageOtherTest.StartCustomDownload(Args(0), "未知")
+                            PageOtherTest.StartCustomDownload(Arg0, "未知")
                         End Try
                     End Sub)
 
                 Case EventType.修改设置, EventType.写入设置
                     If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 UiLauncherTransparent|400")
-                    Settings.SetSafe(Args(0), Args(1), Instance:=McInstanceSelected)
-                    If Args.Length = 2 Then Hint($"已写入设置:{Args(0)} → {Args(1)}", HintType.Green)
+                    Settings.SetSafe(Arg0, Arg1, Instance:=McInstanceSelected)
+                    If Args.Length = 2 Then Hint($"已写入设置:{Arg0} → {Arg1}", HintType.Green)
 
                 Case EventType.修改变量, EventType.写入变量
                     If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 VariableName|SomeValue")
-                    WriteReg("CustomEvent" & Args(0), Args(1))
-                    If Args.Length = 2 Then Hint($"已写入变量:{Args(0)} → {Args(1)}", HintType.Green)
+                    Try
+                        RegistryUtils.Write($"HKEY_CURRENT_USER\Software\{RegFolder}", $"CustomEvent{Arg0}", Arg1)
+                        If Args.Length = 2 Then Hint($"已写入变量:{Arg0} → {Arg1}", HintType.Green)
+                    Catch ex As Exception
+                        Logger.Warn(ex, $"写入变量失败:{Arg0} → {Arg1}", LogBehavior.Toast)
+                    End Try
 
                 Case EventType.加入房间
                     RunInUi(

+ 17 - 19
Plain Craft Launcher 2/Modules/ModMain.vb

@@ -799,26 +799,16 @@ NextFile:
     ''' 如果失败,则抛出异常。
     ''' </summary>
     Public Sub SetGPUPreference(Executeable As String)
-        Const REG_KEY As String = "Software\Microsoft\DirectX\UserGpuPreferences"
+        Const REG_KEY As String = "HKEY_CURRENT_USER\Software\Microsoft\DirectX\UserGpuPreferences"
         Const REG_VALUE As String = "GpuPreference=2;"
         '查看现有设置
-        Using ReadOnlyKey = My.Computer.Registry.CurrentUser.OpenSubKey(REG_KEY, False)
-            If ReadOnlyKey IsNot Nothing Then
-                If REG_VALUE = ReadOnlyKey.GetValue(Executeable)?.ToString() Then
-                    Logger.Info($"无需调整显卡设置:{Executeable}")
-                    Return
-                End If
-            Else
-                '创建父级键
-                Logger.Info($"需要创建显卡设置的父级键")
-                My.Computer.Registry.CurrentUser.CreateSubKey(REG_KEY)
-            End If
-        End Using
+        If RegistryUtils.Read(REG_KEY, Executeable).result?.ToString() = REG_VALUE Then
+            Logger.Info($"无需调整显卡设置:{Executeable}")
+            Return
+        End If
         '写入新设置
-        Using WriteKey = My.Computer.Registry.CurrentUser.OpenSubKey(REG_KEY, True)
-            WriteKey.SetValue(Executeable, REG_VALUE)
-            Logger.Info($"已调整显卡设置:{Executeable}")
-        End Using
+        RegistryUtils.Write(REG_KEY, Executeable, REG_VALUE)
+        Logger.Info($"已调整显卡设置:{Executeable}")
     End Sub
 
     ''' <summary>
@@ -867,11 +857,19 @@ NextFile:
             Else
                 Text = Text.Replace("{version}", Replacer(McInstanceSelected.Version.VanillaName))
             End If
+            Text = Text.Replace("{forge}", Replacer(If(McInstanceSelected.Version.HasForge, McInstanceSelected.Version.Forge, "")))
+            Text = Text.Replace("{fabric}", Replacer(If(McInstanceSelected.Version.HasFabric, McInstanceSelected.Version.Fabric, "")))
+            Text = Text.Replace("{neoforge}", Replacer(If(McInstanceSelected.Version.HasNeoForge, McInstanceSelected.Version.NeoForge, "")))
+            Text = Text.Replace("{liteloader}", Replacer(If(McInstanceSelected.Version.HasLiteLoader, "true", "")))
         Else
             Text = Text.Replace("{version_path}", Replacer(Nothing)) : Text = Text.Replace("{verpath}", Replacer(Nothing))
             Text = Text.Replace("{version_indie}", Replacer(Nothing)) : Text = Text.Replace("{verindie}", Replacer(Nothing))
             Text = Text.Replace("{name}", Replacer(Nothing))
             Text = Text.Replace("{version}", Replacer(Nothing))
+            Text = Text.Replace("{forge}", Replacer(Nothing))
+            Text = Text.Replace("{fabric}", Replacer(Nothing))
+            Text = Text.Replace("{neoforge}", Replacer(Nothing))
+            Text = Text.Replace("{liteloader}", Replacer(Nothing))
         End If
         '登录信息
         If McLoginLoader.State = LoadState.Finished Then
@@ -896,8 +894,8 @@ NextFile:
         Text = Text.RegexReplace("\{hint\}", Function() Replacer(PageOtherTest.GetRandomHint()))
         Text = Text.RegexReplace("\{cave\}", Function() Replacer(PageOtherTest.GetRandomCave()))
         Text = Text.RegexReplace("\{setup:([a-zA-Z0-9]+)\}", Function(m) Replacer(Settings.GetSafe(m.Groups(1).Value, McInstanceSelected)))
-        Text = Text.RegexReplace("\{varible:([^:\}]+)(?::([^\}]+))?\}", Function(m) Replacer(ReadReg("CustomEvent" & m.Groups(1).Value, m.Groups(2).Value)))
-        Text = Text.RegexReplace("\{variable:([^:\}]+)(?::([^\}]+))?\}", Function(m) Replacer(ReadReg("CustomEvent" & m.Groups(1).Value, m.Groups(2).Value)))
+        Text = Text.RegexReplace("\{varible:([^:\}]+)(?::([^\}]+))?\}", Function(m) Replacer(RegistryUtils.TryRead($"HKEY_CURRENT_USER\Software\{RegFolder}", $"CustomEvent{m.Groups(1).Value}", m.Groups(2).Value)))
+        Text = Text.RegexReplace("\{variable:([^:\}]+)(?::([^\}]+))?\}", Function(m) Replacer(RegistryUtils.TryRead($"HKEY_CURRENT_USER\Software\{RegFolder}", $"CustomEvent{m.Groups(1).Value}", m.Groups(2).Value)))
         Return Text
     End Function
 

+ 1 - 3
Plain Craft Launcher 2/Modules/Resource/ResourceProject.vb

@@ -502,7 +502,6 @@ Public Class ResourceProject
         '获取 Mod 加载器描述
         Dim ModLoaderDescriptionFull As String, ModLoaderDescriptionPart As String
         Dim ModLoadersForDesc = ModLoaders.Flags().ToList()
-        If Settings.Get(Of Boolean)("ToolDownloadIgnoreQuilt") Then ModLoadersForDesc.Remove(ModLoaders.Quilt)
         Select Case ModLoadersForDesc.Count
             Case 0
                 If ModLoadersForDesc.IsSingle Then
@@ -519,8 +518,7 @@ Public Class ResourceProject
                 Dim NewestDrop As Integer = If(Drops.Any, Drops.First, 9999)
                 If ModLoadersForDesc.Contains(ModLoaders.Forge) AndAlso
                    (NewestDrop < 140 OrElse ModLoadersForDesc.Contains(ModLoaders.Fabric)) AndAlso
-                   (NewestDrop < 200 OrElse ModLoadersForDesc.Contains(ModLoaders.NeoForge)) AndAlso
-                   (NewestDrop < 140 OrElse ModLoadersForDesc.Contains(ModLoaders.Quilt) OrElse Settings.Get(Of Boolean)("ToolDownloadIgnoreQuilt")) Then
+                   (NewestDrop < 200 OrElse ModLoadersForDesc.Contains(ModLoaders.NeoForge)) Then
                     ModLoaderDescriptionFull = "任意"
                     ModLoaderDescriptionPart = ""
                 Else

+ 0 - 5
Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb

@@ -179,11 +179,6 @@ Public Class ResourceSearcher
             End If
         End If
 
-        '拒绝 1.13- Quilt(这个版本根本没有 Quilt)
-        If Request.ModLoaders = ModLoaders.Quilt AndAlso CompareVersion(If(Request.GameVersion, "1.15"), "1.14") = -1 Then
-            Throw New Exception("Quilt 不支持 Minecraft " & Request.GameVersion)
-        End If
-
 #End Region
 
 #Region "中文搜索"

+ 1 - 1
Plain Craft Launcher 2/Modules/Resource/ResourceVersion.vb

@@ -348,7 +348,7 @@ Public Class ResourceVersion
                 .Height = 42
                 .Type = MyListItem.CheckType.Clickable
                 .Tag = Me
-                .Title = If(IsBadDisplay, FileName, Display)
+                .Title = If(IsBadDisplay, FileName, Display).BeforeLastOfAny({".zip", ".jar", ".mrpack", ".litemod"}, True)
                 .Logo = $"{PathImage}ReleaseTypes/{ReleaseType}.png"
                 AddHandler .Click, ClickHandler
                 '描述

+ 2 - 2
Plain Craft Launcher 2/My Project/AssemblyInfo.vb

@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
 ' 方法是按如下所示使用“*”
 
-<Assembly: AssemblyVersion("2.13.0.1")>
-<Assembly: AssemblyFileVersion("2.13.0.1")>
+<Assembly: AssemblyVersion("2.13.1.0")>
+<Assembly: AssemblyFileVersion("2.13.1.0")>
 <Assembly: NeutralResourcesLanguage("")>

+ 5 - 25
Plain Craft Launcher 2/My Project/Resources.Designer.vb

@@ -139,47 +139,27 @@ Namespace My.Resources
                 Return CType(obj,Byte())
             End Get
         End Property
-        
-        '''<summary>
-        '''  查找 System.Byte[] 类型的本地化资源。
-        '''</summary>
-        Friend ReadOnly Property JavaWrapper() As Byte()
-            Get
-                Dim obj As Object = ResourceManager.GetObject("JavaWrapper", resourceCulture)
-                Return CType(obj,Byte())
-            End Get
-        End Property
-        
+
         '''<summary>
         '''  查找 System.Byte[] 类型的本地化资源。
         '''</summary>
         Friend ReadOnly Property libwebp64() As Byte()
             Get
                 Dim obj As Object = ResourceManager.GetObject("libwebp64", resourceCulture)
-                Return CType(obj,Byte())
-            End Get
-        End Property
-        
-        '''<summary>
-        '''  查找 System.Byte[] 类型的本地化资源。
-        '''</summary>
-        Friend ReadOnly Property LUA() As Byte()
-            Get
-                Dim obj As Object = ResourceManager.GetObject("LUA", resourceCulture)
-                Return CType(obj,Byte())
+                Return CType(obj, Byte())
             End Get
         End Property
-        
+
         '''<summary>
         '''  查找 System.Byte[] 类型的本地化资源。
         '''</summary>
         Friend ReadOnly Property MeloongCore() As Byte()
             Get
                 Dim obj As Object = ResourceManager.GetObject("MeloongCore", resourceCulture)
-                Return CType(obj,Byte())
+                Return CType(obj, Byte())
             End Get
         End Property
-        
+
         '''<summary>
         '''  查找 System.Byte[] 类型的本地化资源。
         '''</summary>

+ 3 - 6
Plain Craft Launcher 2/My Project/Resources.resx

@@ -142,21 +142,18 @@
   <data name="Imazen.WebP" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Imazen.WebP.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
-  <data name="JavaWrapper" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\java-wrapper.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </data>
   <data name="libwebp64" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\libwebp64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
-  <data name="LUA" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\lwjgl-unsafe-agent.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </data>
   <data name="MeloongCore" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\..\PCLCS\bin\MeloongCore.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
   <data name="MeloongCore.Wpf" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\..\PCLCS\bin\MeloongCore.Wpf.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
+  <data name="Microsoft.Win32.Registry" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\..\PCLCS\bin\Microsoft.Win32.Registry.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </data>
   <data name="NAudio" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>

+ 2 - 37
Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb

@@ -368,7 +368,7 @@ pause"
         '添加 Java Wrapper 作为主 Jar
         Dim Arguments As String
         If UseJavaWrapper AndAlso Not Settings.Get(Of Boolean)("LaunchAdvanceDisableJLW") Then
-            Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" -jar ""{ExtractPatch("JavaWrapper")}"" optifine.Installer"
+            Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.Value.TrimEnd("\")}"" -Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" -jar ""{LaunchUtils.ExtractPatch("Launch\JavaWrapper.jar", PathPure.Value)}"" optifine.Installer"
         Else
             Arguments = $"-Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" optifine.Installer"
         End If
@@ -939,7 +939,7 @@ Retry:
         '添加 Java Wrapper 作为主 Jar
         Dim Arguments As String
         If UseJavaWrapper AndAlso Not Settings.Get(Of Boolean)("LaunchAdvanceDisableJLW") Then
-            Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{ExtractPatch("JavaWrapper")}"" com.bangbang93.ForgeInstaller ""{McFolder}"
+            Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.Value.TrimEnd("\")}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{LaunchUtils.ExtractPatch("Launch\JavaWrapper.jar", PathPure.Value)}"" com.bangbang93.ForgeInstaller ""{McFolder}"
         Else
             Arguments = $"-cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" com.bangbang93.ForgeInstaller ""{McFolder}"
         End If
@@ -2160,39 +2160,4 @@ Retry:
     ''' </summary>
     Private VanillaSyncLock As New Object
 
-    ''' <summary>
-    ''' 释放补丁文件并返回完整文件路径。
-    ''' </summary>
-    ''' <param name="Patch">"LUA" 或 "JavaWrapper"。</param>
-    Public Function ExtractPatch(Patch As String) As String
-        Dim PatchPath As String = $"{PathPure}{Patch}.jar"
-        Logger.Info($"选定的 {Patch} 路径:{PatchPath}")
-        Static Lock As New Object
-        SyncLock Lock '避免 OptiFine 和 Forge 安装时同时释放导致冲突
-            Try
-                ExtractResources(PatchPath, Patch)
-            Catch ex As Exception
-                If FileUtils.Exists(PatchPath) Then
-                    '因为未知原因可能变为只读文件(#4243)
-                    Logger.Warn(ex, $"{Patch} 文件释放失败,但文件已存在,将在删除后尝试重新生成")
-                    Try
-                        FileUtils.Delete(PatchPath)
-                        ExtractResources(PatchPath, Patch)
-                    Catch ex2 As Exception
-                        Logger.Warn(ex2, $"{Patch} 文件重新释放失败,将尝试更换文件名重新生成")
-                        PatchPath = $"{PathPure}{Patch}2.jar"
-                        Try
-                            ExtractResources(PatchPath, Patch)
-                        Catch ex3 As Exception
-                            Throw New FileNotFoundException($"释放 {Patch} 最终尝试失败", ex3)
-                        End Try
-                    End Try
-                Else
-                    Throw New FileNotFoundException($"释放 {Patch} 失败", ex)
-                End If
-            End Try
-        End SyncLock
-        Return PatchPath
-    End Function
-
 End Module

+ 1 - 1
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb

@@ -1120,7 +1120,7 @@ Public Class PageDownloadInstall
 #Region "安装"
 
     Private Sub TextSelectName_KeyDown(sender As Object, e As KeyEventArgs) Handles TextSelectName.KeyDown
-        If e.Key = Key.Enter AndAlso BtnStart.IsEnabled Then BtnStart_Click()
+        If e.Key = Key.Enter AndAlso IsInSelectPage AndAlso BtnStart.IsEnabled Then BtnStart_Click()
     End Sub
     Private Sub BtnStart_Click() Handles BtnStart.Click
         '确认版本隔离

+ 2 - 5
Plain Craft Launcher 2/Pages/PageDownload/Resource/PageDownloadCompDetail.xaml.vb

@@ -175,10 +175,7 @@ GroupDone:
                 If Project.ModLoaders.Flags.Count > 1 AndAlso '工程至少有两个加载器
                     Version.ResourceType = ResourceTypes.Mod AndAlso '是 Mod
                     McVersion.IsFormatFit(VerName) Then '不是 “快照版本” 之类的
-                    For Each Loader In Version.ModLoaders.Flags
-                        If Loader = ModLoaders.Quilt AndAlso Settings.Get(Of Boolean)("ToolDownloadIgnoreQuilt") Then Continue For
-                        Loaders.Add(Loader.ToString & " ")
-                    Next
+                    Loaders.AddRange(Version.ModLoaders.Flags.Select(Function(f) f.ToString & " "))
                 End If
                 If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
                 '实际添加
@@ -329,7 +326,7 @@ GroupDone:
             Loader.Start(McFolderSelected & "versions\" & InstanceName & "\")
             LoaderTaskbarAdd(Loader)
             FrmMain.BtnExtraDownload.ShowRefresh()
-            FrmMain.BtnExtraDownload.Ribble()
+            FrmMain.PageChange(FormMain.PageType.TaskManager)
 
         Catch ex As Exception
             Logger.Error(ex, "下载资源整合包失败")

+ 1 - 1
Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml

@@ -34,6 +34,7 @@
                     <TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" />
                     <local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" IsEditable="True" IsTextSearchEnabled="False">
                         <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
+                        <local:MyComboBoxItem Content="26.2" />
                         <local:MyComboBoxItem Content="26.1" />
                         <local:MyComboBoxItem Content="1.21.11" />
                         <local:MyComboBoxItem Content="1.21.8" />
@@ -51,7 +52,6 @@
                         <local:MyComboBoxItem Content="Forge" Tag="1" />
                         <local:MyComboBoxItem Content="NeoForge" Tag="16" />
                         <local:MyComboBoxItem Content="Fabric" Tag="4" />
-                        <local:MyComboBoxItem Content="Quilt" Tag="8" />
                         <local:MyComboBoxItem Content="LiteLoader" Tag="2" />
                     </local:MyComboBox>
                     <TextBlock VerticalAlignment="Center" Grid.Column="4" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />

+ 13 - 1
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml

@@ -181,6 +181,18 @@
                                 RequireModLoaderOrOptiFine="True" />
                             </local:MyCheckBox.Tag>
                         </local:MyCheckBox>
+                        <StackPanel Margin="30,0,0,0"
+                                Visibility="{Binding Checked, ElementName=CheckOptionsShaderPacks, Converter={StaticResource BooleanToVisibilityConverter}}">
+                            <local:MyCheckBox x:Name="CheckOptionsShaderPackSettings">
+                                <local:MyCheckBox.Tag>
+                                    <local:ExportOption
+                                Title="光影包设置"
+                                Description="已选光影包的自定义设置"
+                                ShowRules="shaderpacks/*.txt"
+                                DefaultChecked="True" />
+                                </local:MyCheckBox.Tag>
+                            </local:MyCheckBox>
+                        </StackPanel>
                         <StackPanel Margin="30,0,0,0" x:Name="PanOptionsShaderPacks"
                                 Visibility="{Binding Checked, ElementName=CheckOptionsShaderPacks, Converter={StaticResource BooleanToVisibilityConverter}}">
                         </StackPanel>
@@ -299,4 +311,4 @@
             x:Name="BtnExport" Text="开始导出"
             LogoScale="1.1" Logo="M511 995a128 128 0 0 1-57-13L70 791a126 126 0 0 1-70-113V311a126 126 0 0 1 15-60V248c1-2 3-5 5-8a127 127 0 0 1 49-42L454 13a128 128 0 0 1 112 0l383 190a126 126 0 0 1 72 113v360a126 126 0 0 1-70 115L568 984c-17 7-37 11-57 11z m42-470v370l360-178c14-7 23-21 23-38v-335L554 524zM85 330v347a42 42 0 0 0 23 38l360 178V523L85 330zM135 260l375 189 137-65L286 188 135 260z m245-118l363 197 150-71-365-180a42 42 0 0 0-37 0l-111 53z" />
     </Grid>
-</local:MyPageRight>
+</local:MyPageRight>

+ 19 - 5
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.vb

@@ -76,6 +76,7 @@ Public Class PageInstanceExport
                     If Not SubFolder.EnumerateFileSystemInfos().Any() Then Continue For
                     Dim NewCheckBox As New MyCheckBox With {. _
                         Tag = New ExportOption With {.Title = SubFolder.Name, .DefaultChecked = True, .Rules = StringUtils.LikePatternEscape($"{Folder}/{SubFolder.Name}/")}}
+                    If AcceptCompressedFile Then GetExportOption(NewCheckBox).Description = "文件夹"
                     If Panel Is PanOptionsSaves Then GetExportOption(NewCheckBox).Description = SubFolder.LastWriteTime.ToString("yyyy'/'MM'/'dd HH':'mm")
                     Panel.Children.Add(NewCheckBox)
                 Next
@@ -249,9 +250,22 @@ Public Class PageInstanceExport
             For Each CheckBox In GetAllOptions(False)
                 If Not CheckBox.Checked Then Continue For
                 Dim TargetOption = GetExportOption(CheckBox)
-                If TargetOption.Rules Is Nothing Then Continue For
+                Dim Rules = If(TargetOption.Rules?.Split("|"c).ToList(), New List(Of String))
+
+                '动态 Rules
+                If CheckBox Is CheckOptionsShaderPackSettings Then '光影包设置:只导出勾选的光影包的设置
+                    For Each ShaderPackCheckBox In PanOptionsShaderPacks.Children.OfType(Of MyCheckBox)()
+                        If Not ShaderPackCheckBox.Checked Then Continue For
+                        Dim ShaderPackOption = GetExportOption(ShaderPackCheckBox)
+                        Dim SettingFileName = ShaderPackOption.Rules.TrimEnd("/") & ".txt"
+                        If Not FileUtils.Exists(Path.Combine(PageInstanceLeft.Instance.PathIndie, SettingFileName)) Then Continue For
+                        Rules.Add(StringUtils.LikePatternEscape($"shaderpacks/{SettingFileName}"))
+                    Next
+                End If
+
+                If Not Rules.Any() Then Continue For
                 Yield $"# {TargetOption.Title}"
-                For Each Rule In TargetOption.Rules.Split("|"c)
+                For Each Rule In Rules
                     Yield Rule
                 Next
                 Yield ""
@@ -412,7 +426,7 @@ Public Class PageInstanceExport
         Dim LoaderName As String = $"导出整合包:" & PackName
         For Each OngoingLoader In LoaderTaskbar
             If OngoingLoader.Name <> LoaderName Then Continue For
-            FrmMain.PageChange(FormMain.PageType.DownloadManager)
+            FrmMain.PageChange(FormMain.PageType.TaskManager)
             Return
         Next
 
@@ -608,7 +622,7 @@ Public Class PageInstanceExport
                 Try
                     If ModrinthUploadMode Then Return 'Modrinth 上传模式下,不从 CurseForge 获取信息
                     Dim CurseForgeHashes = Loader.Input.Select(Function(m) m.CurseForgeHash)
-                    Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432/", HttpMethod.Post,
+                    Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432", HttpMethod.Post,
                         $"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches")
                     For Each ResultJson As JObject In CurseForgeRaw
                         If Not ResultJson.ContainsKey("file") Then Continue For
@@ -712,7 +726,7 @@ Public Class PageInstanceExport
         LoaderTaskbarAdd(MainLoader)
         FrmMain.BtnExtraDownload.ShowRefresh()
         FrmMain.BtnExtraDownload.Ribble()
-        FrmMain.PageChange(FormMain.PageType.DownloadManager)
+        FrmMain.PageChange(FormMain.PageType.TaskManager)
     End Sub
 
 #End Region

+ 4 - 1
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceMod.xaml.vb

@@ -309,7 +309,10 @@ Install:
                 For Each ModFile In FilePathList
                     Dim NewFileName = PathUtils.GetLastPart(ModFile).Replace(".disabled", "").Replace(".old", "")
                     If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227
-                    FileUtils.Copy(ModFile, Instance.PathIndie & "mods\" & NewFileName)
+                    NewFileName = Instance.PathIndie & "mods\" & NewFileName
+                    If ModFile = NewFileName Then Continue For '防止安装相同文件导致文件被删除
+                    FileUtils.Delete(NewFileName, True)
+                    FileUtils.Copy(ModFile, NewFileName)
                 Next
                 If FilePathList.IsSingle Then
                     Hint($"已安装 {PathUtils.GetLastPart(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Green)

+ 6 - 12
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml

@@ -62,18 +62,12 @@
                 </StackPanel>
             </local:MyCard>
             <local:MyCard Margin="0,0,0,15" Title="快捷方式" x:Name="PanFolder">
-                <StackPanel Margin="25,40,25,15">
-                    <Grid Margin="0,2,0,7" Height="35">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                        </Grid.ColumnDefinitions>
-                        <local:MyButton x:Name="BtnFolderVersion" Text="版本文件夹" MinWidth="140" Padding="13,0" Margin="0,0,20,0" />
-                        <local:MyButton x:Name="BtnFolderSaves" Text="存档文件夹" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="1" />
-                        <local:MyButton x:Name="BtnFolderMods" Text="Mod 文件夹" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="2" />
-                    </Grid>
-                </StackPanel>
+                <WrapPanel Margin="25,30,25,20">
+                    <local:MyButton x:Name="BtnFolderVersion" Text="版本文件夹" MinWidth="140" Padding="13,0" Margin="0,13,20,0" Height="35" />
+                    <local:MyButton x:Name="BtnFolderSaves" Text="存档文件夹" MinWidth="140" Padding="13,0" Margin="0,13,20,0" Height="35"/>
+                    <local:MyButton x:Name="BtnFolderMods" Text="Mod 文件夹" MinWidth="140" Padding="13,0" Margin="0,13,20,0" Height="35"/>
+                    <local:MyButton x:Name="BtnFolderScreen" Text="截图文件夹" MinWidth="140" Padding="13,0" Margin="0,13,20,0" Height="35" />
+                </WrapPanel>
             </local:MyCard>
             <local:MyCard Margin="0,0,0,15" Title="高级管理" x:Name="PanManage">
                 <StackPanel Margin="25,40,25,15">

+ 14 - 3
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.vb

@@ -109,7 +109,8 @@ Public Class PageInstanceOverall
             Dim OldPath As String = PageInstanceLeft.Instance.PathVersion
             '修改此部分的同时修改快速安装的版本名检测*
             Dim NewName As String = MyMsgBoxInput("重命名版本", "", OldName, New ObjectModel.Collection(Of Validate) From {
-                New ValidateFolderName(McFolderSelected & "versions", IgnoreCase:=False)})
+                New ValidateFolderName(McFolderSelected & "versions", IgnoreList:=New List(Of String) From {OldName})
+            })
             If String.IsNullOrWhiteSpace(NewName) Then Return
             Dim NewPath As String = McFolderSelected & "versions\" & NewName & "\"
             '重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储
@@ -157,7 +158,7 @@ Public Class PageInstanceOverall
     End Sub
 
     '版本图标
-    Private Sub ComboDisplayLogo_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ComboDisplayLogo.SelectionChanged
+    Private Sub ComboDisplayLogo_SelectionChanged() Handles ItemDisplayLogoCustom.PreviewMouseLeftButtonUp, ComboDisplayLogo.SelectionChanged
         If Not (IsLoad AndAlso AniControlEnabled = 0) Then Return
         '选择 自定义 时修改图片
         Try
@@ -228,6 +229,13 @@ Public Class PageInstanceOverall
         OpenExplorer(Folder)
     End Sub
 
+    '截图文件夹
+    Private Sub BtnFolderScreen_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnFolderScreen.Click
+        Dim Folder As String = PageInstanceLeft.Instance.PathIndie & "screenshots\"
+        DirectoryUtils.Create(Folder)
+        OpenExplorer(Folder)
+    End Sub
+
 #End Region
 
 #Region "卡片:管理"
@@ -298,8 +306,11 @@ Public Class PageInstanceOverall
         Try
             Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
             Dim IsHintIndie As Boolean = PageInstanceLeft.Instance.State <> McInstanceState.Error AndAlso PageInstanceLeft.Instance.PathIndie <> McFolderSelected
+            Dim SavesFolder = DirectoryUtils.GetInfo(PageInstanceLeft.Instance.PathIndie & "saves\")
+            Dim SaveEntries = If(SavesFolder.Exists, SavesFolder.EnumerateDirectories.OrderByDescending(Function(Save) Save.LastWriteTime).Select(Function(Save) $"{Save.Name}(上次修改:{StringUtils.FormatTimeSpan(Save.LastWriteTime - Date.Now, False)})").ToList, New List(Of String))
             Select Case MyMsgBox($"你确定要{If(IsShiftPressed, "永久", "")}删除版本 {PageInstanceLeft.Instance.Name} 吗?" &
-                        If(IsHintIndie, vbCrLf & "由于该版本开启了版本隔离,删除版本时该版本对应的存档、资源包、Mod 等文件也将被一并删除!", ""),
+                        If(IsHintIndie, vbCrLf & "该版本对应的存档、资源包、Mod 等文件也将被一并删除!" &
+                            If(SaveEntries.Any, vbCrLf & vbCrLf & "这会删除以下存档:" & vbCrLf & "· " & SaveEntries.Join(vbCrLf & "· "), ""), ""),
                         "版本删除确认", , "取消",, IsHintIndie OrElse IsShiftPressed)
                 Case 1
                     PageInstanceLeft.Instance.ResetSettingsCache()

+ 3 - 3
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.vb

@@ -83,7 +83,7 @@ Public Class PageInstanceSetup
             Settings.Reset("VersionServerLogin", Instance:=PageInstanceLeft.Instance)
             Settings.Reset("VersionArgumentIndieV2", Instance:=PageInstanceLeft.Instance)
             Settings.Reset("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance)
-            Configs.InstanceForcedJava.Reset(PageInstanceLeft.Instance.Config)
+            Configs.JavaForced.Reset(PageInstanceLeft.Instance.Config)
             JavaListRefreshWorker.Start()
 
             Logger.Info("已初始化版本独立设置")
@@ -474,7 +474,7 @@ PreFin:
         '========================================== 显示结果 ==========================================
         BtnArgumentJavaSearch.IsEnabled = True
         ComboArgumentJavaSelect.IsEnabled = True
-        Dim SelectedJava As Java = Configs.InstanceForcedJava.Get(PageInstanceLeft.Instance.Config)
+        Dim SelectedJava As Java = Configs.JavaForced.Get(PageInstanceLeft.Instance.Config)
         '更新下拉框文本
         If Not Configs.JavaList.Get().Any() Then
             LabArgumentJava.Text = "未找到 Java,点击以导入已有的 Java"
@@ -492,7 +492,7 @@ PreFin:
                 AddHandler JavaItem.MouseLeftButtonUp, Sub(sender As Object, e As MouseButtonEventArgs) e.Handled = True
                 AddHandler JavaItem.Click,
                 Sub()
-                    Configs.InstanceForcedJava.Set(JavaEntry, PageInstanceLeft.Instance.Config)
+                    Configs.JavaForced.Set(JavaEntry, PageInstanceLeft.Instance.Config)
                     UpdateJavaList()
                     ComboArgumentJavaSelect.IsDropDownOpen = False
                 End Sub

+ 6 - 0
Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb

@@ -108,6 +108,12 @@ Public Class PageLaunchRight
                     Case 17
                         Logger.Info("Bangumi 番剧主页")
                         Url = "https://bangumi.p.kaphia.qzz.io"
+                    Case 18
+                        Logger.Info("Bilibili 热门")
+                        Url = "https://bilibili.p.kaphia.qzz.io"
+                    Case 19
+                        Logger.Info("Music 云音乐热门")
+                        Url = "https://cloudmusic.p.kaphia.qzz.io"
                 End Select
         End Select
         '联网下载

+ 1 - 1
Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml

@@ -21,7 +21,7 @@
             <TextBlock Name="TextEmail" Text="加载中" Margin="8,4,8,0" FontSize="12" HorizontalAlignment="Center" TextTrimming="CharacterEllipsis" Foreground="{DynamicResource ColorBrushGray3}" />
         </StackPanel>
         <local:MyIconButton ToolTip="更换角色" Grid.Row="1" Height="14" Opacity="0" x:Name="BtnEdit" ToolTipService.InitialShowDelay="50" Grid.Column="0" HorizontalAlignment="Center" Logo="F1 M 53.2929,21.2929L 54.7071,22.7071C 56.4645,24.4645 56.4645,27.3137 54.7071,29.0711L 52.2323,31.5459L 44.4541,23.7677L 46.9289,21.2929C 48.6863,19.5355 51.5355,19.5355 53.2929,21.2929 Z M 31.7262,52.052L 23.948,44.2738L 43.0399,25.182L 50.818,32.9601L 31.7262,52.052 Z M 23.2409,47.1023L 28.8977,52.7591L 21.0463,54.9537L 23.2409,47.1023 Z" Margin="8,0,0,0" VerticalAlignment="Center" />
-        <local:MyIconButton ToolTip="退出登录" Grid.Row="1" Height="14" Opacity="0" x:Name="BtnExit" ToolTipService.InitialShowDelay="50" Grid.Column="2" HorizontalAlignment="Center" Logo="F1 M 51.0071,19.0027L 51.0071,27.0038L 48.0067,27.0038L 48.0067,22.0031L 25.0035,22.0031L 25.0035,54.0075L 48.0067,54.0075L 48.0067,49.0068L 51.0071,49.0068L 51.0071,57.008L 22.1698,57.008L 22.0031,19.0027L 51.0071,19.0027 Z M 30.0042,35.0049L 45.2563,35.0049L 37.005,28.0039L 47.0066,28.0039L 58.5082,38.0053L 47.0066,48.0067L 37.005,48.0067L 45.2563,41.0057L 30.0042,41.0057L 30.0042,35.0049 Z" Margin="0,0,8,0" VerticalAlignment="Center" />
+        <local:MyIconButton ToolTip="切换账号" Grid.Row="1" Height="14" Opacity="0" x:Name="BtnExit" ToolTipService.InitialShowDelay="50" Grid.Column="2" HorizontalAlignment="Center" Logo="M512 0A512 512 0 1 0 1024 512 512 512 0 0 0 512 0z m0 941.407086A429.407086 429.407086 0 1 1 941.407086 512 429.407086 429.407086 0 0 1 512 941.407086z m235.139657-368.64H264.045714a43.505371 43.505371 0 0 0-31.246628 72.060343l159.305143 166.765714a41.281829 41.281829 0 1 0 59.626057-56.788114l-94.997943-99.474286H747.227429a41.311086 41.311086 0 1 0 0-82.622172zM262.670629 450.940343H745.764571a43.505371 43.505371 0 0 0 31.246629-72.352914l-159.305143-166.765715a41.281829 41.281829 0 1 0-59.713828 57.022172l94.968685 99.474285H262.670629a41.281829 41.281829 0 0 0 0 82.563658z" Margin="0,0,8,0" VerticalAlignment="Center" />
     </Grid>
     <local:MySkin HorizontalAlignment="Center" VerticalAlignment="Top" x:Name="Skin" HasCape="False" />
 </Grid>

+ 1 - 1
Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb

@@ -18,7 +18,7 @@ Public Class PageLoginMs
                 ComboAccounts.Items.Add(Item)
             Next
         Catch ex As Exception
-            Logger.Error(ex, $"微软登录信息出错,登录信息已被重置({Settings.Get(Of String)("LoginMsJson")})", LogBehavior.Toast)
+            Logger.Error(ex, $"微软登录信息出错,登录信息已被重置", LogBehavior.Toast)
             Settings.Set("LoginMsJson", "{}")
         End Try
         '如果不保留输入,刷新列表后自动选择第一项

+ 6 - 2
Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml

@@ -28,6 +28,8 @@
                             <Separator />
                             <local:MyMenuItem Click="BtnSkinCape_Click" Header="修改披风"/>
                             <local:MyMenuItem Click="BtnSkinCapeRefresh_Click" Header="刷新披风列表"/>
+                            <local:MyMenuItem Header="使用 CDKEY 兑换奖励"
+                                              local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.minecraft.net/zh-hans/redeem" />
                         </ContextMenu>
                     </local:MyIconButton.ContextMenu>
                 </local:MyIconButton>
@@ -36,8 +38,10 @@
                                 LogoScale="1.1" Logo="M462.336 924.891429L73.142857 950.857143l25.965714-389.193143 467.017143-467.017143a73.398857 73.398857 0 0 1 103.789715 0l259.437714 259.437714a73.398857 73.398857 0 0 1 0 103.789715l-467.017143 467.017143z m155.684571-778.349715L202.861714 561.664l259.474286 259.474286L877.458286 405.942857 618.057143 146.541714zM151.003429 873.033143l233.508571-25.965714-207.579429-207.579429-25.965714 233.545143z m544.841142-492.982857l51.894858 51.894857-233.508572 233.508571-51.931428-51.894857 233.545142-233.508571z">
                     <local:MyIconButton.ContextMenu>
                         <ContextMenu Closed="HidePanel" HorizontalOffset="10" VerticalOffset="18">
-                            <local:MyMenuItem Header="修改密码" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://account.live.com/password/Change" />
-                            <local:MyMenuItem Header="修改玩家名" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.minecraft.net/zh-hans/msaprofile/mygames/editprofile" />
+                            <local:MyMenuItem Header="修改密码" 
+                                              local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://account.live.com/password/Change" />
+                            <local:MyMenuItem Header="修改玩家名" 
+                                              local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.minecraft.net/zh-hans/msaprofile/mygames/editprofile" />
                         </ContextMenu>
                     </local:MyIconButton.ContextMenu>
                 </local:MyIconButton>

+ 1 - 1
Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml

@@ -22,7 +22,7 @@
         </StackPanel>
         <local:MyIconButton ToolTip="更改密码" Grid.Row="1" Height="14" Opacity="0" x:Name="BtnEdit" ToolTipService.InitialShowDelay="50" Grid.Column="0" HorizontalAlignment="Center" Logo="F1 M 53.2929,21.2929L 54.7071,22.7071C 56.4645,24.4645 56.4645,27.3137 54.7071,29.0711L 52.2323,31.5459L 44.4541,23.7677L 46.9289,21.2929C 48.6863,19.5355 51.5355,19.5355 53.2929,21.2929 Z M 31.7262,52.052L 23.948,44.2738L 43.0399,25.182L 50.818,32.9601L 31.7262,52.052 Z M 23.2409,47.1023L 28.8977,52.7591L 21.0463,54.9537L 23.2409,47.1023 Z" Margin="8,0,0,0" VerticalAlignment="Center"
                   local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://login.mc-user.com:233/account/changepw" />
-        <local:MyIconButton ToolTip="退出登录" Grid.Row="1" Height="14" Opacity="0" x:Name="BtnExit" ToolTipService.InitialShowDelay="50" Grid.Column="2" HorizontalAlignment="Center" Logo="F1 M 51.0071,19.0027L 51.0071,27.0038L 48.0067,27.0038L 48.0067,22.0031L 25.0035,22.0031L 25.0035,54.0075L 48.0067,54.0075L 48.0067,49.0068L 51.0071,49.0068L 51.0071,57.008L 22.1698,57.008L 22.0031,19.0027L 51.0071,19.0027 Z M 30.0042,35.0049L 45.2563,35.0049L 37.005,28.0039L 47.0066,28.0039L 58.5082,38.0053L 47.0066,48.0067L 37.005,48.0067L 45.2563,41.0057L 30.0042,41.0057L 30.0042,35.0049 Z" Margin="0,0,8,0" VerticalAlignment="Center" />
+        <local:MyIconButton ToolTip="切换账号" Grid.Row="1" Height="14" Opacity="0" x:Name="BtnExit" ToolTipService.InitialShowDelay="50" Grid.Column="2" HorizontalAlignment="Center" Logo="M512 0A512 512 0 1 0 1024 512 512 512 0 0 0 512 0z m0 941.407086A429.407086 429.407086 0 1 1 941.407086 512 429.407086 429.407086 0 0 1 512 941.407086z m235.139657-368.64H264.045714a43.505371 43.505371 0 0 0-31.246628 72.060343l159.305143 166.765714a41.281829 41.281829 0 1 0 59.626057-56.788114l-94.997943-99.474286H747.227429a41.311086 41.311086 0 1 0 0-82.622172zM262.670629 450.940343H745.764571a43.505371 43.505371 0 0 0 31.246629-72.352914l-159.305143-166.765715a41.281829 41.281829 0 1 0-59.713828 57.022172l94.968685 99.474285H262.670629a41.281829 41.281829 0 0 0 0 82.563658z" Margin="0,0,8,0" VerticalAlignment="Center" />
     </Grid>
     <local:MySkin HorizontalAlignment="Center" VerticalAlignment="Top" x:Name="Skin" HasCape="False" />
 </Grid>

+ 2 - 2
Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb

@@ -487,8 +487,8 @@ Public Class PageLinkMain
         If FileUtils.Exists(PathEasyTier & "EasyTier.zip") Then
             '解压
             Dim ExtractPath As String = RequestTaskTempFolder()
-            FileUtils.ExtractToDirectory(PathEasyTier & "EasyTier.zip", ExtractPath,
-                progressHandler:=Sub(Percentage) Task.Progress = Percentage * 0.05)
+            'FileUtils.ExtractToDirectory(PathEasyTier & "EasyTier.zip", ExtractPath,
+            '    progressHandler:=Sub(Percentage) Task.Progress = Percentage * 0.05)
             DirectoryUtils.Copy(DirectoryUtils.EnumerateDirectories(ExtractPath, True).First, PathEasyTier)
             '重命名
             FileUtils.Move(PathEasyTier & "easytier-core.exe", PathEasyTier & "联机模块.exe")

+ 313 - 312
Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml

@@ -11,6 +11,7 @@
                     <Grid.RowDefinitions>
                         <RowDefinition Height="45" />
                         <RowDefinition Height="45" />
+                        <RowDefinition Height="45" />
                     </Grid.RowDefinitions>
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition Width="40" />
@@ -18,21 +19,27 @@
                         <ColumnDefinition Width="150" />
                     </Grid.ColumnDefinitions>
                     <local:MyListItem IsHitTestVisible="False" Title="龙腾猫跃" Margin="-5,0,15,0" Info="Plain Craft Launcher 的开发者!" Grid.Row="0" Grid.Column="1" />
-                    <local:MyListItem IsHitTestVisible="False" Title="Plain Craft Launcher 2" Margin="-5,0,15,0" Info="当前版本:%VERSION%(%VERSIONCODE%.%BRANCH%)" Grid.Row="1" Grid.Column="1" x:Name="ItemAboutPcl" />
-                    <Image Source="/Plain Craft Launcher 2;component/Images/Heads/Logo.png" Grid.Row="1" Margin="3">
+                    <local:MyListItem IsHitTestVisible="False" Title="HerobrineXia" Margin="-5,0,15,0" Info="Plain Craft Launcher 的协力开发者!" Grid.Row="1" Grid.Column="1" />
+                    <local:MyListItem IsHitTestVisible="False" Title="Plain Craft Launcher 2" Margin="-5,0,15,0" Info="当前版本:%VERSION%(%VERSIONCODE%.%BRANCH%)" Grid.Row="2" Grid.Column="1" x:Name="ItemAboutPcl" />
+                    <Image Source="/Plain Craft Launcher 2;component/Images/Heads/LTCat.jpg" Grid.Row="0" Margin="3">
                         <Image.Clip>
                             <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
                         </Image.Clip>
                     </Image>
-                    <Image Source="/Plain Craft Launcher 2;component/Images/Heads/LTCat.jpg" Grid.Row="0" Margin="3">
+                    <Image Source="/Plain Craft Launcher 2;component/Images/Heads/HerobrineXia.png" Grid.Row="1" Margin="3">
+                        <Image.Clip>
+                            <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
+                        </Image.Clip>
+                    </Image>
+                    <Image Source="/Plain Craft Launcher 2;component/Images/Heads/Logo.png" Grid.Row="2" Margin="3">
                         <Image.Clip>
                             <EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
                         </Image.Clip>
                     </Image>
                     <local:MyButton Text="赞助 PCL !" Grid.Column="2" Grid.Row="0" Height="35" ColorType="Highlight"
                                     local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://meloong.com/afd/a/LTCat" />
-                    <local:MyButton Text="查看源代码" Grid.Column="2" Grid.Row="1" Height="35" 
-                                    local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/Hex-Dragon/PCL2" />
+                    <local:MyButton Text="检查更新" Grid.Column="2" Grid.Row="2" Height="35" 
+                                    x:Name="BtnAboutUpdate" />
                 </Grid>
             </local:MyCard>
             <local:MyCard Margin="0,0,0,15" Title="特别鸣谢">
@@ -124,335 +131,329 @@
             <local:MyCard Margin="0,0,0,15" Title="赞助者">
                 <StackPanel Margin="25,40,19,20">
                     <TextBlock HorizontalAlignment="Left" Text="以下是近期的高级赞助者们!感谢大家对 PCL 的支持!!!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
-                    <WrapPanel Margin="0,0,0,10">
                        <TextBlock Margin="0,1.5,6,0" Text="." />
-                        <TextBlock Margin="0,1.5,6,0" Text="7" />
-                        <TextBlock Margin="0,1.5,6,0" Text="ln" />
-                        <TextBlock Margin="0,1.5,6,0" Text="sc" />
-                        <TextBlock Margin="0,1.5,6,0" Text="龙" />
-                        <TextBlock Margin="0,1.5,6,0" Text="人" />
-                        <TextBlock Margin="0,1.5,6,0" Text="溈" />
-                        <TextBlock Margin="0,1.5,6,0" Text="域" />
-                        <TextBlock Margin="0,1.5,6,0" Text="菌" />
-                        <TextBlock Margin="0,1.5,6,0" Text="。" />
-                        <TextBlock Margin="0,1.5,6,0" Text="東" />
-                        <TextBlock Margin="0,1.5,6,0" Text="喆" />
-                        <TextBlock Margin="0,1.5,6,0" Text="辞" />
-                        <TextBlock Margin="0,1.5,6,0" Text="溯" />
+                    <WrapPanel Margin="0,0,0,10">
                        <TextBlock Margin="0,1.5,6,0" Text="L" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Z" />
+                        <TextBlock Margin="0,1.5,6,0" Text="N" />
+                        <TextBlock Margin="0,1.5,6,0" Text="...:" />
+                        <TextBlock Margin="0,1.5,6,0" Text="妖" />
+                        <TextBlock Margin="0,1.5,6,0" Text="萧" />
                         <TextBlock Margin="0,1.5,6,0" Text="乔" />
-                        <TextBlock Margin="0,1.5,6,0" Text="liy" />
-                        <TextBlock Margin="0,1.5,6,0" Text="xu" />
-                        <TextBlock Margin="0,1.5,6,0" Text="lor" />
-                        <TextBlock Margin="0,1.5,6,0" Text="💢" />
-                        <TextBlock Margin="0,1.5,6,0" Text="ikii" />
-                        <TextBlock Margin="0,1.5,6,0" Text="ym" />
-                        <TextBlock Margin="0,1.5,6,0" Text="tstt" />
-                        <TextBlock Margin="0,1.5,6,0" Text="hjk" />
-                        <TextBlock Margin="0,1.5,6,0" Text="s11" />
-                        <TextBlock Margin="0,1.5,6,0" Text="gxx" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Lhy" />
-                        <TextBlock Margin="0,1.5,6,0" Text="jojo" />
-                        <TextBlock Margin="0,1.5,6,0" Text="沙轻" />
-                        <TextBlock Margin="0,1.5,6,0" Text="阳阳" />
-                        <TextBlock Margin="0,1.5,6,0" Text="画卿" />
-                        <TextBlock Margin="0,1.5,6,0" Text="幽灵" />
-                        <TextBlock Margin="0,1.5,6,0" Text="御衡" />
-                        <TextBlock Margin="0,1.5,6,0" Text="语墨" />
-                        <TextBlock Margin="0,1.5,6,0" Text="若希" />
-                        <TextBlock Margin="0,1.5,6,0" Text="少帅" />
-                        <TextBlock Margin="0,1.5,6,0" Text="小怂" />
-                        <TextBlock Margin="0,1.5,6,0" Text="叶虚" />
-                        <TextBlock Margin="0,1.5,6,0" Text="伍十" />
-                        <TextBlock Margin="0,1.5,6,0" Text="计计" />
-                        <TextBlock Margin="0,1.5,6,0" Text="雪雪" />
-                        <TextBlock Margin="0,1.5,6,0" Text="李镜" />
-                        <TextBlock Margin="0,1.5,6,0" Text="迪勒" />
-                        <TextBlock Margin="0,1.5,6,0" Text="。。" />
-                        <TextBlock Margin="0,1.5,6,0" Text="优优" />
-                        <TextBlock Margin="0,1.5,6,0" Text="青烬" />
-                        <TextBlock Margin="0,1.5,6,0" Text="苏籁" />
-                        <TextBlock Margin="0,1.5,6,0" Text="阿江" />
-                        <TextBlock Margin="0,1.5,6,0" Text="绵绵" />
-                        <TextBlock Margin="0,1.5,6,0" Text="萧白" />
-                        <TextBlock Margin="0,1.5,6,0" Text="枫灵" />
-                        <TextBlock Margin="0,1.5,6,0" Text="豆腐" />
-                        <TextBlock Margin="0,1.5,6,0" Text="无聊" />
-                        <TextBlock Margin="0,1.5,6,0" Text="闻序" />
-                        <TextBlock Margin="0,1.5,6,0" Text="风鸢" />
-                        <TextBlock Margin="0,1.5,6,0" Text="殉情" />
-                        <TextBlock Margin="0,1.5,6,0" Text="朱磊" />
-                        <TextBlock Margin="0,1.5,6,0" Text="先森" />
-                        <TextBlock Margin="0,1.5,6,0" Text="文博" />
-                        <TextBlock Margin="0,1.5,6,0" Text="月白" />
-                        <TextBlock Margin="0,1.5,6,0" Text="角慕" />
-                        <TextBlock Margin="0,1.5,6,0" Text="楽天" />
-                        <TextBlock Margin="0,1.5,6,0" Text="九杳" />
-                        <TextBlock Margin="0,1.5,6,0" Text="昨易" />
-                        <TextBlock Margin="0,1.5,6,0" Text="W.H" />
-                        <TextBlock Margin="0,1.5,6,0" Text="嘟嘟" />
-                        <TextBlock Margin="0,1.5,6,0" Text="断疆" />
-                        <TextBlock Margin="0,1.5,6,0" Text="麋鹿" />
-                        <TextBlock Margin="0,1.5,6,0" Text="云心" />
-                        <TextBlock Margin="0,1.5,6,0" Text="睚眦" />
-                        <TextBlock Margin="0,1.5,6,0" Text="诡奇" />
-                        <TextBlock Margin="0,1.5,6,0" Text="咲狐" />
-                        <TextBlock Margin="0,1.5,6,0" Text="白云" />
-                        <TextBlock Margin="0,1.5,6,0" Text="泽闻" />
-                        <TextBlock Margin="0,1.5,6,0" Text="逍遥" />
-                        <TextBlock Margin="0,1.5,6,0" Text="木鱼" />
-                        <TextBlock Margin="0,1.5,6,0" Text="凌月" />
-                        <TextBlock Margin="0,1.5,6,0" Text="梓昕" />
-                        <TextBlock Margin="0,1.5,6,0" Text="白菜" />
-                        <TextBlock Margin="0,1.5,6,0" Text="云上" />
-                        <TextBlock Margin="0,1.5,6,0" Text="老赵" />
-                        <TextBlock Margin="0,1.5,6,0" Text="拾岳" />
-                        <TextBlock Margin="0,1.5,6,0" Text="济川" />
-                        <TextBlock Margin="0,1.5,6,0" Text="樾安" />
-                        <TextBlock Margin="0,1.5,6,0" Text="蜜狳" />
-                        <TextBlock Margin="0,1.5,6,0" Text="七月" />
-                        <TextBlock Margin="0,1.5,6,0" Text="北瓜" />
-                        <TextBlock Margin="0,1.5,6,0" Text="昔涟" />
-                        <TextBlock Margin="0,1.5,6,0" Text="浅璃" />
-                        <TextBlock Margin="0,1.5,6,0" Text="成盏" />
+                        <TextBlock Margin="0,1.5,6,0" Text="cc" />
+                        <TextBlock Margin="0,1.5,6,0" Text="!" />
+                        <TextBlock Margin="0,1.5,6,0" Text="一" />
+                        <TextBlock Margin="0,1.5,6,0" Text="韆" />
+                        <TextBlock Margin="0,1.5,6,0" Text="莫" />
+                        <TextBlock Margin="0,1.5,6,0" Text="无" />
+                        <TextBlock Margin="0,1.5,6,0" Text="澍" />
+                        <TextBlock Margin="0,1.5,6,0" Text="ttt" />
+                        <TextBlock Margin="0,1.5,6,0" Text="88" />
+                        <TextBlock Margin="0,1.5,6,0" Text="33" />
+                        <TextBlock Margin="0,1.5,6,0" Text="kk" />
+                        <TextBlock Margin="0,1.5,6,0" Text="jjb" />
+                        <TextBlock Margin="0,1.5,6,0" Text="+1" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Iirs" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Lio" />
+                        <TextBlock Margin="0,1.5,6,0" Text="lrw" />
+                        <TextBlock Margin="0,1.5,6,0" Text="LLL" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Sht" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Nul" />
+                        <TextBlock Margin="0,1.5,6,0" Text="250" />
+                        <TextBlock Margin="0,1.5,6,0" Text="kile" />
+                        <TextBlock Margin="0,1.5,6,0" Text="pbc" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Aya" />
+                        <TextBlock Margin="0,1.5,6,0" Text="mjp" />
+                        <TextBlock Margin="0,1.5,6,0" Text="冒子" />
+                        <TextBlock Margin="0,1.5,6,0" Text="王道" />
+                        <TextBlock Margin="0,1.5,6,0" Text="鸡人" />
+                        <TextBlock Margin="0,1.5,6,0" Text="喵根" />
+                        <TextBlock Margin="0,1.5,6,0" Text="归墟" />
+                        <TextBlock Margin="0,1.5,6,0" Text="键来" />
                         <TextBlock Margin="0,1.5,6,0" Text="而后" />
                         <TextBlock Margin="0,1.5,6,0" Text="南安" />
-                        <TextBlock Margin="0,1.5,6,0" Text="ryan" />
-                        <TextBlock Margin="0,1.5,6,0" Text="xx_α" />
-                        <TextBlock Margin="0,1.5,6,0" Text="欸·柚" />
-                        <TextBlock Margin="0,1.5,6,0" Text="liutd" />
-                        <TextBlock Margin="0,1.5,6,0" Text="KIO3" />
-                        <TextBlock Margin="0,1.5,6,0" Text=" 无悔" />
+                        <TextBlock Margin="0,1.5,6,0" Text="曰久" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小翼" />
+                        <TextBlock Margin="0,1.5,6,0" Text="鲤逐" />
+                        <TextBlock Margin="0,1.5,6,0" Text="陌天" />
+                        <TextBlock Margin="0,1.5,6,0" Text="eqw" />
+                        <TextBlock Margin="0,1.5,6,0" Text="缘泠" />
+                        <TextBlock Margin="0,1.5,6,0" Text="烨落" />
+                        <TextBlock Margin="0,1.5,6,0" Text="安安" />
+                        <TextBlock Margin="0,1.5,6,0" Text="寒叙" />
+                        <TextBlock Margin="0,1.5,6,0" Text="诶嘿" />
+                        <TextBlock Margin="0,1.5,6,0" Text="月月" />
+                        <TextBlock Margin="0,1.5,6,0" Text="凌迟" />
+                        <TextBlock Margin="0,1.5,6,0" Text="泰吉" />
+                        <TextBlock Margin="0,1.5,6,0" Text="楚渡" />
+                        <TextBlock Margin="0,1.5,6,0" Text="将夜" />
+                        <TextBlock Margin="0,1.5,6,0" Text="滴雨" />
+                        <TextBlock Margin="0,1.5,6,0" Text="无萤" />
+                        <TextBlock Margin="0,1.5,6,0" Text="秋水" />
+                        <TextBlock Margin="0,1.5,6,0" Text="团子" />
+                        <TextBlock Margin="0,1.5,6,0" Text="川儿" />
+                        <TextBlock Margin="0,1.5,6,0" Text="冥曌" />
+                        <TextBlock Margin="0,1.5,6,0" Text="红中" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小云" />
+                        <TextBlock Margin="0,1.5,6,0" Text="诗人" />
+                        <TextBlock Margin="0,1.5,6,0" Text="狐狸" />
+                        <TextBlock Margin="0,1.5,6,0" Text="游阙" />
+                        <TextBlock Margin="0,1.5,6,0" Text="悠真" />
+                        <TextBlock Margin="0,1.5,6,0" Text="天雨" />
+                        <TextBlock Margin="0,1.5,6,0" Text="章凤" />
+                        <TextBlock Margin="0,1.5,6,0" Text="空空" />
+                        <TextBlock Margin="0,1.5,6,0" Text="去衣" />
+                        <TextBlock Margin="0,1.5,6,0" Text="老抽" />
+                        <TextBlock Margin="0,1.5,6,0" Text="七海" />
+                        <TextBlock Margin="0,1.5,6,0" Text="品茗" />
+                        <TextBlock Margin="0,1.5,6,0" Text="白桦" />
+                        <TextBlock Margin="0,1.5,6,0" Text="狐斋" />
+                        <TextBlock Margin="0,1.5,6,0" Text="猫神" />
+                        <TextBlock Margin="0,1.5,6,0" Text="乙总" />
+                        <TextBlock Margin="0,1.5,6,0" Text="屺野" />
+                        <TextBlock Margin="0,1.5,6,0" Text="极光" />
+                        <TextBlock Margin="0,1.5,6,0" Text="哈哈" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小洛" />
+                        <TextBlock Margin="0,1.5,6,0" Text="璃辰" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Byet" />
+                        <TextBlock Margin="0,1.5,6,0" Text="ZDD" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Um1" />
+                        <TextBlock Margin="0,1.5,6,0" Text="2514" />
                         <TextBlock Margin="0,1.5,6,0" Text="4440" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Dr.松" />
-                        <TextBlock Margin="0,1.5,6,0" Text="LiMu" />
-                        <TextBlock Margin="0,1.5,6,0" Text="KING" />
-                        <TextBlock Margin="0,1.5,6,0" Text="ᝰᧁꫀꪑⅈꪀⅈ💫" />
-                        <TextBlock Margin="0,1.5,6,0" Text="ming" />
-                        <TextBlock Margin="0,1.5,6,0" Text="CIYE_" />
-                        <TextBlock Margin="0,1.5,6,0" Text="祇–仆" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Pluto" />
-                        <TextBlock Margin="0,1.5,6,0" Text="LYX_7" />
-                        <TextBlock Margin="0,1.5,6,0" Text="刘666" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Dong" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Lecen" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Hikari" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Vertin" />
-                        <TextBlock Margin="0,1.5,6,0" Text="35035" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Dye乄" />
-                        <TextBlock Margin="0,1.5,6,0" Text="白椰菜" />
-                        <TextBlock Margin="0,1.5,6,0" Text="小白龙" />
-                        <TextBlock Margin="0,1.5,6,0" Text="TeRiRi" />
-                        <TextBlock Margin="0,1.5,6,0" Text="索菲亚" />
-                        <TextBlock Margin="0,1.5,6,0" Text="穷哥们" />
-                        <TextBlock Margin="0,1.5,6,0" Text="华华子" />
-                        <TextBlock Margin="0,1.5,6,0" Text="欢喜果" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Fu_jc" />
+                        <TextBlock Margin="0,1.5,6,0" Text="LEVA" />
+                        <TextBlock Margin="0,1.5,6,0" Text="ZNLL" />
+                        <TextBlock Margin="0,1.5,6,0" Text="joker" />
+                        <TextBlock Margin="0,1.5,6,0" Text="RXZY" />
+                        <TextBlock Margin="0,1.5,6,0" Text="白成y" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Rofni" />
+                        <TextBlock Margin="0,1.5,6,0" Text="mzqc" />
+                        <TextBlock Margin="0,1.5,6,0" Text="jason" />
+                        <TextBlock Margin="0,1.5,6,0" Text="xxlzta" />
+                        <TextBlock Margin="0,1.5,6,0" Text="end_x" />
+                        <TextBlock Margin="0,1.5,6,0" Text="QWYJ" />
+                        <TextBlock Margin="0,1.5,6,0" Text="qwqw" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Angel" />
+                        <TextBlock Margin="0,1.5,6,0" Text="晓空er" />
+                        <TextBlock Margin="0,1.5,6,0" Text="肥富帅" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小王子" />
+                        <TextBlock Margin="0,1.5,6,0" Text="狐狸涩" />
                         <TextBlock Margin="0,1.5,6,0" Text="大涡流" />
                         <TextBlock Margin="0,1.5,6,0" Text="无名氏" />
-                        <TextBlock Margin="0,1.5,6,0" Text="power" />
-                        <TextBlock Margin="0,1.5,6,0" Text="苏清绾" />
-                        <TextBlock Margin="0,1.5,6,0" Text="四月初" />
-                        <TextBlock Margin="0,1.5,6,0" Text="雪落骆" />
-                        <TextBlock Margin="0,1.5,6,0" Text="秋天爽" />
-                        <TextBlock Margin="0,1.5,6,0" Text="茏三颜" />
-                        <TextBlock Margin="0,1.5,6,0" Text="月落蝶" />
-                        <TextBlock Margin="0,1.5,6,0" Text="蒲咩咩" />
-                        <TextBlock Margin="0,1.5,6,0" Text="糖不哭" />
-                        <TextBlock Margin="0,1.5,6,0" Text="风雨颜" />
-                        <TextBlock Margin="0,1.5,6,0" Text="花江湖" />
-                        <TextBlock Margin="0,1.5,6,0" Text="大馒头" />
-                        <TextBlock Margin="0,1.5,6,0" Text="啊哈哈" />
-                        <TextBlock Margin="0,1.5,6,0" Text="云与海" />
-                        <TextBlock Margin="0,1.5,6,0" Text="V0rtex" />
-                        <TextBlock Margin="0,1.5,6,0" Text="杨子普" />
-                        <TextBlock Margin="0,1.5,6,0" Text="大阿科" />
-                        <TextBlock Margin="0,1.5,6,0" Text="夷希微" />
-                        <TextBlock Margin="0,1.5,6,0" Text="吃不饱" />
-                        <TextBlock Margin="0,1.5,6,0" Text="爱熙熙" />
-                        <TextBlock Margin="0,1.5,6,0" Text="丁老王" />
-                        <TextBlock Margin="0,1.5,6,0" Text="吕雪源" />
-                        <TextBlock Margin="0,1.5,6,0" Text="赵亦勋" />
-                        <TextBlock Margin="0,1.5,6,0" Text="为南西" />
-                        <TextBlock Margin="0,1.5,6,0" Text="下午觉" />
-                        <TextBlock Margin="0,1.5,6,0" Text="李寒衣" />
-                        <TextBlock Margin="0,1.5,6,0" Text="水不湿" />
-                        <TextBlock Margin="0,1.5,6,0" Text="椛芷茈" />
-                        <TextBlock Margin="0,1.5,6,0" Text="李察维" />
-                        <TextBlock Margin="0,1.5,6,0" Text="十六夜" />
-                        <TextBlock Margin="0,1.5,6,0" Text="皮小风" />
+                        <TextBlock Margin="0,1.5,6,0" Text="紫风狐" />
+                        <TextBlock Margin="0,1.5,6,0" Text="范桂圆" />
+                        <TextBlock Margin="0,1.5,6,0" Text="芸芸云" />
+                        <TextBlock Margin="0,1.5,6,0" Text="快夏波" />
                         <TextBlock Margin="0,1.5,6,0" Text="陈知远" />
-                        <TextBlock Margin="0,1.5,6,0" Text="TaLula" />
-                        <TextBlock Margin="0,1.5,6,0" Text="N线🧵" />
-                        <TextBlock Margin="0,1.5,6,0" Text="秋辞白." />
-                        <TextBlock Margin="0,1.5,6,0" Text="Keil_v5" />
-                        <TextBlock Margin="0,1.5,6,0" Text="laimati" />
-                        <TextBlock Margin="0,1.5,6,0" Text="TraSok" />
-                        <TextBlock Margin="0,1.5,6,0" Text="CH2N8" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Ls-盛望" />
-                        <TextBlock Margin="0,1.5,6,0" Text="FiLin12" />
-                        <TextBlock Margin="0,1.5,6,0" Text="cz_awa" />
-                        <TextBlock Margin="0,1.5,6,0" Text="SYMYR" />
-                        <TextBlock Margin="0,1.5,6,0" Text="524950" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Trigger" />
+                        <TextBlock Margin="0,1.5,6,0" Text="梦华书" />
+                        <TextBlock Margin="0,1.5,6,0" Text="星期天" />
+                        <TextBlock Margin="0,1.5,6,0" Text="铸日者" />
+                        <TextBlock Margin="0,1.5,6,0" Text="晴云雯" />
+                        <TextBlock Margin="0,1.5,6,0" Text="叶龙辉" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小零蚀" />
+                        <TextBlock Margin="0,1.5,6,0" Text="唐墨白" />
+                        <TextBlock Margin="0,1.5,6,0" Text="香子兰" />
+                        <TextBlock Margin="0,1.5,6,0" Text="胡萝北" />
+                        <TextBlock Margin="0,1.5,6,0" Text="乐永昶" />
+                        <TextBlock Margin="0,1.5,6,0" Text="lingke" />
+                        <TextBlock Margin="0,1.5,6,0" Text="东雪莲" />
+                        <TextBlock Margin="0,1.5,6,0" Text="伊文斯" />
+                        <TextBlock Margin="0,1.5,6,0" Text="丁乙恒" />
+                        <TextBlock Margin="0,1.5,6,0" Text="朔望月" />
+                        <TextBlock Margin="0,1.5,6,0" Text="V0rt3x" />
+                        <TextBlock Margin="0,1.5,6,0" Text="提灯狼" />
+                        <TextBlock Margin="0,1.5,6,0" Text="王孟清" />
+                        <TextBlock Margin="0,1.5,6,0" Text="牛排鸭" />
+                        <TextBlock Margin="0,1.5,6,0" Text="王靖淳" />
+                        <TextBlock Margin="0,1.5,6,0" Text="嘿嘿地" />
+                        <TextBlock Margin="0,1.5,6,0" Text="鹿露璐" />
+                        <TextBlock Margin="0,1.5,6,0" Text="琪露诺" />
+                        <TextBlock Margin="0,1.5,6,0" Text="亚波人" />
+                        <TextBlock Margin="0,1.5,6,0" Text="卿天岚" />
+                        <TextBlock Margin="0,1.5,6,0" Text="哈士奇" />
+                        <TextBlock Margin="0,1.5,6,0" Text="江溪渺" />
+                        <TextBlock Margin="0,1.5,6,0" Text="浮千傀" />
+                        <TextBlock Margin="0,1.5,6,0" Text="恰啦啦" />
+                        <TextBlock Margin="0,1.5,6,0" Text="梦痕丿" />
+                        <TextBlock Margin="0,1.5,6,0" Text="α-蒎烯" />
+                        <TextBlock Margin="0,1.5,6,0" Text="慕qwq" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Twicat" />
+                        <TextBlock Margin="0,1.5,6,0" Text="stenac" />
+                        <TextBlock Margin="0,1.5,6,0" Text="JOKER" />
+                        <TextBlock Margin="0,1.5,6,0" Text="半日谣." />
+                        <TextBlock Margin="0,1.5,6,0" Text="Triple9" />
+                        <TextBlock Margin="0,1.5,6,0" Text="gediao" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Zen1th" />
                         <TextBlock Margin="0,1.5,6,0" Text="CH南宫" />
-                        <TextBlock Margin="0,1.5,6,0" Text="bajie79" />
-                        <TextBlock Margin="0,1.5,6,0" Text="_xundu" />
-                        <TextBlock Margin="0,1.5,6,0" Text="TSLOLY" />
-                        <TextBlock Margin="0,1.5,6,0" Text="ncg303" />
-                        <TextBlock Margin="0,1.5,6,0" Text="cqg36k" />
-                        <TextBlock Margin="0,1.5,6,0" Text="YueYue" />
-                        <TextBlock Margin="0,1.5,6,0" Text="火羽白S" />
-                        <TextBlock Margin="0,1.5,6,0" Text="AMumi" />
+                        <TextBlock Margin="0,1.5,6,0" Text="qiumin" />
+                        <TextBlock Margin="0,1.5,6,0" Text="cui白烁" />
+                        <TextBlock Margin="0,1.5,6,0" Text="anyayu" />
+                        <TextBlock Margin="0,1.5,6,0" Text="SISENG" />
+                        <TextBlock Margin="0,1.5,6,0" Text="ro-suto" />
                         <TextBlock Margin="0,1.5,6,0" Text="GAGUA" />
-                        <TextBlock Margin="0,1.5,6,0" Text="shijie02" />
-                        <TextBlock Margin="0,1.5,6,0" Text="LULULU" />
-                        <TextBlock Margin="0,1.5,6,0" Text="iso3824" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Yununy" />
-                        <TextBlock Margin="0,1.5,6,0" Text="pnd6ou" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Liuaovo" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Akashi7" />
-                        <TextBlock Margin="0,1.5,6,0" Text="softtype" />
-                        <TextBlock Margin="0,1.5,6,0" Text="dumpyy" />
-                        <TextBlock Margin="0,1.5,6,0" Text="LO_WSY" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Mirtium" />
-                        <TextBlock Margin="0,1.5,6,0" Text="adccadc" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Bug虫爷" />
-                        <TextBlock Margin="0,1.5,6,0" Text="DylanPL" />
-                        <TextBlock Margin="0,1.5,6,0" Text="moxuan" />
-                        <TextBlock Margin="0,1.5,6,0" Text="elyruirui" />
-                        <TextBlock Margin="0,1.5,6,0" Text="井上青叶" />
-                        <TextBlock Margin="0,1.5,6,0" Text="懒人ROY" />
-                        <TextBlock Margin="0,1.5,6,0" Text="殇殇月月" />
-                        <TextBlock Margin="0,1.5,6,0" Text="日隅汐音" />
-                        <TextBlock Margin="0,1.5,6,0" Text="小猫渔民" />
-                        <TextBlock Margin="0,1.5,6,0" Text="凤辞时笙" />
-                        <TextBlock Margin="0,1.5,6,0" Text="清苍星海" />
-                        <TextBlock Margin="0,1.5,6,0" Text="芒果挺忙" />
-                        <TextBlock Margin="0,1.5,6,0" Text="只鱼二三" />
-                        <TextBlock Margin="0,1.5,6,0" Text="エンソウ" />
-                        <TextBlock Margin="0,1.5,6,0" Text="高露威姿" />
-                        <TextBlock Margin="0,1.5,6,0" Text="雪本柚子" />
-                        <TextBlock Margin="0,1.5,6,0" Text="萌新求带" />
-                        <TextBlock Margin="0,1.5,6,0" Text="顾炎武月" />
-                        <TextBlock Margin="0,1.5,6,0" Text="刻记牛杂" />
-                        <TextBlock Margin="0,1.5,6,0" Text="小飞小飞" />
-                        <TextBlock Margin="0,1.5,6,0" Text="纯真雪豹" />
-                        <TextBlock Margin="0,1.5,6,0" Text="罗兹瓦尔" />
-                        <TextBlock Margin="0,1.5,6,0" Text="安静的雨" />
-                        <TextBlock Margin="0,1.5,6,0" Text="北牧辰曦" />
-                        <TextBlock Margin="0,1.5,6,0" Text="下次一定" />
-                        <TextBlock Margin="0,1.5,6,0" Text="飞天土钩" />
-                        <TextBlock Margin="0,1.5,6,0" Text="曲线生活" />
-                        <TextBlock Margin="0,1.5,6,0" Text="管那么多" />
-                        <TextBlock Margin="0,1.5,6,0" Text="我叫杨戬" />
-                        <TextBlock Margin="0,1.5,6,0" Text="乐风昭苏" />
-                        <TextBlock Margin="0,1.5,6,0" Text="丨离凡丨" />
-                        <TextBlock Margin="0,1.5,6,0" Text="如图建系" />
-                        <TextBlock Margin="0,1.5,6,0" Text="酒筵辞夕" />
-                        <TextBlock Margin="0,1.5,6,0" Text="踏马的淦" />
-                        <TextBlock Margin="0,1.5,6,0" Text="夜殇羽镰" />
-                        <TextBlock Margin="0,1.5,6,0" Text="星尘墨韵" />
-                        <TextBlock Margin="0,1.5,6,0" Text="聆听冰风" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Yi_xuan" />
+                        <TextBlock Margin="0,1.5,6,0" Text="MC芬达" />
+                        <TextBlock Margin="0,1.5,6,0" Text="shallow" />
+                        <TextBlock Margin="0,1.5,6,0" Text="𝕳轩辕氏" />
+                        <TextBlock Margin="0,1.5,6,0" Text="谜茶360" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Eventful" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Molioos" />
+                        <TextBlock Margin="0,1.5,6,0" Text="logicum" />
+                        <TextBlock Margin="0,1.5,6,0" Text="一叶知秋" />
+                        <TextBlock Margin="0,1.5,6,0" Text="狼烟居士" />
+                        <TextBlock Margin="0,1.5,6,0" Text="千风伶羽" />
+                        <TextBlock Margin="0,1.5,6,0" Text="mumiao" />
+                        <TextBlock Margin="0,1.5,6,0" Text="欧刃赛卌" />
+                        <TextBlock Margin="0,1.5,6,0" Text="蓝白幻影" />
                         <TextBlock Margin="0,1.5,6,0" Text="鸭梨山大" />
                         <TextBlock Margin="0,1.5,6,0" Text="一条鱼瓯" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Kang_XL" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Crispykit" />
-                        <TextBlock Margin="0,1.5,6,0" Text="vorinshe" />
-                        <TextBlock Margin="0,1.5,6,0" Text="凉曦luke" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Eiluosha" />
-                        <TextBlock Margin="0,1.5,6,0" Text="GKD小哥" />
+                        <TextBlock Margin="0,1.5,6,0" Text="苇渚泊舟" />
+                        <TextBlock Margin="0,1.5,6,0" Text="花开富贵" />
+                        <TextBlock Margin="0,1.5,6,0" Text="多肉藕片" />
+                        <TextBlock Margin="0,1.5,6,0" Text="浮屠阿仙" />
+                        <TextBlock Margin="0,1.5,6,0" Text="繁星萤火" />
+                        <TextBlock Margin="0,1.5,6,0" Text="沐风沐雨" />
+                        <TextBlock Margin="0,1.5,6,0" Text="金槍羽翼" />
+                        <TextBlock Margin="0,1.5,6,0" Text="龘羅孖倆" />
+                        <TextBlock Margin="0,1.5,6,0" Text="鸽子王雷" />
+                        <TextBlock Margin="0,1.5,6,0" Text="红莲焚霞" />
+                        <TextBlock Margin="0,1.5,6,0" Text="老凌野少" />
+                        <TextBlock Margin="0,1.5,6,0" Text="孤酒青魇" />
+                        <TextBlock Margin="0,1.5,6,0" Text="天空奇己" />
+                        <TextBlock Margin="0,1.5,6,0" Text="霜月秋阳" />
+                        <TextBlock Margin="0,1.5,6,0" Text="啃瓜咸鱼" />
+                        <TextBlock Margin="0,1.5,6,0" Text="淡墨染星" />
+                        <TextBlock Margin="0,1.5,6,0" Text="2k2k114" />
+                        <TextBlock Margin="0,1.5,6,0" Text="肉蛋葱鸡" />
+                        <TextBlock Margin="0,1.5,6,0" Text="傻鹅二号" />
+                        <TextBlock Margin="0,1.5,6,0" Text="动漫阿宅" />
+                        <TextBlock Margin="0,1.5,6,0" Text="只若初见" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Sakuzyo" />
+                        <TextBlock Margin="0,1.5,6,0" Text="1415145" />
+                        <TextBlock Margin="0,1.5,6,0" Text="消失的喵" />
+                        <TextBlock Margin="0,1.5,6,0" Text="春山如笑" />
+                        <TextBlock Margin="0,1.5,6,0" Text="幻天阿绝" />
+                        <TextBlock Margin="0,1.5,6,0" Text="忘道蜂枫" />
+                        <TextBlock Margin="0,1.5,6,0" Text="心软的神" />
+                        <TextBlock Margin="0,1.5,6,0" Text="砂锅豆腐" />
+                        <TextBlock Margin="0,1.5,6,0" Text="好人好逝" />
+                        <TextBlock Margin="0,1.5,6,0" Text="登峰破晓" />
+                        <TextBlock Margin="0,1.5,6,0" Text="东隅未殁" />
+                        <TextBlock Margin="0,1.5,6,0" Text="MuMAA" />
+                        <TextBlock Margin="0,1.5,6,0" Text="溯枫qwq" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Tacenda" />
+                        <TextBlock Margin="0,1.5,6,0" Text="sky fung" />
+                        <TextBlock Margin="0,1.5,6,0" Text="👁👄👃" />
+                        <TextBlock Margin="0,1.5,6,0" Text="秋慕owo" />
+                        <TextBlock Margin="0,1.5,6,0" Text="船长Yuki" />
                         <TextBlock Margin="0,1.5,6,0" Text="是小61呀" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Disbelief" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Manatsu" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Ace_墨尘" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Murousa" />
-                        <TextBlock Margin="0,1.5,6,0" Text="mulberry" />
-                        <TextBlock Margin="0,1.5,6,0" Text="lyh20218" />
-                        <TextBlock Margin="0,1.5,6,0" Text="HIK4RI39" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Gwen_jin" />
-                        <TextBlock Margin="0,1.5,6,0" Text="EthanCAi" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Maplefor" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Dryadove" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Xiaomo_y" />
-                        <TextBlock Margin="0,1.5,6,0" Text="DWS3333" />
-                        <TextBlock Margin="0,1.5,6,0" Text="EnochHcx" />
+                        <TextBlock Margin="0,1.5,6,0" Text="47号虾球" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Alancnel" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Muertesl" />
+                        <TextBlock Margin="0,1.5,6,0" Text="猫幺Suro" />
+                        <TextBlock Margin="0,1.5,6,0" Text="i&apos;g&apos;d&apos;y&apos;f&apos;s" />
+                        <TextBlock Margin="0,1.5,6,0" Text="xiaochen" />
+                        <TextBlock Margin="0,1.5,6,0" Text="ㅤSIMV9r" />
+                        <TextBlock Margin="0,1.5,6,0" Text="alpHabet" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Charlotte" />
+                        <TextBlock Margin="0,1.5,6,0" Text="paperfish" />
+                        <TextBlock Margin="0,1.5,6,0" Text="stealtoup" />
+                        <TextBlock Margin="0,1.5,6,0" Text="bingyan0" />
+                        <TextBlock Margin="0,1.5,6,0" Text="MselQAQ" />
+                        <TextBlock Margin="0,1.5,6,0" Text="UZQueen" />
                         <TextBlock Margin="0,1.5,6,0" Text="hihospital" />
-                        <TextBlock Margin="0,1.5,6,0" Text="_東森浮星_" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Com_XDN" />
-                        <TextBlock Margin="0,1.5,6,0" Text="SEIGLE404" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Kevin2022" />
-                        <TextBlock Margin="0,1.5,6,0" Text="梓晨Otaku" />
-                        <TextBlock Margin="0,1.5,6,0" Text="凌点工作室" />
-                        <TextBlock Margin="0,1.5,6,0" Text="千秋万载猹" />
-                        <TextBlock Margin="0,1.5,6,0" Text="超级大月光" />
-                        <TextBlock Margin="0,1.5,6,0" Text="精酿糯米酒" />
-                        <TextBlock Margin="0,1.5,6,0" Text="不「成」器" />
-                        <TextBlock Margin="0,1.5,6,0" Text="无常之客星" />
-                        <TextBlock Margin="0,1.5,6,0" Text="第一年冬天" />
-                        <TextBlock Margin="0,1.5,6,0" Text="大王上早八" />
-                        <TextBlock Margin="0,1.5,6,0" Text="爱吃小笼包" />
-                        <TextBlock Margin="0,1.5,6,0" Text="红楼彡揽月" />
-                        <TextBlock Margin="0,1.5,6,0" Text="画海听竹者" />
-                        <TextBlock Margin="0,1.5,6,0" Text="白哥咯咯咯" />
-                        <TextBlock Margin="0,1.5,6,0" Text="懒得喷喷喷" />
-                        <TextBlock Margin="0,1.5,6,0" Text="估计不会玩" />
-                        <TextBlock Margin="0,1.5,6,0" Text="伊南宁门特" />
-                        <TextBlock Margin="0,1.5,6,0" Text="秋山有希子" />
-                        <TextBlock Margin="0,1.5,6,0" Text="氧化氧化氧" />
-                        <TextBlock Margin="0,1.5,6,0" Text="傻悠不知道" />
-                        <TextBlock Margin="0,1.5,6,0" Text="不爱吃灼芋" />
-                        <TextBlock Margin="0,1.5,6,0" Text="山枕檀痕涴" />
-                        <TextBlock Margin="0,1.5,6,0" Text="你是妖怪叭" />
-                        <TextBlock Margin="0,1.5,6,0" Text="不知名玩家" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Prifo_lone" />
+                        <TextBlock Margin="0,1.5,6,0" Text="有....暗星!" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Hitsser 1.0" />
+                        <TextBlock Margin="0,1.5,6,0" Text="一只憨火龙" />
+                        <TextBlock Margin="0,1.5,6,0" Text="异色收集癖" />
+                        <TextBlock Margin="0,1.5,6,0" Text="DsxiaKsxia" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Plainsman" />
                         <TextBlock Margin="0,1.5,6,0" Text="湛蓝一四七" />
-                        <TextBlock Margin="0,1.5,6,0" Text="翰墨续丹青" />
                         <TextBlock Margin="0,1.5,6,0" Text="凛果与百橙" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Touma000" />
-                        <TextBlock Margin="0,1.5,6,0" Text="回忆de天空" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Yunlimeng" />
-                        <TextBlock Margin="0,1.5,6,0" Text="GODxianyu" />
+                        <TextBlock Margin="0,1.5,6,0" Text="叶落才知秋" />
+                        <TextBlock Margin="0,1.5,6,0" Text="好喝的氦三" />
+                        <TextBlock Margin="0,1.5,6,0" Text="星河奈叶风" />
+                        <TextBlock Margin="0,1.5,6,0" Text="魔法且河豚" />
+                        <TextBlock Margin="0,1.5,6,0" Text="魏小泓泓泓" />
+                        <TextBlock Margin="0,1.5,6,0" Text="阴冷潮湿酱" />
+                        <TextBlock Margin="0,1.5,6,0" Text="一只白色缨" />
+                        <TextBlock Margin="0,1.5,6,0" Text="结局的椰子" />
+                        <TextBlock Margin="0,1.5,6,0" Text="三玖二拾柒" />
+                        <TextBlock Margin="0,1.5,6,0" Text="旭旭大魔王" />
+                        <TextBlock Margin="0,1.5,6,0" Text="离人如飘萍" />
+                        <TextBlock Margin="0,1.5,6,0" Text="秋葉逐殘夏" />
+                        <TextBlock Margin="0,1.5,6,0" Text="水星有海吗" />
+                        <TextBlock Margin="0,1.5,6,0" Text="ac纯萌新cy" />
+                        <TextBlock Margin="0,1.5,6,0" Text="岁月suiyue" />
+                        <TextBlock Margin="0,1.5,6,0" Text="陌然MajorC" />
+                        <TextBlock Margin="0,1.5,6,0" Text="-Pareidolia." />
+                        <TextBlock Margin="0,1.5,6,0" Text="蛙蛙大王Kzr" />
                         <TextBlock Margin="0,1.5,6,0" Text="Yhcmdbfwz" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Equilibrium" />
-                        <TextBlock Margin="0,1.5,6,0" Text="陌泽陌泽MZ" />
-                        <TextBlock Margin="0,1.5,6,0" Text="咖啡R3borN" />
-                        <TextBlock Margin="0,1.5,6,0" Text="1234567890" />
-                        <TextBlock Margin="0,1.5,6,0" Text="GUGUGAGA" />
-                        <TextBlock Margin="0,1.5,6,0" Text="2366445223" />
-                        <TextBlock Margin="0,1.5,6,0" Text="arrovartsk77" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Elegytairitsu" />
-                        <TextBlock Margin="0,1.5,6,0" Text="南小彩的梦想" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Ayers赜蠹嬭" />
+                        <TextBlock Margin="0,1.5,6,0" Text="We1J1uSh1" />
+                        <TextBlock Margin="0,1.5,6,0" Text="xinghen233" />
+                        <TextBlock Margin="0,1.5,6,0" Text="kingkongair" />
                         <TextBlock Margin="0,1.5,6,0" Text="最后一只斑鸠" />
-                        <TextBlock Margin="0,1.5,6,0" Text="刻晴天下第一" />
-                        <TextBlock Margin="0,1.5,6,0" Text="幸运的蓝耀星" />
-                        <TextBlock Margin="0,1.5,6,0" Text="整没用的红球" />
-                        <TextBlock Margin="0,1.5,6,0" Text="端午节吃饺子" />
-                        <TextBlock Margin="0,1.5,6,0" Text="DLurker7840" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Don_Quixote" />
+                        <TextBlock Margin="0,1.5,6,0" Text="随便写的名字" />
+                        <TextBlock Margin="0,1.5,6,0" Text="芥末味青豌豆" />
+                        <TextBlock Margin="0,1.5,6,0" Text="鹅给金华额度" />
+                        <TextBlock Margin="0,1.5,6,0" Text="LisaPatorsed" />
+                        <TextBlock Margin="0,1.5,6,0" Text="鸡屁股配大蒜" />
+                        <TextBlock Margin="0,1.5,6,0" Text="我真没想开摆" />
+                        <TextBlock Margin="0,1.5,6,0" Text="我不想取名字" />
+                        <TextBlock Margin="0,1.5,6,0" Text="平安京的封兽" />
+                        <TextBlock Margin="0,1.5,6,0" Text="被压力的鸭梨" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小田love白子" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Sasha_Xiong" />
+                        <TextBlock Margin="0,1.5,6,0" Text="赤狸_crisnow" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Name0emaN" />
+                        <TextBlock Margin="0,1.5,6,0" Text="happypickles" />
+                        <TextBlock Margin="0,1.5,6,0" Text="无中生有为dd" />
+                        <TextBlock Margin="0,1.5,6,0" Text="polarisdream" />
+                        <TextBlock Margin="0,1.5,6,0" Text="YHKooooooy" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Sakura2403ly" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Flying Potato" />
+                        <TextBlock Margin="0,1.5,6,0" Text="陈昊骏泥碳GR" />
                         <TextBlock Margin="0,1.5,6,0" Text="funnyzhuling" />
-                        <TextBlock Margin="0,1.5,6,0" Text="AYGY暗夜古韵" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Kecdl_Chacha" />
-                        <TextBlock Margin="0,1.5,6,0" Text="对方正在输入 ..." />
-                        <TextBlock Margin="0,1.5,6,0" Text="Chihaya-Anon" />
-                        <TextBlock Margin="0,1.5,6,0" Text="虚域染指亦起舞" />
-                        <TextBlock Margin="0,1.5,6,0" Text="半人半灵的麻薯" />
-                        <TextBlock Margin="0,1.5,6,0" Text="霜雪焉能见太阳" />
-                        <TextBlock Margin="0,1.5,6,0" Text="章鱼哥的琪露诺" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Turbo_Zhang" />
+                        <TextBlock Margin="0,1.5,6,0" Text="SUBLawrence" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Epsilon-9新人" />
+                        <TextBlock Margin="0,1.5,6,0" Text="TheDovebach" />
+                        <TextBlock Margin="0,1.5,6,0" Text="wobushi_furry" />
+                        <TextBlock Margin="0,1.5,6,0" Text="FTC夏日的余晖" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Isshiki Satoshi" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Srive_Schegler" />
+                        <TextBlock Margin="0,1.5,6,0" Text="1080p安全卫士" />
+                        <TextBlock Margin="0,1.5,6,0" Text="开心上学玩游戏" />
                         <TextBlock Margin="0,1.5,6,0" Text="重生之发财传奇" />
                         <TextBlock Margin="0,1.5,6,0" Text="某科学的小狐狸" />
+                        <TextBlock Margin="0,1.5,6,0" Text="爱喝可乐的猫猫" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Vsinger-洛天依" />
+                        <TextBlock Margin="0,1.5,6,0" Text="芙利莲最も強い" />
+                        <TextBlock Margin="0,1.5,6,0" Text="洋葱香菜炒蛋子" />
+                        <TextBlock Margin="0,1.5,6,0" Text="不开心,不快乐" />
+                        <TextBlock Margin="0,1.5,6,0" Text="忧郁的破产鼠鼠" />
+                        <TextBlock Margin="0,1.5,6,0" Text="我的世界爱好者" />
+                        <TextBlock Margin="0,1.5,6,0" Text="半透明的小透明" />
+                        <TextBlock Margin="0,1.5,6,0" Text="到处闲逛的咸鱼" />
+                        <TextBlock Margin="0,1.5,6,0" Text="什么落寒都不是" />
+                        <TextBlock Margin="0,1.5,6,0" Text="没什么名字好取" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Wanderer5147" />
+                        <TextBlock Margin="0,1.5,6,0" Text="取个名字耗阳寿" />
                         <TextBlock Margin="0,1.5,6,0" Text="AAA神秘人批发" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Bangbang2025" />
                         <TextBlock Margin="0,1.5,6,0" Text="贝吉蒙Begimon" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Kozume_Kenma" />
-                        <TextBlock Margin="0,1.5,6,0" Text="Taskmgr-MEMZ" />
-                        <TextBlock Margin="0,1.5,6,0" Text="漫天星火为谁舞?" />
-                        <TextBlock Margin="0,1.5,6,0" Text="常凱申(刘小胖)" />
-                        <TextBlock Margin="0,1.5,6,0" Text="赚够三千万就瘦瘦" />
-                        <TextBlock Margin="0,1.5,6,0" Text="大道五十天衍四九" />
-                        <TextBlock Margin="0,1.5,6,0" Text="爱停电用户_查尔德" />
-                        <TextBlock Margin="0,1.5,6,0" Text="狸猫曾在学校烤面包" />
-                        <TextBlock Margin="0,1.5,6,0" Text="(´o̴̶̷̤ㅂo̴̶̷̤`)" />
-                        <TextBlock Margin="0,1.5,6,0" Text="克洛伊.冯.爱因兹贝伦" />
-                        <TextBlock Margin="0,1.5,6,0" Text="(*^ワ^*)^_^$$" />
-                        <TextBlock Margin="0,1.5,6,0" Text="GongzhuHuanerAwA" />
-                        <TextBlock Margin="0,1.5,6,0" Text="幽兰黛尔【Druandal】" />
-                        <TextBlock Margin="0,1.5,6,0" Text="codm我要玩一辈子cx-9" />
+                        <TextBlock Margin="0,1.5,6,0" Text="取个名字真难0.0" />
+                        <TextBlock Margin="0,1.5,6,0" Text="NoTuring_Steve" />
+                        <TextBlock Margin="0,1.5,6,0" Text="冰冰watermelon" />
+                        <TextBlock Margin="0,1.5,6,0" Text="DOODOODOOD" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小句号就是小句号" />
+                        <TextBlock Margin="0,1.5,6,0" Text="弹跳爆炸小鱼珠🐟" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Xanadu Silk Fable" />
+                        <TextBlock Margin="0,1.5,6,0" Text="看我的都得白内障了" />
+                        <TextBlock Margin="0,1.5,6,0" Text="【点击请输入文本】" />
+                        <TextBlock Margin="0,1.5,6,0" Text="AAA难办批发商乌鸦" />
+                        <TextBlock Margin="0,1.5,6,0" Text="zhuanzhuanzhaun!" />
+                        <TextBlock Margin="0,1.5,6,0" Text="你上课记得记得你先忙" />
                     </WrapPanel>
                     <Grid Height="35">
                         <Grid.ColumnDefinitions>

+ 3 - 0
Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml.vb

@@ -27,5 +27,8 @@ Public Class PageOtherAbout
     Private Sub BtnDonateOutput_Click(sender As Object, e As EventArgs) Handles BtnDonateOutput.Click
         GeneratePotatoCode()
     End Sub
+    Private Sub BtnAboutUpdate_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnAboutUpdate.Click
+        UpdateCheckByButton()
+    End Sub
 
 End Class

+ 4 - 1
Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb

@@ -185,8 +185,11 @@ Public Class PageSelectRight
         Try
             Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
             Dim IsHintIndie As Boolean = Instance.State <> McInstanceState.Error AndAlso Instance.PathIndie <> McFolderSelected
+            Dim SavesFolder = DirectoryUtils.GetInfo(Instance.PathIndie & "saves\")
+            Dim SaveEntries = If(SavesFolder.Exists, SavesFolder.EnumerateDirectories.OrderByDescending(Function(Save) Save.LastWriteTime).Select(Function(Save) $"{Save.Name}(上次修改:{StringUtils.FormatTimeSpan(Save.LastWriteTime - Date.Now, False)})").ToList, New List(Of String))
             Select Case MyMsgBox($"你确定要{If(IsShiftPressed, "永久", "")}删除版本 {Instance.Name} 吗?" &
-                        If(IsHintIndie, vbCrLf & "由于该版本开启了版本隔离,删除版本时该版本对应的存档、资源包、Mod 等文件也将被一并删除!", ""),
+                        If(IsHintIndie, vbCrLf & "该版本对应的存档、资源包、Mod 等文件也将被一并删除!", "") &
+                        If(SaveEntries.Any, vbCrLf & vbCrLf & "这会删除以下存档:" & vbCrLf & "· " & SaveEntries.Join(vbCrLf & "· "), ""),
                         "版本删除确认", , "取消",, True)
                 Case 1
                     Instance.ResetSettingsCache()

+ 0 - 3
Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml

@@ -64,7 +64,6 @@
                             <RowDefinition Height="7" />
                             <RowDefinition Height="28" />
                             <RowDefinition Height="7" />
-                            <RowDefinition Height="Auto" />
                         </Grid.RowDefinitions>
                         <TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="来源" Margin="0,0,25,0" />
                         <local:MyComboBox x:Name="ComboDownloadMod" Grid.Row="0" Grid.ColumnSpan="2" local:SettingService.Key="ToolDownloadMod" Grid.Column="1">
@@ -87,8 +86,6 @@
                             <local:MyComboBoxItem Content="标题显示译名,详情显示文件名" IsSelected="True" />
                             <local:MyComboBoxItem Content="标题显示文件名,详情显示译名" />
                         </local:MyComboBox>
-                        <local:MyCheckBox Margin="0,2,0,4" Text="在显示 Mod 加载器时忽略 Quilt" Grid.Row="6" Height="22" Grid.ColumnSpan="2"
-                                          x:Name="CheckDownloadIgnoreQuilt" local:SettingService.Key="ToolDownloadIgnoreQuilt" />
                     </Grid>
                 </StackPanel>
             </local:MyCard>

+ 2 - 0
Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml

@@ -284,6 +284,8 @@
                             <local:MyComboBoxItem local:SettingService.Value="15" Content="Minecraft 芝士站(作者:awaEric233)" />
                             <local:MyComboBoxItem local:SettingService.Value="16" Content="整合包推荐引擎(作者:CHMYGZ)" />
                             <local:MyComboBoxItem local:SettingService.Value="17" Content="Bangumi 番剧主页(作者:wzyaeu)" />
+                            <local:MyComboBoxItem local:SettingService.Value="18" Content="Bilibili 热门(作者:wzyaeu)" />
+                            <local:MyComboBoxItem local:SettingService.Value="19" Content="Music 云音乐热门(作者:wzyaeu)" />
                         </local:MyComboBox>
                     </Grid>
                 </StackPanel>

+ 17 - 5
Plain Craft Launcher 2/Pages/PageSetup/Settings.vb

@@ -120,7 +120,6 @@ Public Class Settings
         New Setting("ToolDownloadVersion", 1, Source:=Sources.Registry),
         New Setting("ToolDownloadTranslate", 0, Source:=Sources.Registry),
         New Setting("ToolDownloadTranslateV2", 1, Source:=Sources.Registry),
-        New Setting("ToolDownloadIgnoreQuilt", True, Source:=Sources.Registry),
         New Setting("ToolDownloadCert", False, Source:=Sources.Registry, OnChanged:=AddressOf ModNet.ShouldValidateSslCertificateOnLogin),
         New Setting("ToolDownloadMod", 2, Source:=Sources.Registry),
         New Setting("ToolModLocalNameStyle", 0, Source:=Sources.Registry),
@@ -261,7 +260,11 @@ Public Class Settings
                 Case Sources.Normal
                     WriteIni("Setup", Key, Value)
                 Case Sources.Registry
-                    WriteReg(Key, Value)
+                    Try
+                        RegistryUtils.Write($"HKEY_CURRENT_USER\Software\{RegFolder}", Key, Value)
+                    Catch ex As Exception
+                        Logger.Warn(ex, $"写入注册表失败({Key} → {Value})", LogBehavior.Toast)
+                    End Try
                 Case Sources.Instance
                     If Instance Is Nothing Then Throw New Exception($"保存版本独立设置 {Key} 时未提供目标版本")
                     WriteIni(Instance.PathVersion & "PCL\Setup.ini", Key, Value)
@@ -327,7 +330,7 @@ Public Class Settings
                 Case Sources.Normal
                     GotValue = ReadIni("Setup", Key, DefaultValue)
                 Case Sources.Registry
-                    GotValue = ReadReg(Key, DefaultValue)
+                    GotValue = RegistryUtils.TryRead($"HKEY_CURRENT_USER\Software\{RegFolder}", Key, DefaultValue)
                 Case Sources.Instance
                     If Instance Is Nothing Then
                         Throw New Exception($"读取版本设置 {Key} 时未提供目标版本")
@@ -386,7 +389,11 @@ Public Class Settings
                 Case Sources.Normal
                     DeleteIniKey("Setup", Key)
                 Case Sources.Registry
-                    DeleteReg(Key)
+                    Try
+                        RegistryUtils.Delete($"HKEY_CURRENT_USER\Software\{RegFolder}", Key)
+                    Catch ex As Exception
+                        Logger.Warn(ex, $"删除注册表失败({Key})", LogBehavior.Toast)
+                    End Try
                 Case Sources.Instance
                     If Instance Is Nothing Then Throw New Exception($"重置版本设置 {Key} 时未提供目标版本")
                     DeleteIniKey(Instance.PathVersion & "PCL\Setup.ini", Key)
@@ -414,7 +421,12 @@ Public Class Settings
             Case Sources.Normal
                 Return HasIniKey("Setup", Key)
             Case Sources.Registry
-                Return HasReg(Key)
+                Try
+                    Return RegistryUtils.Has($"HKEY_CURRENT_USER\Software\{RegFolder}", Key)
+                Catch ex As Exception
+                    Logger.Warn(ex, $"判断注册表 {Key} 是否存在时出错")
+                    Return False
+                End Try
             Case Else 'Source.Instance
                 If Instance Is Nothing Then Throw New Exception($"判断版本设置 {Key} 是否存在时未提供目标版本")
                 Return HasIniKey(Instance.PathVersion & "PCL\Setup.ini", Key)

+ 14 - 14
Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb

@@ -32,7 +32,7 @@ Public Class PageSpeedLeft
     '定时器任务
     Private ReadOnly RightCards As New Dictionary(Of String, MyCard)
     Private Sub Watcher()
-        If Not FrmMain.PageCurrent = FormMain.PageType.DownloadManager Then Return
+        If Not FrmMain.PageCurrent = FormMain.PageType.TaskManager Then Return
         Try
 
 #Region "更新左边栏"
@@ -55,7 +55,7 @@ Public Class PageSpeedLeft
 #End Region
 
         Catch ex As Exception
-            Logger.Error(ex, "下载管理左栏监视出错")
+            Logger.Error(ex, "任务管理左栏监视出错")
         End Try
         If FrmSpeedRight Is Nothing OrElse FrmSpeedRight.PanMain Is Nothing Then Return
         Try
@@ -63,7 +63,7 @@ Public Class PageSpeedLeft
                 TaskRefresh(Loader)
             Next
         Catch ex As Exception
-            Logger.Error(ex, "下载管理右栏监视出错")
+            Logger.Error(ex, "任务管理右栏监视出错")
         End Try
     End Sub
     Public Sub TaskRefresh(Loader As LoaderBase)
@@ -106,7 +106,7 @@ Public Class PageSpeedLeft
 #Region "进度不同,更新卡片"
                             Try
                                 If Card.Children.Count < LoaderList.Count * 2 Then
-                                    Logger.Warn($"刷新下载管理卡片 {Loader.Name} 失败:卡片中仅有 {Card.Children.Count} 个子项,要求至少有 {LoaderList.Count * 2} 个子项")
+                                    Logger.Warn($"刷新任务管理卡片 {Loader.Name} 失败:卡片中仅有 {Card.Children.Count} 个子项,要求至少有 {LoaderList.Count * 2} 个子项")
                                     Exit Try
                                 End If
                                 Dim Row As Integer = 0
@@ -133,12 +133,12 @@ Public Class PageSpeedLeft
                                     Row += 1
                                 Next
                             Catch ex As Exception
-                                Logger.Error(ex, $"刷新下载管理卡片 {Loader.Name} 失败")
+                                Logger.Error(ex, $"刷新任务管理卡片 {Loader.Name} 失败")
                             End Try
 #End Region
                     End Select
                 Catch ex As Exception
-                    Logger.Error(ex, $"更新下载管理显示失败({Loader.State})")
+                    Logger.Error(ex, $"更新任务管理显示失败({Loader.State})")
                 End Try
             ElseIf Not (Loader.State = LoadState.Canceled OrElse Loader.State = LoadState.Finished) Then
                 Try
@@ -177,23 +177,23 @@ Public Class PageSpeedLeft
                     Try
                         Card = GetObjectFromXML(CardXAML)
                     Catch ex As Exception
-                        Logger.Warn(ex, "新建下载管理卡片失败")
+                        Logger.Warn(ex, "新建任务管理卡片失败")
                         Logger.Info($"出错的卡片内容:{vbCrLf}{CardXAML}")
                         Throw
                     End Try
                     FrmSpeedRight.PanMain.Children.Insert(0, Card)
                     RightCards.Add(Loader.Name, Card)
-                    Logger.Info($"新建下载管理卡片:{Loader.Name}")
+                    Logger.Info($"新建任务管理卡片:{Loader.Name}")
                     '添加取消按钮
                     Dim Cancel As New MyIconButton With {.Name = "BtnCancel", .Logo = "F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z", .Height = 20, .Margin = New Thickness(0, 10, 10, 0), .LogoScale = 1.1, .HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Top}
                     Card.Children.Add(Cancel)
                     AddHandler Cancel.Click,
                     Sub(sender As MyIconButton, e As EventArgs)
                         AniDispose(sender, False)
-                        AniDispose(Card, True, Sub() If FrmSpeedRight.PanMain.Children.Count = 0 AndAlso FrmMain.PageCurrent = FormMain.PageType.DownloadManager Then FrmMain.PageBack())
+                        AniDispose(Card, True, Sub() If FrmSpeedRight.PanMain.Children.Count = 0 AndAlso FrmMain.PageCurrent = FormMain.PageType.TaskManager Then FrmMain.PageBack())
                         RightCards.Remove(Loader.Name)
                         LoaderTaskbar.Remove(Loader)
-                        Logger.Info($"关闭下载管理卡片:{Loader.Name},且移出任务列表")
+                        Logger.Info($"关闭任务管理卡片:{Loader.Name},且移出任务列表")
                         RunInThread(Sub() Loader.Cancel())
                     End Sub
                     '如果已经失败,再刷新一次,修改成失败的控件
@@ -203,11 +203,11 @@ Public Class PageSpeedLeft
                     End If
 #End Region
                 Catch ex As Exception
-                    Logger.Error(ex, "添加下载管理卡片失败")
+                    Logger.Error(ex, "添加任务管理卡片失败")
                 End Try
             End If
         Catch ex As Exception
-            Logger.Error(ex, "刷新下载管理显示失败")
+            Logger.Error(ex, "刷新任务管理显示失败")
         End Try
     End Sub
     Public Sub TaskRemove(Loader As Object)
@@ -218,7 +218,7 @@ Public Class PageSpeedLeft
                 Dim Card As Grid = RightCards(Loader.Name)
                 FrmSpeedRight.PanMain.Children.Remove(Card)
                 RightCards.Remove(Loader.Name)
-                Logger.Info($"移除下载管理卡片:{Loader.Name}")
+                Logger.Info($"移除任务管理卡片:{Loader.Name}")
             End Sub)
         End If
     End Sub
@@ -227,7 +227,7 @@ Public Class PageSpeedLeft
     ''' 若没有任务,尝试返回主页。
     ''' </summary>
     Private Sub TryReturnToHome()
-        If FrmSpeedRight.PanMain.Children.Count = 0 AndAlso FrmMain.PageCurrent = FormMain.PageType.DownloadManager Then
+        If FrmSpeedRight.PanMain.Children.Count = 0 AndAlso FrmMain.PageCurrent = FormMain.PageType.TaskManager Then
             FrmMain.PageBack()
         End If
     End Sub

+ 5 - 0
Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj

@@ -939,9 +939,14 @@
       <LogicalName>MeloongCore.Wpf.dll</LogicalName>
       <Link>Resources\MeloongCore.Wpf.dll</Link>
     </None>
+    <None Include="..\PCLCS\bin\Microsoft.Win32.Registry.dll">
+      <LogicalName>Microsoft.Win32.Registry.dll</LogicalName>
+      <Link>Resources\Microsoft.Win32.Registry.dll</Link>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <Resource Include="Images\Heads\ChongQing.png" />
+    <Resource Include="Images\Heads\HerobrineXia.png" />
 
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است