Przeglądaj źródła

Merge pull request #43 from Hex-Dragon/main

u
薄奚梦灵 1 rok temu
rodzic
commit
124f5c2f8b
63 zmienionych plików z 1277 dodań i 1991 usunięć
  1. 2 1
      Plain Craft Launcher 2/Application.xaml
  2. 4 0
      Plain Craft Launcher 2/Application.xaml.vb
  3. 1 1
      Plain Craft Launcher 2/Controls/MyListItem.xaml.vb
  4. 2 2
      Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.vb
  5. 0 1
      Plain Craft Launcher 2/Controls/MyResizer.vb
  6. 1 2
      Plain Craft Launcher 2/Controls/MyScrollViewer.vb
  7. 24 29
      Plain Craft Launcher 2/FormMain.xaml.vb
  8. 15 12
      Plain Craft Launcher 2/Modules/Base/ModBase.vb
  9. 2 2
      Plain Craft Launcher 2/Modules/Base/ModLoader.vb
  10. 14 13
      Plain Craft Launcher 2/Modules/Base/ModValidate.vb
  11. 165 185
      Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
  12. 0 4
      Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
  13. 73 33
      Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
  14. 10 12
      Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
  15. 38 33
      Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
  16. 119 151
      Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
  17. 6 2
      Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
  18. 94 148
      Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
  19. 2 2
      Plain Craft Launcher 2/My Project/AssemblyInfo.vb
  20. 0 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml
  21. 28 20
      Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.vb
  22. 95 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml
  23. 110 31
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.vb
  24. 0 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml
  25. 47 27
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb
  26. 26 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadDataPack.xaml
  27. 2 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadDataPack.xaml.vb
  28. 35 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadMod.xaml
  29. 2 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadMod.xaml.vb
  30. 28 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadPack.xaml
  31. 2 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadPack.xaml.vb
  32. 45 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadResourcePack.xaml
  33. 2 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadResourcePack.xaml.vb
  34. 31 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadShader.xaml
  35. 2 0
      Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadShader.xaml.vb
  36. 42 36
      Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
  37. 0 111
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadDataPack.xaml
  38. 0 122
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadDataPack.xaml.vb
  39. 4 4
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
  40. 32 32
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml
  41. 39 26
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb
  42. 0 122
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
  43. 0 111
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
  44. 0 128
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml.vb
  45. 0 126
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadResourcePack.xaml
  46. 0 124
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadResourcePack.xaml.vb
  47. 0 115
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadShader.xaml
  48. 0 122
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadShader.xaml.vb
  49. 3 0
      Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb
  50. 30 33
      Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
  51. 1 1
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb
  52. 6 1
      Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
  53. 9 6
      Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb
  54. 2 1
      Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb
  55. 1 1
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb
  56. 29 21
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml
  57. 3 1
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb
  58. 1 1
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb
  59. 0 0
      Plain Craft Launcher 2/Pages/PageVersion/MyLocalModItem.xaml
  60. 0 0
      Plain Craft Launcher 2/Pages/PageVersion/MyLocalModItem.xaml.vb
  61. 5 4
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
  62. 41 29
      Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj
  63. 2 2
      Plain Craft Launcher 2/Resources/Custom.xaml

+ 2 - 1
Plain Craft Launcher 2/Application.xaml

@@ -209,7 +209,7 @@
                     </Setter.Value>
                     </Setter.Value>
                 </Setter>
                 </Setter>
             </Style>
             </Style>
-            <Style TargetType="local:MyScrollViewer">
+            <Style TargetType="local:MyScrollViewer" x:Name="StyleMyScrollViewer">
                 <Setter Property="OverridesDefaultStyle" Value="True" />
                 <Setter Property="OverridesDefaultStyle" Value="True" />
                 <Setter Property="CanContentScroll" Value="False" />
                 <Setter Property="CanContentScroll" Value="False" />
                 <Setter Property="PanningMode" Value="VerticalOnly" />
                 <Setter Property="PanningMode" Value="VerticalOnly" />
@@ -225,6 +225,7 @@
                     </Setter.Value>
                     </Setter.Value>
                 </Setter>
                 </Setter>
             </Style>
             </Style>
+            <Style TargetType="local:PageComp" BasedOn="{StaticResource {x:Type local:MyScrollViewer}}" />
             <Style TargetType="ScrollViewer" x:Key="ScrollViewerFullMargin">
             <Style TargetType="ScrollViewer" x:Key="ScrollViewerFullMargin">
                 <Setter Property="OverridesDefaultStyle" Value="True" />
                 <Setter Property="OverridesDefaultStyle" Value="True" />
                 <Setter Property="CanContentScroll" Value="False" />
                 <Setter Property="CanContentScroll" Value="False" />

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

@@ -115,7 +115,11 @@ WaitRetry:
             LogStart()
             LogStart()
             '添加日志
             '添加日志
             Log($"[Start] 程序版本:{VersionDisplayName} ({VersionCode}{If(CommitHash = "", "", $",#{CommitHash}")})")
             Log($"[Start] 程序版本:{VersionDisplayName} ({VersionCode}{If(CommitHash = "", "", $",#{CommitHash}")})")
+#If RELEASE Then
+            Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",正式版", "")}")
+#Else
             Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}")
             Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}")
+#End If
             Log($"[Start] 程序路径:{PathWithName}")
             Log($"[Start] 程序路径:{PathWithName}")
             Log($"[Start] 系统编码:{Encoding.Default.HeaderName} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})")
             Log($"[Start] 系统编码:{Encoding.Default.HeaderName} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})")
             Log($"[Start] 管理员权限:{IsAdmin()}")
             Log($"[Start] 管理员权限:{IsAdmin()}")

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

@@ -345,7 +345,7 @@ Public Class MyListItem
             Return _Checked
             Return _Checked
         End Get
         End Get
         Set(value As Boolean)
         Set(value As Boolean)
-            SetChecked(value, False, True)
+            SetChecked(value, False, value <> _Checked) '仅在值发生变化时触发动画 (#4596)
         End Set
         End Set
     End Property
     End Property
     ''' <summary>
     ''' <summary>

+ 2 - 2
Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.vb

@@ -1,4 +1,4 @@
-Public Class MyMsgInput
+Public Class MyMsgInput
 
 
     Private ReadOnly MyConverter As MyMsgBoxConverter
     Private ReadOnly MyConverter As MyMsgBoxConverter
     Private ReadOnly Uuid As Integer = GetUuid()
     Private ReadOnly Uuid As Integer = GetUuid()
@@ -72,7 +72,7 @@ Public Class MyMsgInput
     End Sub
     End Sub
 
 
     Public Sub Btn1_Click() Handles Btn1.Click
     Public Sub Btn1_Click() Handles Btn1.Click
-        TextArea.Validate()
+        TextArea.Validate() '#5773
         If MyConverter.IsExited OrElse Not TextArea.IsValidated Then Exit Sub
         If MyConverter.IsExited OrElse Not TextArea.IsValidated Then Exit Sub
         MyConverter.IsExited = True
         MyConverter.IsExited = True
         MyConverter.Result = TextArea.Text
         MyConverter.Result = TextArea.Text

+ 0 - 1
Plain Craft Launcher 2/Controls/MyResizer.vb

@@ -311,6 +311,5 @@ Public Class MyResizer
     End Sub
     End Sub
 
 
     Private Declare Function GetCursorPos Lib "user32.dll" (<Out()> ByRef lpPoint As PointAPI) As Boolean
     Private Declare Function GetCursorPos Lib "user32.dll" (<Out()> ByRef lpPoint As PointAPI) As Boolean
-
     Private Declare Function GetAsyncKeyState Lib "user32.dll" (vKey As Integer) As Short
     Private Declare Function GetAsyncKeyState Lib "user32.dll" (vKey As Integer) As Short
 End Class
 End Class

+ 1 - 2
Plain Craft Launcher 2/Controls/MyScrollViewer.vb

@@ -12,8 +12,7 @@
                 (GetType(ComboBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, ComboBox).IsDropDownOpen) OrElse
                 (GetType(ComboBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, ComboBox).IsDropDownOpen) OrElse
                 (GetType(TextBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, TextBox).AcceptsReturn) OrElse
                 (GetType(TextBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, TextBox).AcceptsReturn) OrElse
                 GetType(ComboBoxItem).IsAssignableFrom(SourceType) OrElse
                 GetType(ComboBoxItem).IsAssignableFrom(SourceType) OrElse
-                TypeOf e.Source Is CheckBox
-           ) Then
+                TypeOf e.Source Is CheckBox) Then
             '如果当前是在对有滚动条的下拉框或文本框执行,则不接管操作
             '如果当前是在对有滚动条的下拉框或文本框执行,则不接管操作
             Exit Sub
             Exit Sub
         End If
         End If

+ 24 - 29
Plain Craft Launcher 2/FormMain.xaml.vb

@@ -10,6 +10,12 @@ Public Class FormMain
         Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
         Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
         '统计更新日志条目
         '统计更新日志条目
 #If BETA Then
 #If BETA Then
+        If LastVersion < 357 Then 'Release 2.10.0
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:下载资源包、光影包、数据包"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:允许设置文件下载源"))
+            FeatureCount += 9
+            BugCount += 26
+        End If
         If LastVersion < 355 Then 'Release 2.9.3
         If LastVersion < 355 Then 'Release 2.9.3
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:Minecraft 会优先使用独立显卡运行"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:Minecraft 会优先使用独立显卡运行"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:简化下载新版本第二步的 UI"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:简化下载新版本第二步的 UI"))
@@ -66,6 +72,12 @@ Public Class FormMain
         '3:BUG+ IMP* FEAT-
         '3:BUG+ IMP* FEAT-
         '2:BUG* IMP-
         '2:BUG* IMP-
         '1:BUG-
         '1:BUG-
+        If LastVersion < 356 Then 'Snapshot 2.10.0
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:下载资源包、光影包、数据包"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:允许设置文件下载源"))
+            FeatureCount += 9
+            BugCount += 26
+        End If
         If LastVersion < 354 Then 'Snapshot 2.9.3
         If LastVersion < 354 Then 'Snapshot 2.9.3
             If LastVersion = 352 Then
             If LastVersion = 352 Then
                 FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:低版本 MC 没有声音"))
                 FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:低版本 MC 没有声音"))
@@ -74,7 +86,7 @@ Public Class FormMain
             FeatureCount += 8
             FeatureCount += 8
             BugCount += 8
             BugCount += 8
         End If
         End If
-        If LastVersion < 353 Then 'Snapshot 2.9.2
+        If LastVersion < 352 Then 'Snapshot 2.9.2
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:Minecraft 会优先使用独立显卡运行"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:Minecraft 会优先使用独立显卡运行"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:简化下载新版本第二步的 UI"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:简化下载新版本第二步的 UI"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:使用新的版本隔离策略"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:使用新的版本隔离策略"))
@@ -145,7 +157,7 @@ Public Class FormMain
         '整理更新日志文本
         '整理更新日志文本
         Dim ContentList As New List(Of String)
         Dim ContentList As New List(Of String)
         Dim SortedFeatures = FeatureList.OrderByDescending(Function(f) f.Key).ToList
         Dim SortedFeatures = FeatureList.OrderByDescending(Function(f) f.Key).ToList
-        If Not SortedFeatures.Any() AndAlso FeatureCount = 0 AndAlso BugCount = 0 Then ContentList.Add("龙猫忘记写更新日志啦!可以去提醒他一下……")
+        If Not SortedFeatures.Any() AndAlso FeatureCount = 0 AndAlso BugCount = 0 Then ContentList.Add("没有更新日志……")
         For i = 0 To Math.Min(9, SortedFeatures.Count - 1) '最多取 10 项
         For i = 0 To Math.Min(9, SortedFeatures.Count - 1) '最多取 10 项
             ContentList.Add(SortedFeatures(i).Value)
             ContentList.Add(SortedFeatures(i).Value)
         Next
         Next
@@ -311,8 +323,8 @@ Public Class FormMain
             '启动加载器池
             '启动加载器池
             Try
             Try
                 JavaListInit() '延后到同意协议后再执行,避免在初次启动时进行进程操作
                 JavaListInit() '延后到同意协议后再执行,避免在初次启动时进行进程操作
-                Thread.Sleep(200)
-                DlClientListMojangLoader.Start(1)
+                Thread.Sleep(100)
+                DlClientListMojangLoader.Start(1) 'PCL 会同时根据这里的加载结果决定是否使用官方源进行下载
                 RunCountSub()
                 RunCountSub()
                 ServerLoader.Start(1)
                 ServerLoader.Start(1)
                 RunInNewThread(AddressOf TryClearTaskTemp, "TryClearTaskTemp", ThreadPriority.BelowNormal)
                 RunInNewThread(AddressOf TryClearTaskTemp, "TryClearTaskTemp", ThreadPriority.BelowNormal)
@@ -743,12 +755,12 @@ Public Class FormMain
                     End If
                     End If
                 Next
                 Next
             End If
             End If
-            '自定义主页
+            '主页
             Dim Extension As String = FilePath.AfterLast(".").ToLower
             Dim Extension As String = FilePath.AfterLast(".").ToLower
             If Extension = "xaml" Then
             If Extension = "xaml" Then
-                Log("[System] 文件后缀为 XAML,作为自定义主页加载")
+                Log("[System] 文件后缀为 XAML,作为主页加载")
                 If File.Exists(Path & "PCL\Custom.xaml") Then
                 If File.Exists(Path & "PCL\Custom.xaml") Then
-                    If MyMsgBox("已存在一个自定义主页文件,是否要将它覆盖?", "覆盖确认", "覆盖", "取消") = 2 Then
+                    If MyMsgBox("已存在一个主页文件,是否要将它覆盖?", "覆盖确认", "覆盖", "取消") = 2 Then
                         Exit Sub
                         Exit Sub
                     End If
                     End If
                 End If
                 End If
@@ -927,9 +939,9 @@ Public Class FormMain
         DownloadLiteLoader = 9
         DownloadLiteLoader = 9
         DownloadMod = 11
         DownloadMod = 11
         DownloadPack = 12
         DownloadPack = 12
-        DownloadResourcePack = 13
-        DownloadShader = 14
-        DownloadDataPack = 15
+        DownloadDataPack = 13
+        DownloadResourcePack = 14
+        DownloadShader = 15
         SetupLaunch = 0
         SetupLaunch = 0
         SetupUI = 1
         SetupUI = 1
         SetupSystem = 2
         SetupSystem = 2
@@ -960,26 +972,9 @@ Public Class FormMain
             Case PageType.VersionSetup
             Case PageType.VersionSetup
                 Return "版本设置 - " & If(PageVersionLeft.Version Is Nothing, "未知版本", PageVersionLeft.Version.Name)
                 Return "版本设置 - " & If(PageVersionLeft.Version Is Nothing, "未知版本", PageVersionLeft.Version.Name)
             Case PageType.CompDetail
             Case PageType.CompDetail
-                Dim Project As CompProject = Stack.Additional(0)
-                Select Case Project.Type
-                    Case CompType.Mod
-                        Return "Mod 下载 - " & Project.TranslatedName
-                    Case CompType.ModPack
-                        Return "整合包下载 - " & Project.TranslatedName
-                    Case CompType.DataPack
-                        If Project.IsMix Then
-                            Return "Mod / 数据包下载 - " & Project.TranslatedName
-                        Else
-                            Return "数据包下载 - " & Project.TranslatedName
-                        End If
-                    Case CompType.ResourcePack
-                        Return "资源包下载 - " & Project.TranslatedName
-                    Case Else 'CompType.Shader
-                        Return "光影包下载 - " & Project.TranslatedName
-                End Select
+                Return "资源下载 - " & CType(Stack.Additional(0), CompProject).TranslatedName
             Case PageType.HelpDetail
             Case PageType.HelpDetail
-                Dim Entry As HelpEntry = Stack.Additional(0)
-                Return Entry.Title
+                Return CType(Stack.Additional(0), HelpEntry).Title
             Case Else
             Case Else
                 Return ""
                 Return ""
         End Select
         End Select

+ 15 - 12
Plain Craft Launcher 2/Modules/Base/ModBase.vb

@@ -13,13 +13,13 @@ Public Module ModBase
 #Region "声明"
 #Region "声明"
 
 
     '下列版本信息由更新器自动修改
     '下列版本信息由更新器自动修改
-    Public Const VersionBaseName As String = "2.9.3" '不含分支前缀的显示用版本名
-    Public Const VersionStandardCode As String = "2.9.3." & VersionBranchCode '标准格式的四段式版本号
+    Public Const VersionBaseName As String = "2.10.0" '不含分支前缀的显示用版本名
+    Public Const VersionStandardCode As String = "2.10.0." & VersionBranchCode '标准格式的四段式版本号
     Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
     Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
 #If BETA Then
 #If BETA Then
-    Public Const VersionCode As Integer = 355 'Release
+    Public Const VersionCode As Integer = 357 'Release
 #Else
 #Else
-    Public Const VersionCode As Integer = 354 'Snapshot
+    Public Const VersionCode As Integer = 356 'Snapshot
 #End If
 #End If
     '自动生成的版本信息
     '自动生成的版本信息
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -745,7 +745,6 @@ Public Module ModBase
             Dim IsRight As Boolean = FilePath.EndsWithF("\")
             Dim IsRight As Boolean = FilePath.EndsWithF("\")
             FilePath = Left(FilePath, Len(FilePath) - 1)
             FilePath = Left(FilePath, Len(FilePath) - 1)
             GetPathFromFullPath = Left(FilePath, FilePath.LastIndexOfAny({"\", "/"})) & If(IsRight, "\", "/")
             GetPathFromFullPath = Left(FilePath, FilePath.LastIndexOfAny({"\", "/"})) & If(IsRight, "\", "/")
-            If GetPathFromFullPath = "" Then Throw New Exception("不包含路径:" & FilePath)
         Else
         Else
             '是文件路径
             '是文件路径
             GetPathFromFullPath = Left(FilePath, FilePath.LastIndexOfAny({"\", "/"}) + 1)
             GetPathFromFullPath = Left(FilePath, FilePath.LastIndexOfAny({"\", "/"}) + 1)
@@ -2333,13 +2332,17 @@ NextElement:
     ''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
     ''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
     ''' <param name="Arguments">运行参数。</param>
     ''' <param name="Arguments">运行参数。</param>
     Public Sub ShellOnly(FileName As String, Optional Arguments As String = "")
     Public Sub ShellOnly(FileName As String, Optional Arguments As String = "")
-        FileName = ShortenPath(FileName)
-        Using Program As New Process
-            Program.StartInfo.Arguments = Arguments
-            Program.StartInfo.FileName = FileName
-            Log("[System] 执行外部命令:" & FileName & " " & Arguments)
-            Program.Start()
-        End Using
+        Try
+            FileName = ShortenPath(FileName)
+            Using Program As New Process
+                Program.StartInfo.Arguments = Arguments
+                Program.StartInfo.FileName = FileName
+                Log("[System] 执行外部命令:" & FileName & " " & Arguments)
+                Program.Start()
+            End Using
+        Catch ex As Exception
+            Log(ex, "打开文件或程序失败:" & FileName, LogLevel.Msgbox)
+        End Try
     End Sub
     End Sub
     ''' <summary>
     ''' <summary>
     ''' 前台运行文件并返回返回值。
     ''' 前台运行文件并返回返回值。

+ 2 - 2
Plain Craft Launcher 2/Modules/Base/ModLoader.vb

@@ -625,8 +625,8 @@ Restart:
     End Sub
     End Sub
     Public Function LoaderTaskbarProgressGet() As Double
     Public Function LoaderTaskbarProgressGet() As Double
         Try
         Try
-            If Not LoaderTaskbar.Any Then Return 1
-            Return MathClamp(LoaderTaskbar.Select(Function(e) e.Progress).Average(), 0, 1)
+            If Not LoaderTaskbar.Where(Function(l) l.Show).Any Then Return 1
+            Return MathClamp(LoaderTaskbar.Where(Function(l) l.Show).Select(Function(l) l.Progress).Average(), 0, 1)
         Catch ex As Exception
         Catch ex As Exception
             Log(ex, "获取任务栏进度出错", LogLevel.Feedback)
             Log(ex, "获取任务栏进度出错", LogLevel.Feedback)
             Return 0.5
             Return 0.5

+ 14 - 13
Plain Craft Launcher 2/Modules/Base/ModValidate.vb

@@ -9,6 +9,7 @@ Public Module ModValidate
         Dim Result As String = ""
         Dim Result As String = ""
         For Each ValidateRule As Validate In ValidateRules
         For Each ValidateRule As Validate In ValidateRules
             Result = ValidateRule.Validate(Text)
             Result = ValidateRule.Validate(Text)
+            If Result Is Nothing Then Return ""
             If Result <> "" Then Return Result
             If Result <> "" Then Return Result
         Next
         Next
         Return Result
         Return Result
@@ -21,7 +22,7 @@ End Module
 ''' </summary>
 ''' </summary>
 Public MustInherit Class Validate
 Public MustInherit Class Validate
     ''' <summary>
     ''' <summary>
-    ''' 验证某字符串是否符合验证要求。若符合,返回空字符串;若不符合,返回错误原因。
+    ''' 验证某字符串是否符合验证要求。若符合,返回空字符串;若不符合,返回错误原因;若需要中断检查并直接通过,返回 Nothing。
     ''' </summary>
     ''' </summary>
     Public MustOverride Function Validate(Str As String) As String
     Public MustOverride Function Validate(Str As String) As String
 End Class
 End Class
@@ -135,9 +136,9 @@ Public Class ValidateLength
         Me.Max = Max
         Me.Max = Max
     End Sub
     End Sub
     Public Overrides Function Validate(Str As String) As String
     Public Overrides Function Validate(Str As String) As String
-        If Len(Str) <> Max AndAlso Max = Min Then Return "长度必须为 " & Max & " 个字符!"
-        If Len(Str) > Max Then Return "长度最长为 " & Max & " 个字符!"
-        If Len(Str) < Min Then Return "长度至少需 " & Min & " 个字符!"
+        If Len(Str) <> Max AndAlso Max = Min Then Return $"长度必须为 {Max} 个字符!"
+        If Len(Str) > Max Then Return $"长度最长为 {Max} 个字符!"
+        If Len(Str) < Min Then Return $"长度至少需 {Min} 个字符!"
         Return ""
         Return ""
     End Function
     End Function
 End Class
 End Class
@@ -234,21 +235,21 @@ Public Class ValidateFolderName
         Try
         Try
             '检查是否为空
             '检查是否为空
             Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
             Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
-            If Not LengthCheck = "" Then Return LengthCheck
+            If LengthCheck <> "" Then Return LengthCheck
             '检查空格
             '检查空格
             If Str.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
             If Str.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
             If Str.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
             If Str.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
             '检查长度
             '检查长度
             LengthCheck = New ValidateLength(1, 100).Validate(Str)
             LengthCheck = New ValidateLength(1, 100).Validate(Str)
-            If Not LengthCheck = "" Then Return LengthCheck
+            If LengthCheck <> "" Then Return LengthCheck
             '检查尾部小数点
             '检查尾部小数点
             If Str.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
             If Str.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
             '检查特殊字符
             '检查特殊字符
             Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件夹名不可包含 % 字符!").Validate(Str)
             Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件夹名不可包含 % 字符!").Validate(Str)
-            If Not CharactCheck = "" Then Return CharactCheck
+            If CharactCheck <> "" Then Return CharactCheck
             '检查特殊字符串
             '检查特殊字符串
             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)
             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 Not InvalidStrCheck = "" Then Return InvalidStrCheck
+            If InvalidStrCheck <> "" Then Return InvalidStrCheck
             '检查 NTFS 8.3 文件名(#4505)
             '检查 NTFS 8.3 文件名(#4505)
             If RegexCheck(Str, ".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!"
             If RegexCheck(Str, ".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!"
             '检查文件夹重名
             '检查文件夹重名
@@ -295,15 +296,15 @@ Public Class ValidateFileName
             If Str.EndsWithF(" ") Then Return "文件名不能以空格结尾!"
             If Str.EndsWithF(" ") Then Return "文件名不能以空格结尾!"
             '检查长度
             '检查长度
             LengthCheck = New ValidateLength(1, 253).Validate(Str & If(ParentFolder, ""))
             LengthCheck = New ValidateLength(1, 253).Validate(Str & If(ParentFolder, ""))
-            If Not LengthCheck = "" Then Return LengthCheck
+            If LengthCheck <> "" Then Return LengthCheck
             '检查尾部小数点
             '检查尾部小数点
             If Str.EndsWithF(".") Then Return "文件名不能以小数点结尾!"
             If Str.EndsWithF(".") Then Return "文件名不能以小数点结尾!"
             '检查特殊字符
             '检查特殊字符
             Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件名不可包含 % 字符!").Validate(Str)
             Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件名不可包含 % 字符!").Validate(Str)
-            If Not CharactCheck = "" Then Return CharactCheck
+            If CharactCheck <> "" Then Return CharactCheck
             '检查特殊字符串
             '检查特殊字符串
             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)
             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 Not InvalidStrCheck = "" Then Return InvalidStrCheck
+            If InvalidStrCheck <> "" Then Return InvalidStrCheck
             '检查 NTFS 8.3 文件名(#4505)
             '检查 NTFS 8.3 文件名(#4505)
             If RegexCheck(Str, ".{2,}~\d") Then Return "文件名不能包含这一特殊格式!"
             If RegexCheck(Str, ".{2,}~\d") Then Return "文件名不能包含这一特殊格式!"
             '检查文件重名
             '检查文件重名
@@ -342,10 +343,10 @@ Public Class ValidateFolderPath
         If Not Str.TrimEnd("\").EndsWithF(":") Then Str = Str.TrimEnd("\")
         If Not Str.TrimEnd("\").EndsWithF(":") Then Str = Str.TrimEnd("\")
         '检查是否为空
         '检查是否为空
         Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
         Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
-        If Not LengthCheck = "" Then Return LengthCheck
+        If LengthCheck <> "" Then Return LengthCheck
         '检查长度
         '检查长度
         LengthCheck = New ValidateLength(1, 254).Validate(Str)
         LengthCheck = New ValidateLength(1, 254).Validate(Str)
-        If Not LengthCheck = "" Then Return LengthCheck
+        If LengthCheck <> "" Then Return LengthCheck
         '检查开头
         '检查开头
         If Str.StartsWithF("\\Mac\") Then GoTo Fin
         If Str.StartsWithF("\\Mac\") Then GoTo Fin
         For Each Drive As DriveInfo In My.Computer.FileSystem.Drives
         For Each Drive As DriveInfo In My.Computer.FileSystem.Drives

+ 165 - 185
Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb

@@ -2,6 +2,10 @@
 
 
     Public Enum CompType
     Public Enum CompType
         ''' <summary>
         ''' <summary>
+        ''' 允许任意种类,或种类未知。
+        ''' </summary>
+        Any = -1
+        ''' <summary> 
         ''' Mod。
         ''' Mod。
         ''' </summary>
         ''' </summary>
         [Mod] = 0
         [Mod] = 0
@@ -18,9 +22,14 @@
         ''' </summary>
         ''' </summary>
         Shader = 3
         Shader = 3
         ''' <summary>
         ''' <summary>
-        ''' 数据包。
+        ''' CurseForge:数据包。
+        ''' Modrinth:数据包,或数据包与 Mod 的混合。
         ''' </summary>
         ''' </summary>
         DataPack = 4
         DataPack = 4
+        ''' <summary>
+        ''' 服务端插件。
+        ''' </summary>
+        Plugin = 5
     End Enum
     End Enum
     Public Enum CompModLoaderType
     Public Enum CompModLoaderType
         'https://docs.curseforge.com/?http#tocS_ModLoaderType
         'https://docs.curseforge.com/?http#tocS_ModLoaderType
@@ -119,13 +128,10 @@
         Public ReadOnly FromCurseForge As Boolean
         Public ReadOnly FromCurseForge As Boolean
         ''' <summary>
         ''' <summary>
         ''' 工程的种类。
         ''' 工程的种类。
+        ''' 由于 Modrinth 混合使用 Mod 和数据包,结果不一定准确。
         ''' </summary>
         ''' </summary>
         Public ReadOnly Type As CompType
         Public ReadOnly Type As CompType
         ''' <summary>
         ''' <summary>
-        ''' 是否为 Mod / 数据包融合工程。
-        ''' </summary>
-        Public ReadOnly IsMix As Boolean
-        ''' <summary>
         ''' 工程的短名。例如 technical-enchant。
         ''' 工程的短名。例如 technical-enchant。
         ''' </summary>
         ''' </summary>
         Public ReadOnly Slug As String
         Public ReadOnly Slug As String
@@ -190,7 +196,9 @@
             Get
             Get
                 If Not LoadedDatabase Then
                 If Not LoadedDatabase Then
                     LoadedDatabase = True
                     LoadedDatabase = True
-                    If Type = CompType.Mod Then _DatabaseEntry = CompDatabase.FirstOrDefault(Function(c) If(FromCurseForge, c.CurseForgeSlug, c.ModrinthSlug) = Slug)
+                    If Type = CompType.Mod OrElse Type = CompType.DataPack Then
+                        _DatabaseEntry = CompDatabase.FirstOrDefault(Function(c) If(FromCurseForge, c.CurseForgeSlug, c.ModrinthSlug) = Slug)
+                    End If
                 End If
                 End If
                 Return _DatabaseEntry
                 Return _DatabaseEntry
             End Get
             End Get
@@ -266,6 +274,20 @@
                             LogoUrl = Data("logo")("thumbnailUrl")
                             LogoUrl = Data("logo")("thumbnailUrl")
                         End If
                         End If
                     End If
                     End If
+                    'Type
+                    If Website.Contains("/mc-mods/") OrElse Website.Contains("/mod/") Then
+                        Type = CompType.Mod
+                    ElseIf Website.Contains("/modpacks/") Then
+                        Type = CompType.ModPack
+                    ElseIf Website.Contains("/resourcepacks/") Then
+                        Type = CompType.ResourcePack
+                    ElseIf Website.Contains("/texture-packs/") Then
+                        Type = CompType.ResourcePack
+                    ElseIf Website.Contains("/shaders/") Then
+                        Type = CompType.Shader
+                    Else
+                        Type = CompType.DataPack
+                    End If
                     'FileIndexes / GameVersions / ModLoaders
                     'FileIndexes / GameVersions / ModLoaders
                     ModLoaders = New List(Of CompModLoaderType)
                     ModLoaders = New List(Of CompModLoaderType)
                     Dim Files As New List(Of KeyValuePair(Of Integer, List(Of String))) 'FileId, GameVersions
                     Dim Files As New List(Of KeyValuePair(Of Integer, List(Of String))) 'FileId, GameVersions
@@ -286,26 +308,12 @@
                         Select(Function(v) CInt(Val(v.Split(".")(1).BeforeFirst("-")))).Where(Function(v) v > 0).
                         Select(Function(v) CInt(Val(v.Split(".")(1).BeforeFirst("-")))).Where(Function(v) v > 0).
                         Distinct.OrderByDescending(Function(v) v).ToList
                         Distinct.OrderByDescending(Function(v) v).ToList
                     ModLoaders = ModLoaders.Distinct.OrderBy(Of Integer)(Function(t) t).ToList
                     ModLoaders = ModLoaders.Distinct.OrderBy(Of Integer)(Function(t) t).ToList
-                    'Type
-                    If Website.Contains("/mc-mods/") OrElse Website.Contains("/mod/") Then
-                        Type = CompType.Mod
-                    ElseIf Website.Contains("/modpacks/") Then
-                        Type = CompType.ModPack
-                    ElseIf Website.Contains("/resourcepacks/") Then
-                        Type = CompType.ResourcePack
-                    ElseIf Website.Contains("/texture-packs/") Then
-                        Type = CompType.ResourcePack
-                    ElseIf Website.Contains("/shaders/")
-                        Type = CompType.Shader
-                    Else
-                        Type = CompType.DataPack
-                    End If
                     'Tags
                     'Tags
                     Tags = New List(Of String)
                     Tags = New List(Of String)
-                    For Each Category In If(Data("categories"), New JArray). '镜像源 API 可能丢失此字段:https://github.com/Hex-Dragon/PCL2/issues/4267#issuecomment-2254590831
+                    For Each Category In If(Data("categories"), New JArray). '镜像源 API 可能丢失此字段 (4267#issuecomment-2254590831)
                         Select(Of Integer)(Function(t) t("id")).Distinct.OrderByDescending(Function(c) c)
                         Select(Of Integer)(Function(t) t("id")).Distinct.OrderByDescending(Function(c) c)
                         Select Case Category
                         Select Case Category
-                        'Mod
+                            'Mod
                             Case 406 : Tags.Add("世界元素")
                             Case 406 : Tags.Add("世界元素")
                             Case 407 : Tags.Add("生物群系")
                             Case 407 : Tags.Add("生物群系")
                             Case 410 : Tags.Add("维度")
                             Case 410 : Tags.Add("维度")
@@ -329,7 +337,7 @@
                             Case 435 : Tags.Add("服务器")
                             Case 435 : Tags.Add("服务器")
                             Case 5191 : Tags.Add("改良")
                             Case 5191 : Tags.Add("改良")
                             Case 421 : Tags.Add("支持库")
                             Case 421 : Tags.Add("支持库")
-                        '整合包
+                            '整合包
                             Case 4484 : Tags.Add("多人")
                             Case 4484 : Tags.Add("多人")
                             Case 4479 : Tags.Add("硬核")
                             Case 4479 : Tags.Add("硬核")
                             Case 4483 : Tags.Add("战斗")
                             Case 4483 : Tags.Add("战斗")
@@ -346,39 +354,36 @@
                             Case 4480 : Tags.Add("基于地图")
                             Case 4480 : Tags.Add("基于地图")
                             Case 4481 : Tags.Add("轻量")
                             Case 4481 : Tags.Add("轻量")
                             Case 4482 : Tags.Add("大型")
                             Case 4482 : Tags.Add("大型")
-                        '数据包
-                            Case 6946 : Tags.Add("Mod 支持")
-                            Case 6947 : Tags.Add("杂项")
+                            '资源包
+                            Case 403 : Tags.Add("原版风")
+                            Case 400 : Tags.Add("写实风")
+                            Case 401 : Tags.Add("现代风")
+                            Case 402 : Tags.Add("中世纪")
+                            Case 399 : Tags.Add("蒸汽朋克")
+                            Case 5244 : Tags.Add("含字体")
+                            Case 404 : Tags.Add("动态效果")
+                            Case 4465 : Tags.Add("兼容 Mod")
+                            Case 393 : Tags.Add("16x")
+                            Case 394 : Tags.Add("32x")
+                            Case 395 : Tags.Add("64x")
+                            Case 396 : Tags.Add("128x")
+                            Case 397 : Tags.Add("256x")
+                            Case 398 : Tags.Add("超高清")
+                            Case 5193 : Tags.Add("数据包") '有这个 Tag 的项会从资源包请求中被移除
+                            '光影包
+                            Case 6553 : Tags.Add("写实风")
+                            Case 6554 : Tags.Add("幻想风")
+                            Case 6555 : Tags.Add("原版风")
+                            '数据包
                             Case 6948 : Tags.Add("冒险")
                             Case 6948 : Tags.Add("冒险")
                             Case 6949 : Tags.Add("幻想")
                             Case 6949 : Tags.Add("幻想")
                             Case 6950 : Tags.Add("支持库")
                             Case 6950 : Tags.Add("支持库")
-                            Case 6951 : Tags.Add("科技")
                             Case 6952 : Tags.Add("魔法")
                             Case 6952 : Tags.Add("魔法")
-                            Case 6953 : Tags.Add("实用工具")
-                        '光影包
-                            Case 6553 : Tags.Add("写实")
-                            Case 6554 : Tags.Add("幻想")
-                            Case 6555 : Tags.Add("原版风")
-                        '资源包
-                            Case 5244 : Tags.Add("字体包")
-                            Case 5193 : Tags.Add("数据包")
-                            Case 399 : Tags.Add("蒸汽朋克")
-                            Case 396 : Tags.Add("128x")
-                            Case 398 : Tags.Add("512x 或更高")
-                            Case 397 : Tags.Add("256x")
-                            Case 405 : Tags.Add("其他")
-                            Case 395 : Tags.Add("64x")
-                            Case 400 : Tags.Add("仿真")
-                            Case 393 : Tags.Add("16x")
-                            Case 403 : Tags.Add("传统")
-                            Case 394 : Tags.Add("32x")
-                            Case 404 : Tags.Add("动态效果")
-                            Case 4465 : Tags.Add("模组支持")
-                            Case 402 : Tags.Add("中世纪")
-                            Case 401 : Tags.Add("现代")
+                            Case 6946 : Tags.Add("Mod 相关")
+                            Case 6951 : Tags.Add("科技")
+                            Case 6953 : Tags.Add("实用")
                         End Select
                         End Select
                     Next
                     Next
-                    If Not Tags.Any() Then Tags.Add("杂项")
 #End Region
 #End Region
                 Else
                 Else
 #Region "Modrinth"
 #Region "Modrinth"
@@ -400,16 +405,11 @@
                                        Distinct.OrderByDescending(Function(v) v).ToList
                                        Distinct.OrderByDescending(Function(v) v).ToList
                     'Type
                     'Type
                     Select Case Data("project_type").ToString
                     Select Case Data("project_type").ToString
-                        Case "mod" : Type = CompType.Mod
                         Case "modpack" : Type = CompType.ModPack
                         Case "modpack" : Type = CompType.ModPack
                         Case "resourcepack" : Type = CompType.ResourcePack
                         Case "resourcepack" : Type = CompType.ResourcePack
-                        Case "datapack" : Type = CompType.DataPack
                         Case "shader" : Type = CompType.Shader
                         Case "shader" : Type = CompType.Shader
+                        Case Else : Type = CompType.Mod 'Modrinth 将数据包标为 Mod
                     End Select
                     End Select
-                    If Data("categories").ToArray.Contains("datapack") Then 'Modrinth 上的数据包由于未知原因,返回的 project_type 为 mod,这里做兜底处理
-                        Type = CompType.DataPack
-                        IsMix = Data("categories").ToArray.Contains("forge") OrElse Data("categories").ToArray.Contains("fabric") OrElse Data("categories").ToArray.Contains("neoforge") OrElse Data("categories").ToArray.Contains("quilt")
-                    End If
                     'Tags & ModLoaders
                     'Tags & ModLoaders
                     Tags = New List(Of String)
                     Tags = New List(Of String)
                     ModLoaders = New List(Of CompModLoaderType)
                     ModLoaders = New List(Of CompModLoaderType)
@@ -430,117 +430,75 @@
                             Case "fabric" : ModLoaders.Add(CompModLoaderType.Fabric)
                             Case "fabric" : ModLoaders.Add(CompModLoaderType.Fabric)
                             Case "quilt" : ModLoaders.Add(CompModLoaderType.Quilt)
                             Case "quilt" : ModLoaders.Add(CompModLoaderType.Quilt)
                             Case "neoforge" : ModLoaders.Add(CompModLoaderType.NeoForge)
                             Case "neoforge" : ModLoaders.Add(CompModLoaderType.NeoForge)
-                            'Mod
-                            Case "worldgen" : Tags.Add("世界元素")
+                            Case "datapack" : Type = CompType.DataPack '若包含数据包版本,则优先标为 DataPack
+                            '共用
                             Case "technology" : Tags.Add("科技")
                             Case "technology" : Tags.Add("科技")
+                            Case "magic" : Tags.Add("魔法")
+                            Case "adventure" : Tags.Add("冒险")
+                            Case "utility" : Tags.Add("实用")
+                            Case "optimization" : Tags.Add("性能优化")
+                            Case "vanilla-like" : Tags.Add("原版风")
+                            Case "realistic" : Tags.Add("写实风")
+                            'Mod/数据包
+                            Case "worldgen" : Tags.Add("世界元素")
                             Case "food" : Tags.Add("食物/烹饪")
                             Case "food" : Tags.Add("食物/烹饪")
                             Case "game-mechanics" : Tags.Add("游戏机制")
                             Case "game-mechanics" : Tags.Add("游戏机制")
                             Case "transportation" : Tags.Add("运输")
                             Case "transportation" : Tags.Add("运输")
                             Case "storage" : Tags.Add("仓储")
                             Case "storage" : Tags.Add("仓储")
-                            Case "magic" : Tags.Add("魔法")
-                            Case "adventure" : Tags.Add("冒险")
-                            Case "decoration" : Tags.Add("装饰")
-                            Case "mobs" : Tags.Add("生物")
-                            Case "equipment" : Tags.Add("装备")
-                            Case "optimization" : Tags.Add("性能优化")
+                            Case "decoration" : If Type <> CompType.ResourcePack Then Tags.Add("装饰")
+                            Case "mobs" : If Type <> CompType.ResourcePack Then Tags.Add("生物")
+                            Case "equipment" : If Type <> CompType.ResourcePack Then Tags.Add("装备")
                             Case "social" : Tags.Add("服务器")
                             Case "social" : Tags.Add("服务器")
-                            Case "utility" : Tags.Add("改良")
                             Case "library" : Tags.Add("支持库")
                             Case "library" : Tags.Add("支持库")
                             '整合包
                             '整合包
                             Case "multiplayer" : Tags.Add("多人")
                             Case "multiplayer" : Tags.Add("多人")
-                            Case "optimization" : Tags.Add("性能优化")
                             Case "challenging" : Tags.Add("硬核")
                             Case "challenging" : Tags.Add("硬核")
                             Case "combat" : Tags.Add("战斗")
                             Case "combat" : Tags.Add("战斗")
                             Case "quests" : Tags.Add("任务")
                             Case "quests" : Tags.Add("任务")
-                            Case "technology" : Tags.Add("科技")
-                            Case "magic" : Tags.Add("魔法")
-                            Case "adventure" : Tags.Add("冒险")
-                            Case "kitchen-sink" : Tags.Add("水槽包/大杂烩")
+                            Case "kitchen-sink" : Tags.Add("水槽包")
                             Case "lightweight" : Tags.Add("轻量")
                             Case "lightweight" : Tags.Add("轻量")
-                            '数据包
-                            Case "adventure" : Tags.Add("冒险")
-                            Case "cursed" : Tags.Add("Cursed")
-                            Case "decoration" : Tags.Add("装饰")
-                            Case "economy" : Tags.Add("经济")
-                            Case "equipment" : Tags.Add("装备")
-                            Case "food" : Tags.Add("食物")
-                            Case "game-mechanics" : Tags.Add("游戏机制")
-                            Case "library" : Tags.Add("支持库")
-                            Case "magic" : Tags.Add("魔法")
-                            Case "management" : Tags.Add("管理")
-                            Case "minigame" : Tags.Add("小游戏")
-                            Case "mobs" : Tags.Add("生物")
-                            Case "optimization" : Tags.Add("优化")
-                            Case "social" : Tags.Add("社交")
-                            Case "storage" : Tags.Add("存储")
-                            Case "technology" : Tags.Add("科技")
-                            Case "transportation" : Tags.Add("交通")
-                            Case "utility" : Tags.Add("实用工具")
-                            Case "worldgen" : Tags.Add("世界生成")
-                            '光影包
-                            Case "cartoon" : Tags.Add("卡通")
-                            Case "cursed" : Tags.Add("Cursed")
-                            Case "fantasy" : Tags.Add("幻想")
-                            Case "realistic" : Tags.Add("写实")
-                            Case "semi-realistic" : Tags.Add("半写实")
-                            Case "vanilla-like" : Tags.Add("原版风")
-
-                            Case "atmosphere" : Tags.Add("大气环境")
-                            Case "bloom" : Tags.Add("植被")
-                            Case "colored-lighting" : Tags.Add("光源着色")
-                            Case "foliage" : Tags.Add("树叶")
-                            Case "path-tracing" : Tags.Add("路径追踪")
-                            Case "pbr" : Tags.Add("PBR")
-                            Case "reflections" : Tags.Add("反射")
-                            Case "shadows" : Tags.Add("阴影")
-
-                            Case "potato" : Tags.Add("土豆画质")
-                            Case "low" : Tags.Add("低性能影响")
-                            Case "medium" : Tags.Add("中性能影响")
-                            Case "high" : Tags.Add("高性能影响")
-                            Case "screenshot" : Tags.Add("极致画质")
-
-                            Case "canvas" : Tags.Add("Canvas")
-                            Case "iris" : Tags.Add("Iris")
-                            Case "optifine" : Tags.Add("OptiFine")
-                            Case "vanilla" : Tags.Add("原版光影")
                             '资源包
                             '资源包
-                            Case "8x-" : Tags.Add("8x-")
+                            Case "simplistic" : Tags.Add("简洁")
+                            Case "combat" : Tags.Add("战斗")
+                            Case "tweaks" : Tags.Add("改良")
+
+                            Case "8x-" : Tags.Add("极简")
                             Case "16x" : Tags.Add("16x")
                             Case "16x" : Tags.Add("16x")
                             Case "32x" : Tags.Add("32x")
                             Case "32x" : Tags.Add("32x")
                             Case "48x" : Tags.Add("48x")
                             Case "48x" : Tags.Add("48x")
                             Case "64x" : Tags.Add("64x")
                             Case "64x" : Tags.Add("64x")
                             Case "128x" : Tags.Add("128x")
                             Case "128x" : Tags.Add("128x")
                             Case "256x" : Tags.Add("256x")
                             Case "256x" : Tags.Add("256x")
-                            Case "512x+" : Tags.Add("512x+")
-                            Case "audio" : Tags.Add("声音")
-                            Case "blocks" : Tags.Add("方块")
-                            Case "combat" : Tags.Add("战斗")
+                            Case "512x+" : Tags.Add("超高清")
+
+                            Case "audio" : Tags.Add("含声音")
+                            Case "fonts" : Tags.Add("含字体")
+                            Case "models" : Tags.Add("含模型")
+                            Case "gui" : Tags.Add("含 UI")
+                            Case "locale" : Tags.Add("含语言")
                             Case "core-shaders" : Tags.Add("核心着色器")
                             Case "core-shaders" : Tags.Add("核心着色器")
-                            Case "cursed" : Tags.Add("Cursed")
-                            Case "decoration" : Tags.Add("装饰")
-                            Case "entities" : Tags.Add("实体")
-                            Case "environment" : Tags.Add("环境")
-                            Case "equipment" : Tags.Add("装备")
-                            Case "fonts" : Tags.Add("字体")
-                            Case "gui" : Tags.Add("GUI")
-                            Case "items" : Tags.Add("物品")
-                            Case "locale" : Tags.Add("本地化")
-                            Case "modded" : Tags.Add("Modded")
-                            Case "models" : Tags.Add("模型")
-                            Case "realistic" : Tags.Add("写实")
-                            Case "simplistic" : Tags.Add("扁平")
-                            Case "themed" : Tags.Add("主题")
-                            Case "tweaks" : Tags.Add("优化")
-                            Case "utility" : Tags.Add("实用")
-                            Case "vanilla-like" : Tags.Add("类原生")
+                            Case "modded" : Tags.Add("兼容 Mod")
+                            '光影包
+                            Case "fantasy" : Tags.Add("幻想风")
+                            Case "semi-realistic" : Tags.Add("半写实风")
+                            Case "cartoon" : Tags.Add("卡通风")
+                            '暂时不添加性能负荷 Tag
+                            'Case "potato" : Tags.Add("极低")
+                            'Case "low" : Tags.Add("低")
+                            'Case "medium" : Tags.Add("中")
+                            'Case "high" : Tags.Add("高")
+                            Case "colored-lighting" : Tags.Add("彩色光照")
+                            Case "path-tracing" : Tags.Add("路径追踪")
+                            Case "pbr" : Tags.Add("PBR")
+                            Case "reflections" : Tags.Add("反射")
+                            Case "vanilla" : Tags.Add("原版可用")
                         End Select
                         End Select
                     Next
                     Next
-                    If Not Tags.Any() Then Tags.Add("杂项")
-                    Tags.Sort()
-                    ModLoaders.Sort()
 #End Region
 #End Region
                 End If
                 End If
+                If Not Tags.Any() Then Tags.Add("其他")
+                Tags.Sort()
+                ModLoaders.Sort()
             End If
             End If
             '保存缓存
             '保存缓存
             CompProjectCache(Id) = Me
             CompProjectCache(Id) = Me
@@ -663,7 +621,7 @@
                 NewItem.ColumnVersion1.Width = New GridLength(0)
                 NewItem.ColumnVersion1.Width = New GridLength(0)
                 NewItem.ColumnVersion2.MaxWidth = 0
                 NewItem.ColumnVersion2.MaxWidth = 0
                 NewItem.ColumnVersion3.Width = New GridLength(0)
                 NewItem.ColumnVersion3.Width = New GridLength(0)
-            ElseIf ShowMcVersionDesc AndAlso ShowMcVersionDesc Then
+            ElseIf ShowMcVersionDesc AndAlso ShowLoaderDesc Then
                 '全部显示
                 '全部显示
                 NewItem.LabVersion.Text = If(ModLoaderDescriptionPart = "", "", ModLoaderDescriptionPart & " ") & GameVersionDescription
                 NewItem.LabVersion.Text = If(ModLoaderDescriptionPart = "", "", ModLoaderDescriptionPart & " ") & GameVersionDescription
             ElseIf ShowMcVersionDesc Then
             ElseIf ShowMcVersionDesc Then
@@ -793,8 +751,8 @@ NoSubtitle:
             If FromCurseForge = Project.FromCurseForge Then Return False
             If FromCurseForge = Project.FromCurseForge Then Return False
             'Mod 加载器一致
             'Mod 加载器一致
             If ModLoaders.Count <> Project.ModLoaders.Count OrElse ModLoaders.Except(Project.ModLoaders).Any() Then Return False
             If ModLoaders.Count <> Project.ModLoaders.Count OrElse ModLoaders.Except(Project.ModLoaders).Any() Then Return False
-            'MC 版本一致
-            If GameVersions.Count <> Project.GameVersions.Count OrElse GameVersions.Except(Project.GameVersions).Any() Then Return False
+            '若不为光影,则要求 MC 版本一致
+            If Type <> CompType.Shader AndAlso (GameVersions.Count <> Project.GameVersions.Count OrElse GameVersions.Except(Project.GameVersions).Any()) Then Return False
             '最近更新时间差距在一周以内
             '最近更新时间差距在一周以内
             If LastUpdate IsNot Nothing AndAlso Project.LastUpdate IsNot Nothing AndAlso
             If LastUpdate IsNot Nothing AndAlso Project.LastUpdate IsNot Nothing AndAlso
                Math.Abs((LastUpdate - Project.LastUpdate).Value.TotalDays) > 7 Then Return False
                Math.Abs((LastUpdate - Project.LastUpdate).Value.TotalDays) > 7 Then Return False
@@ -1020,7 +978,7 @@ NoSubtitle:
 
 
         '中文请求关键字处理
         '中文请求关键字处理
         Dim IsChineseSearch As Boolean = RegexCheck(RawFilter, "[\u4e00-\u9fbb]") AndAlso Not String.IsNullOrEmpty(RawFilter)
         Dim IsChineseSearch As Boolean = RegexCheck(RawFilter, "[\u4e00-\u9fbb]") AndAlso Not String.IsNullOrEmpty(RawFilter)
-        If IsChineseSearch AndAlso Task.Input.Type = CompType.Mod Then
+        If IsChineseSearch AndAlso (Task.Input.Type = CompType.Mod OrElse Task.Input.Type = CompType.DataPack) Then
             '构造搜索请求
             '构造搜索请求
             Dim SearchEntries As New List(Of SearchEntry(Of CompDatabaseEntry))
             Dim SearchEntries As New List(Of SearchEntry(Of CompDatabaseEntry))
             For Each Entry In CompDatabase
             For Each Entry In CompDatabase
@@ -1111,7 +1069,9 @@ Retry:
                         Task.Progress += 0.2
                         Task.Progress += 0.2
                         Dim ProjectList As New List(Of CompProject)
                         Dim ProjectList As New List(Of CompProject)
                         For Each JsonEntry As JObject In RequestResult("data")
                         For Each JsonEntry As JObject In RequestResult("data")
-                            ProjectList.Add(New CompProject(JsonEntry))
+                            Dim Project As New CompProject(JsonEntry)
+                            If Task.Input.Type = CompType.ResourcePack AndAlso Project.Tags.Contains("数据包") Then Continue For 'CurseForge 将一些数据包分类成了资源包
+                            ProjectList.Add(Project)
                         Next
                         Next
                         '更新结果
                         '更新结果
                         SyncLock ResultsLock
                         SyncLock ResultsLock
@@ -1146,7 +1106,6 @@ Retry:
                         '更新结果
                         '更新结果
                         SyncLock ResultsLock
                         SyncLock ResultsLock
                             For Each Project In ProjectList
                             For Each Project In ProjectList
-                                If Task.Input.Type = CompType.Mod AndAlso Not Project.ModLoaders.Any() Then Continue For '过滤插件(#2458)
                                 RawResults.Add(Project)
                                 RawResults.Add(Project)
                             Next
                             Next
                         End SyncLock
                         End SyncLock
@@ -1174,8 +1133,8 @@ Retry:
                 If [Error] IsNot Nothing Then
                 If [Error] IsNot Nothing Then
                     Throw [Error]
                     Throw [Error]
                 Else
                 Else
-                    If IsChineseSearch AndAlso Task.Input.Type <> CompType.Mod Then
-                        Throw New Exception($"{If(Task.Input.Type = CompType.ModPack, "整合包", "资源包")}搜索仅支持英文")
+                    If IsChineseSearch AndAlso Not (Task.Input.Type = CompType.Mod OrElse Task.Input.Type = CompType.DataPack) Then
+                        Throw New Exception("没有搜索结果,请尝试使用英文搜索")
                     ElseIf Task.Input.Source = CompSourceType.CurseForge AndAlso Task.Input.Tag.StartsWithF("/") Then
                     ElseIf Task.Input.Source = CompSourceType.CurseForge AndAlso Task.Input.Tag.StartsWithF("/") Then
                         Throw New Exception("CurseForge 不兼容所选的类型")
                         Throw New Exception("CurseForge 不兼容所选的类型")
                     ElseIf Task.Input.Source = CompSourceType.Modrinth AndAlso Task.Input.Tag.EndsWithF("/") Then
                     ElseIf Task.Input.Source = CompSourceType.Modrinth AndAlso Task.Input.Tag.EndsWithF("/") Then
@@ -1233,10 +1192,23 @@ Retry:
 #Region "将结果排序并添加"
 #Region "将结果排序并添加"
 
 
         Dim Scores As New Dictionary(Of CompProject, Double) '排序分
         Dim Scores As New Dictionary(Of CompProject, Double) '排序分
+        Dim GetDownloadCountMult =
+        Function(Project As CompProject) As Double
+            Select Case Task.Input.Type
+                Case CompType.Mod, CompType.ModPack
+                    Return If(Project.FromCurseForge, 1, 7)
+                Case CompType.DataPack
+                    Return If(Project.FromCurseForge, 10, 1)
+                Case CompType.ResourcePack, CompType.Shader
+                    Return If(Project.FromCurseForge, 1, 5)
+                Case Else
+                    Return 1
+            End Select
+        End Function
         If String.IsNullOrEmpty(Task.Input.SearchText) Then
         If String.IsNullOrEmpty(Task.Input.SearchText) Then
             '如果没有搜索文本,按下载量将结果排序
             '如果没有搜索文本,按下载量将结果排序
             For Each Result As CompProject In RealResults
             For Each Result As CompProject In RealResults
-                Scores.Add(Result, Result.DownloadCount * If(Result.FromCurseForge, 1, 5))
+                Scores.Add(Result, Result.DownloadCount * GetDownloadCountMult(Result))
             Next
             Next
         Else
         Else
             '如果有搜索文本,按关联度将结果排序
             '如果有搜索文本,按关联度将结果排序
@@ -1244,7 +1216,7 @@ Retry:
             Dim Entry As New List(Of SearchEntry(Of CompProject))
             Dim Entry As New List(Of SearchEntry(Of CompProject))
             For Each Result As CompProject In RealResults
             For Each Result As CompProject In RealResults
                 Scores.Add(Result, If(Result.WikiId > 0, 0.2, 0) +
                 Scores.Add(Result, If(Result.WikiId > 0, 0.2, 0) +
-                           Math.Log10(Math.Max(Result.DownloadCount, 1) * If(Result.FromCurseForge, 1, 5)) / 9)
+                           Math.Log10(Math.Max(Result.DownloadCount, 1) * GetDownloadCountMult(Result)) / 9)
                 Entry.Add(New SearchEntry(Of CompProject) With {.Item = Result, .SearchSource = New List(Of KeyValuePair(Of String, Double)) From {
                 Entry.Add(New SearchEntry(Of CompProject) With {.Item = Result, .SearchSource = New List(Of KeyValuePair(Of String, Double)) From {
                           New KeyValuePair(Of String, Double)(If(IsChineseSearch, Result.TranslatedName, Result.RawName), 1),
                           New KeyValuePair(Of String, Double)(If(IsChineseSearch, Result.TranslatedName, Result.RawName), 1),
                           New KeyValuePair(Of String, Double)(Result.Description, 0.05)}})
                           New KeyValuePair(Of String, Double)(Result.Description, 0.05)}})
@@ -1327,7 +1299,7 @@ Retry:
                     Case CompFileStatus.Beta
                     Case CompFileStatus.Beta
                         Return If(ModeDebug, "Beta 版", "测试版")
                         Return If(ModeDebug, "Beta 版", "测试版")
                     Case Else
                     Case Else
-                        Return If(ModeDebug, "Alpha 版", "测试版")
+                        Return If(ModeDebug, "Alpha 版", "早期测试版")
                 End Select
                 End Select
             End Get
             End Get
         End Property
         End Property
@@ -1375,8 +1347,8 @@ Retry:
         ''' <summary>
         ''' <summary>
         ''' 从文件 Json 中初始化实例。若出错会抛出异常。
         ''' 从文件 Json 中初始化实例。若出错会抛出异常。
         ''' </summary>
         ''' </summary>
-        Public Sub New(Data As JObject, Type As CompType)
-            Me.Type = Type
+        Public Sub New(Data As JObject, DefaultType As CompType)
+            Type = DefaultType
             If Data.ContainsKey("FromCurseForge") Then
             If Data.ContainsKey("FromCurseForge") Then
 #Region "CompJson"
 #Region "CompJson"
                 FromCurseForge = Data("FromCurseForge").ToObject(Of Boolean)
                 FromCurseForge = Data("FromCurseForge").ToObject(Of Boolean)
@@ -1414,7 +1386,7 @@ Retry:
                     DownloadUrls.AddRange(DownloadUrls.Select(Function(u) DlSourceModGet(u)).ToList) '添加镜像源,这个写法是为了让镜像源排在后面
                     DownloadUrls.AddRange(DownloadUrls.Select(Function(u) DlSourceModGet(u)).ToList) '添加镜像源,这个写法是为了让镜像源排在后面
                     DownloadUrls = DownloadUrls.Distinct.ToList '最终去重
                     DownloadUrls = DownloadUrls.Distinct.ToList '最终去重
                     'Dependencies
                     'Dependencies
-                    If Type = CompType.Mod Then
+                    If Data.ContainsKey("dependencies") Then
                         RawDependencies = Data("dependencies").
                         RawDependencies = Data("dependencies").
                             Where(Function(d) d("relationType").ToObject(Of Integer) = 3 AndAlso '种类为依赖
                             Where(Function(d) d("relationType").ToObject(Of Integer) = 3 AndAlso '种类为依赖
                                               d("modId").ToObject(Of Integer) <> 306612 AndAlso d("modId").ToObject(Of Integer) <> 634179). '排除 Fabric API 和 Quilt API
                                               d("modId").ToObject(Of Integer) <> 306612 AndAlso d("modId").ToObject(Of Integer) <> 634179). '排除 Fabric API 和 Quilt API
@@ -1425,7 +1397,7 @@ Retry:
                     GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.")).Select(Function(v) v.Replace("-snapshot", " 预览版")).ToList
                     GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.")).Select(Function(v) v.Replace("-snapshot", " 预览版")).ToList
                     If GameVersions.Count > 1 Then
                     If GameVersions.Count > 1 Then
                         GameVersions = GameVersions.Sort(AddressOf VersionSortBoolean).ToList
                         GameVersions = GameVersions.Sort(AddressOf VersionSortBoolean).ToList
-                        If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)}
+                        If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)} '整合包理应只 “支持” 一个版本
                     ElseIf GameVersions.Count = 1 Then
                     ElseIf GameVersions.Count = 1 Then
                         GameVersions = GameVersions.ToList
                         GameVersions = GameVersions.ToList
                     Else
                     Else
@@ -1452,8 +1424,27 @@ Retry:
                         DownloadUrls = New List(Of String) From {File("url"), DlSourceModGet(File("url"))}.Distinct.ToList '同时添加了镜像源
                         DownloadUrls = New List(Of String) From {File("url"), DlSourceModGet(File("url"))}.Distinct.ToList '同时添加了镜像源
                         Hash = File("hashes")("sha1")
                         Hash = File("hashes")("sha1")
                     End If
                     End If
+                    'ModLoaders
+                    '结果可能混杂着 Mod、数据包和服务端插件
+                    Dim RawLoaders As List(Of String) = Data("loaders").Select(Function(v) v.ToString).ToList
+                    ModLoaders = New List(Of CompModLoaderType)
+                    If Type = CompType.Mod Then '以尽量宽容的方式检测加载器,以免同时兼容两种的项被删除
+                        If RawLoaders.Intersect({"bukkit", "folia", "paper", "purpur", "spigot"}).Any() Then Type = CompType.Plugin 'Veinminer Enchantment 同时支持服务端与 Fabric
+                        If RawLoaders.Contains("datapack") Then Type = CompType.DataPack
+                        If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge) : Type = CompType.Mod
+                        If RawLoaders.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge) : Type = CompType.Mod
+                        If RawLoaders.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric) : Type = CompType.Mod
+                        If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt) : Type = CompType.Mod
+                    ElseIf Type = CompType.DataPack Then
+                        If RawLoaders.Intersect({"bukkit", "folia", "paper", "purpur", "spigot"}).Any() Then Type = CompType.Plugin
+                        If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge) : Type = CompType.Mod
+                        If RawLoaders.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge) : Type = CompType.Mod
+                        If RawLoaders.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric) : Type = CompType.Mod
+                        If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt) : Type = CompType.Mod
+                        If RawLoaders.Contains("datapack") Then Type = CompType.DataPack
+                    End If
                     'Dependencies
                     'Dependencies
-                    If Type = CompType.Mod Then
+                    If Data.ContainsKey("dependencies") Then
                         RawDependencies = Data("dependencies").
                         RawDependencies = Data("dependencies").
                             Where(Function(d) d("dependency_type") = "required" AndAlso '种类为依赖
                             Where(Function(d) d("dependency_type") = "required" AndAlso '种类为依赖
                                               d("project_id") <> "P7dR8mSH" AndAlso d("project_id") <> "qvIfYCYJ" AndAlso '排除 Fabric API 和 Quilt API
                                               d("project_id") <> "P7dR8mSH" AndAlso d("project_id") <> "qvIfYCYJ" AndAlso '排除 Fabric API 和 Quilt API
@@ -1466,7 +1457,7 @@ Retry:
                                                Select(Function(v) If(v.Contains("-"), v.BeforeFirst("-") & " 预览版", If(v.StartsWithF("b1."), "远古版本", v))).ToList
                                                Select(Function(v) If(v.Contains("-"), v.BeforeFirst("-") & " 预览版", If(v.StartsWithF("b1."), "远古版本", v))).ToList
                     If GameVersions.Count > 1 Then
                     If GameVersions.Count > 1 Then
                         GameVersions = GameVersions.Sort(AddressOf VersionSortBoolean).ToList
                         GameVersions = GameVersions.Sort(AddressOf VersionSortBoolean).ToList
-                        If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)}
+                        If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)} '整合包理应只 “支持” 一个版本
                     ElseIf GameVersions.Count = 1 Then
                     ElseIf GameVersions.Count = 1 Then
                         '无需处理
                         '无需处理
                     ElseIf RawVersions.Any(Function(v) RegexCheck(v, "[0-9]{2}w[0-9]{2}[a-z]{1}")) Then
                     ElseIf RawVersions.Any(Function(v) RegexCheck(v, "[0-9]{2}w[0-9]{2}[a-z]{1}")) Then
@@ -1474,13 +1465,6 @@ Retry:
                     Else
                     Else
                         GameVersions = New List(Of String) From {"未知版本"}
                         GameVersions = New List(Of String) From {"未知版本"}
                     End If
                     End If
-                    'ModLoaders
-                    Dim RawLoaders As List(Of String) = Data("loaders").Select(Function(v) v.ToString).ToList
-                    ModLoaders = New List(Of CompModLoaderType)
-                    If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge)
-                    If RawLoaders.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge)
-                    If RawLoaders.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric)
-                    If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
 #End Region
 #End Region
                 End If
                 End If
             End If
             End If
@@ -1528,12 +1512,8 @@ Retry:
             Dim Title As String = If(BadDisplayName, FileName, DisplayName)
             Dim Title As String = If(BadDisplayName, FileName, DisplayName)
             Dim Info As New List(Of String)
             Dim Info As New List(Of String)
             If Title <> FileName.BeforeLast(".") Then Info.Add(FileName.BeforeLast("."))
             If Title <> FileName.BeforeLast(".") Then Info.Add(FileName.BeforeLast("."))
-            Select Case Type
-                Case CompType.Mod
-                    If Dependencies.Any Then Info.Add(Dependencies.Count & " 个前置 Mod")
-                Case CompType.ModPack
-                    If GameVersions.All(Function(v) v.Contains("w")) Then Info.Add($"游戏版本 {Join(GameVersions, "、")}")
-            End Select
+            If Dependencies.Any Then Info.Add(Dependencies.Count & " 项前置")
+            If GameVersions.All(Function(v) Not IsVersionNameLikeRelease(v)) Then Info.Add($"游戏版本 {Join(GameVersions, "、")}")
             If DownloadCount > 0 Then 'CurseForge 的下载次数经常错误地返回 0
             If DownloadCount > 0 Then 'CurseForge 的下载次数经常错误地返回 0
                 Info.Add("下载 " & If(DownloadCount > 100000, Math.Round(DownloadCount / 10000) & " 万次", DownloadCount & " 次"))
                 Info.Add("下载 " & If(DownloadCount > 100000, Math.Round(DownloadCount / 10000) & " 万次", DownloadCount & " 次"))
             End If
             End If
@@ -1599,7 +1579,7 @@ Retry:
             TargetProject = New CompProject(DlModRequest("https://api.modrinth.com/v2/project/" & ProjectId, IsJson:=True))
             TargetProject = New CompProject(DlModRequest("https://api.modrinth.com/v2/project/" & ProjectId, IsJson:=True))
         End If
         End If
         '获取工程对象的文件列表
         '获取工程对象的文件列表
-        If Not CompFilesCache.ContainsKey(ProjectId) Then '有缓存也不能直接返回,这时候前置 Mod 可能没获取(#5173)
+        If Not CompFilesCache.ContainsKey(ProjectId) Then '有缓存也不能直接返回,这时候前置可能没获取(#5173)
             Log("[Comp] 开始获取文件列表:" & ProjectId)
             Log("[Comp] 开始获取文件列表:" & ProjectId)
             Dim ResultJsonArray As JArray
             Dim ResultJsonArray As JArray
             If FromCurseForge Then
             If FromCurseForge Then
@@ -1617,15 +1597,15 @@ Retry:
                 ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version", IsJson:=True)
                 ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version", IsJson:=True)
             End If
             End If
             CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)).
             CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)).
-                Where(Function(a) a.Available).ToList.Distinct(Function(a, b) a.Id = b.Id) 'CurseForge 可能会重复返回相同项(#1330)
+                Where(Function(a) a.Available).ToList.
+                Distinct(Function(a, b) a.Id = b.Id) 'CurseForge 可能会重复返回相同项(#1330)
         End If
         End If
-        '获取前置 Mod 列表
-        If TargetProject.Type <> CompType.Mod Then Return CompFilesCache(ProjectId)
+        '获取前置列表
         Dim Deps As List(Of String) = CompFilesCache(ProjectId).SelectMany(Function(f) f.RawDependencies).Distinct().ToList
         Dim Deps As List(Of String) = CompFilesCache(ProjectId).SelectMany(Function(f) f.RawDependencies).Distinct().ToList
         Dim UndoneDeps = Deps.Where(Function(f) Not CompProjectCache.ContainsKey(f)).ToList
         Dim UndoneDeps = Deps.Where(Function(f) Not CompProjectCache.ContainsKey(f)).ToList
-        '获取前置 Mod 工程信息
+        '获取前置工程信息
         If UndoneDeps.Any Then
         If UndoneDeps.Any Then
-            Log($"[Comp] {ProjectId} 文件列表中还需要获取信息的前置 Mod:{Join(UndoneDeps, ",")}")
+            Log($"[Comp] {ProjectId} 文件列表中还需要获取信息的前置:{Join(UndoneDeps, ",")}")
             Dim Projects As JArray
             Dim Projects As JArray
             If TargetProject.FromCurseForge Then
             If TargetProject.FromCurseForge Then
                 Projects = GetJson(DlModRequest("https://api.curseforge.com/v1/mods",
                 Projects = GetJson(DlModRequest("https://api.curseforge.com/v1/mods",
@@ -1634,10 +1614,10 @@ Retry:
                 Projects = DlModRequest($"https://api.modrinth.com/v2/projects?ids=[""{Join(UndoneDeps, """,""")}""]", IsJson:=True)
                 Projects = DlModRequest($"https://api.modrinth.com/v2/projects?ids=[""{Join(UndoneDeps, """,""")}""]", IsJson:=True)
             End If
             End If
             For Each Project In Projects
             For Each Project In Projects
-                Dim NewProject As New CompProject(Project) '在 New 的时候就添加了缓存
+                Dim Unused As New CompProject(Project) '在 New 的时候会添加缓存以便之后读取
             Next
             Next
         End If
         End If
-        '更新前置 Mod 信息
+        '更新前置信息
         If Deps.Any Then
         If Deps.Any Then
             For Each DepProject In Deps.Where(Function(id) CompProjectCache.ContainsKey(id)).Select(Function(id) CompProjectCache(id))
             For Each DepProject In Deps.Where(Function(id) CompProjectCache.ContainsKey(id)).Select(Function(id) CompProjectCache(id))
                 For Each File In CompFilesCache(ProjectId)
                 For Each File In CompFilesCache(ProjectId)
@@ -1651,7 +1631,7 @@ Retry:
     End Function
     End Function
 
 
     ''' <summary>
     ''' <summary>
-    ''' 预载包含大量 CompFile 的卡片,添加必要的元素和前置 Mod 列表。
+    ''' 预载包含大量 CompFile 的卡片,添加必要的元素和前置列表。
     ''' </summary>
     ''' </summary>
     Public Sub CompFilesCardPreload(Stack As StackPanel, Files As List(Of CompFile))
     Public Sub CompFilesCardPreload(Stack As StackPanel, Files As List(Of CompFile))
         '获取卡片对应的前置 ID
         '获取卡片对应的前置 ID
@@ -1661,18 +1641,18 @@ Retry:
         If Not Deps.Any() Then Exit Sub
         If Not Deps.Any() Then Exit Sub
         Deps = Deps.Where(
         Deps = Deps.Where(
         Function(dep)
         Function(dep)
-            If Not CompProjectCache.ContainsKey(dep) Then Log($"[Comp] 未找到 ID {dep} 的前置 Mod 信息", LogLevel.Debug)
+            If Not CompProjectCache.ContainsKey(dep) Then Log($"[Comp] 未找到 ID {dep} 的前置信息", LogLevel.Debug)
             Return CompProjectCache.ContainsKey(dep)
             Return CompProjectCache.ContainsKey(dep)
         End Function).ToList
         End Function).ToList
         '添加开头间隔
         '添加开头间隔
-        Stack.Children.Add(New TextBlock With {.Text = "前置 Mod", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 2, 0, 5)})
-        '添加前置 Mod 列表
+        Stack.Children.Add(New TextBlock With {.Text = "前置资源", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 2, 0, 5)})
+        '添加前置列表
         For Each Dep In Deps
         For Each Dep In Deps
             Dim Item = CompProjectCache(Dep).ToCompItem(False, False)
             Dim Item = CompProjectCache(Dep).ToCompItem(False, False)
             Stack.Children.Add(Item)
             Stack.Children.Add(Item)
         Next
         Next
         '添加结尾间隔
         '添加结尾间隔
-        Stack.Children.Add(New TextBlock With {.Text = "可选版本", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 12, 0, 5)})
+        Stack.Children.Add(New TextBlock With {.Text = "版本列表", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 12, 0, 5)})
     End Sub
     End Sub
 
 
 #End Region
 #End Region

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

@@ -858,7 +858,6 @@ NextStack:
             "确定", If(IsHandAnalyze OrElse DirectFile Is Nothing, "", "查看日志"), If(IsHandAnalyze, "", "导出错误报告"),
             "确定", If(IsHandAnalyze OrElse DirectFile Is Nothing, "", "查看日志"), If(IsHandAnalyze, "", "导出错误报告"),
             Button2Action:=If(IsHandAnalyze OrElse DirectFile Is Nothing, Nothing,
             Button2Action:=If(IsHandAnalyze OrElse DirectFile Is Nothing, Nothing,
             Sub()
             Sub()
-            Try
                 '弹窗选择:查看日志
                 '弹窗选择:查看日志
                 If File.Exists(DirectFile.Value.Key) Then
                 If File.Exists(DirectFile.Value.Key) Then
                     ShellOnly(DirectFile.Value.Key)
                     ShellOnly(DirectFile.Value.Key)
@@ -867,9 +866,6 @@ NextStack:
                     WriteFile(FilePath, Join(DirectFile.Value.Value, vbCrLf))
                     WriteFile(FilePath, Join(DirectFile.Value.Value, vbCrLf))
                     ShellOnly(FilePath)
                     ShellOnly(FilePath)
                 End If
                 End If
-            Catch ex As Exception
-                Log(ex,"尝试打开文件失败",LogLevel.Hint)
-            End Try
             End Sub))
             End Sub))
             Case 3
             Case 3
                 '弹窗选择:导出错误报告
                 '弹窗选择:导出错误报告

+ 73 - 33
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb

@@ -197,10 +197,17 @@
     Public DlClientListMojangLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Mojang", AddressOf DlClientListMojangMain)
     Public DlClientListMojangLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Mojang", AddressOf DlClientListMojangMain)
     Private IsNewClientVersionHinted As Boolean = False
     Private IsNewClientVersionHinted As Boolean = False
     Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult))
     Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult))
+        Dim StartTime As Long = GetTimeTick()
         Dim Json As JObject = NetGetCodeByRequestRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json", IsJson:=True)
         Dim Json As JObject = NetGetCodeByRequestRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json", IsJson:=True)
         Try
         Try
             Dim Versions As JArray = Json("versions")
             Dim Versions As JArray = Json("versions")
             If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
             If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
+            '确定官方源是否可用
+            If Not DlPreferMojang Then
+                Dim DeltaTime = GetTimeTick() - StartTime
+                DlPreferMojang = DeltaTime < 4000
+                Log($"[Download] Mojang 官方源加载耗时:{DeltaTime}ms,{If(DlPreferMojang, "可优先使用官方源", "不优先使用官方源")}")
+            End If
             '添加 PCL 特供项
             '添加 PCL 特供项
             If File.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(ReadFile(PathTemp & "Cache\download.json")))
             If File.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(ReadFile(PathTemp & "Cache\download.json")))
             '返回
             '返回
@@ -1171,18 +1178,54 @@
 
 
 #Region "DlSource | 镜像下载源"
 #Region "DlSource | 镜像下载源"
 
 
-    Public Function DlSourceResourceGet(Original As String) As String()
+    Private DlPreferMojang As Boolean = False
+    ''' <summary>
+    ''' 下载文件(而非获取版本列表)的时候,是否优先使用官方源。
+    ''' </summary>
+    Public ReadOnly Property DlSourcePreferMojang As Boolean
+        Get
+            Return Setup.Get("ToolDownloadSource") = 2 OrElse (Setup.Get("ToolDownloadSource") = 1 AndAlso DlPreferMojang)
+        End Get
+    End Property
+    ''' <summary>
+    ''' 下载文件(而非获取版本列表)的时候,根据是否优先使用官方源决定使用 Url 的顺序。
+    ''' </summary>
+    Public Function DlSourceOrder(OfficialUrls As IEnumerable(Of String), MirrorUrls As IEnumerable(Of String)) As IEnumerable(Of String)
+        Return If(DlSourcePreferMojang, OfficialUrls.Union(MirrorUrls), MirrorUrls.Union(OfficialUrls))
+    End Function
+    ''' <summary>
+    ''' 获取版本列表(而非下载文件)的时候,是否优先使用官方源。
+    ''' </summary>
+    Public ReadOnly Property DlVersionListPreferMojang As Boolean
+        Get
+            Return Setup.Get("ToolDownloadVersion") = 2 OrElse (Setup.Get("ToolDownloadVersion") = 1 AndAlso DlPreferMojang)
+        End Get
+    End Property
+    ''' <summary>
+    ''' 获取版本列表(而非下载文件)的时候,根据是否优先使用官方源决定使用 Url 的顺序。
+    ''' </summary>
+    Public Function DlVersionListOrder(OfficialUrls As IEnumerable(Of String), MirrorUrls As IEnumerable(Of String)) As IEnumerable(Of String)
+        Return If(DlVersionListPreferMojang, OfficialUrls.Union(MirrorUrls), MirrorUrls.Union(OfficialUrls))
+    End Function
+
+
+    ''' <summary>
+    ''' 下载 Assets 文件。
+    ''' </summary>
+    Public Function DlSourceAssetsGet(Original As String) As IEnumerable(Of String)
         Original = Original.Replace("http://resources.download.minecraft.net", "https://resources.download.minecraft.net")
         Original = Original.Replace("http://resources.download.minecraft.net", "https://resources.download.minecraft.net")
-        Return {
-            Original.
+        Return DlSourceOrder(
+            {Original},
+            {Original.
                 Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/assets").
                 Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/assets").
                 Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/assets").
                 Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/assets").
-                Replace("https://resources.download.minecraft.net", "https://bmclapi2.bangbang93.com/assets"),
-            Original
-        }
+                Replace("https://resources.download.minecraft.net", "https://bmclapi2.bangbang93.com/assets")
+            })
     End Function
     End Function
-
-    Public Function DlSourceLibraryGet(Original As String) As String()
+    ''' <summary>
+    ''' 下载 Libraries 文件。
+    ''' </summary>
+    Public Function DlSourceLibraryGet(Original As String) As IEnumerable(Of String)
         If {"minecraftforge", "fabricmc", "neoforged"}.Any(Function(k) Original.Contains(k)) Then '不添加原版源
         If {"minecraftforge", "fabricmc", "neoforged"}.Any(Function(k) Original.Contains(k)) Then '不添加原版源
             Return {
             Return {
                 Original.
                 Original.
@@ -1195,44 +1238,41 @@
                     Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
                     Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
             }
             }
         Else
         Else
-            Return {
-                Original.
+            Return DlSourceOrder(
+                {Original},
+                {Original.
                     Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/maven").
                     Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/maven").
                     Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/maven").
                     Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/maven").
                     Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/maven"),
                     Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/maven"),
-                Original.
+                 Original.
                     Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/libraries").
                     Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/libraries").
                     Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/libraries").
                     Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/libraries").
-                    Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries"),
-                Original
-            }
+                    Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
+                })
         End If
         End If
     End Function
     End Function
-
-    Public Function DlSourceModGet(Original As String) As String
-        Return Original
-        'Return Original.
-        '    Replace("api.modrinth.com", "mod.mcimirror.top/modrinth").
-        '    Replace("staging-api.modrinth.com", "mod.mcimirror.top/modrinth").
-        '    Replace("cdn.modrinth.com", "mod.mcimirror.top").
-        '    Replace("api.curseforge.com", "mod.mcimirror.top/curseforge").
-        '    Replace("edge.forgecdn.net", "mod.mcimirror.top").
-        '    Replace("mediafilez.forgecdn.net", "mod.mcimirror.top").
-        '    Replace("media.forgecdn.net", "mod.mcimirror.top")
-    End Function
-
-    Public Function DlSourceLauncherOrMetaGet(Original As String) As String()
+    ''' <summary>
+    ''' 下载 Launcher 或 Meta 文件。
+    ''' 不应使用它来获取版本列表(因为它只使用文件下载源设置来决定源顺序)。
+    ''' </summary>
+    Public Function DlSourceLauncherOrMetaGet(Original As String) As IEnumerable(Of String)
         If Original Is Nothing Then Throw New Exception("无对应的 json 下载地址")
         If Original Is Nothing Then Throw New Exception("无对应的 json 下载地址")
-        Return {
-            Original.
+        Return DlSourceOrder(
+            {Original},
+            {Original.
                 Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com").
                 Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com").
                 Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com").
                 Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com").
                 Replace("https://launcher.mojang.com", "https://bmclapi2.bangbang93.com").
                 Replace("https://launcher.mojang.com", "https://bmclapi2.bangbang93.com").
-                Replace("https://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com"),
-            Original
-        }
+                Replace("https://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com")
+            })
+    End Function
+
+    'Mod 下载源
+    Public Function DlSourceModGet(Original As String) As String
+        Return Original
     End Function
     End Function
 
 
+    'Loader 自动切换
     Private Sub DlSourceLoader(Of InputType, OutputType)(MainLoader As LoaderTask(Of InputType, OutputType),
     Private Sub DlSourceLoader(Of InputType, OutputType)(MainLoader As LoaderTask(Of InputType, OutputType),
                                                          LoaderList As List(Of KeyValuePair(Of LoaderTask(Of InputType, OutputType), Integer)),
                                                          LoaderList As List(Of KeyValuePair(Of LoaderTask(Of InputType, OutputType), Integer)),
                                                          Optional IsForceRestart As Boolean = False)
                                                          Optional IsForceRestart As Boolean = False)

+ 10 - 12
Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb

@@ -372,8 +372,7 @@ ExitUserJavaCheck:
             For Each Java In AllowedJavaList
             For Each Java In AllowedJavaList
                 '如果在官启文件夹启动,会将官启自带 Java 错误视作 MC 文件夹指定 Java,导致了 #2054 的第二例
                 '如果在官启文件夹启动,会将官启自带 Java 错误视作 MC 文件夹指定 Java,导致了 #2054 的第二例
                 If Java.PathFolder.Contains(".minecraft\cache\java") Then Continue For
                 If Java.PathFolder.Contains(".minecraft\cache\java") Then Continue For
-                '#5780
-                If Java.PathFolder.Contains("PCL\MyDownload") Then Continue For
+                If Java.PathFolder.Contains("PCL\MyDownload\") Then Continue For '#5780
                 If TargetJavaList.Contains(Java) Then
                 If TargetJavaList.Contains(Java) Then
                     '直接使用指定的 Java
                     '直接使用指定的 Java
                     AllowedJavaList = New List(Of JavaEntry) From {Java}
                     AllowedJavaList = New List(Of JavaEntry) From {Java}
@@ -558,9 +557,8 @@ NoUserJava:
             Dim JavaWithoutInherit As New Dictionary(Of String, Boolean)
             Dim JavaWithoutInherit As New Dictionary(Of String, Boolean)
             For Each Pair In JavaPreList
             For Each Pair In JavaPreList
                 If Pair.Key.Contains("java8path_target_") OrElse Pair.Key.Contains("javapath_target_") OrElse Pair.Key.Contains("javatmp") OrElse Pair.Key.ContainsF("system32") Then
                 If Pair.Key.Contains("java8path_target_") OrElse Pair.Key.Contains("javapath_target_") OrElse Pair.Key.Contains("javatmp") OrElse Pair.Key.ContainsF("system32") Then
-                    Log("[Java] 位于 " & Pair.Key & " 的 Java 包含特殊引用")
+                    Log("[Java] 位于 " & Pair.Key & " 的 Java 位于特殊路径,不应优先使用")
                 Else
                 Else
-                    Log("[Java] 位于 " & Pair.Key & " 的 Java 不含特殊引用")
                     JavaWithoutInherit.Add(Pair.Key, Pair.Value)
                     JavaWithoutInherit.Add(Pair.Key, Pair.Value)
                 End If
                 End If
             Next
             Next
@@ -714,8 +712,8 @@ Wait:
             Return False
             Return False
         Else
         Else
             Return MyMsgBox($"PCL 未找到 {VersionDescription},是否需要 PCL 自动下载?" & vbCrLf &
             Return MyMsgBox($"PCL 未找到 {VersionDescription},是否需要 PCL 自动下载?" & vbCrLf &
-                            $"如果你已经安装了 {VersionDescription},请在 设置 → 启动选项 → 游戏 Java 中手动导入。",
-                            "未找到 Java", "自动下载", "取消") = 1
+                            $"如果你已经安装了 {VersionDescription},可以在 设置 → 启动选项 → 游戏 Java 中手动导入。",
+                            "自动下载 Java?", "自动下载", "取消") = 1
         End If
         End If
     End Function
     End Function
 
 
@@ -744,10 +742,10 @@ Wait:
     Private LastJavaBaseDir As String = Nothing '用于在下载中断或失败时删除未完成下载的 Java 文件夹,防止残留只下了一半但 -version 能跑的 Java
     Private LastJavaBaseDir As String = Nothing '用于在下载中断或失败时删除未完成下载的 Java 文件夹,防止残留只下了一半但 -version 能跑的 Java
     Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile)))
     Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile)))
         Log("[Java] 开始获取 Java 下载信息")
         Log("[Java] 开始获取 Java 下载信息")
-        Dim IndexFileStr As String = NetGetCodeByLoader(
-            {"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json",
-             "https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
-        IsJson:=True)
+        Dim IndexFileStr As String = NetGetCodeByLoader(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)
         '获取下载地址
         '获取下载地址
         Dim MainEntry As JObject = CType(GetJson(IndexFileStr), JObject)($"windows-x{If(Is32BitSystem, "86", "64")}")
         Dim MainEntry As JObject = CType(GetJson(IndexFileStr), JObject)($"windows-x{If(Is32BitSystem, "86", "64")}")
         Dim Entries = MainEntry.Children.Reverse. '选择最靠后的一项(最新)
         Dim Entries = MainEntry.Children.Reverse. '选择最靠后的一项(最新)
@@ -756,7 +754,7 @@ Wait:
         Dim Address As String = TargetEntry.Value("manifest")("url")
         Dim Address As String = TargetEntry.Value("manifest")("url")
         Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}")
         Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}")
         '获取文件列表
         '获取文件列表
-        Dim ListFileStr As String = NetGetCodeByLoader({Address.Replace("piston-meta.mojang.com", "bmclapi2.bangbang93.com"), Address}, IsJson:=True)
+        Dim ListFileStr As String = NetGetCodeByLoader(DlSourceOrder({Address}, {Address.Replace("piston-meta.mojang.com", "bmclapi2.bangbang93.com")}), IsJson:=True)
         LastJavaBaseDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\runtime\" & TargetEntry.Key & "\"
         LastJavaBaseDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\runtime\" & TargetEntry.Key & "\"
         Dim Results As New List(Of NetFile)
         Dim Results As New List(Of NetFile)
         For Each File As JProperty In CType(GetJson(ListFileStr), JObject)("files")
         For Each File As JProperty In CType(GetJson(ListFileStr), JObject)("files")
@@ -769,7 +767,7 @@ Wait:
             End If
             End If
             If Checker.Check(LastJavaBaseDir & File.Name) Is Nothing Then Continue For '跳过已存在的文件
             If Checker.Check(LastJavaBaseDir & File.Name) Is Nothing Then Continue For '跳过已存在的文件
             Dim Url As String = Info("url")
             Dim Url As String = Info("url")
-            Results.Add(New NetFile({Url.Replace("piston-data.mojang.com", "bmclapi2.bangbang93.com"), Url}, LastJavaBaseDir & File.Name, Checker))
+            Results.Add(New NetFile(DlSourceOrder({Url}, {Url.Replace("piston-data.mojang.com", "bmclapi2.bangbang93.com")}), LastJavaBaseDir & File.Name, Checker))
         Next
         Next
         Loader.Output = Results
         Loader.Output = Results
         Log($"[Java] 需要下载 {Results.Count} 个文件,目标文件夹:{LastJavaBaseDir}")
         Log($"[Java] 需要下载 {Results.Count} 个文件,目标文件夹:{LastJavaBaseDir}")

+ 38 - 33
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb

@@ -1134,23 +1134,22 @@ Retry:
         Dim MinVer As New Version(0, 0, 0, 0), MaxVer As New Version(999, 999, 999, 999)
         Dim MinVer As New Version(0, 0, 0, 0), MaxVer As New Version(999, 999, 999, 999)
 
 
         'MC 大版本检测
         'MC 大版本检测
-        If (McVersionCurrent.ReleaseTime >= New Date(2024, 4, 2) AndAlso McVersionCurrent.Version.McCodeMain = 99) OrElse
-            (McVersionCurrent.Version.McCodeMain > 20 AndAlso McVersionCurrent.Version.McCodeMain <> 99) OrElse
-            (McVersionCurrent.Version.McCodeMain = 20 AndAlso McVersionCurrent.Version.McCodeSub >= 5) Then
+        If (Not McVersionCurrent.Version.IsStandardVersion AndAlso McVersionCurrent.ReleaseTime >= New Date(2024, 4, 2)) OrElse
+           (McVersionCurrent.Version.IsStandardVersion AndAlso McVersionCurrent.Version.McVersion >= New Version(1, 20, 5)) Then
             '1.20.5+(24w14a+):至少 Java 21
             '1.20.5+(24w14a+):至少 Java 21
             MinVer = New Version(1, 21, 0, 0)
             MinVer = New Version(1, 21, 0, 0)
-        ElseIf (McVersionCurrent.ReleaseTime >= New Date(2021, 11, 16) AndAlso McVersionCurrent.Version.McCodeMain = 99) OrElse
-            (McVersionCurrent.Version.McCodeMain >= 18 AndAlso McVersionCurrent.Version.McCodeMain <> 99) Then
+        ElseIf (Not McVersionCurrent.Version.IsStandardVersion AndAlso McVersionCurrent.ReleaseTime >= New Date(2021, 11, 16)) OrElse
+            (McVersionCurrent.Version.IsStandardVersion AndAlso McVersionCurrent.Version.McVersion >= New Version(1, 18)) Then
             '1.18 pre2+:至少 Java 17
             '1.18 pre2+:至少 Java 17
             MinVer = New Version(1, 17, 0, 0)
             MinVer = New Version(1, 17, 0, 0)
-        ElseIf (McVersionCurrent.ReleaseTime >= New Date(2021, 5, 11) AndAlso McVersionCurrent.Version.McCodeMain = 99) OrElse
-           (McVersionCurrent.Version.McCodeMain >= 17 AndAlso McVersionCurrent.Version.McCodeMain <> 99) Then
+        ElseIf (Not McVersionCurrent.Version.IsStandardVersion AndAlso McVersionCurrent.ReleaseTime >= New Date(2021, 5, 11)) OrElse
+           (McVersionCurrent.Version.IsStandardVersion AndAlso McVersionCurrent.Version.McVersion >= New Version(1, 17)) Then
             '1.17+ (21w19a+):至少 Java 16
             '1.17+ (21w19a+):至少 Java 16
             MinVer = New Version(1, 16, 0, 0)
             MinVer = New Version(1, 16, 0, 0)
         ElseIf McVersionCurrent.ReleaseTime.Year >= 2017 Then 'Minecraft 1.12 与 1.11 的分界线正好是 2017 年,太棒了
         ElseIf McVersionCurrent.ReleaseTime.Year >= 2017 Then 'Minecraft 1.12 与 1.11 的分界线正好是 2017 年,太棒了
             '1.12+:至少 Java 8
             '1.12+:至少 Java 8
             MinVer = New Version(1, 8, 0, 0)
             MinVer = New Version(1, 8, 0, 0)
-        ElseIf McVersionCurrent.ReleaseTime <= New Date(2013, 5, 1) AndAlso McVersionCurrent.ReleaseTime.Year >= 2001 Then '避免某些版本的 1960 癌
+        ElseIf McVersionCurrent.ReleaseTime <= New Date(2013, 5, 1) AndAlso McVersionCurrent.ReleaseTime.Year >= 2001 Then '避免某些版本写个 1960 年
             '1.5.2-:最高 Java 12
             '1.5.2-:最高 Java 12
             MaxVer = New Version(1, 12, 999, 999)
             MaxVer = New Version(1, 12, 999, 999)
         End If
         End If
@@ -1161,11 +1160,11 @@ Retry:
         End If
         End If
 
 
         'OptiFine 检测
         'OptiFine 检测
-        If McVersionCurrent.Version.HasOptiFine Then
-            If McVersionCurrent.Version.McCodeMain <= 7 AndAlso McVersionCurrent.Version.McCodeMain > 0 Then
+        If McVersionCurrent.Version.HasOptiFine AndAlso McVersionCurrent.Version.IsStandardVersion Then '不管非标准版本
+            If McVersionCurrent.Version.McVersion < New Version(1, 7) Then
                 '<1.7:至多 Java 8
                 '<1.7:至多 Java 8
                 MaxVer = New Version(1, 8, 999, 999)
                 MaxVer = New Version(1, 8, 999, 999)
-            ElseIf McVersionCurrent.Version.McCodeMain >= 8 AndAlso McVersionCurrent.Version.McCodeMain <= 11 Then
+            ElseIf McVersionCurrent.Version.McVersion >= New Version(1, 8) AndAlso McVersionCurrent.Version.McVersion < New Version(1, 12) Then
                 '1.8 - 1.11:必须恰好 Java 8
                 '1.8 - 1.11:必须恰好 Java 8
                 MinVer = New Version(1, 8, 0, 0) : MaxVer = New Version(1, 8, 999, 999)
                 MinVer = New Version(1, 8, 0, 0) : MaxVer = New Version(1, 8, 999, 999)
             ElseIf McVersionCurrent.Version.McCodeMain = 12 Then
             ElseIf McVersionCurrent.Version.McCodeMain = 12 Then
@@ -1176,14 +1175,14 @@ Retry:
 
 
         'Forge 检测
         'Forge 检测
         If McVersionCurrent.Version.HasForge Then
         If McVersionCurrent.Version.HasForge Then
-            If McVersionCurrent.Version.McName = "1.7.2" Then
-                '1.7.2:必须 Java 7
+            If McVersionCurrent.Version.McVersion >= New Version(1, 6, 1) AndAlso McVersionCurrent.Version.McVersion <= New Version(1, 7, 2) Then
+                '1.6.1 - 1.7.2:必须 Java 7
                 MinVer = If(New Version(1, 7, 0, 0) > MinVer, New Version(1, 7, 0, 0), MinVer)
                 MinVer = If(New Version(1, 7, 0, 0) > MinVer, New Version(1, 7, 0, 0), MinVer)
                 MaxVer = If(New Version(1, 7, 999, 999) < MaxVer, New Version(1, 7, 999, 999), MaxVer)
                 MaxVer = If(New Version(1, 7, 999, 999) < MaxVer, New Version(1, 7, 999, 999), MaxVer)
-            ElseIf McVersionCurrent.Version.McCodeMain <= 12 AndAlso McVersionCurrent.Version.McCodeMain > 0 Then
+            ElseIf McVersionCurrent.Version.McCodeMain <= 12 OrElse Not McVersionCurrent.Version.IsStandardVersion Then '非标准版本
                 '<=1.12:Java 8
                 '<=1.12:Java 8
                 MaxVer = New Version(1, 8, 999, 999)
                 MaxVer = New Version(1, 8, 999, 999)
-            ElseIf McVersionCurrent.Version.McCodeMain <= 14 AndAlso McVersionCurrent.Version.McCodeMain >= 13 Then
+            ElseIf McVersionCurrent.Version.McCodeMain <= 14 Then
                 '1.13 - 1.14:Java 8 - 10
                 '1.13 - 1.14:Java 8 - 10
                 MinVer = If(New Version(1, 8, 0, 0) > MinVer, New Version(1, 8, 0, 0), MinVer)
                 MinVer = If(New Version(1, 8, 0, 0) > MinVer, New Version(1, 8, 0, 0), MinVer)
                 MaxVer = If(New Version(1, 10, 999, 999) < MaxVer, New Version(1, 10, 999, 999), MaxVer)
                 MaxVer = If(New Version(1, 10, 999, 999) < MaxVer, New Version(1, 10, 999, 999), MaxVer)
@@ -1201,11 +1200,11 @@ Retry:
         End If
         End If
 
 
         'Fabric 检测
         'Fabric 检测
-        If McVersionCurrent.Version.HasFabric Then
-            If McVersionCurrent.Version.McCodeMain >= 15 AndAlso McVersionCurrent.Version.McCodeMain <= 16 AndAlso McVersionCurrent.Version.McCodeMain <> -1 Then
+        If McVersionCurrent.Version.HasFabric AndAlso McVersionCurrent.Version.IsStandardVersion Then '不管非标准版本
+            If McVersionCurrent.Version.McCodeMain >= 15 AndAlso McVersionCurrent.Version.McCodeMain <= 16 Then
                 '1.15 - 1.16:Java 8+
                 '1.15 - 1.16:Java 8+
                 MinVer = If(New Version(1, 8, 0, 0) > MinVer, New Version(1, 8, 0, 0), MinVer)
                 MinVer = If(New Version(1, 8, 0, 0) > MinVer, New Version(1, 8, 0, 0), MinVer)
-            ElseIf McVersionCurrent.Version.McCodeMain >= 18 AndAlso McVersionCurrent.Version.McCodeMain < 99 Then
+            ElseIf McVersionCurrent.Version.McCodeMain >= 18 Then
                 '1.18+:Java 17+
                 '1.18+:Java 17+
                 MinVer = If(New Version(1, 17, 0, 0) > MinVer, New Version(1, 17, 0, 0), MinVer)
                 MinVer = If(New Version(1, 17, 0, 0) > MinVer, New Version(1, 17, 0, 0), MinVer)
             End If
             End If
@@ -1232,18 +1231,22 @@ Retry:
             If Task.IsAborted Then Exit Sub '中断加载会导致 JavaSelect 异常地返回空值,误判找不到 Java
             If Task.IsAborted Then Exit Sub '中断加载会导致 JavaSelect 异常地返回空值,误判找不到 Java
             McLaunchLog("无合适的 Java,需要确认是否自动下载")
             McLaunchLog("无合适的 Java,需要确认是否自动下载")
             Dim JavaCode As String
             Dim JavaCode As String
-            If MinVer >= New Version(1, 22, 0, 0) Then '潜在的向后兼容
+            If MinVer >= New Version(1, 22) Then '潜在的向后兼容
                 JavaCode = MinVer.Minor
                 JavaCode = MinVer.Minor
                 If Not JavaDownloadConfirm("Java " & JavaCode) Then Throw New Exception("$$")
                 If Not JavaDownloadConfirm("Java " & JavaCode) Then Throw New Exception("$$")
-            ElseIf MinVer >= New Version(1, 21, 0, 0) Then
+            ElseIf MinVer >= New Version(1, 21) Then
                 JavaCode = 21
                 JavaCode = 21
                 If Not JavaDownloadConfirm("Java 21") Then Throw New Exception("$$")
                 If Not JavaDownloadConfirm("Java 21") Then Throw New Exception("$$")
-            ElseIf MinVer >= New Version(1, 9, 0, 0) Then
+            ElseIf MinVer >= New Version(1, 9) Then
                 JavaCode = 17
                 JavaCode = 17
                 If Not JavaDownloadConfirm("Java 17") Then Throw New Exception("$$")
                 If Not JavaDownloadConfirm("Java 17") Then Throw New Exception("$$")
-            ElseIf MaxVer < New Version(1, 8, 0, 0) Then
+            ElseIf MaxVer < New Version(1, 8) Then
                 JavaCode = 7
                 JavaCode = 7
-                If Not JavaDownloadConfirm("Java 7", True) Then Throw New Exception("$$")
+                If McVersionCurrent.Version.HasForge Then
+                    MyMsgBox("你需要先安装 LegacyJavaFixer Mod,或自行安装 Java 7,然后才能启动该版本。", "未找到 Java")
+                Else
+                    If Not JavaDownloadConfirm("Java 7", True) Then Throw New Exception("$$")
+                End If
             ElseIf MinVer > New Version(1, 8, 0, 140) AndAlso MaxVer < New Version(1, 8, 0, 321) Then
             ElseIf MinVer > New Version(1, 8, 0, 140) AndAlso MaxVer < New Version(1, 8, 0, 321) Then
                 JavaCode = "8u141"
                 JavaCode = "8u141"
                 If Not JavaDownloadConfirm("Java 8.0.141 ~ 8.0.320", True) Then Throw New Exception("$$")
                 If Not JavaDownloadConfirm("Java 8.0.141 ~ 8.0.320", True) Then Throw New Exception("$$")
@@ -1350,12 +1353,14 @@ Retry:
             Arguments += " " & McLaunchArgumentsGameNew(McVersionCurrent)
             Arguments += " " & McLaunchArgumentsGameNew(McVersionCurrent)
             McLaunchLog("新版 Game 参数获取成功")
             McLaunchLog("新版 Game 参数获取成功")
         End If
         End If
-        '编码参数(#5818、#5892)
+        '编码参数(#4700、#5892、#5909)
         If McLaunchJavaSelected.VersionCode > 8 Then
         If McLaunchJavaSelected.VersionCode > 8 Then
-            If Not Arguments.Contains("-Dfile.encoding=") Then Arguments += " -Dfile.encoding=UTF-8"
             If Not Arguments.Contains("-Dstdout.encoding=") Then Arguments += " -Dstdout.encoding=UTF-8"
             If Not Arguments.Contains("-Dstdout.encoding=") Then Arguments += " -Dstdout.encoding=UTF-8"
             If Not Arguments.Contains("-Dstderr.encoding=") Then Arguments += " -Dstderr.encoding=UTF-8"
             If Not Arguments.Contains("-Dstderr.encoding=") Then Arguments += " -Dstderr.encoding=UTF-8"
         End If
         End If
+        If McLaunchJavaSelected.VersionCode >= 18 Then
+            If Not Arguments.Contains("-Dfile.encoding=") Then Arguments += " -Dfile.encoding=COMPAT"
+        End If
         '替换参数
         '替换参数
         Dim ReplaceArguments = McLaunchArgumentsReplace(McVersionCurrent, Loader)
         Dim ReplaceArguments = McLaunchArgumentsReplace(McVersionCurrent, Loader)
         If String.IsNullOrWhiteSpace(ReplaceArguments("${version_type}")) Then
         If String.IsNullOrWhiteSpace(ReplaceArguments("${version_type}")) Then
@@ -1675,16 +1680,16 @@ NextVersion:
         '窗口尺寸参数
         '窗口尺寸参数
         Dim GameSize As Size
         Dim GameSize As Size
         Select Case Setup.Get("LaunchArgumentWindowType")
         Select Case Setup.Get("LaunchArgumentWindowType")
-            Case 2
+            Case 2 '与启动器尺寸一致
                 Dim Result As Size
                 Dim Result As Size
                 RunInUiWait(Sub() Result = New Size(GetPixelSize(FrmMain.PanForm.ActualWidth), GetPixelSize(FrmMain.PanForm.ActualHeight)))
                 RunInUiWait(Sub() Result = New Size(GetPixelSize(FrmMain.PanForm.ActualWidth), GetPixelSize(FrmMain.PanForm.ActualHeight)))
                 GameSize = Result
                 GameSize = Result
-            Case 3
-                GameSize = New Size(Math.Max(100, Setup.Get("LaunchArgumentWindowWidth") - 2), Math.Max(100, Setup.Get("LaunchArgumentWindowHeight") - 2))
+                GameSize.Height -= 29.5 * DPI / 96 '标题栏高度
+            Case 3 '自定义
+                GameSize = New Size(Math.Max(100, Setup.Get("LaunchArgumentWindowWidth")), Math.Max(100, Setup.Get("LaunchArgumentWindowHeight")))
             Case Else
             Case Else
-                GameSize = New Size(875 - 2, 540 - 2)
+                GameSize = New Size(875, 540)
         End Select
         End Select
-        GameSize.Height -= 29.5 * DPI / 96 '标题栏高度
         If McVersionCurrent.Version.McCodeMain <= 12 AndAlso
         If McVersionCurrent.Version.McCodeMain <= 12 AndAlso
             McLaunchJavaSelected.VersionCode <= 8 AndAlso McLaunchJavaSelected.Version.Revision >= 200 AndAlso McLaunchJavaSelected.Version.Revision <= 321 AndAlso
             McLaunchJavaSelected.VersionCode <= 8 AndAlso McLaunchJavaSelected.Version.Revision >= 200 AndAlso McLaunchJavaSelected.Version.Revision <= 321 AndAlso
             Not McVersionCurrent.Version.HasOptiFine AndAlso Not McVersionCurrent.Version.HasForge Then
             Not McVersionCurrent.Version.HasOptiFine AndAlso Not McVersionCurrent.Version.HasForge Then
@@ -1713,7 +1718,7 @@ NextVersion:
                 CpStrings.Add(Library.LocalPath)
                 CpStrings.Add(Library.LocalPath)
             End If
             End If
         Next
         Next
-        If OptiFineCp IsNot Nothing Then CpStrings.Insert(CpStrings.Count - 2, OptiFineCp)
+        If OptiFineCp IsNot Nothing Then CpStrings.Insert(CpStrings.Count - 2, OptiFineCp) 'OptiFine 的总是需要放到倒数第二位
         GameArguments.Add("${classpath}", Join(CpStrings.Select(Function(c) ShortenPath(c)), ";"))
         GameArguments.Add("${classpath}", Join(CpStrings.Select(Function(c) ShortenPath(c)), ";"))
 
 
         Return GameArguments
         Return GameArguments
@@ -2095,7 +2100,7 @@ IgnoreCustomSkin:
         '输出 bat
         '输出 bat
         Try
         Try
             Dim CmdString As String =
             Dim CmdString As String =
-                $"{If(McLaunchJavaSelected.VersionCode > 8, "chcp 65001>nul" & vbCrLf, "")}" &
+                $"{If(McLaunchJavaSelected.VersionCode > 8 AndAlso McLaunchJavaSelected.VersionCode < 18, "chcp 65001>nul" & vbCrLf, "")}" &
                 "@echo off" & vbCrLf &
                 "@echo off" & vbCrLf &
                 $"title 启动 - {McVersionCurrent.Name}" & vbCrLf &
                 $"title 启动 - {McVersionCurrent.Name}" & vbCrLf &
                 "echo 游戏正在启动,请稍候。" & vbCrLf &
                 "echo 游戏正在启动,请稍候。" & vbCrLf &
@@ -2107,7 +2112,7 @@ IgnoreCustomSkin:
                 "echo 游戏已退出。" & vbCrLf &
                 "echo 游戏已退出。" & vbCrLf &
                 "pause"
                 "pause"
             WriteFile(If(CurrentLaunchOptions.SaveBatch, Path & "PCL\LatestLaunch.bat"), SecretFilter(CmdString, "F"),
             WriteFile(If(CurrentLaunchOptions.SaveBatch, Path & "PCL\LatestLaunch.bat"), SecretFilter(CmdString, "F"),
-                      Encoding:=If(Encoding.Default.Equals(Encoding.UTF8), Encoding.UTF8, Encoding.GetEncoding("GB18030")))
+                      Encoding:=If(McLaunchJavaSelected.VersionCode > 8, Encoding.UTF8, Encoding.Default))
             If CurrentLaunchOptions.SaveBatch IsNot Nothing Then
             If CurrentLaunchOptions.SaveBatch IsNot Nothing Then
                 McLaunchLog("导出启动脚本完成,强制结束启动过程")
                 McLaunchLog("导出启动脚本完成,强制结束启动过程")
                 AbortHint = "导出启动脚本成功!"
                 AbortHint = "导出启动脚本成功!"

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

@@ -207,46 +207,43 @@ Public Module ModMinecraft
         ''' </summary>
         ''' </summary>
         Public ReadOnly Property PathIndie As String
         Public ReadOnly Property PathIndie As String
             Get
             Get
-                InitPathIndie(Modable)
+                If Setup.IsUnset("VersionArgumentIndieV2", Version:=Me) Then
+                    '决定该版本是否应该被隔离
+                    Dim ShouldBeIndie =
+                    Function() As Boolean
+                        '从老的版本独立设置中迁移:-1 未决定,0 使用全局设置,1 手动开启,2 手动关闭
+                        If Not Setup.IsUnset("VersionArgumentIndie", Version:=Me) AndAlso Setup.Get("VersionArgumentIndie", Version:=Me) > 0 Then
+                            Log($"[Minecraft] 版本隔离初始化({Name}):从老的版本独立设置中迁移")
+                            Return Setup.Get("VersionArgumentIndie", Version:=Me) = 1
+                        End If
+                        '若版本文件夹下包含 mods 或 saves 文件夹,则自动开启版本隔离
+                        Dim ModFolder As New DirectoryInfo(Path & "mods\")
+                        Dim SaveFolder As New DirectoryInfo(Path & "saves\")
+                        If (ModFolder.Exists AndAlso ModFolder.EnumerateFiles.Any) OrElse (SaveFolder.Exists AndAlso SaveFolder.EnumerateDirectories.Any) Then
+                            Log($"[Minecraft] 版本隔离初始化({Name}):版本文件夹下存在 mods 或 saves 文件夹,自动开启")
+                            Return True
+                        End If
+                        '根据全局的默认设置决定是否隔离
+                        Log($"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Setup.Get("LaunchArgumentIndieV2")})判断")
+                        Dim IsRelease As Boolean = State = McVersionState.Fool OrElse State = McVersionState.Old OrElse State = McVersionState.Snapshot
+                        Select Case Setup.Get("LaunchArgumentIndieV2")
+                            Case 0 '关闭
+                                Return False
+                            Case 1 '仅隔离可安装 Mod 的版本
+                                Return Modable
+                            Case 2 '仅隔离非正式版
+                                Return IsRelease
+                            Case 3 '隔离非正式版与可安装 Mod 的版本
+                                Return Modable OrElse IsRelease
+                            Case Else '隔离所有版本
+                                Return True
+                        End Select
+                    End Function
+                    Setup.Set("VersionArgumentIndieV2", ShouldBeIndie(), Version:=Me)
+                End If
                 Return If(Setup.Get("VersionArgumentIndieV2", Version:=Me), Path, PathMcFolder)
                 Return If(Setup.Get("VersionArgumentIndieV2", Version:=Me), Path, PathMcFolder)
             End Get
             End Get
         End Property
         End Property
-        ''' <summary>
-        ''' 决定该版本是否应该被隔离。
-        ''' </summary>
-        Public Sub InitPathIndie(Modable As Boolean)
-            If Not Setup.IsUnset("VersionArgumentIndieV2", Version:=Me) Then Return
-            Dim ShouldBeIndie =
-            Function() As Boolean
-                '从老的版本独立设置中迁移:-1 未决定,0 使用全局设置,1 手动开启,2 手动关闭
-                If Not Setup.IsUnset("VersionArgumentIndie", Version:=Me) AndAlso Setup.Get("VersionArgumentIndie", Version:=Me) > 0 Then
-                    Log($"[Minecraft] 版本隔离初始化({Name}):从老的版本独立设置中迁移")
-                    Return Setup.Get("VersionArgumentIndie", Version:=Me) = 1
-                End If
-                '若版本文件夹下包含 mods 或 saves 文件夹,则自动开启版本隔离
-                Dim ModFolder As New DirectoryInfo(Path & "mods\")
-                Dim SaveFolder As New DirectoryInfo(Path & "saves\")
-                If (ModFolder.Exists AndAlso ModFolder.EnumerateFiles.Any) OrElse (SaveFolder.Exists AndAlso SaveFolder.EnumerateFiles.Any) Then
-                    Log($"[Minecraft] 版本隔离初始化({Name}):版本文件夹下存在 mods 或 saves 文件夹,自动开启")
-                    Return True
-                End If
-                '根据全局的默认设置决定是否隔离
-                Log($"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Setup.Get("LaunchArgumentIndieV2")})判断")
-                Select Case Setup.Get("LaunchArgumentIndieV2")
-                    Case 0 '关闭
-                        Return False
-                    Case 1 '仅隔离可安装 Mod 的版本
-                        Return Modable
-                    Case 2 '仅隔离非正式版
-                        Return State = McVersionState.Fool OrElse State = McVersionState.Old OrElse State = McVersionState.Snapshot
-                    Case 3 '隔离非正式版与可安装 Mod 的版本
-                        Return Modable OrElse State = McVersionState.Fool OrElse State = McVersionState.Old OrElse State = McVersionState.Snapshot
-                    Case Else '隔离所有版本
-                        Return True
-                End Select
-            End Function
-            Setup.Set("VersionArgumentIndieV2", ShouldBeIndie(), Version:=Me)
-        End Sub
 
 
         ''' <summary>
         ''' <summary>
         ''' 该版本的版本文件夹名称。
         ''' 该版本的版本文件夹名称。
@@ -318,14 +315,6 @@ Public Module ModMinecraft
                             _Version.McName = "pending"
                             _Version.McName = "pending"
                             GoTo VersionSearchFinish
                             GoTo VersionSearchFinish
                         End If
                         End If
-                        '从 JumpLoader 信息中获取版本号
-                        If HasJumpLoader Then
-                            Try
-                                _Version.McName = JsonObject("jumploader")("jars")("minecraft")(0)("gameVersion")
-                                GoTo VersionSearchFinish
-                            Catch
-                            End Try
-                        End If
                         '从 PCL 下载的版本信息中获取版本号
                         '从 PCL 下载的版本信息中获取版本号
                         If JsonObject("clientVersion") IsNot Nothing Then
                         If JsonObject("clientVersion") IsNot Nothing Then
                             _Version.McName = JsonObject("clientVersion")
                             _Version.McName = JsonObject("clientVersion")
@@ -382,7 +371,6 @@ Public Module ModMinecraft
                             _Version.McName = Regex
                             _Version.McName = Regex
                             GoTo VersionSearchFinish
                             GoTo VersionSearchFinish
                         End If
                         End If
-                        'FUTURE: [Quilt 支持] 从 Quilt 版本中获取版本号
                         '从 jar 项中获取版本号
                         '从 jar 项中获取版本号
                         If JsonObject("jar") IsNot Nothing Then
                         If JsonObject("jar") IsNot Nothing Then
                             _Version.McName = JsonObject("jar").ToString
                             _Version.McName = JsonObject("jar").ToString
@@ -432,7 +420,7 @@ VersionSearchFinish:
                         _Version.McCodeMain = If(SplitResult.Length <= 2, Val(SplitResult), "0")
                         _Version.McCodeMain = If(SplitResult.Length <= 2, Val(SplitResult), "0")
                         SplitResult = If(SplitVersion.Count >= 3, SplitVersion(2), "0")
                         SplitResult = If(SplitVersion.Count >= 3, SplitVersion(2), "0")
                         _Version.McCodeSub = If(SplitResult.Length <= 2, Val(SplitResult), "0")
                         _Version.McCodeSub = If(SplitResult.Length <= 2, Val(SplitResult), "0")
-                    ElseIf _Version.McName.Contains("w") OrElse _Version.McName = "pending" Then
+                    ElseIf (Not IsVersionNameLikeRelease(_Version.McName)) OrElse _Version.McName = "pending" Then
                         _Version.McCodeMain = 99
                         _Version.McCodeMain = 99
                         _Version.McCodeSub = 99
                         _Version.McCodeSub = 99
                     End If
                     End If
@@ -562,25 +550,6 @@ Recheck:
                     Catch ex As Exception
                     Catch ex As Exception
                         Throw New Exception("初始化版本 JSON 时失败(" & If(Name, "null") & ")", ex)
                         Throw New Exception("初始化版本 JSON 时失败(" & If(Name, "null") & ")", ex)
                     End Try
                     End Try
-                    Try
-                        '处理 JumpLoader
-                        If Text.Contains("minecraftforge") AndAlso File.Exists(PathIndie & "config\jumploader.json") Then
-                            For Each ModFile In Directory.EnumerateFiles(PathIndie & "mods")
-                                Dim FileName As String = GetFileNameFromPath(ModFile)
-                                If FileName.EndsWithF(".jar", True) AndAlso FileName.ContainsF("jumploader", True) Then
-                                    Log("[Minecraft] 发现 JumpLoader 分支项:" & FileName)
-                                    HasJumpLoader = True
-                                    Exit For
-                                End If
-                            Next
-                        End If
-                        If HasJumpLoader Then
-                            _JsonObject.Remove("jumploader")
-                            _JsonObject.Add("jumploader", GetJson(ReadFile(PathIndie & "config\jumploader.json")))
-                        End If
-                    Catch ex As Exception
-                        Log(ex, "处理 JumpLoader 失败")
-                    End Try
                 End If
                 End If
                 Return _JsonObject
                 Return _JsonObject
             End Get
             End Get
@@ -601,10 +570,6 @@ Recheck:
         ''' Json 是否为 HMCL 格式。
         ''' Json 是否为 HMCL 格式。
         ''' </summary>
         ''' </summary>
         Public Property IsHmclFormatJson As Boolean = False
         Public Property IsHmclFormatJson As Boolean = False
-        ''' <summary>
-        ''' 是否包含 JumpLoader。
-        ''' </summary>
-        Public Property HasJumpLoader As Boolean = False
 
 
         ''' <summary>
         ''' <summary>
         ''' 版本 jar 中的 version.json 文件对象。
         ''' 版本 jar 中的 version.json 文件对象。
@@ -748,7 +713,6 @@ Recheck:
                             Version.HasLiteLoader = True
                             Version.HasLiteLoader = True
                         End If
                         End If
                         'Fabric、Forge
                         'Fabric、Forge
-                        'FUTURE: [Quilt 支持] 确认这里的玩意儿对不对
                         If RealJson.Contains("net.fabricmc:fabric-loader") OrElse RealJson.Contains("org.quiltmc:quilt-loader") Then
                         If RealJson.Contains("net.fabricmc:fabric-loader") OrElse RealJson.Contains("org.quiltmc:quilt-loader") Then
                             State = McVersionState.Fabric
                             State = McVersionState.Fabric
                             Version.HasFabric = True
                             Version.HasFabric = True
@@ -859,7 +823,6 @@ ExitDataLoad:
                     Info = "发生了未知错误,请向作者反馈此问题"
                     Info = "发生了未知错误,请向作者反馈此问题"
             End Select
             End Select
             If Not State = McVersionState.Error Then
             If Not State = McVersionState.Error Then
-                If HasJumpLoader Then Info += ", JumpLoader"
                 If Setup.Get("VersionServerLogin", Version:=Me) = 3 Then Info += ", 统一通行证验证"
                 If Setup.Get("VersionServerLogin", Version:=Me) = 3 Then Info += ", 统一通行证验证"
                 If Setup.Get("VersionServerLogin", Version:=Me) = 4 Then Info += ", Authlib 验证"
                 If Setup.Get("VersionServerLogin", Version:=Me) = 4 Then Info += ", Authlib 验证"
             End If
             End If
@@ -919,6 +882,24 @@ ExitDataLoad:
         ''' 原版次版本号,如 2(For 1.12.2),快照则固定为 99。不可用则为 -1。
         ''' 原版次版本号,如 2(For 1.12.2),快照则固定为 99。不可用则为 -1。
         ''' </summary>
         ''' </summary>
         Public McCodeSub As Integer = -1
         Public McCodeSub As Integer = -1
+        ''' <summary>
+        ''' 是否为非快照版,且读取到了一个有效的原版版本号。
+        ''' </summary>
+        Public ReadOnly Property IsStandardVersion As Boolean
+            Get
+                Return McCodeMain > -1 AndAlso McCodeMain < 99 AndAlso McCodeSub > -1 AndAlso McCodeSub < 99
+            End Get
+        End Property
+        ''' <summary>
+        ''' 标准的原版版本号。
+        ''' 若为快照版或没有有效版本号,则返回 0。
+        ''' </summary>
+        Public ReadOnly Property McVersion As Version
+            Get
+                If Not IsStandardVersion Then Return New Version(0, 0, 0)
+                Return New Version(1, McCodeMain, McCodeSub)
+            End Get
+        End Property
 
 
         'OptiFine
         'OptiFine
 
 
@@ -1728,10 +1709,6 @@ OnLoaded:
         ''' 原 Json 中的 Name 项。
         ''' 原 Json 中的 Name 项。
         ''' </summary>
         ''' </summary>
         Public OriginalName As String
         Public OriginalName As String
-        ''' <summary>
-        ''' 是否为 JumpLoader 项。
-        ''' </summary>
-        Public IsJumpLoader As Boolean = False
 
 
         Public Overrides Function ToString() As String
         Public Overrides Function ToString() As String
             Return If(IsNatives, "[Native] ", "") & GetString(Size) & " | " & LocalPath
             Return If(IsNatives, "[Native] ", "") & GetString(Size) & " | " & LocalPath
@@ -1794,65 +1771,58 @@ OnLoaded:
 
 
         '获取当前支持库列表
         '获取当前支持库列表
         Log("[Minecraft] 获取支持库列表:" & Version.Name)
         Log("[Minecraft] 获取支持库列表:" & Version.Name)
-        McLibListGet = McLibListGetWithJson(Version.JsonObject, JumpLoaderFolder:=Version.PathIndie & ".jumploader\")
+        McLibListGet = McLibListGetWithJson(Version.JsonObject)
+        If Not IncludeVersionJar Then Return McLibListGet
 
 
         '需要添加原版 Jar
         '需要添加原版 Jar
-        If IncludeVersionJar Then
-            Dim RealVersion As McVersion
-            Dim RequiredJar As String = Version.JsonObject("jar")?.ToString
-            If Version.IsHmclFormatJson OrElse RequiredJar Is Nothing Then
-                'HMCL 项直接使用自身的 Jar
-                '根据 Inherit 获取最深层版本
-                Dim OriginalVersion As McVersion = Version
-                '1.17+ 的 Forge 不寻找 Inherit
-                If Not ((Version.Version.HasForge OrElse Version.Version.HasNeoForge) AndAlso Version.Version.McCodeMain >= 17) Then
-                    Do Until OriginalVersion.InheritVersion = ""
-                        If OriginalVersion.InheritVersion = OriginalVersion.Name Then Exit Do
-                        OriginalVersion = New McVersion(PathMcFolder & "versions\" & OriginalVersion.InheritVersion & "\")
-                    Loop
-                End If
-                '需要新建对象,否则后面的 Check 会导致 McVersionCurrent 的 State 变回 Original
-                '复现:启动一个 Snapshot 版本
-                RealVersion = New McVersion(OriginalVersion.Path)
-            Else
-                'Json 已提供 Jar 字段,使用该字段的信息
-                RealVersion = New McVersion(RequiredJar)
-            End If
-            Dim ClientUrl As String, ClientSHA1 As String
-            '判断需求的版本是否存在
-            '不能调用 RealVersion.Check(),可能会莫名其妙地触发 CheckPermission 正被另一进程使用,导致误判前置不存在
-            If Not File.Exists(RealVersion.Path & RealVersion.Name & ".json") Then
-                RealVersion = Version
-                Log("[Minecraft] 可能缺少前置版本 " & RealVersion.Name & ",找不到对应的 json 文件", LogLevel.Debug)
-            End If
-            '获取详细下载信息
-            If RealVersion.JsonObject("downloads") IsNot Nothing AndAlso RealVersion.JsonObject("downloads")("client") IsNot Nothing Then
-                ClientUrl = RealVersion.JsonObject("downloads")("client")("url")
-                ClientSHA1 = RealVersion.JsonObject("downloads")("client")("sha1")
-            Else
-                ClientUrl = Nothing
-                ClientSHA1 = Nothing
+        Dim RealVersion As McVersion
+        Dim RequiredJar As String = Version.JsonObject("jar")?.ToString
+        If Version.IsHmclFormatJson OrElse RequiredJar Is Nothing Then
+            'HMCL 项直接使用自身的 Jar
+            '根据 Inherit 获取最深层版本
+            Dim OriginalVersion As McVersion = Version
+            '1.17+ 的 Forge 不寻找 Inherit
+            If Not ((Version.Version.HasForge OrElse Version.Version.HasNeoForge) AndAlso Version.Version.McCodeMain >= 17) Then
+                Do Until OriginalVersion.InheritVersion = ""
+                    If OriginalVersion.InheritVersion = OriginalVersion.Name Then Exit Do
+                    OriginalVersion = New McVersion(PathMcFolder & "versions\" & OriginalVersion.InheritVersion & "\")
+                Loop
             End If
             End If
-            '把所需的原版 Jar 添加进去
-            McLibListGet.Add(New McLibToken With {.LocalPath = RealVersion.Path & RealVersion.Name & ".jar", .Size = 0, .IsNatives = False, .Url = ClientUrl, .SHA1 = ClientSHA1})
+            '需要新建对象,否则后面的 Check 会导致 McVersionCurrent 的 State 变回 Original
+            '复现:启动一个 Snapshot 版本
+            RealVersion = New McVersion(OriginalVersion.Path)
+        Else
+            'Json 已提供 Jar 字段,使用该字段的信息
+            RealVersion = New McVersion(RequiredJar)
+        End If
+        Dim ClientUrl As String, ClientSHA1 As String
+        '判断需求的版本是否存在
+        '不能调用 RealVersion.Check(),可能会莫名其妙地触发 CheckPermission 正被另一进程使用,导致误判前置不存在
+        If Not File.Exists(RealVersion.Path & RealVersion.Name & ".json") Then
+            RealVersion = Version
+            Log("[Minecraft] 可能缺少前置版本 " & RealVersion.Name & ",找不到对应的 json 文件", LogLevel.Debug)
         End If
         End If
+        '获取详细下载信息
+        If RealVersion.JsonObject("downloads") IsNot Nothing AndAlso RealVersion.JsonObject("downloads")("client") IsNot Nothing Then
+            ClientUrl = RealVersion.JsonObject("downloads")("client")("url")
+            ClientSHA1 = RealVersion.JsonObject("downloads")("client")("sha1")
+        Else
+            ClientUrl = Nothing
+            ClientSHA1 = Nothing
+        End If
+        '把所需的原版 Jar 添加进去
+        McLibListGet.Add(New McLibToken With {.LocalPath = RealVersion.Path & RealVersion.Name & ".jar", .Size = 0, .IsNatives = False, .Url = ClientUrl, .SHA1 = ClientSHA1})
 
 
     End Function
     End Function
     ''' <summary>
     ''' <summary>
     ''' 获取 Minecraft 某一版本忽视继承的支持库列表,即结果中没有继承项。
     ''' 获取 Minecraft 某一版本忽视继承的支持库列表,即结果中没有继承项。
     ''' </summary>
     ''' </summary>
-    Public Function McLibListGetWithJson(JsonObject As JObject, Optional KeepSameNameDifferentVersionResult As Boolean = False, Optional CustomMcFolder As String = Nothing, Optional JumpLoaderFolder As String = Nothing) As List(Of McLibToken)
+    Public Function McLibListGetWithJson(JsonObject As JObject, Optional KeepSameNameDifferentVersionResult As Boolean = False, Optional CustomMcFolder As String = Nothing) As List(Of McLibToken)
         CustomMcFolder = If(CustomMcFolder, PathMcFolder)
         CustomMcFolder = If(CustomMcFolder, PathMcFolder)
         Dim BasicArray As New List(Of McLibToken)
         Dim BasicArray As New List(Of McLibToken)
 
 
         '添加基础 Json 项
         '添加基础 Json 项
         Dim AllLibs As JArray = JsonObject("libraries")
         Dim AllLibs As JArray = JsonObject("libraries")
-        '添加 JumpLoader Json 项
-        If JsonObject("jumploader") IsNot Nothing AndAlso JsonObject("jumploader")("jars") IsNot Nothing AndAlso JsonObject("jumploader")("jars")("maven") IsNot Nothing Then
-            For Each JumpLoaderToken In JsonObject("jumploader")("jars")("maven")
-                AllLibs.Add(JumpLoaderToken)
-            Next
-        End If
 
 
         '转换为 LibToken
         '转换为 LibToken
         For Each Library As JObject In AllLibs.Children
         For Each Library As JObject In AllLibs.Children
@@ -1865,14 +1835,6 @@ OnLoaded:
             '检查是否需要(Rules)
             '检查是否需要(Rules)
             If Not McJsonRuleCheck(Library("rules")) Then Continue For
             If Not McJsonRuleCheck(Library("rules")) Then Continue For
 
 
-            '检查 JumpLoader
-            Dim IsJumpLoader As Boolean = False
-            If Library("mavenPath") IsNot Nothing Then
-                IsJumpLoader = True
-                If Library("name") Is Nothing Then Library.Add("name", Library("mavenPath")) '这里的修改会导致原 Json 内容改变
-                If Library("repoUrl") IsNot Nothing AndAlso Library("url") Is Nothing Then Library.Add("url", Library("repoUrl"))
-            End If
-
             '获取根节点下的 url
             '获取根节点下的 url
             Dim RootUrl As String = Library("url")
             Dim RootUrl As String = Library("url")
             If RootUrl IsNot Nothing Then
             If RootUrl IsNot Nothing Then
@@ -1882,15 +1844,10 @@ OnLoaded:
             '根据是否本地化处理(Natives)
             '根据是否本地化处理(Natives)
             If Library("natives") Is Nothing Then '没有 Natives
             If Library("natives") Is Nothing Then '没有 Natives
                 Dim LocalPath As String
                 Dim LocalPath As String
-                If IsJumpLoader Then
-                    LocalPath = McLibGet(Library("name"), CustomMcFolder:=If(JumpLoaderFolder, CustomMcFolder))
-                Else
-                    LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder)
-                End If
+                LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder)
                 Try
                 Try
                     If Library("downloads") IsNot Nothing AndAlso Library("downloads")("artifact") IsNot Nothing Then
                     If Library("downloads") IsNot Nothing AndAlso Library("downloads")("artifact") IsNot Nothing Then
                         BasicArray.Add(New McLibToken With {
                         BasicArray.Add(New McLibToken With {
-                            .IsJumpLoader = IsJumpLoader,
                             .OriginalName = Library("name"),
                             .OriginalName = Library("name"),
                             .Url = If(RootUrl, Library("downloads")("artifact")("url")),
                             .Url = If(RootUrl, Library("downloads")("artifact")("url")),
                             .LocalPath = If(Library("downloads")("artifact")("path") Is Nothing, McLibGet(Library("name"),
                             .LocalPath = If(Library("downloads")("artifact")("path") Is Nothing, McLibGet(Library("name"),
@@ -1899,17 +1856,16 @@ OnLoaded:
                             .IsNatives = False,
                             .IsNatives = False,
                             .SHA1 = Library("downloads")("artifact")("sha1")?.ToString})
                             .SHA1 = Library("downloads")("artifact")("sha1")?.ToString})
                     Else
                     Else
-                        BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing})
+                        BasicArray.Add(New McLibToken With {.OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing})
                     End If
                     End If
                 Catch ex As Exception
                 Catch ex As Exception
                     Log(ex, "处理实际支持库列表失败(无 Natives," & If(Library("name"), "Nothing").ToString & ")")
                     Log(ex, "处理实际支持库列表失败(无 Natives," & If(Library("name"), "Nothing").ToString & ")")
-                    BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing})
+                    BasicArray.Add(New McLibToken With {.OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing})
                 End Try
                 End Try
             ElseIf Library("natives")("windows") IsNot Nothing Then '有 Windows Natives
             ElseIf Library("natives")("windows") IsNot Nothing Then '有 Windows Natives
                 Try
                 Try
                     If Library("downloads") IsNot Nothing AndAlso Library("downloads")("classifiers") IsNot Nothing AndAlso Library("downloads")("classifiers")("natives-windows") IsNot Nothing Then
                     If Library("downloads") IsNot Nothing AndAlso Library("downloads")("classifiers") IsNot Nothing AndAlso Library("downloads")("classifiers")("natives-windows") IsNot Nothing Then
                         BasicArray.Add(New McLibToken With {
                         BasicArray.Add(New McLibToken With {
-                             .IsJumpLoader = IsJumpLoader,
                              .OriginalName = Library("name"),
                              .OriginalName = Library("name"),
                              .Url = If(RootUrl, Library("downloads")("classifiers")("natives-windows")("url")),
                              .Url = If(RootUrl, Library("downloads")("classifiers")("natives-windows")("url")),
                              .LocalPath = If(Library("downloads")("classifiers")("natives-windows")("path") Is Nothing,
                              .LocalPath = If(Library("downloads")("classifiers")("natives-windows")("path") Is Nothing,
@@ -1919,11 +1875,11 @@ OnLoaded:
                              .IsNatives = True,
                              .IsNatives = True,
                              .SHA1 = Library("downloads")("classifiers")("natives-windows")("sha1").ToString})
                              .SHA1 = Library("downloads")("classifiers")("natives-windows")("sha1").ToString})
                     Else
                     Else
-                        BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")), .Size = 0, .IsNatives = True, .SHA1 = Nothing})
+                        BasicArray.Add(New McLibToken With {.OriginalName = Library("name"), .Url = RootUrl, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")), .Size = 0, .IsNatives = True, .SHA1 = Nothing})
                     End If
                     End If
                 Catch ex As Exception
                 Catch ex As Exception
                     Log(ex, "处理实际支持库列表失败(有 Natives," & If(Library("name"), "Nothing").ToString & ")")
                     Log(ex, "处理实际支持库列表失败(有 Natives," & If(Library("name"), "Nothing").ToString & ")")
-                    BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")), .Size = 0, .IsNatives = True, .SHA1 = Nothing})
+                    BasicArray.Add(New McLibToken With {.OriginalName = Library("name"), .Url = RootUrl, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")), .Size = 0, .IsNatives = True, .SHA1 = Nothing})
                 End Try
                 End Try
             End If
             End If
 
 
@@ -1940,7 +1896,7 @@ OnLoaded:
             Return GetFolderNameFromPath(GetPathFromFullPath(Token.LocalPath))
             Return GetFolderNameFromPath(GetPathFromFullPath(Token.LocalPath))
         End Function
         End Function
         For i = 0 To BasicArray.Count - 1
         For i = 0 To BasicArray.Count - 1
-            Dim Key As String = BasicArray(i).Name & BasicArray(i).IsNatives.ToString & BasicArray(i).IsJumpLoader.ToString
+            Dim Key As String = BasicArray(i).Name & BasicArray(i).IsNatives.ToString
             If ResultArray.ContainsKey(Key) Then
             If ResultArray.ContainsKey(Key) Then
                 Dim BasicArrayVersion As String = GetVersion(BasicArray(i))
                 Dim BasicArrayVersion As String = GetVersion(BasicArray(i))
                 Dim ResultArrayVersion As String = GetVersion(ResultArray(Key))
                 Dim ResultArrayVersion As String = GetVersion(ResultArray(Key))
@@ -1964,7 +1920,7 @@ OnLoaded:
     ''' 获取版本缺失的支持库文件所对应的 NetTaskFile。
     ''' 获取版本缺失的支持库文件所对应的 NetTaskFile。
     ''' </summary>
     ''' </summary>
     Public Function McLibFix(Version As McVersion) As List(Of NetFile)
     Public Function McLibFix(Version As McVersion) As List(Of NetFile)
-        If Not Version.IsLoaded Then Version.Load() '确保例如 JumpLoader 等项被合并入 Json
+        If Not Version.IsLoaded Then Version.Load()
         Dim Result As New List(Of NetFile)
         Dim Result As New List(Of NetFile)
 
 
         '更新此方法时需要同步更新 Forge 新版自动安装方法!
         '更新此方法时需要同步更新 Forge 新版自动安装方法!
@@ -1978,7 +1934,7 @@ OnLoaded:
         End Try
         End Try
 
 
         'Library 文件
         'Library 文件
-        Result.AddRange(McLibFixFromLibToken(McLibListGet(Version, False), JumpLoaderFolder:=Version.PathIndie & ".jumploader\"))
+        Result.AddRange(McLibFixFromLibToken(McLibListGet(Version, False)))
 
 
         '统一通行证文件
         '统一通行证文件
         If Setup.Get("VersionServerLogin", Version:=Version) = 3 Then
         If Setup.Get("VersionServerLogin", Version:=Version) = 3 Then
@@ -2053,7 +2009,7 @@ OnLoaded:
     ''' <summary>
     ''' <summary>
     ''' 将 McLibToken 列表转换为 NetFile。无需下载的文件会被自动过滤。
     ''' 将 McLibToken 列表转换为 NetFile。无需下载的文件会被自动过滤。
     ''' </summary>
     ''' </summary>
-    Public Function McLibFixFromLibToken(Libs As List(Of McLibToken), Optional CustomMcFolder As String = Nothing, Optional JumpLoaderFolder As String = Nothing) As List(Of NetFile)
+    Public Function McLibFixFromLibToken(Libs As List(Of McLibToken), Optional CustomMcFolder As String = Nothing) As List(Of NetFile)
         CustomMcFolder = If(CustomMcFolder, PathMcFolder)
         CustomMcFolder = If(CustomMcFolder, PathMcFolder)
         Dim Result As New List(Of NetFile)
         Dim Result As New List(Of NetFile)
         '获取
         '获取
@@ -2065,18 +2021,23 @@ OnLoaded:
             Dim Urls As New List(Of String)
             Dim Urls As New List(Of String)
             If Token.Url Is Nothing AndAlso Token.Name = "net.minecraftforge:forge:universal" Then
             If Token.Url Is Nothing AndAlso Token.Name = "net.minecraftforge:forge:universal" Then
                 '特判修复 Forge 部分 universal 文件缺失 URL(#5455)
                 '特判修复 Forge 部分 universal 文件缺失 URL(#5455)
-                Token.Url = "https://maven.minecraftforge.net" & Token.LocalPath.Replace(If(Token.IsJumpLoader, JumpLoaderFolder, CustomMcFolder) & "libraries", "").Replace("\", "/")
+                Token.Url = "https://maven.minecraftforge.net" & Token.LocalPath.Replace(CustomMcFolder & "libraries", "").Replace("\", "/")
             End If
             End If
             If Token.Url IsNot Nothing Then
             If Token.Url IsNot Nothing Then
                 '获取 URL 的真实地址
                 '获取 URL 的真实地址
                 Urls.Add(Token.Url)
                 Urls.Add(Token.Url)
                 If Token.Url.Contains("launcher.mojang.com/v1/objects") OrElse Token.Url.Contains("client.txt") OrElse
                 If Token.Url.Contains("launcher.mojang.com/v1/objects") OrElse Token.Url.Contains("client.txt") OrElse
                    Token.Url.Contains(".tsrg") Then
                    Token.Url.Contains(".tsrg") Then
-                    Urls.AddRange(DlSourceLauncherOrMetaGet(Token.Url).ToList()) 'Mappings(#4425)
+                    Urls.AddRange(DlSourceLauncherOrMetaGet(Token.Url)) 'Mappings(#4425)
                 End If
                 End If
                 If Token.Url.Contains("maven") Then
                 If Token.Url.Contains("maven") Then
-                    Urls.Insert(0, Token.Url.Replace(Mid(Token.Url, 1, Token.Url.IndexOfF("maven")), "https://bmclapi2.bangbang93.com/").
-                        Replace("maven.fabricmc.net", "maven").Replace("maven.minecraftforge.net", "maven").Replace("maven.neoforged.net/releases", "maven"))
+                    Dim BmclapiUrl As String =
+                        Token.Url.Replace(Mid(Token.Url, 1, Token.Url.IndexOfF("maven")), "https://bmclapi2.bangbang93.com/").Replace("maven.fabricmc.net", "maven").Replace("maven.minecraftforge.net", "maven").Replace("maven.neoforged.net/releases", "maven")
+                    If DlSourcePreferMojang Then
+                        Urls.Add(BmclapiUrl) '官方源优先
+                    Else
+                        Urls.Insert(0, BmclapiUrl) '镜像源优先
+                    End If
                 End If
                 End If
             End If
             End If
             If Token.LocalPath.Contains("transformer-discovery-service") Then
             If Token.LocalPath.Contains("transformer-discovery-service") Then
@@ -2086,13 +2047,13 @@ OnLoaded:
                 Continue For
                 Continue For
             ElseIf Token.LocalPath.Contains("optifine\OptiFine") Then
             ElseIf Token.LocalPath.Contains("optifine\OptiFine") Then
                 'OptiFine 主 Jar
                 'OptiFine 主 Jar
-                Dim OptiFineBase As String = Token.LocalPath.Replace(If(Token.IsJumpLoader, JumpLoaderFolder, CustomMcFolder) & "libraries\optifine\OptiFine\", "").Split("_")(0) & "/" & GetFileNameFromPath(Token.LocalPath).Replace("-", "_")
+                Dim OptiFineBase As String = Token.LocalPath.Replace(CustomMcFolder & "libraries\optifine\OptiFine\", "").Split("_")(0) & "/" & GetFileNameFromPath(Token.LocalPath).Replace("-", "_")
                 OptiFineBase = "/maven/com/optifine/" & OptiFineBase
                 OptiFineBase = "/maven/com/optifine/" & OptiFineBase
                 If OptiFineBase.Contains("_pre") Then OptiFineBase = OptiFineBase.Replace("com/optifine/", "com/optifine/preview_")
                 If OptiFineBase.Contains("_pre") Then OptiFineBase = OptiFineBase.Replace("com/optifine/", "com/optifine/preview_")
                 Urls.Add("https://bmclapi2.bangbang93.com" & OptiFineBase)
                 Urls.Add("https://bmclapi2.bangbang93.com" & OptiFineBase)
             ElseIf Urls.Count <= 2 Then
             ElseIf Urls.Count <= 2 Then
                 '普通文件
                 '普通文件
-                Urls.AddRange(DlSourceLibraryGet("https://libraries.minecraft.net" & Token.LocalPath.Replace(If(Token.IsJumpLoader, JumpLoaderFolder, CustomMcFolder) & "libraries", "").Replace("\", "/")))
+                Urls.AddRange(DlSourceLibraryGet("https://libraries.minecraft.net" & Token.LocalPath.Replace(CustomMcFolder & "libraries", "").Replace("\", "/")))
             End If
             End If
             Result.Add(New NetFile(Urls.Distinct, Token.LocalPath, Checker))
             Result.Add(New NetFile(Urls.Distinct, Token.LocalPath, Checker))
         Next
         Next
@@ -2275,7 +2236,7 @@ OnLoaded:
                 If File.Exists AndAlso (Token.Size = 0 OrElse Token.Size = File.Length) AndAlso
                 If File.Exists AndAlso (Token.Size = 0 OrElse Token.Size = File.Length) AndAlso
                     (Not CheckHash OrElse Token.Hash Is Nothing OrElse Token.Hash = GetFileSHA1(Token.LocalPath)) Then Continue For
                     (Not CheckHash OrElse Token.Hash Is Nothing OrElse Token.Hash = GetFileSHA1(Token.LocalPath)) Then Continue For
                 '文件不存在,添加下载
                 '文件不存在,添加下载
-                Result.Add(New NetFile(DlSourceResourceGet("https://resources.download.minecraft.net/" & Left(Token.Hash, 2) & "/" & Token.Hash), Token.LocalPath, New FileChecker(ActualSize:=If(Token.Size = 0, -1, Token.Size), Hash:=Token.Hash)))
+                Result.Add(New NetFile(DlSourceAssetsGet($"https://resources.download.minecraft.net/{Left(Token.Hash, 2)}/{Token.Hash}"), Token.LocalPath, New FileChecker(ActualSize:=If(Token.Size = 0, -1, Token.Size), Hash:=Token.Hash)))
             Next
             Next
         Catch ex As Exception
         Catch ex As Exception
             Log(ex, "获取版本缺失的资源文件下载列表失败")
             Log(ex, "获取版本缺失的资源文件下载列表失败")
@@ -2399,6 +2360,13 @@ NextEntry:
         End Function
         End Function
     End Class
     End Class
 
 
+    ''' <summary>
+    ''' 判断版本名是否类似正式版。
+    ''' </summary>
+    Public Function IsVersionNameLikeRelease(VerName As String) As Boolean
+        Return VerName.StartsWithF("1.") AndAlso Not (VerName.Contains("w") OrElse VerName.Contains("pre") OrElse VerName.Contains("rc") OrElse VerName.Contains("-"))
+    End Function
+
     ''' <summary>
     ''' <summary>
     ''' 为邮箱地址或手机号账号进行部分打码。
     ''' 为邮箱地址或手机号账号进行部分打码。
     ''' </summary>
     ''' </summary>

+ 6 - 2
Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb

@@ -837,7 +837,7 @@ Finished:
                         '仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod
                         '仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod
                         If Not (PageVersionLeft.Version IsNot Nothing AndAlso PageVersionLeft.Version.Version.HasForge AndAlso
                         If Not (PageVersionLeft.Version IsNot Nothing AndAlso PageVersionLeft.Version.Version.HasForge AndAlso
                                 PageVersionLeft.Version.Version.McCodeMain < 13 AndAlso
                                 PageVersionLeft.Version.Version.McCodeMain < 13 AndAlso
-                                File.Directory.Name = "1." & PageVersionLeft.Version.Version.McCodeMain & "." & PageVersionLeft.Version.Version.McCodeSub) Then
+                                File.Directory.Name = $"1.{PageVersionLeft.Version.Version.McCodeMain}.{PageVersionLeft.Version.Version.McCodeSub}") Then
                             Continue For
                             Continue For
                         End If
                         End If
                     End If
                     End If
@@ -1127,7 +1127,11 @@ Finished:
         Next
         Next
         WriteFile(PathTemp & "Cache\LocalMod.json", Cache.ToString(If(ModeDebug, Newtonsoft.Json.Formatting.Indented, Newtonsoft.Json.Formatting.None)))
         WriteFile(PathTemp & "Cache\LocalMod.json", Cache.ToString(If(ModeDebug, Newtonsoft.Json.Formatting.Indented, Newtonsoft.Json.Formatting.None)))
         '刷新边栏
         '刷新边栏
-        RunInUi(Sub() FrmVersionMod?.RefreshBars())
+        If FrmVersionMod?.Filter = PageVersionMod.FilterType.CanUpdate Then
+            RunInUi(Sub() FrmVersionMod?.RefreshUI()) '同步 “可更新” 列表 (#4677)
+        Else
+            RunInUi(Sub() FrmVersionMod?.RefreshBars())
+        End If
     End Sub
     End Sub
     Public Function GetTargetModLoaders() As List(Of CompModLoaderType)
     Public Function GetTargetModLoaders() As List(Of CompModLoaderType)
         Dim ModLoaders As New List(Of CompModLoaderType)
         Dim ModLoaders As New List(Of CompModLoaderType)

+ 94 - 148
Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb

@@ -109,7 +109,7 @@ Public Module ModModpack
         End Try
         End Try
     End Function
     End Function
 
 
-    Private Sub ExtractModpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase, LoaderProgressDelta As Double)
+    Private Sub ExtractModpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase, ProgressIncrement As Double)
         '解压文件
         '解压文件
         Dim RetryCount As Integer = 1
         Dim RetryCount As Integer = 1
         Dim Encode = Encoding.GetEncoding("GB18030")
         Dim Encode = Encoding.GetEncoding("GB18030")
@@ -117,15 +117,15 @@ Public Module ModModpack
         Try
         Try
 Retry:
 Retry:
             Loader.Progress = InitialProgress
             Loader.Progress = InitialProgress
-            '完全不知道为啥会出现文件正在被另一进程使用的问题,总之多试试
             DeleteDirectory(InstallTemp)
             DeleteDirectory(InstallTemp)
-            ExtractFile(FileAddress, InstallTemp, Encode, ProgressIncrementHandler:=Sub(Delta) Loader.Progress += Delta * LoaderProgressDelta)
+            ExtractFile(FileAddress, InstallTemp, Encode, ProgressIncrementHandler:=Sub(Delta) Loader.Progress += Delta * ProgressIncrement)
         Catch ex As Exception
         Catch ex As Exception
             Log(ex, "第 " & RetryCount & " 次解压尝试失败")
             Log(ex, "第 " & RetryCount & " 次解压尝试失败")
             If TypeOf ex Is ArgumentException Then
             If TypeOf ex Is ArgumentException Then
                 Encode = Encoding.UTF8
                 Encode = Encoding.UTF8
                 Log("[ModPack] 已切换压缩包解压编码为 UTF8")
                 Log("[ModPack] 已切换压缩包解压编码为 UTF8")
             End If
             End If
+            '完全不知道为啥会出现文件正在被另一进程使用的问题,总之加个重试
             If RetryCount < 5 Then
             If RetryCount < 5 Then
                 Thread.Sleep(RetryCount * 2000)
                 Thread.Sleep(RetryCount * 2000)
                 If Loader IsNot Nothing AndAlso Loader.LoadingState <> MyLoading.MyLoadingState.Run Then Exit Sub
                 If Loader IsNot Nothing AndAlso Loader.LoadingState <> MyLoading.MyLoadingState.Run Then Exit Sub
@@ -135,6 +135,35 @@ Retry:
                 Throw New Exception("解压整合包文件失败", ex)
                 Throw New Exception("解压整合包文件失败", ex)
             End If
             End If
         End Try
         End Try
+        Loader.Progress = InitialProgress + ProgressIncrement
+    End Sub
+    ''' <summary>
+    ''' 从整合包的 override 目录复制文件,同时设置 PCL 的配置文件与版本隔离。
+    ''' 对路径末尾是否为 \ 没有要求。
+    ''' </summary>
+    Private Sub CopyOverrideDirectory(OverridesFolder As String, VersionFolder As String, Loader As LoaderBase, ProgressIncrement As Double)
+        If Not OverridesFolder.EndsWithF("\") Then OverridesFolder += "\"
+        If Not VersionFolder.EndsWithF("\") Then VersionFolder += "\"
+        '复制文件
+        If Directory.Exists(OverridesFolder) Then
+            Log($"[ModPack] 处理整合包覆写文件夹:{OverridesFolder} → {VersionFolder}")
+            CopyDirectory(OverridesFolder, VersionFolder, Sub(Delta) Loader.Progress += Delta * ProgressIncrement)
+        Else
+            Log($"[ModPack] 整合包中没有覆写文件夹:{OverridesFolder}")
+            Loader.Progress += ProgressIncrement
+        End If
+        '设置 ini
+        Dim OverridesIni As String = $"{OverridesFolder}PCL\Setup.ini"
+        Dim VersionIni As String = $"{VersionFolder}PCL\Setup.ini"
+        If File.Exists(OverridesIni) Then
+            WriteIni(OverridesIni, "VersionArgumentIndie", 1) '开启版本隔离
+            WriteIni(OverridesIni, "VersionArgumentIndieV2", True)
+            CopyFile(OverridesIni, VersionIni) '覆写已有的 ini
+        Else
+            WriteIni(VersionIni, "VersionArgumentIndie", 1) '开启版本隔离
+            WriteIni(VersionIni, "VersionArgumentIndieV2", True)
+        End If
+        IniClearCache(VersionIni) '重置缓存,避免被安装过程中写入的 ini 覆盖
     End Sub
     End Sub
 
 
 #Region "不同类型整合包的安装方法"
 #Region "不同类型整合包的安装方法"
@@ -184,7 +213,7 @@ Retry:
                 Log("[ModPack] 未知 Mod 加载器:" & Id)
                 Log("[ModPack] 未知 Mod 加载器:" & Id)
             End If
             End If
         Next
         Next
-        '解压与配置文件
+        '解压
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallLoaders As New List(Of LoaderBase)
         Dim InstallLoaders As New List(Of LoaderBase)
         Dim OverrideHome As String = If(Json("overrides"), "")
         Dim OverrideHome As String = If(Json("overrides"), "")
@@ -192,21 +221,10 @@ Retry:
             InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
             InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
             Sub(Task As LoaderTask(Of String, Integer))
             Sub(Task As LoaderTask(Of String, Integer))
                 ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
                 ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
-                Task.Progress = 0.6
-                '复制结果
-                Log("[ModPack] 整合包 override 目标:" & OverrideHome)
-                Dim OverrideRoot = InstallTemp & ArchiveBaseFolder & If(OverrideHome = "." OrElse OverrideHome = "./", "", OverrideHome) '#5613
-                If Directory.Exists(OverrideRoot) Then
-                    Dim CopyTarget = $"{PathMcFolder}versions\{VersionName}"
-                    CopyDirectory(OverrideRoot, CopyTarget, Sub(Delta) Task.Progress += Delta * 0.35)
-                    Log($"[ModPack] 整合包 override 复制:{OverrideRoot} -> {CopyTarget}")
-                Else
-                    Log($"[ModPack] 整合包中未找到 override 文件夹:{OverrideRoot}")
-                End If
-                Task.Progress = 0.95
-                '开启版本隔离
-                WriteIni($"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini", "VersionArgumentIndie", 1)
-                WriteIni($"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini", "VersionArgumentIndieV2", True)
+                CopyOverrideDirectory(
+                    InstallTemp & ArchiveBaseFolder & If(OverrideHome = "." OrElse OverrideHome = "./", "", OverrideHome), '#5613
+                    $"{PathMcFolder}versions\{VersionName}",
+                    Task, 0.4)
             End Sub) With {
             End Sub) With {
             .ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
             .ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
         End If
         End If
@@ -245,24 +263,24 @@ Retry:
                             Continue For
                             Continue For
                         End If
                         End If
                     End If
                     End If
-                    '建立 CompFile
-                    Dim File As New CompFile(ModJson, CompType.Mod)
-                    If Not File.Available Then Continue For
                     '根据 modules 和文件名后缀判断资源类型
                     '根据 modules 和文件名后缀判断资源类型
-                    Dim TargetFolder As String
+                    Dim TargetFolder As String, Type As CompType
                     If ModJson("modules").Any Then 'modules 可能返回 null(#1006)
                     If ModJson("modules").Any Then 'modules 可能返回 null(#1006)
                         Dim ModuleNames = CType(ModJson("modules"), JArray).Select(Function(l) l("name").ToString).ToList
                         Dim ModuleNames = CType(ModJson("modules"), JArray).Select(Function(l) l("name").ToString).ToList
                         If ModuleNames.Contains("META-INF") OrElse ModuleNames.Contains("mcmod.info") OrElse
                         If ModuleNames.Contains("META-INF") OrElse ModuleNames.Contains("mcmod.info") OrElse
-                           File.FileName.EndsWithF(".jar", True) Then
-                            TargetFolder = "mods"
+                           ModJson?("FileName")?.ToString?.EndsWithF(".jar", True) Then
+                            TargetFolder = "mods" : Type = CompType.Mod
                         ElseIf ModuleNames.Contains("pack.mcmeta") Then
                         ElseIf ModuleNames.Contains("pack.mcmeta") Then
-                            TargetFolder = "resourcepacks"
+                            TargetFolder = "resourcepacks" : Type = CompType.ResourcePack
                         Else
                         Else
-                            TargetFolder = "shaderpacks"
+                            TargetFolder = "shaderpacks" : Type = CompType.Shader
                         End If
                         End If
                     Else
                     Else
-                        TargetFolder = "mods"
+                        TargetFolder = "mods" : Type = CompType.Mod
                     End If
                     End If
+                    '建立 CompFile
+                    Dim File As New CompFile(ModJson, Type)
+                    If Not File.Available Then Continue For
                     '实际的添加
                     '实际的添加
                     FileList.Add(Id, File.ToNetFile($"{PathMcFolder}versions\{VersionName}\{TargetFolder}\"))
                     FileList.Add(Id, File.ToNetFile($"{PathMcFolder}versions\{VersionName}\{TargetFolder}\"))
                     Task.Progress += 1 / (1 + ModList.Count)
                     Task.Progress += 1 / (1 + ModList.Count)
@@ -285,16 +303,11 @@ Retry:
             .NeoForgeVersion = NeoForgeVersion,
             .NeoForgeVersion = NeoForgeVersion,
             .FabricVersion = FabricVersion
             .FabricVersion = FabricVersion
         }
         }
-        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
-        '构造 Libraries 加载器
-        Dim LoadersLib As New List(Of LoaderBase)
-        LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
-        LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
+        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
         '构造总加载器
         '构造总加载器
         Dim Loaders As New List(Of LoaderBase)
         Dim Loaders As New List(Of LoaderBase)
         Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
         Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
         Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
         Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
-        Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
         Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
         Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
         Sub(Task As LoaderTask(Of String, String))
         Sub(Task As LoaderTask(Of String, String))
             '设置图标
             '设置图标
@@ -379,29 +392,20 @@ Retry:
             If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
             If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
             If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
             If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
         End If
         End If
-        '解压和配置文件
+        '解压
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallLoaders As New List(Of LoaderBase)
         Dim InstallLoaders As New List(Of LoaderBase)
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         Sub(Task As LoaderTask(Of String, Integer))
         Sub(Task As LoaderTask(Of String, Integer))
-            ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
-            Task.Progress = 0.6
-            '复制 overrides 文件夹和 client-overrides 文件夹
-            If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then
-                CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName,
-                    Sub(Delta) Task.Progress += Delta * 0.25)
-            Else
-                Log("[ModPack] 整合包中未找到 override 目录,已跳过")
-            End If
-            Task.Progress = 0.85
-            If Directory.Exists(InstallTemp & ArchiveBaseFolder & "client-overrides") Then
-                CopyDirectory(InstallTemp & ArchiveBaseFolder & "client-overrides", PathMcFolder & "versions\" & VersionName,
-                    Sub(Delta) Task.Progress += Delta * 0.1)
-            End If
-            Task.Progress = 0.95
-            '开启版本隔离
-            WriteIni($"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini", "VersionArgumentIndie", 1)
-            WriteIni($"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini", "VersionArgumentIndieV2", True)
+            ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.5)
+            CopyOverrideDirectory(
+                InstallTemp & ArchiveBaseFolder & "overrides",
+                PathMcFolder & "versions\" & VersionName,
+                Task, 0.4)
+            CopyOverrideDirectory(
+                InstallTemp & ArchiveBaseFolder & "client-overrides",
+                PathMcFolder & "versions\" & VersionName,
+                Task, 0.1)
         End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
         End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
         '获取下载文件列表
         '获取下载文件列表
         Dim FileList As New List(Of NetFile)
         Dim FileList As New List(Of NetFile)
@@ -422,7 +426,12 @@ Retry:
             Dim Urls = File("downloads").Select(Function(t) t.ToString.Replace("://edge.forgecdn", "://media.forgecdn")).ToList
             Dim Urls = File("downloads").Select(Function(t) t.ToString.Replace("://edge.forgecdn", "://media.forgecdn")).ToList
             Urls.AddRange(Urls.Select(Function(u) DlSourceModGet(u)).ToList)
             Urls.AddRange(Urls.Select(Function(u) DlSourceModGet(u)).ToList)
             Urls = Urls.Distinct.ToList()
             Urls = Urls.Distinct.ToList()
-            FileList.Add(New NetFile(Urls, PathMcFolder & "versions\" & VersionName & "\" & File("path").ToString,
+            Dim TargetPath As String = $"{PathMcFolder}versions\{VersionName}\{File("path")}"
+            If Not IO.Path.GetFullPath(TargetPath).StartsWithF($"{PathMcFolder}versions\{VersionName}\", True) Then
+                MyMsgBox($"整合包的文件路径超出了版本文件夹,请向整合包作者反馈此问题!" & vbCrLf & "错误的文件:" & TargetPath, "文件路径校验失败", IsWarn:=True)
+                Throw New CancelledException
+            End If
+            FileList.Add(New NetFile(Urls, TargetPath,
                 New FileChecker(ActualSize:=File("fileSize").ToObject(Of Long), Hash:=File("hashes")("sha1").ToString), True))
                 New FileChecker(ActualSize:=File("fileSize").ToObject(Of Long), Hash:=File("hashes")("sha1").ToString), True))
         Next
         Next
         If FileList.Any Then
         If FileList.Any Then
@@ -438,20 +447,15 @@ Retry:
             .NeoForgeVersion = NeoForgeVersion,
             .NeoForgeVersion = NeoForgeVersion,
             .FabricVersion = FabricVersion
             .FabricVersion = FabricVersion
         }
         }
-        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
-        '构造 Libraries 加载器
-        Dim LoadersLib As New List(Of LoaderBase)
-        LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
-        LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
+        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
         '构造总加载器
         '构造总加载器
         Dim Loaders As New List(Of LoaderBase)
         Dim Loaders As New List(Of LoaderBase)
         Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
         Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
         Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
         Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
-        Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
         Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
         Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
         Sub(Task As LoaderTask(Of String, String))
         Sub(Task As LoaderTask(Of String, String))
             '设置图标
             '设置图标
-            Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
+            Dim VersionFolder As String = $"{PathMcFolder}versions\{VersionName}\"
             If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
             If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
                 File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
                 File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
                 WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
                 WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
@@ -502,67 +506,38 @@ Retry:
         If Validate.Validate(VersionName) <> "" Then VersionName = ""
         If Validate.Validate(VersionName) <> "" Then VersionName = ""
         If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
         If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
         If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
         If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
-        '解压与配置文件
+        '解压
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallLoaders As New List(Of LoaderBase)
         Dim InstallLoaders As New List(Of LoaderBase)
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         Sub(Task As LoaderTask(Of String, Integer))
         Sub(Task As LoaderTask(Of String, Integer))
             ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
             ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
-            Task.Progress = 0.6
-            '复制结果
-            If Directory.Exists(InstallTemp & ArchiveBaseFolder & "minecraft") Then
-                CopyDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", PathMcFolder & "versions\" & VersionName, Sub(Delta) Task.Progress += Delta * 0.35)
-            Else
-                Log("[ModPack] 整合包中未找到 minecraft override 目录,已跳过")
-            End If
-            Task.Progress = 0.95
-            '开启版本隔离
-            WriteIni($"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini", "VersionArgumentIndie", 1)
-            WriteIni($"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini", "VersionArgumentIndieV2", True)
+            CopyOverrideDirectory(
+                InstallTemp & ArchiveBaseFolder & "minecraft",
+                PathMcFolder & "versions\" & VersionName,
+                Task, 0.4)
         End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
         End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
-        '构造加载器
+        '构造游戏本体安装加载器
         If Json("gameVersion") Is Nothing Then Throw New Exception("该 HMCL 整合包未提供游戏版本信息,无法安装!")
         If Json("gameVersion") Is Nothing Then Throw New Exception("该 HMCL 整合包未提供游戏版本信息,无法安装!")
         Dim Request As New McInstallRequest With {
         Dim Request As New McInstallRequest With {
             .TargetVersionName = VersionName,
             .TargetVersionName = VersionName,
             .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
             .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
             .MinecraftName = Json("gameVersion").ToString
             .MinecraftName = Json("gameVersion").ToString
         }
         }
-        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
-        '构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
-        Dim LoadersLib As New List(Of LoaderBase)
-        LoadersLib.Add(New LoaderTask(Of String, String)("重命名版本 Json(副加载器)",
-        Sub()
-            Dim RealFileName As String = PathMcFolder & "versions\" & VersionName & "\" & VersionName & ".json"
-            Dim OldFileName As String = PathMcFolder & "versions\" & VersionName & "\pack.json"
-            If File.Exists(OldFileName) Then
-                '修改 id
-                Dim FileJson = GetJson(ReadFile(OldFileName))
-                FileJson("id") = VersionName
-                '替换文件
-                File.Delete(OldFileName)
-                WriteFile(RealFileName, FileJson.ToString)
-                Log("[ModPack] 已重命名版本 Json:" & RealFileName)
-            End If
-        End Sub) With {.ProgressWeight = 0.1, .Show = False})
-        LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
-        LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
+        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
         '构造总加载器
         '构造总加载器
         Dim Loaders As New List(Of LoaderBase) From {
         Dim Loaders As New List(Of LoaderBase) From {
-            New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)},
-            New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)},
-            New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8}
+            New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)},
+            New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)}
         }
         }
-
         '重复任务检查
         '重复任务检查
         Dim LoaderName As String = "HMCL 整合包安装:" & VersionName & " "
         Dim LoaderName As String = "HMCL 整合包安装:" & VersionName & " "
         If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
         If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
             Hint("该整合包正在安装中!", HintType.Critical)
             Hint("该整合包正在安装中!", HintType.Critical)
             Throw New CancelledException
             Throw New CancelledException
         End If
         End If
-
         '启动
         '启动
         Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
         Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
-        'If Archive IsNot Nothing Then Archive.Dispose() '解除占用,以免在加载器中触发 “正由另一进程使用,因此该进程无法访问此文件”
         Loader.Start(Request.TargetVersionFolder)
         Loader.Start(Request.TargetVersionFolder)
         LoaderTaskbarAdd(Loader)
         LoaderTaskbarAdd(Loader)
         FrmMain.BtnExtraDownload.ShowRefresh()
         FrmMain.BtnExtraDownload.ShowRefresh()
@@ -586,24 +561,17 @@ Retry:
         If Validate.Validate(VersionName) <> "" Then VersionName = ""
         If Validate.Validate(VersionName) <> "" Then VersionName = ""
         If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
         If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
         If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
         If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
-        '解压、配置设置文件
+        '解压
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim SetupFile As String = $"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini"
         Dim SetupFile As String = $"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini"
         Dim InstallLoaders As New List(Of LoaderBase)
         Dim InstallLoaders As New List(Of LoaderBase)
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         Sub(Task As LoaderTask(Of String, Integer))
         Sub(Task As LoaderTask(Of String, Integer))
-            ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
-            Task.Progress = 0.6
-            '复制结果
-            If Directory.Exists(InstallTemp & ArchiveBaseFolder & ".minecraft") Then
-                CopyDirectory(InstallTemp & ArchiveBaseFolder & ".minecraft", PathMcFolder & "versions\" & VersionName, Sub(Delta) Task.Progress += Delta * 0.35)
-            Else
-                Log("[ModPack] 整合包中未找到 override .minecraft 目录,已跳过")
-            End If
-            Task.Progress = 0.95
-            '开启版本隔离
-            WriteIni(SetupFile, "VersionArgumentIndie", 1)
-            WriteIni(SetupFile, "VersionArgumentIndieV2", True)
+            ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.55)
+            CopyOverrideDirectory(
+                InstallTemp & ArchiveBaseFolder & ".minecraft",
+                PathMcFolder & "versions\" & VersionName,
+                Task, 0.4)
             '读取 MMC 设置文件(#2655)
             '读取 MMC 设置文件(#2655)
             Try
             Try
                 Dim MMCSetupFile As String = InstallTemp & ArchiveBaseFolder & "instance.cfg"
                 Dim MMCSetupFile As String = InstallTemp & ArchiveBaseFolder & "instance.cfg"
@@ -682,16 +650,11 @@ Retry:
             End Select
             End Select
         Next
         Next
         '构造加载器
         '构造加载器
-        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
-        '构造 Libraries 加载器
-        Dim LoadersLib As New List(Of LoaderBase)
-        LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
-        LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
+        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
         '构造总加载器
         '构造总加载器
         Dim Loaders As New List(Of LoaderBase)
         Dim Loaders As New List(Of LoaderBase)
-        Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
-        Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
-        Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
+        Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
+        Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
 
 
         '重复任务检查
         '重复任务检查
         Dim LoaderName As String = "MMC 整合包安装:" & VersionName & " "
         Dim LoaderName As String = "MMC 整合包安装:" & VersionName & " "
@@ -728,24 +691,16 @@ Retry:
             If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
             If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
             If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
             If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
         End If
         End If
-        '解压与配置文件
+        '解压
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallTemp As String = RequestTaskTempFolder()
         Dim InstallLoaders As New List(Of LoaderBase)
         Dim InstallLoaders As New List(Of LoaderBase)
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
         Sub(Task As LoaderTask(Of String, Integer))
         Sub(Task As LoaderTask(Of String, Integer))
             ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
             ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
-            Task.Progress = 0.6
-            '复制结果
-            If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then
-                CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName,
-                    Sub(Delta) Task.Progress += 0.35 * Delta)
-            Else
-                Log("[ModPack] 整合包中未找到 overrides 目录,已跳过")
-            End If
-            Task.Progress = 0.95
-            '开启版本隔离
-            WriteIni($"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini", "VersionArgumentIndie", 1)
-            WriteIni($"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini", "VersionArgumentIndieV2", True)
+            CopyOverrideDirectory(
+                InstallTemp & ArchiveBaseFolder & "overrides",
+                PathMcFolder & "versions\" & VersionName,
+                Task, 0.4)
         End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
         End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
         '构造加载器
         '构造加载器
         If Json("addons") Is Nothing Then Throw New Exception("该 MCBBS 整合包未提供游戏版本附加信息,无法安装!")
         If Json("addons") Is Nothing Then Throw New Exception("该 MCBBS 整合包未提供游戏版本附加信息,无法安装!")
@@ -767,16 +722,11 @@ Retry:
             .NeoForgeVersion = If(Addons.ContainsKey("neoforge"), Addons("neoforge"), Nothing),
             .NeoForgeVersion = If(Addons.ContainsKey("neoforge"), Addons("neoforge"), Nothing),
             .FabricVersion = If(Addons.ContainsKey("fabric"), Addons("fabric"), Nothing)
             .FabricVersion = If(Addons.ContainsKey("fabric"), Addons("fabric"), Nothing)
         }
         }
-        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
-        '构造 Libraries 加载器
-        Dim LoadersLib As New List(Of LoaderBase)
-        LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
-        LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
+        Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request)
         '构造总加载器
         '构造总加载器
         Dim Loaders As New List(Of LoaderBase)
         Dim Loaders As New List(Of LoaderBase)
-        Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
-        Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
-        Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
+        Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
+        Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
 
 
         '重复任务检查
         '重复任务检查
         Dim LoaderName As String = "MCBBS 整合包安装:" & VersionName & " "
         Dim LoaderName As String = "MCBBS 整合包安装:" & VersionName & " "
@@ -830,13 +780,9 @@ Retry:
                     Log("[Modpack] 找到压缩包中附带的启动器:" & Launcher)
                     Log("[Modpack] 找到压缩包中附带的启动器:" & Launcher)
                     If MyMsgBox($"整合包里似乎自带了启动器,是否换用它继续安装?{vbCrLf}即将打开:{Launcher}", "换用整合包启动器?", "换用", "不换用") = 1 Then
                     If MyMsgBox($"整合包里似乎自带了启动器,是否换用它继续安装?{vbCrLf}即将打开:{Launcher}", "换用整合包启动器?", "换用", "不换用") = 1 Then
                         OpenExplorer(TargetFolder)
                         OpenExplorer(TargetFolder)
-                        Try
-                            ShellOnly(Launcher, "--wait") '要求等待已有的 PCL 退出
-                            Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序")
-                            FrmMain.EndProgram(False)
-                        Catch ex As Exception
-                            Log(ex, "打开文件失败", LogLevel.Msgbox)
-                        End Try
+                        ShellOnly(Launcher, "--wait") '要求等待已有的 PCL 退出
+                        Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序")
+                        FrmMain.EndProgram(False)
                         Return
                         Return
                     End If
                     End If
                 Else
                 Else

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

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

+ 0 - 0
Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml → Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml


+ 28 - 20
Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml.vb → Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.vb

@@ -92,7 +92,7 @@
             Log("[Control] 按下资源工程列表项:" & LabTitle.Text)
             Log("[Control] 按下资源工程列表项:" & LabTitle.Text)
         End If
         End If
     End Sub
     End Sub
-    Private Sub ProjectClick(sender As MyCompItem, e As EventArgs) Handles Me.Click
+    Private Sub MyCompItem_Click(sender As MyCompItem, e As EventArgs) Handles Me.Click
         '记录当前展开的卡片标题(#2712)
         '记录当前展开的卡片标题(#2712)
         Dim Titles As New List(Of String)
         Dim Titles As New List(Of String)
         If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
         If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
@@ -103,29 +103,37 @@
             FrmMain.PageCurrent.Additional(1) = Titles
             FrmMain.PageCurrent.Additional(1) = Titles
         End If
         End If
         '打开详情页
         '打开详情页
-        Dim TargetVersion As String
-        Dim TargetLoader As CompModLoaderType
-        If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
+        Dim TargetType As CompType
+        Dim TargetVersion As String = Nothing
+        Dim TargetLoader As CompModLoaderType = CompModLoaderType.Any
+        If FrmMain.PageCurrent.Page = FormMain.PageType.Download Then
+            '从下载页进入
+            Select Case FrmMain.PageCurrentSub
+                Case FormMain.PageSubType.DownloadMod
+                    TargetType = CompType.Mod
+                    TargetVersion = FrmDownloadMod.Content.Loader.Input.GameVersion
+                    TargetLoader = FrmDownloadMod.Content.Loader.Input.ModLoader
+                Case FormMain.PageSubType.DownloadPack
+                    TargetType = CompType.ModPack
+                    TargetVersion = FrmDownloadPack.Content.Loader.Input.GameVersion
+                Case FormMain.PageSubType.DownloadDataPack
+                    TargetType = CompType.DataPack
+                    TargetVersion = FrmDownloadDataPack.Content.Loader.Input.GameVersion
+                Case FormMain.PageSubType.DownloadResourcePack
+                    TargetType = CompType.ResourcePack
+                    TargetVersion = FrmDownloadResourcePack.Content.Loader.Input.GameVersion
+                Case FormMain.PageSubType.DownloadShader
+                    TargetType = CompType.Shader
+                    TargetVersion = FrmDownloadShader.Content.Loader.Input.GameVersion
+            End Select
+        Else
+            '从详情页进入(查看前置)
+            TargetType = CompType.Any '允许任意类别
             TargetVersion = FrmMain.PageCurrent.Additional(2)
             TargetVersion = FrmMain.PageCurrent.Additional(2)
             TargetLoader = FrmMain.PageCurrent.Additional(3)
             TargetLoader = FrmMain.PageCurrent.Additional(3)
-        Else
-            Select Case CType(sender.Tag, CompProject).Type
-                Case CompType.Mod
-                    TargetVersion = If(PageDownloadMod.Loader.Input.GameVersion, "")
-                    TargetLoader = PageDownloadMod.Loader.Input.ModLoader
-                Case CompType.ModPack
-                    TargetVersion = If(PageDownloadPack.Loader.Input.GameVersion, "")
-                Case CompType.DataPack
-                    TargetVersion = If(PageDownloadDataPack.Loader.Input.GameVersion, "")
-                Case CompType.Shader
-                    TargetVersion = If(PageDownloadShader.Loader.Input.GameVersion, "")
-                Case Else 'CompType.ResourcePack
-                    TargetVersion = If(PageDownloadResourcePack.Loader.Input.GameVersion, "")
-            End Select
         End If
         End If
-        If CType(sender.Tag, CompProject).Type <> CompType.Mod Then TargetLoader = CompModLoaderType.Any
         FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
         FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
-                           .Additional = {sender.Tag, New List(Of String), TargetVersion, TargetLoader}})
+                           .Additional = {sender.Tag, New List(Of String), TargetVersion, TargetLoader, TargetType}})
     End Sub
     End Sub
 
 
     '鼠标点击判定
     '鼠标点击判定

+ 95 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml

@@ -0,0 +1,95 @@
+<local:MyScrollViewer x:Class="PageComp"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+      xmlns:local="clr-namespace:PCL"
+      mc:Ignorable="d" 
+      VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
+    <StackPanel Orientation="Vertical" Margin="25">
+        <local:MyCard Title="搜索XXX" Margin="0,0,0,15" x:Name="PanAlways">
+            <StackPanel Margin="25,40,25,15">
+                <Grid Margin="0,0,0,11" HorizontalAlignment="Stretch">
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="Auto" />
+                        <ColumnDefinition Width="1.3*" />
+                        <ColumnDefinition Width="1.2*" />
+                        <ColumnDefinition Width="50" />
+                        <ColumnDefinition Width="Auto" />
+                        <ColumnDefinition Width="1*" />
+                    </Grid.ColumnDefinitions>
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="28" />
+                        <RowDefinition Height="9" />
+                        <RowDefinition Height="28" />
+                    </Grid.RowDefinitions>
+                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,18,0" />
+                    <local:MyTextBox x:Name="TextSearchName" Grid.Column="1" Grid.ColumnSpan="2" />
+                    <TextBlock VerticalAlignment="Center" Grid.Column="4" HorizontalAlignment="Left" Text="来源" Margin="0,0,18,0" />
+                    <local:MyComboBox x:Name="ComboSearchSource" Grid.Column="5">
+                        <local:MyComboBoxItem Content="全部" Tag="3" IsSelected="True" />
+                        <local:MyComboBoxItem Content="CurseForge" Tag="1" />
+                        <local:MyComboBoxItem Content="Modrinth" Tag="2" />
+                    </local:MyComboBox>
+                    <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" MaxDropDownHeight="320">
+                        <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
+                        <local:MyComboBoxItem Content="1.21.5" />
+                        <local:MyComboBoxItem Content="1.21.1" />
+                        <local:MyComboBoxItem Content="1.20.6" />
+                        <local:MyComboBoxItem Content="1.20.1" />
+                        <local:MyComboBoxItem Content="1.19.4" />
+                        <local:MyComboBoxItem Content="1.19.2" />
+                        <local:MyComboBoxItem Content="1.18.2" />
+                        <local:MyComboBoxItem Content="1.16.5" />
+                        <local:MyComboBoxItem Content="1.12.2" />
+                        <local:MyComboBoxItem Content="1.10.2" />
+                        <local:MyComboBoxItem Content="1.8.9" />
+                        <local:MyComboBoxItem Content="1.7.10" />
+                    </local:MyComboBox>
+                    <local:MyComboBox x:Name="ComboSearchLoader" Visibility="Collapsed" Grid.Row="2" Grid.Column="2" MaxDropDownHeight="320" Margin="10,0,0,0">
+                        <local:MyComboBoxItem Content="任意 Mod 加载器" IsSelected="True" Tag="0" />
+                        <local:MyComboBoxItem Content="Forge" Tag="1" />
+                        <local:MyComboBoxItem Content="NeoForge" Tag="6" />
+                        <local:MyComboBoxItem Content="Fabric" Tag="4" />
+                        <local:MyComboBoxItem Content="Quilt" Tag="5" />
+                    </local:MyComboBox>
+                    <TextBlock VerticalAlignment="Center" Grid.Column="4" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
+                    <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="5" Grid.Row="2" MaxDropDownHeight="320" />
+                </Grid>
+                <Grid Margin="0,4,0,6" 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="BtnSearchRun" Text="搜索" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
+                    <local:MyButton x:Name="BtnSearchReset" Text="重置条件" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="1" />
+                    <local:MyButton x:Name="BtnSearchInstallModPack" Text="安装已有整合包" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="2"
+                                    ToolTip="在当前选择的 Minecraft 文件夹下安装整合包" ToolTipService.HorizontalOffset="-55" ToolTipService.VerticalOffset="5" />
+                </Grid>
+            </StackPanel>
+        </local:MyCard>
+        <StackPanel x:Name="PanContent">
+            <local:MyHint x:Name="HintError" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,结果可能不全。&#xa;请尝试使用 VPN 或加速器以改善网络。" IsWarn="True" Margin="0,0,0,15" />
+            <local:MyCard x:Name="CardProjects" UseAnimation="False">
+                <StackPanel x:Name="PanProjects" Margin="12" />
+            </local:MyCard>
+            <local:MyCard Margin="0,15,0,0" x:Name="CardPages" HorizontalAlignment="Center">
+                <StackPanel Orientation="Horizontal" Height="23" Margin="10,7">
+                    <local:MyIconButton x:Name="BtnPageFirst" IsEnabled="False" Opacity="0.2" Margin="0,0.5,5,0.5"
+                        Logo="M496.213333 329.856L315.306667 510.848l180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z m298.666667 0l-180.949333 180.992 180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z" />
+                    <local:MyIconButton x:Name="BtnPageLeft" IsEnabled="False" Opacity="0.2" Margin="0,0,5,0"
+                        Logo="M650.752 278.357333l-241.322667 241.365334 241.322667 241.365333a42.666667 42.666667 0 1 1-60.330667 60.330667l-271.530666-271.530667a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.416-27.648l271.530666-271.530666a42.666667 42.666667 0 0 1 60.330667 60.330666z" />
+                    <TextBlock x:Name="LabPage" Text="1" 
+                               Margin="8,0,13,0" FontSize="15" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush3}" />
+                    <local:MyIconButton x:Name="BtnPageRight" Margin="0,0,30,0"
+                        Logo="M404.309333 278.357333l241.322667 241.365334-241.322667 241.365333a42.666667 42.666667 0 1 0 60.330667 60.330667l271.530667-271.530667a42.453333 42.453333 0 0 0 11.818666-22.613333l0.597334-5.034667v-5.034667a42.496 42.496 0 0 0-12.416-27.648L464.64 218.026667a42.666667 42.666667 0 0 0-60.330667 60.330666z" />
+                </StackPanel>
+            </local:MyCard>
+        </StackPanel>
+        <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
+            <local:MyLoading Text="正在获取XXX列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
+        </local:MyCard>
+    </StackPanel>
+</local:MyScrollViewer>

+ 110 - 31
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb → Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.vb

@@ -1,17 +1,79 @@
-Public Class PageDownloadMod
+Imports System.Windows.Markup
+
+<ContentProperty("SearchTags")>
+Public Class PageComp
+
+#Region "属性"
+
+    ''' <summary>
+    ''' 用于 XAML 快速设置的 Tag 下拉框列表。
+    ''' </summary>
+    Public ReadOnly Property SearchTags As ItemCollection
+        Get
+            Return ComboSearchTag.Items
+        End Get
+    End Property
+
+    ''' <summary>
+    ''' 英文前后不含空格的可读资源类型名,例如 "Mod"、"整合包"。
+    ''' </summary>
+    Public Property TypeName As String
+        Get
+            Return _TypeName
+        End Get
+        Set(Value As String)
+            If _TypeName = Value Then Return
+            _TypeName = Value
+            Loader.Name = $"社区资源获取:{Value}"
+        End Set
+    End Property
+    Private _TypeName As String = ""
 
 
-    Public Const PageSize = 40
     ''' <summary>
     ''' <summary>
-    ''' 在切换到该页面时自动设置的目标版本。
+    ''' 英文前后含一个空格的可读资源类型名,例如 " Mod "、"整合包"。
+    ''' </summary>
+    Public Property TypeNameSpaced As String
+        Get
+            Return _TypeNameSpaced
+        End Get
+        Set(Value As String)
+            If _TypeNameSpaced = Value Then Return
+            _TypeNameSpaced = Value
+            PanAlways.Title = $"搜索{Value}"
+            Load.Text = $"正在获取{Value}列表"
+        End Set
+    End Property
+    Private _TypeNameSpaced As String = ""
+
+    ''' <summary>
+    ''' 该页面对应的资源类型。
+    ''' </summary>
+    Public Property PageType As CompType
+        Get
+            Return _Type
+        End Get
+        Set(Value As CompType)
+            If _Type = Value Then Return
+            _Type = Value
+            BtnSearchInstallModPack.Visibility = If(Value = CompType.ModPack, Visibility.Visible, Visibility.Collapsed)
+        End Set
+    End Property
+    Private _Type As CompType = -1
+
+#End Region
+
+#Region "加载"
+
+    ''' <summary>
+    ''' 在切换到页面时,应自动将筛选项设置为与该目标 MC 版本和加载器相同。
     ''' </summary>
     ''' </summary>
     Public Shared TargetVersion As McVersion = Nothing
     Public Shared TargetVersion As McVersion = Nothing
 
 
-    '加载器信息
-    Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject Mod", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
-    Public Shared Storage As New CompProjectStorage
-    Public Shared Page As Integer = 0
+    '在点击 MyCompItem 时会获取 Loader 的输入,以使资源详情页面可以应用相同的筛选项
+    Public Loader As New LoaderTask(Of CompProjectRequest, Integer)("社区资源获取:XXX", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
+
     Private IsLoaderInited As Boolean = False
     Private IsLoaderInited As Boolean = False
-    Private Sub PageDownloadMod_Inited(sender As Object, e As EventArgs) Handles Me.Loaded
+    Private Sub PageCompControls_Inited(sender As Object, e As EventArgs) Handles Me.Loaded
         '不知道从 Initialized 改成 Loaded 会不会有问题,但用 Initialized 会导致初始的筛选器修改被覆盖回默认值
         '不知道从 Initialized 改成 Loaded 会不会有问题,但用 Initialized 会导致初始的筛选器修改被覆盖回默认值
         If TargetVersion IsNot Nothing Then
         If TargetVersion IsNot Nothing Then
             '设置目标
             '设置目标
@@ -34,43 +96,55 @@
             TargetVersion = Nothing
             TargetVersion = Nothing
             '如果已经完成请求,则重新开始
             '如果已经完成请求,则重新开始
             If IsLoaderInited Then StartNewSearch()
             If IsLoaderInited Then StartNewSearch()
-            PanScroll.ScrollToHome()
+            ScrollToHome()
         End If
         End If
         '加载器初始化
         '加载器初始化
         If IsLoaderInited Then Return
         If IsLoaderInited Then Return
         IsLoaderInited = True
         IsLoaderInited = True
-        PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
+        CType(Parent, MyPageRight).PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
         If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
         If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
     End Sub
     End Sub
-    Private Shared Function LoaderInput() As CompProjectRequest
-        Dim Request As New CompProjectRequest(CompType.Mod, Storage, (Page + 1) * PageSize)
-        If FrmDownloadMod IsNot Nothing Then
-            Dim ModLoader As CompModLoaderType = Val(FrmDownloadMod.ComboSearchLoader.SelectedItem.Tag)
-            Dim GameVersion As String = If(FrmDownloadMod.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
-                    If(FrmDownloadMod.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadMod.TextSearchVersion.Text.Contains("w"), FrmDownloadMod.TextSearchVersion.Text, Nothing))
+    Private Function LoaderInput() As CompProjectRequest
+        Dim Request As New CompProjectRequest(PageType, Storage, (Page + 1) * PageSize)
+        Dim GameVersion As String = If(TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
+                If(TextSearchVersion.Text.Contains(".") OrElse TextSearchVersion.Text.Contains("w"), TextSearchVersion.Text, Nothing))
+        Dim ModLoader As CompModLoaderType = CompModLoaderType.Any
+        If PageType = CompType.Mod Then '只有 Mod 考虑加载器
+            ModLoader = Val(ComboSearchLoader.SelectedItem.Tag)
             If GameVersion IsNot Nothing AndAlso GameVersion.Contains(".") AndAlso Val(GameVersion.Split(".")(1)) < 14 AndAlso '1.14-
             If GameVersion IsNot Nothing AndAlso GameVersion.Contains(".") AndAlso Val(GameVersion.Split(".")(1)) < 14 AndAlso '1.14-
                 ModLoader = CompModLoaderType.Forge Then '选择了 Forge
                 ModLoader = CompModLoaderType.Forge Then '选择了 Forge
                 ModLoader = CompModLoaderType.Any '此时,视作没有筛选 Mod Loader(因为部分老 Mod 没有设置自己支持的加载器)
                 ModLoader = CompModLoaderType.Any '此时,视作没有筛选 Mod Loader(因为部分老 Mod 没有设置自己支持的加载器)
             End If
             End If
-            With Request
-                .SearchText = FrmDownloadMod.TextSearchName.Text
-                .GameVersion = GameVersion
-                .Tag = FrmDownloadMod.ComboSearchTag.SelectedItem.Tag
-                .ModLoader = ModLoader
-                .Source = CType(Val(FrmDownloadMod.ComboSearchSource.SelectedItem.Tag), CompSourceType)
-            End With
         End If
         End If
+        With Request
+            .SearchText = TextSearchName.Text
+            .GameVersion = GameVersion
+            .Tag = ComboSearchTag.SelectedItem.Tag
+            .ModLoader = ModLoader
+            .Source = CType(Val(ComboSearchSource.SelectedItem.Tag), CompSourceType)
+        End With
         Return Request
         Return Request
     End Function
     End Function
 
 
+#End Region
+
+    Public Storage As New CompProjectStorage
+    ''' <summary>
+    ''' 每页展示的结果数量。
+    ''' </summary>
+    Public Const PageSize = 40
+    Public Page As Integer = 0
+
     '结果 UI 化
     '结果 UI 化
     Private Sub Load_OnFinish()
     Private Sub Load_OnFinish()
         Try
         Try
-            Log($"[Comp] 开始可视化 Mod 列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
+            Log($"[Comp] 开始可视化{TypeNameSpaced}列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
             '列表项
             '列表项
             PanProjects.Children.Clear()
             PanProjects.Children.Clear()
             For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
             For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
-                PanProjects.Children.Add(Storage.Results(i).ToCompItem(Loader.Input.GameVersion Is Nothing, Loader.Input.ModLoader = CompModLoaderType.Any))
+                PanProjects.Children.Add(Storage.Results(i).ToCompItem(
+                    ShowMcVersionDesc:=Loader.Input.GameVersion Is Nothing,
+                    ShowLoaderDesc:=Loader.Input.ModLoader = CompModLoaderType.Any AndAlso (PageType = CompType.Mod OrElse PageType = CompType.ModPack)))
             Next
             Next
             '页码
             '页码
             CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
             CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
@@ -94,9 +168,9 @@
                 HintError.Text = Storage.ErrorMessage
                 HintError.Text = Storage.ErrorMessage
             End If
             End If
             '强制返回顶部
             '强制返回顶部
-            PanBack.ScrollToTop()
+            ScrollToTop()
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, "可视化 Mod 列表出错", LogLevel.Feedback)
+            Log(ex, $"可视化{TypeNameSpaced}列表出错", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -107,8 +181,8 @@
                 Dim ErrorMessage As String = ""
                 Dim ErrorMessage As String = ""
                 If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
                 If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
                 If ErrorMessage.Contains("不是有效的 json 文件") Then
                 If ErrorMessage.Contains("不是有效的 json 文件") Then
-                    Log("[Download] 下载的 Mod 列表 json 文件损坏,已自动重试", LogLevel.Debug)
-                    PageLoaderRestart()
+                    Log($"[Download] 下载的{TypeNameSpaced}列表 json 文件损坏,已自动重试", LogLevel.Debug)
+                    CType(Parent, MyPageRight).PageLoaderRestart()
                 End If
                 End If
         End Select
         End Select
     End Sub
     End Sub
@@ -128,7 +202,7 @@
         CardPages.IsEnabled = False
         CardPages.IsEnabled = False
         Page = NewPage
         Page = NewPage
         FrmMain.BackToTop()
         FrmMain.BackToTop()
-        Log($"[Download] Mod 切换到第 {Page + 1} 页")
+        Log($"[Download] {TypeName}:切换到第 {Page + 1} 页")
         RunInThread(
         RunInThread(
         Sub()
         Sub()
             Thread.Sleep(100) '等待向上滚的动画结束
             Thread.Sleep(100) '等待向上滚的动画结束
@@ -166,7 +240,7 @@
         If Not TextSearchVersion.IsDropDownOpen Then UpdateSearchLoaderVisibility()
         If Not TextSearchVersion.IsDropDownOpen Then UpdateSearchLoaderVisibility()
     End Sub
     End Sub
     Private Sub UpdateSearchLoaderVisibility() Handles TextSearchVersion.DropDownClosed
     Private Sub UpdateSearchLoaderVisibility() Handles TextSearchVersion.DropDownClosed
-        If TextSearchVersion.Text.Contains(".") OrElse TextSearchVersion.Text.Contains("w") Then
+        If PageType = CompType.Mod AndAlso (TextSearchVersion.Text.Contains(".") OrElse TextSearchVersion.Text.Contains("w")) Then
             ComboSearchLoader.Visibility = Visibility.Visible
             ComboSearchLoader.Visibility = Visibility.Visible
             Grid.SetColumnSpan(TextSearchVersion, 1)
             Grid.SetColumnSpan(TextSearchVersion, 1)
         Else
         Else
@@ -178,4 +252,9 @@
 
 
 #End Region
 #End Region
 
 
+    '安装已有整合包按钮
+    Private Sub BtnSearchInstallModPack_Click(sender As Object, e As EventArgs) Handles BtnSearchInstallModPack.Click
+        ModpackInstall()
+    End Sub
+
 End Class
 End Class

+ 0 - 0
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml → Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml


+ 47 - 27
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb → Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb

@@ -4,23 +4,29 @@
 #Region "加载器"
 #Region "加载器"
 
 
     Private CompFileLoader As New LoaderTask(Of Integer, List(Of CompFile))(
     Private CompFileLoader As New LoaderTask(Of Integer, List(Of CompFile))(
-        "Comp File", Sub(Task As LoaderTask(Of Integer, List(Of CompFile))) Task.Output = CompFilesGet(Project.Id, Project.FromCurseForge))
+        "Comp File",
+        Sub(Task)
+            LoadTargetFromAdditional()
+            Task.Output = CompFilesGet(Project.Id, Project.FromCurseForge)
+        End Sub)
 
 
     '初始化加载器信息
     '初始化加载器信息
     Private Sub PageDownloadCompDetail_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
     Private Sub PageDownloadCompDetail_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
-        Project = FrmMain.PageCurrent.Additional(0)
-        TargetVersion = FrmMain.PageCurrent.Additional(2)
-        TargetLoader = FrmMain.PageCurrent.Additional(3)
+        LoadTargetFromAdditional()
         PageLoaderInit(Load, PanLoad, PanMain, CardIntro, CompFileLoader, AddressOf Load_OnFinish)
         PageLoaderInit(Load, PanLoad, PanMain, CardIntro, CompFileLoader, AddressOf Load_OnFinish)
     End Sub
     End Sub
-    Private Sub PageDownloadCompDetail_Loaded(sender As Object, e As EventArgs) Handles Me.Loaded
-        'Initialized 只会执行一次
+    Public Sub LoadTargetFromAdditional() Handles Me.Loaded
         Project = FrmMain.PageCurrent.Additional(0)
         Project = FrmMain.PageCurrent.Additional(0)
         TargetVersion = FrmMain.PageCurrent.Additional(2)
         TargetVersion = FrmMain.PageCurrent.Additional(2)
         TargetLoader = FrmMain.PageCurrent.Additional(3)
         TargetLoader = FrmMain.PageCurrent.Additional(3)
+        PageType = FrmMain.PageCurrent.Additional(4)
     End Sub
     End Sub
     Private Project As CompProject
     Private Project As CompProject
     Private TargetVersion As String, TargetLoader As CompModLoaderType
     Private TargetVersion As String, TargetLoader As CompModLoaderType
+    ''' <summary>
+    ''' 当前页面应展示的内容类别。可能为 Any。
+    ''' </summary>
+    Private PageType As CompType
     '自动重试
     '自动重试
     Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
     Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
         Select Case CompFileLoader.State
         Select Case CompFileLoader.State
@@ -62,18 +68,30 @@
 
 
     Private VersionFilter As String
     Private VersionFilter As String
     Private IsMajorVersionFilter As Boolean '是否按大版本号筛选(1.21 / 1.20 / 1.19 / ...)而非小版本号(1.21.1 / 1.21 / 1.20.4 / ...)
     Private IsMajorVersionFilter As Boolean '是否按大版本号筛选(1.21 / 1.20 / 1.19 / ...)而非小版本号(1.21.1 / 1.21 / 1.20.4 / ...)
+    '筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表)
+    Private Function GetResults() As List(Of CompFile)
+        Dim Results As List(Of CompFile) = CompFileLoader.Output
+        If PageType = CompType.Any Then
+            Results = Results.Where(Function(r) r.Type <> CompType.Plugin).ToList
+        Else
+            Results = Results.Where(Function(r) r.Type = PageType).ToList
+        End If
+        Return Results
+    End Function
     Private Sub Load_OnFinish()
     Private Sub Load_OnFinish()
+        Dim Results = GetResults()
+
         '初始化筛选器
         '初始化筛选器
         Dim VersionFilters As List(Of String)
         Dim VersionFilters As List(Of String)
 
 
         '按小版本号筛选?
         '按小版本号筛选?
         IsMajorVersionFilter = False
         IsMajorVersionFilter = False
-        VersionFilters = CompFileLoader.Output.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True)).
+        VersionFilters = Results.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True)).
             Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
             Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
         '按大版本号筛选?
         '按大版本号筛选?
         If VersionFilters.Count >= 9 Then
         If VersionFilters.Count >= 9 Then
             IsMajorVersionFilter = True
             IsMajorVersionFilter = True
-            VersionFilters = CompFileLoader.Output.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True)).
+            VersionFilters = Results.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True)).
                 Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
                 Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
         End If
         End If
 
 
@@ -100,7 +118,7 @@
             '自动选择
             '自动选择
             Dim ToCheck As MyRadioButton = Nothing
             Dim ToCheck As MyRadioButton = Nothing
             If TargetVersion <> "" Then
             If TargetVersion <> "" Then
-                Dim TargetFile = CompFileLoader.Output.FirstOrDefault(Function(v) v.GameVersions.Contains(TargetVersion))
+                Dim TargetFile = Results.FirstOrDefault(Function(v) v.GameVersions.Contains(TargetVersion))
                 If TargetFile IsNot Nothing Then
                 If TargetFile IsNot Nothing Then
                     Dim TargetGroup = GetGroupedVersionName(TargetVersion, IsMajorVersionFilter, True)
                     Dim TargetGroup = GetGroupedVersionName(TargetVersion, IsMajorVersionFilter, True)
                     For Each Button As MyRadioButton In PanFilter.Children
                     For Each Button As MyRadioButton In PanFilter.Children
@@ -118,24 +136,26 @@
         UpdateFilterResult()
         UpdateFilterResult()
     End Sub
     End Sub
     Private Sub UpdateFilterResult()
     Private Sub UpdateFilterResult()
+        Dim Results = GetResults()
+
         Dim TargetCardName As String = If(TargetVersion <> "" OrElse TargetLoader <> CompModLoaderType.Any,
         Dim TargetCardName As String = If(TargetVersion <> "" OrElse TargetLoader <> CompModLoaderType.Any,
             $"所选版本:{If(TargetLoader <> CompModLoaderType.Any, TargetLoader.ToString & " ", "")}{TargetVersion}", "")
             $"所选版本:{If(TargetLoader <> CompModLoaderType.Any, TargetLoader.ToString & " ", "")}{TargetVersion}", "")
         '归类到卡片下
         '归类到卡片下
         Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New CardSorter(TargetCardName))
         Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New CardSorter(TargetCardName))
         Dict.Add("其他版本", New List(Of CompFile))
         Dict.Add("其他版本", New List(Of CompFile))
         Dim SupportedLoaders As New List(Of Integer)([Enum].GetValues(GetType(CompModLoaderType)))
         Dim SupportedLoaders As New List(Of Integer)([Enum].GetValues(GetType(CompModLoaderType)))
-        For Each Version As CompFile In CompFileLoader.Output
+        For Each Version As CompFile In Results
             For Each GameVersion In Version.GameVersions
             For Each GameVersion In Version.GameVersions
                 '检查是否符合版本筛选器
                 '检查是否符合版本筛选器
                 If VersionFilter IsNot Nothing AndAlso
                 If VersionFilter IsNot Nothing AndAlso
                     GetGroupedVersionName(GameVersion, IsMajorVersionFilter, True) <> VersionFilter Then Continue For
                     GetGroupedVersionName(GameVersion, IsMajorVersionFilter, True) <> VersionFilter Then Continue For
                 '决定添加到哪个卡片
                 '决定添加到哪个卡片
-                Dim Ver As String = GetGroupedVersionName(GameVersion, False, False)
+                Dim VerName As String = GetGroupedVersionName(GameVersion, False, False)
                 '遍历加入的加载器列表
                 '遍历加入的加载器列表
                 Dim Loaders As New List(Of String)
                 Dim Loaders As New List(Of String)
-                If Project.ModLoaders.Count > 1 AndAlso '至少有两个加载器
-                    Project.Type = CompType.Mod AndAlso '是 Mod
-                    Ver.StartsWith("1.") Then '不是 “快照版本” 之类的
+                If Project.ModLoaders.Count > 1 AndAlso '工程至少有两个加载器
+                    Version.Type = CompType.Mod AndAlso '是 Mod
+                    VerName.StartsWith("1.") Then '不是 “快照版本” 之类的
                     For Each Loader In Version.ModLoaders
                     For Each Loader In Version.ModLoaders
                         If Loader = CompModLoaderType.Quilt AndAlso Setup.Get("ToolDownloadIgnoreQuilt") Then Continue For
                         If Loader = CompModLoaderType.Quilt AndAlso Setup.Get("ToolDownloadIgnoreQuilt") Then Continue For
                         If SupportedLoaders.Contains(Loader) Then Loaders.Add(Loader.ToString & " ")
                         If SupportedLoaders.Contains(Loader) Then Loaders.Add(Loader.ToString & " ")
@@ -144,16 +164,16 @@
                 If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
                 If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
                 '实际添加
                 '实际添加
                 For Each Loader In Loaders
                 For Each Loader In Loaders
-                    Dim TargetCard As String = Loader & Ver
+                    Dim TargetCard As String = Loader & VerName
                     If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile))
                     If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile))
                     If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
                     If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
                 Next
                 Next
             Next
             Next
         Next
         Next
         '添加筛选的版本的卡片
         '添加筛选的版本的卡片
-        If TargetCardName <> "" Then
+        If TargetCardName <> "" AndAlso (VersionFilter Is Nothing OrElse GetGroupedVersionName(TargetVersion, IsMajorVersionFilter, True).StartsWithF(VersionFilter)) Then
             Dict.Add(TargetCardName, New List(Of CompFile))
             Dict.Add(TargetCardName, New List(Of CompFile))
-            For Each Version As CompFile In CompFileLoader.Output
+            For Each Version As CompFile In Results
                 If Version.GameVersions.Contains(TargetVersion) AndAlso
                 If Version.GameVersions.Contains(TargetVersion) AndAlso
                    (TargetLoader = CompModLoaderType.Any OrElse Version.ModLoaders.Contains(TargetLoader)) Then
                    (TargetLoader = CompModLoaderType.Any OrElse Version.ModLoaders.Contains(TargetLoader)) Then
                     '检查是否符合版本筛选器
                     '检查是否符合版本筛选器
@@ -169,7 +189,7 @@
             For Each Pair As KeyValuePair(Of String, List(Of CompFile)) In Dict
             For Each Pair As KeyValuePair(Of String, List(Of CompFile)) In Dict
                 If Not Pair.Value.Any() Then Continue For
                 If Not Pair.Value.Any() Then Continue For
                 '增加卡片
                 '增加卡片
-                Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(Project.Type = CompType.ModPack, 9, 8)} 'FUTURE: Res
+                Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(PageType = CompType.ModPack, 9, 8)} '9 是安装,8 是另存为
                 Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
                 Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
                 NewCard.Children.Add(NewStack)
                 NewCard.Children.Add(NewStack)
                 NewCard.SwapControl = NewStack
                 NewCard.SwapControl = NewStack
@@ -178,7 +198,7 @@
                 If Pair.Key = TargetCardName OrElse
                 If Pair.Key = TargetCardName OrElse
                    (FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
                    (FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
                    CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then
                    CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then
-                    MyCard.StackInstall(NewStack, If(Project.Type = CompType.ModPack, 9, 8), Pair.Key) 'FUTURE: Res
+                    MyCard.StackInstall(NewStack, If(PageType = CompType.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为
                 Else
                 Else
                     NewCard.IsSwaped = True
                     NewCard.IsSwaped = True
                 End If
                 End If
@@ -237,7 +257,7 @@
         AniControlEnabled -= 1
         AniControlEnabled -= 1
     End Sub
     End Sub
 
 
-    '整合包下载(安装)
+    '整合包安装
     Public Sub Install_Click(sender As MyListItem, e As EventArgs)
     Public Sub Install_Click(sender As MyListItem, e As EventArgs)
         Try
         Try
 
 
@@ -282,24 +302,24 @@
             Log(ex, "下载资源整合包失败", LogLevel.Feedback)
             Log(ex, "下载资源整合包失败", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
-    'Mod、资源包下载;整合包另存为
+    '资源下载;整合包另存为
     Public Shared CachedFolder As String = Nothing '仅在本次缓存的下载文件夹
     Public Shared CachedFolder As String = Nothing '仅在本次缓存的下载文件夹
     Public Sub Save_Click(sender As Object, e As EventArgs)
     Public Sub Save_Click(sender As Object, e As EventArgs)
         Dim File As CompFile = If(TypeOf sender Is MyListItem, sender, sender.Parent).Tag
         Dim File As CompFile = If(TypeOf sender Is MyListItem, sender, sender.Parent).Tag
         RunInNewThread(
         RunInNewThread(
         Sub()
         Sub()
             Try
             Try
-                Dim Desc As String = "资源"
-                Select Case Project.Type
+                Dim Desc As String = Nothing
+                Select Case File.Type
                     Case CompType.ModPack : Desc = "整合包"
                     Case CompType.ModPack : Desc = "整合包"
                     Case CompType.Mod : Desc = "Mod "
                     Case CompType.Mod : Desc = "Mod "
                     Case CompType.ResourcePack : Desc = "资源包"
                     Case CompType.ResourcePack : Desc = "资源包"
-                    Case CompType.DataPack : Desc = If(File.FileName.EndsWith(".jar"), "Mod ", "数据包") '有些项目同时包含 Mod 版本和数据包版本
                     Case CompType.Shader : Desc = "光影包"
                     Case CompType.Shader : Desc = "光影包"
+                    Case CompType.DataPack : Desc = "数据包"
                 End Select
                 End Select
                 '确认默认保存位置
                 '确认默认保存位置
                 Dim DefaultFolder As String = Nothing
                 Dim DefaultFolder As String = Nothing
-                If Project.Type = CompType.Mod Then
+                If File.Type = CompType.Mod Then
                     '获取 Mod 所需的加载器种类
                     '获取 Mod 所需的加载器种类
                     Dim AllowForge As Boolean? = Nothing, AllowFabric As Boolean? = Nothing
                     Dim AllowForge As Boolean? = Nothing, AllowFabric As Boolean? = Nothing
                     If File.ModLoaders.Any Then '从文件中获取
                     If File.ModLoaders.Any Then '从文件中获取
@@ -389,13 +409,13 @@
                     Dim Target As String
                     Dim Target As String
                     Target = SelectSaveFile("选择保存位置", FileName,
                     Target = SelectSaveFile("选择保存位置", FileName,
                         Desc & "文件|" &
                         Desc & "文件|" &
-                        If(Project.Type = CompType.Mod,
+                        If(File.Type = CompType.Mod,
                             If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"),
                             If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"),
                             If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
                             If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
                     If Not Target.Contains("\") Then Exit Sub
                     If Not Target.Contains("\") Then Exit Sub
                     '构造步骤加载器
                     '构造步骤加载器
                     Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " "
                     Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " "
-                    If Target <> DefaultFolder AndAlso Project.Type = CompType.Mod Then CachedFolder = GetPathFromFullPath(Target)
+                    If Target <> DefaultFolder AndAlso File.Type = CompType.Mod Then CachedFolder = GetPathFromFullPath(Target)
                     Dim Loaders As New List(Of LoaderBase)
                     Dim Loaders As New List(Of LoaderBase)
                     Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True})
                     Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True})
                     '启动
                     '启动

+ 26 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadDataPack.xaml

@@ -0,0 +1,26 @@
+<local:MyPageRight
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadDataPack"
+    PanScroll="{Binding ElementName=Content}">
+    <local:PageComp x:Name="Content" PageType="DataPack" TypeName="数据包" TypeNameSpaced="数据包">
+        <local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
+        <local:MyComboBoxItem Content="世界元素" Tag="/worldgen" />
+        <local:MyComboBoxItem Content="科技" Tag="6951/technology" />
+        <local:MyComboBoxItem Content="游戏机制" Tag="/game-mechanics" />
+        <local:MyComboBoxItem Content="运输" Tag="/transportation" />
+        <local:MyComboBoxItem Content="仓储" Tag="/storage" />
+        <local:MyComboBoxItem Content="魔法" Tag="6952/magic" />
+        <local:MyComboBoxItem Content="冒险" Tag="6948/adventure" />
+        <local:MyComboBoxItem Content="幻想" Tag="6949/" />
+        <local:MyComboBoxItem Content="装饰" Tag="/decoration" />
+        <local:MyComboBoxItem Content="生物" Tag="/mobs" />
+        <local:MyComboBoxItem Content="实用" Tag="6953/utility" />
+        <local:MyComboBoxItem Content="装备与工具" Tag="/equipment" />
+        <local:MyComboBoxItem Content="性能优化" Tag="/optimization" />
+        <local:MyComboBoxItem Content="服务器" Tag="/social" />
+        <local:MyComboBoxItem Content="支持库" Tag="6950/library" />
+        <local:MyComboBoxItem Content="Mod 相关" Tag="6946/" />
+    </local:PageComp>
+</local:MyPageRight>

+ 2 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadDataPack.xaml.vb

@@ -0,0 +1,2 @@
+Public Class PageDownloadDataPack
+End Class

+ 35 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadMod.xaml

@@ -0,0 +1,35 @@
+<local:MyPageRight
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadMod"
+    PanScroll="{Binding ElementName=Content}">
+    <local:PageComp x:Name="Content" PageType="Mod" TypeName="Mod" TypeNameSpaced=" Mod ">
+        <local:MyComboBoxItem Content="全部" Tag="" IsSelected="True" />
+        <local:MyComboBoxItem Content="世界元素" Tag="406/worldgen" />
+        <local:MyComboBoxItem Content="生物群系" Tag="407/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="维度" Tag="410/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="矿物与资源" Tag="408/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="天然结构" Tag="409/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="科技" Tag="412/technology" />
+        <local:MyComboBoxItem Content="管道与物流" Tag="415/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="自动化" Tag="4843/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="能源" Tag="417/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="红石" Tag="4558/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="食物与烹饪" Tag="436/food" />
+        <local:MyComboBoxItem Content="农业" Tag="416/" Margin="15,0,0,0" />
+        <local:MyComboBoxItem Content="游戏机制" Tag="/game-mechanics" />
+        <local:MyComboBoxItem Content="运输" Tag="414/transportation" />
+        <local:MyComboBoxItem Content="仓储" Tag="420/storage" />
+        <local:MyComboBoxItem Content="魔法" Tag="419/magic" />
+        <local:MyComboBoxItem Content="冒险" Tag="422/adventure" />
+        <local:MyComboBoxItem Content="装饰" Tag="424/decoration" />
+        <local:MyComboBoxItem Content="生物" Tag="411/mobs" />
+        <local:MyComboBoxItem Content="实用" Tag="5191/utility" />
+        <local:MyComboBoxItem Content="装备与工具" Tag="434/equipment" />
+        <local:MyComboBoxItem Content="性能优化" Tag="/optimization" />
+        <local:MyComboBoxItem Content="信息显示" Tag="423/" />
+        <local:MyComboBoxItem Content="服务器" Tag="435/social" />
+        <local:MyComboBoxItem Content="支持库" Tag="421/library" />
+    </local:PageComp>
+</local:MyPageRight>

+ 2 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadMod.xaml.vb

@@ -0,0 +1,2 @@
+Public Class PageDownloadMod
+End Class

+ 28 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadPack.xaml

@@ -0,0 +1,28 @@
+<local:MyPageRight
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadPack"
+    PanScroll="{Binding ElementName=Content}">
+    <local:PageComp x:Name="Content" PageType="ModPack" TypeName="整合包" TypeNameSpaced="整合包">
+        <local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
+        <local:MyComboBoxItem Tag="4484/" Content="多人" />
+        <local:MyComboBoxItem Tag="/optimization" Content="性能优化" />
+        <local:MyComboBoxItem Tag="4479/challenging" Content="硬核" />
+        <local:MyComboBoxItem Tag="4483/combat" Content="战斗" />
+        <local:MyComboBoxItem Tag="4478/quests" Content="任务" />
+        <local:MyComboBoxItem Tag="4472/technology" Content="科技" />
+        <local:MyComboBoxItem Tag="4473/magic" Content="魔法" />
+        <local:MyComboBoxItem Tag="4475/adventure" Content="冒险" />
+        <local:MyComboBoxItem Tag="/kitchen-sink" Content="水槽包" />
+        <local:MyComboBoxItem Tag="4476/" Content="探索" />
+        <local:MyComboBoxItem Tag="4477/" Content="小游戏" />
+        <local:MyComboBoxItem Tag="4471/" Content="科幻" />
+        <local:MyComboBoxItem Tag="4736/" Content="空岛" />
+        <local:MyComboBoxItem Tag="5128/" Content="原版改良" />
+        <local:MyComboBoxItem Tag="4487/" Content="FTB" ToolTip="由 FTB 官方发布" ToolTipService.HorizontalOffset="70" />
+        <local:MyComboBoxItem Tag="4480/" Content="基于地图" />
+        <local:MyComboBoxItem Tag="4481/lightweight" Content="轻量整合" />
+        <local:MyComboBoxItem Tag="4482/" Content="大型整合" />
+    </local:PageComp>
+</local:MyPageRight>

+ 2 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadPack.xaml.vb

@@ -0,0 +1,2 @@
+Public Class PageDownloadPack
+End Class

+ 45 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadResourcePack.xaml

@@ -0,0 +1,45 @@
+<local:MyPageRight
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadResourcePack"
+    PanScroll="{Binding ElementName=Content}">
+    <local:PageComp x:Name="Content" PageType="ResourcePack" TypeName="资源包" TypeNameSpaced="资源包">
+        <local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
+
+        <local:MyComboBoxItem Content="风格" IsEnabled="False" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="原版风" Tag="403/vanilla-like" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="写实风" Tag="400/realistic" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="现代风" Tag="401/" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="中世纪" Tag="402/" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="蒸汽朋克" Tag="399/" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="主题化" Tag="/themed" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="简洁" Tag="/simplistic" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="装饰" Tag="/decoration" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="战斗" Tag="/combat" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="实用" Tag="/utility" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="改良" Tag="/tweaks" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="神经病" Tag="/cursed" />
+
+        <local:MyComboBoxItem Content="特性" IsEnabled="False" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="含实体" Tag="/entities" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="含声音" Tag="/audio" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="含字体" Tag="5244/fonts" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="含模型" Tag="/models" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="含语言" Tag="/locale" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="含 UI" Tag="/gui" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="核心着色器" Tag="/core-shaders" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="动态效果" Tag="404/" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="兼容 Mod" Tag="4465/modded" />
+
+        <local:MyComboBoxItem Content="分辨率" IsEnabled="False" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="8x 或更低" Tag="/8x-" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="16x" Tag="393/16x" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="32x" Tag="394/32x" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="48x" Tag="/48x" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="64x" Tag="395/64x" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="128x" Tag="396/128x" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="256x" Tag="397/256x" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="512x 或更高" Tag="398/512x+" />
+    </local:PageComp>
+</local:MyPageRight>

+ 2 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadResourcePack.xaml.vb

@@ -0,0 +1,2 @@
+Public Class PageDownloadResourcePack
+End Class

+ 31 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadShader.xaml

@@ -0,0 +1,31 @@
+<local:MyPageRight
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadShader"
+    PanScroll="{Binding ElementName=Content}">
+    <local:PageComp x:Name="Content" PageType="Shader" TypeName="光影包" TypeNameSpaced="光影包">
+        <local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
+        
+        <local:MyComboBoxItem Content="风格" IsEnabled="False" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="原版风" Tag="6555/vanilla-like" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="幻想风" Tag="6554/fantasy" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="写实风" Tag="6553/realistic" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="半写实风" Tag="/semi-realistic" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="卡通风" Tag="/cartoon" />
+
+        <local:MyComboBoxItem Content="特性" IsEnabled="False" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="原版可用" Tag="/vanilla" ToolTip="作为资源包加载,可以直接在原版游戏里使用。" ToolTipService.HorizontalOffset="70" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="彩色光照" Tag="/colored-lighting" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="路径追踪" Tag="/path-tracing" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="PBR" Tag="/pbr" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="反射" Tag="/reflections" />
+
+        <local:MyComboBoxItem Content="性能负荷" IsEnabled="False" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="极低" Tag="/potato" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="低" Tag="/low" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="中" Tag="/medium" />
+        <local:MyComboBoxItem Margin="15,0,0,0" Content="高" Tag="/high" />
+        
+    </local:PageComp>
+</local:MyPageRight>

+ 2 - 0
Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadShader.xaml.vb

@@ -0,0 +1,2 @@
+Public Class PageDownloadShader
+End Class

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

@@ -1188,8 +1188,8 @@ Retry:
                     outputWaitHandle.WaitOne(10000)
                     outputWaitHandle.WaitOne(10000)
                     errorWaitHandle.WaitOne(10000)
                     errorWaitHandle.WaitOne(10000)
                     process.Dispose()
                     process.Dispose()
-                    '检查是否安装成功:最后两行中是否有 true(true 可能在倒数第二行,见 #832)
-                    If LastResults.Last = "true" OrElse (LastResults.Count >= 2 AndAlso LastResults(LastResults.Count - 2) = "true") Then Exit Sub
+                    '检查是否安装成功:最后 5 行中是否有 true(true 可能在倒数数行,见 #832)
+                    If LastResults.Reverse().Take(5).Any(Function(l) l = "true") Then Exit Sub
                     Log(Join(LastResults, vbCrLf))
                     Log(Join(LastResults, vbCrLf))
                     Dim LastLines As String = ""
                     Dim LastLines As String = ""
                     For i As Integer = Math.Max(0, LastResults.Count - 5) To LastResults.Count - 1 '最后 5 行
                     For i As Integer = Math.Max(0, LastResults.Count - 5) To LastResults.Count - 1 '最后 5 行
@@ -1346,7 +1346,7 @@ Retry:
                         Dim Address = McLibGet(OriginalName).Replace(".jar", "-mappings." & Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(1))
                         Dim Address = McLibGet(OriginalName).Replace(".jar", "-mappings." & Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(1))
                         Dim ClientMappings As JToken = RawJson("downloads")("client_mappings")
                         Dim ClientMappings As JToken = RawJson("downloads")("client_mappings")
                         Libs.Add(New McLibToken With {
                         Libs.Add(New McLibToken With {
-                                 .IsJumpLoader = False, .IsNatives = False, .LocalPath = Address, .OriginalName = OriginalName,
+                                 .IsNatives = False, .LocalPath = Address, .OriginalName = OriginalName,
                                  .Url = ClientMappings("url"), .Size = ClientMappings("size"), .SHA1 = ClientMappings("sha1")})
                                  .Url = ClientMappings("url"), .Size = ClientMappings("size"), .SHA1 = ClientMappings("sha1")})
                         Log($"[Download] 需要下载 Mappings:{ClientMappings("url")} (SHA1: {ClientMappings("sha1")})")
                         Log($"[Download] 需要下载 Mappings:{ClientMappings("url")} (SHA1: {ClientMappings("sha1")})")
                     End If
                     End If
@@ -2055,7 +2055,7 @@ Retry:
     ''' 获取合并安装加载器列表,并进行前期的缓存清理与 Java 检查工作。
     ''' 获取合并安装加载器列表,并进行前期的缓存清理与 Java 检查工作。
     ''' </summary>
     ''' </summary>
     ''' <exception cref="CancelledException" />
     ''' <exception cref="CancelledException" />
-    Public Function McInstallLoader(Request As McInstallRequest, Optional DontFixLibraries As Boolean = False) As List(Of LoaderBase)
+    Public Function McInstallLoader(Request As McInstallRequest) As List(Of LoaderBase)
         '获取缓存目录(安装 Mod 加载器的文件夹不能包含空格)
         '获取缓存目录(安装 Mod 加载器的文件夹不能包含空格)
         Dim TempMcFolder As String = RequestTaskTempFolder(Request.OptiFineEntry IsNot Nothing OrElse Request.ForgeEntry IsNot Nothing OrElse Request.NeoForgeEntry IsNot Nothing)
         Dim TempMcFolder As String = RequestTaskTempFolder(Request.OptiFineEntry IsNot Nothing OrElse Request.ForgeEntry IsNot Nothing OrElse Request.NeoForgeEntry IsNot Nothing)
 
 
@@ -2086,17 +2086,13 @@ Retry:
         Dim LiteLoaderFolder As String = Nothing
         Dim LiteLoaderFolder As String = Nothing
         If Request.LiteLoaderEntry IsNot Nothing Then LiteLoaderFolder = TempMcFolder & "versions\" & Request.MinecraftName & "-LiteLoader"
         If Request.LiteLoaderEntry IsNot Nothing Then LiteLoaderFolder = TempMcFolder & "versions\" & Request.MinecraftName & "-LiteLoader"
 
 
-        '决定版本隔离情况(#5970)
-        Dim Modable As Boolean = Request.FabricVersion IsNot Nothing OrElse Request.ForgeEntry IsNot Nothing OrElse Request.NeoForgeEntry IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing
-        Dim Version As New McVersion(VersionFolder)
-        Version.InitPathIndie(Modable)
-        Dim ModsFolder As String = If(Modable, VersionFolder, PathMcFolder) & "mods\"
-
         '判断 OptiFine 是否作为 Mod 进行下载
         '判断 OptiFine 是否作为 Mod 进行下载
+        Dim Modable As Boolean = Request.FabricVersion IsNot Nothing OrElse Request.ForgeEntry IsNot Nothing OrElse Request.NeoForgeEntry IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing
+        Dim ModsTempFolder As String = TempMcFolder & "mods\"
         Dim OptiFineAsMod As Boolean = Request.OptiFineEntry IsNot Nothing AndAlso Modable '选择了 OptiFine 与任意 Mod 加载器
         Dim OptiFineAsMod As Boolean = Request.OptiFineEntry IsNot Nothing AndAlso Modable '选择了 OptiFine 与任意 Mod 加载器
         If OptiFineAsMod Then
         If OptiFineAsMod Then
             Log("[Download] OptiFine 将作为 Mod 进行下载")
             Log("[Download] OptiFine 将作为 Mod 进行下载")
-            OptiFineFolder = ModsFolder
+            OptiFineFolder = ModsTempFolder
         End If
         End If
 
 
         '记录日志
         '记录日志
@@ -2118,57 +2114,67 @@ Retry:
         LoaderList.Add(New LoaderTask(Of Integer, Integer)("添加忽略标识", Sub() WriteFile(VersionFolder & ".pclignore", "用于临时地在 PCL 的版本列表中屏蔽此版本。")) With {.Show = False, .Block = False})
         LoaderList.Add(New LoaderTask(Of Integer, Integer)("添加忽略标识", Sub() WriteFile(VersionFolder & ".pclignore", "用于临时地在 PCL 的版本列表中屏蔽此版本。")) With {.Show = False, .Block = False})
         'Fabric API
         'Fabric API
         If Request.FabricApi IsNot Nothing Then
         If Request.FabricApi IsNot Nothing Then
-            LoaderList.Add(New LoaderDownload("下载 Fabric API", New List(Of NetFile) From {Request.FabricApi.ToNetFile(ModsFolder)}) With {.ProgressWeight = 3, .Block = False})
+            LoaderList.Add(New LoaderDownload("下载 Fabric API", New List(Of NetFile) From {Request.FabricApi.ToNetFile(ModsTempFolder)}) With {.ProgressWeight = 3, .Block = False})
         End If
         End If
         'OptiFabric
         'OptiFabric
         If Request.OptiFabric IsNot Nothing Then
         If Request.OptiFabric IsNot Nothing Then
-            LoaderList.Add(New LoaderDownload("下载 OptiFabric", New List(Of NetFile) From {Request.OptiFabric.ToNetFile(ModsFolder)}) With {.ProgressWeight = 3, .Block = False})
+            LoaderList.Add(New LoaderDownload("下载 OptiFabric", New List(Of NetFile) From {Request.OptiFabric.ToNetFile(ModsTempFolder)}) With {.ProgressWeight = 3, .Block = False})
         End If
         End If
         '原版
         '原版
-        Dim ClientLoader = New LoaderCombo(Of String)("下载原版 " & Request.MinecraftName, McDownloadClientLoader(Request.MinecraftName, Request.MinecraftJson, Request.TargetVersionName)) With {.Show = False, .ProgressWeight = 39, .Block = Request.ForgeVersion Is Nothing AndAlso Request.OptiFineEntry Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing}
+        Dim ClientLoader = New LoaderCombo(Of String)("下载原版 " & Request.MinecraftName, McDownloadClientLoader(Request.MinecraftName, Request.MinecraftJson, Request.TargetVersionName)) With {.Show = False, .ProgressWeight = 39,
+            .Block = Request.ForgeVersion Is Nothing AndAlso Request.NeoForgeVersion Is Nothing AndAlso Request.OptiFineEntry Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing}
         LoaderList.Add(ClientLoader)
         LoaderList.Add(ClientLoader)
         'OptiFine
         'OptiFine
         If Request.OptiFineEntry IsNot Nothing Then
         If Request.OptiFineEntry IsNot Nothing Then
             If OptiFineAsMod Then
             If OptiFineAsMod Then
-                LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineSaveLoader(Request.OptiFineEntry, OptiFineFolder & Request.OptiFineEntry.NameFile)) With {.Show = False, .ProgressWeight = 16, .Block = Request.ForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
+                LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineSaveLoader(Request.OptiFineEntry, OptiFineFolder & Request.OptiFineEntry.NameFile)) With {.Show = False, .ProgressWeight = 16,
+                    .Block = Request.ForgeVersion Is Nothing AndAlso Request.NeoForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
             Else
             Else
-                LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineLoader(Request.OptiFineEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) With {.Show = False, .ProgressWeight = 24, .Block = Request.ForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
+                LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineLoader(Request.OptiFineEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) With {.Show = False, .ProgressWeight = 24,
+                    .Block = Request.ForgeVersion Is Nothing AndAlso Request.NeoForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
             End If
             End If
         End If
         End If
         'Forge
         'Forge
         If Request.ForgeVersion IsNot Nothing Then
         If Request.ForgeVersion IsNot Nothing Then
-            LoaderList.Add(New LoaderCombo(Of String)("下载 Forge " & Request.ForgeVersion, McDownloadForgelikeLoader(False, Request.ForgeVersion, "forge-" & Request.ForgeVersion, Request.MinecraftName, Request.ForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder)) With {.Show = False, .ProgressWeight = 25, .Block = Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing AndAlso Request.NeoForgeEntry Is Nothing})
+            LoaderList.Add(New LoaderCombo(Of String)("下载 Forge " & Request.ForgeVersion, McDownloadForgelikeLoader(False, Request.ForgeVersion, "forge-" & Request.ForgeVersion, Request.MinecraftName, Request.ForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder)) With {.Show = False, .ProgressWeight = 25,
+                .Block = Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing AndAlso Request.NeoForgeEntry Is Nothing})
         End If
         End If
         'NeoForge
         'NeoForge
         If Request.NeoForgeVersion IsNot Nothing Then
         If Request.NeoForgeVersion IsNot Nothing Then
-            LoaderList.Add(New LoaderCombo(Of String)("下载 NeoForge " & Request.NeoForgeVersion, McDownloadForgelikeLoader(True, Request.NeoForgeVersion, "neoforge-" & Request.NeoForgeVersion, Request.MinecraftName, Request.NeoForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder)) With {.Show = False, .ProgressWeight = 25, .Block = Request.ForgeEntry Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
+            LoaderList.Add(New LoaderCombo(Of String)("下载 NeoForge " & Request.NeoForgeVersion, McDownloadForgelikeLoader(True, Request.NeoForgeVersion, "neoforge-" & Request.NeoForgeVersion, Request.MinecraftName, Request.NeoForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder)) With {.Show = False, .ProgressWeight = 25,
+                .Block = Request.ForgeEntry Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
         End If
         End If
         'LiteLoader
         'LiteLoader
         If Request.LiteLoaderEntry IsNot Nothing Then
         If Request.LiteLoaderEntry IsNot Nothing Then
-            LoaderList.Add(New LoaderCombo(Of String)("下载 LiteLoader " & Request.MinecraftName, McDownloadLiteLoaderLoader(Request.LiteLoaderEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 1, .Block = Request.FabricVersion Is Nothing})
+            LoaderList.Add(New LoaderCombo(Of String)("下载 LiteLoader " & Request.MinecraftName, McDownloadLiteLoaderLoader(Request.LiteLoaderEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 1,
+                .Block = Request.FabricVersion Is Nothing})
         End If
         End If
         'Fabric
         'Fabric
         If Request.FabricVersion IsNot Nothing Then
         If Request.FabricVersion IsNot Nothing Then
-            LoaderList.Add(New LoaderCombo(Of String)("下载 Fabric " & Request.FabricVersion, McDownloadFabricLoader(Request.FabricVersion, Request.MinecraftName, TempMcFolder, False)) With {.Show = False, .ProgressWeight = 2, .Block = True})
+            LoaderList.Add(New LoaderCombo(Of String)("下载 Fabric " & Request.FabricVersion, McDownloadFabricLoader(Request.FabricVersion, Request.MinecraftName, TempMcFolder, False)) With {.Show = False, .ProgressWeight = 2,
+                .Block = True})
         End If
         End If
         '合并安装
         '合并安装
         LoaderList.Add(New LoaderTask(Of String, String)("安装游戏",
         LoaderList.Add(New LoaderTask(Of String, String)("安装游戏",
-            Sub(Task As LoaderTask(Of String, String))
-                InstallMerge(VersionFolder, VersionFolder, OptiFineFolder, OptiFineAsMod, ForgeFolder, Request.ForgeVersion, NeoForgeFolder, Request.NeoForgeVersion, FabricFolder, LiteLoaderFolder)
-                Task.Progress = 0.3
-                If Directory.Exists(TempMcFolder & "libraries") Then CopyDirectory(TempMcFolder & "libraries", PathMcFolder & "libraries")
-                If Directory.Exists(TempMcFolder & "mods") Then CopyDirectory(TempMcFolder & "mods", ModsFolder)
-                '新建 mods 文件夹
-                If Request.ForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.NeoForgeEntry IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing Then
-                    Directory.CreateDirectory(ModsFolder)
-                    Log("[Download] 自动创建 mods 文件夹:" & ModsFolder)
-                End If
-            End Sub) With {.ProgressWeight = 2, .Block = True})
+        Sub(Task As LoaderTask(Of String, String))
+            '合并 JSON
+            MergeJson(VersionFolder, VersionFolder, OptiFineFolder, OptiFineAsMod, ForgeFolder, Request.ForgeVersion, NeoForgeFolder, Request.NeoForgeVersion, FabricFolder, LiteLoaderFolder)
+            Task.Progress = 0.2
+            '迁移文件
+            If Directory.Exists(TempMcFolder & "libraries") Then CopyDirectory(TempMcFolder & "libraries", PathMcFolder & "libraries")
+            Task.Progress = 0.8
+            Dim ModsFolder = New McVersion(VersionFolder).PathIndie & "mods\" '版本隔离信息在此时被决定
+            If Directory.Exists(ModsTempFolder) Then
+                CopyDirectory(ModsTempFolder, ModsFolder)
+            ElseIf Modable Then
+                Directory.CreateDirectory(ModsFolder)
+                Log("[Download] 自动创建 mods 文件夹:" & ModsFolder)
+            End If
+        End Sub) With {.ProgressWeight = 2, .Block = True})
         '补全文件
         '补全文件
-        If Not DontFixLibraries AndAlso
-        (Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.BeforeFirst(".") >= 20) OrElse Request.NeoForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing) Then
+        If Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.BeforeFirst(".") >= 20) OrElse Request.NeoForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing Then
             Dim LoadersLib As New List(Of LoaderBase)
             Dim LoadersLib As New List(Of LoaderBase)
-            LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
+            LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
             LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
             LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
             LoaderList.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
             LoaderList.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
         End If
         End If
@@ -2179,9 +2185,9 @@ Retry:
     End Function
     End Function
 
 
     ''' <summary>
     ''' <summary>
-    ''' 将多个版本 Json 进行合并,如果目标已存在则直接覆盖。失败会抛出异常。
+    ''' 将多个版本 JSON 进行合并,如果目标已存在则直接覆盖。失败会抛出异常。
     ''' </summary>
     ''' </summary>
-    Private Sub InstallMerge(OutputFolder As String, MinecraftFolder As String, Optional OptiFineFolder As String = Nothing, Optional OptiFineAsMod As Boolean = False, Optional ForgeFolder As String = Nothing, Optional ForgeVersion As String = Nothing, Optional NeoForgeFolder As String = Nothing, Optional NeoForgeVersion As String = Nothing, Optional FabricFolder As String = Nothing, Optional LiteLoaderFolder As String = Nothing)
+    Private Sub MergeJson(OutputFolder As String, MinecraftFolder As String, Optional OptiFineFolder As String = Nothing, Optional OptiFineAsMod As Boolean = False, Optional ForgeFolder As String = Nothing, Optional ForgeVersion As String = Nothing, Optional NeoForgeFolder As String = Nothing, Optional NeoForgeVersion As String = Nothing, Optional FabricFolder As String = Nothing, Optional LiteLoaderFolder As String = Nothing)
         Log("[Download] 开始进行版本合并,输出:" & OutputFolder & ",Minecraft:" & MinecraftFolder &
         Log("[Download] 开始进行版本合并,输出:" & OutputFolder & ",Minecraft:" & MinecraftFolder &
             If(OptiFineFolder IsNot Nothing, ",OptiFine:" & OptiFineFolder, "") &
             If(OptiFineFolder IsNot Nothing, ",OptiFine:" & OptiFineFolder, "") &
             If(ForgeFolder IsNot Nothing, ",Forge:" & ForgeFolder, "") &
             If(ForgeFolder IsNot Nothing, ",Forge:" & ForgeFolder, "") &

+ 0 - 111
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadDataPack.xaml

@@ -1,111 +0,0 @@
-<local:MyPageRight
-    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-    mc:Ignorable="d" x:Class="PageDownloadDataPack"
-    PanScroll="{Binding ElementName=PanBack}">
-    <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
-        <StackPanel Orientation="Vertical" Margin="25">
-            <local:MyCard Title="搜索数据包" Margin="0,0,0,15" x:Name="PanAlways">
-                <StackPanel Margin="25,40,25,15">
-                    <Grid Margin="0,0,0,11" HorizontalAlignment="Stretch">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="2.5*" />
-                            <ColumnDefinition Width="50" />
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="1*" />
-                        </Grid.ColumnDefinitions>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="28" />
-                            <RowDefinition Height="9" />
-                            <RowDefinition Height="28" />
-                        </Grid.RowDefinitions>
-                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,18,0" />
-                        <local:MyTextBox x:Name="TextSearchName" Grid.Column="1" />
-                        <TextBlock VerticalAlignment="Center" Grid.Column="3" HorizontalAlignment="Left" Text="来源" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchSource" Grid.Column="4">
-                            <local:MyComboBoxItem Content="全部" Tag="3" IsSelected="True" />
-                            <local:MyComboBoxItem Content="CurseForge" Tag="1" />
-                            <local:MyComboBoxItem Content="Modrinth" Tag="2" />
-                        </local:MyComboBox>
-                        <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" IsEditable="True" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
-                            <local:MyComboBoxItem Content="1.20.6" />
-                            <local:MyComboBoxItem Content="1.20.4" />
-                            <local:MyComboBoxItem Content="1.20.1" />
-                            <local:MyComboBoxItem Content="1.19.4" />
-                            <local:MyComboBoxItem Content="1.19.2" />
-                            <local:MyComboBoxItem Content="1.18.2" />
-                            <local:MyComboBoxItem Content="1.17.1" />
-                            <local:MyComboBoxItem Content="1.16.5" />
-                            <local:MyComboBoxItem Content="1.15.2" />
-                            <local:MyComboBoxItem Content="1.14.4" />
-                            <local:MyComboBoxItem Content="1.12.2" />
-                            <local:MyComboBoxItem Content="1.11.2" />
-                            <local:MyComboBoxItem Content="1.10.2" />
-                            <local:MyComboBoxItem Content="1.8.9" />
-                            <local:MyComboBoxItem Content="1.7.10" />
-                        </local:MyComboBox>
-                        <TextBlock VerticalAlignment="Center" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="4" Grid.Row="2" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
-                            <local:MyComboBoxItem Content="冒险" Tag="6948/adventure" />
-                            <local:MyComboBoxItem Content="Cursed" Tag="/cursed" />
-                            <local:MyComboBoxItem Content="装饰" Tag="6554/decoration" />
-                            <local:MyComboBoxItem Content="经济" Tag="6553/economy" />
-                            <local:MyComboBoxItem Content="装备" Tag="/equipment" />
-                            <local:MyComboBoxItem Content="食物" Tag="6555/food" />
-                            <local:MyComboBoxItem Content="游戏机制" Tag="/game-mechanics" />
-                            <local:MyComboBoxItem Content="支持库" Tag="6950/library" />
-                            <local:MyComboBoxItem Content="魔法" Tag="6952/magic" />
-                            <local:MyComboBoxItem Content="管理" Tag="/management" />
-                            <local:MyComboBoxItem Content="小游戏" Tag="/minigame" />
-                            <local:MyComboBoxItem Content="生物" Tag="/mobs" />
-                            <local:MyComboBoxItem Content="优化" Tag="/optimization" />
-                            <local:MyComboBoxItem Content="社交" Tag="/social" />
-                            <local:MyComboBoxItem Content="存储" Tag="/storage" />
-                            <local:MyComboBoxItem Content="科技" Tag="6951/technology" />
-                            <local:MyComboBoxItem Content="交通" Tag="/transportation" />
-                            <local:MyComboBoxItem Content="实用工具" Tag="6953/utility" />
-                            <local:MyComboBoxItem Content="世界生成" Tag="/worldgen" />
-                            <local:MyComboBoxItem Content="Mod 支持" Tag="6946/" />
-                            <local:MyComboBoxItem Content="杂项" Tag="6947/" />
-                            <local:MyComboBoxItem Content="幻想" Tag="6949/" />
-                        </local:MyComboBox>
-                    </Grid>
-                    <Grid Margin="0,4,0,6" Height="35">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                        </Grid.ColumnDefinitions>
-                        <local:MyButton x:Name="BtnSearchRun" Text="搜索" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
-                        <local:MyButton x:Name="BtnSearchReset" Text="重置条件" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="1" />
-                    </Grid>
-                </StackPanel>
-            </local:MyCard>
-            <StackPanel x:Name="PanContent">
-                <local:MyHint x:Name="HintError" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,结果可能不全。&#xa;请尝试使用 VPN 或加速器以改善网络。" IsWarn="True" Margin="0,0,0,15" />
-                <local:MyCard x:Name="CardProjects" UseAnimation="False">
-                    <StackPanel x:Name="PanProjects" Margin="12" />
-                </local:MyCard>
-                <local:MyCard Margin="0,15,0,0" x:Name="CardPages" HorizontalAlignment="Center">
-                    <StackPanel Orientation="Horizontal" Height="23" Margin="10,7">
-                        <local:MyIconButton x:Name="BtnPageFirst" IsEnabled="False" Opacity="0.2" Margin="0,0.5,5,0.5"
-                            Logo="M496.213333 329.856L315.306667 510.848l180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z m298.666667 0l-180.949333 180.992 180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z" />
-                        <local:MyIconButton x:Name="BtnPageLeft" IsEnabled="False" Opacity="0.2" Margin="0,0,5,0"
-                            Logo="M650.752 278.357333l-241.322667 241.365334 241.322667 241.365333a42.666667 42.666667 0 1 1-60.330667 60.330667l-271.530666-271.530667a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.416-27.648l271.530666-271.530666a42.666667 42.666667 0 0 1 60.330667 60.330666z" />
-                        <TextBlock x:Name="LabPage" Text="1" 
-                                   Margin="8,0,13,0" FontSize="15" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush3}" />
-                        <local:MyIconButton x:Name="BtnPageRight" Margin="0,0,30,0"
-                            Logo="M404.309333 278.357333l241.322667 241.365334-241.322667 241.365333a42.666667 42.666667 0 1 0 60.330667 60.330667l271.530667-271.530667a42.453333 42.453333 0 0 0 11.818666-22.613333l0.597334-5.034667v-5.034667a42.496 42.496 0 0 0-12.416-27.648L464.64 218.026667a42.666667 42.666667 0 0 0-60.330667 60.330666z" />
-                    </StackPanel>
-                </local:MyCard>
-            </StackPanel>
-            <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
-                <local:MyLoading Text="正在获取数据包列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
-            </local:MyCard>
-        </StackPanel>
-    </local:MyScrollViewer>
-</local:MyPageRight>

+ 0 - 122
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadDataPack.xaml.vb

@@ -1,122 +0,0 @@
-Public Class PageDownloadDataPack
-
-    Public Const PageSize = 40
-
-    '加载器信息
-    Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject Shader", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
-    Public Shared Storage As New CompProjectStorage
-    Public Shared Page As Integer = 0
-    Private Sub PageDownloadShader_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
-        PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
-        If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
-    End Sub
-    Private Shared Function LoaderInput() As CompProjectRequest
-        Dim Request As New CompProjectRequest(CompType.DataPack, Storage, (Page + 1) * PageSize)
-        If FrmDownloadDataPack IsNot Nothing Then
-            With Request
-                .SearchText = FrmDownloadDataPack.TextSearchName.Text
-                .GameVersion = If(FrmDownloadDataPack.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
-                    If(FrmDownloadDataPack.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadDataPack.TextSearchVersion.Text.Contains("w"), FrmDownloadDataPack.TextSearchVersion.Text, Nothing))
-                .Tag = FrmDownloadDataPack.ComboSearchTag.SelectedItem.Tag
-                .Source = CType(Val(FrmDownloadDataPack.ComboSearchSource.SelectedItem.Tag), CompSourceType)
-            End With
-        End If
-        Return Request
-    End Function
-
-    '结果 UI 化
-    Private Sub Load_OnFinish()
-        Try
-            Log($"[Comp] 开始可视化数据包列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
-            '列表项
-            PanProjects.Children.Clear()
-            For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
-                PanProjects.Children.Add(Storage.Results(i).ToCompItem(Loader.Input.GameVersion Is Nothing, False))
-            Next
-            '页码
-            CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
-                                      Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal,
-                                      Visibility.Visible, Visibility.Collapsed)
-            LabPage.Text = Page + 1
-            BtnPageFirst.IsEnabled = Page > 1
-            BtnPageFirst.Opacity = If(BtnPageFirst.IsEnabled, 1, 0.2)
-            BtnPageLeft.IsEnabled = Page > 0
-            BtnPageLeft.Opacity = If(BtnPageLeft.IsEnabled, 1, 0.2)
-            BtnPageRight.IsEnabled = Storage.Results.Count > PageSize * (Page + 1) OrElse
-                                     Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal
-            BtnPageRight.Opacity = If(BtnPageRight.IsEnabled, 1, 0.2)
-            '错误信息
-            If Storage.ErrorMessage Is Nothing Then
-                HintError.Visibility = Visibility.Collapsed
-            Else
-                HintError.Visibility = Visibility.Visible
-                HintError.Text = Storage.ErrorMessage
-            End If
-            '强制返回顶部
-            PanBack.ScrollToTop()
-        Catch ex As Exception
-            Log(ex, "可视化数据包列表出错", LogLevel.Feedback)
-        End Try
-    End Sub
-
-    '自动重试
-    Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
-        Select Case Loader.State
-            Case LoadState.Failed
-                Dim ErrorMessage As String = ""
-                If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
-                If ErrorMessage.Contains("不是有效的 JSON 文件") Then
-                    Log("[Download] 下载的数据包列表 JSON 文件损坏,已自动重试", LogLevel.Debug)
-                    PageLoaderRestart()
-                End If
-        End Select
-    End Sub
-
-    '切换页码
-
-    Private Sub BtnPageFirst_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageFirst.Click
-        ChangePage(0)
-    End Sub
-    Private Sub BtnPageLeft_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageLeft.Click
-        ChangePage(Page - 1)
-    End Sub
-    Private Sub BtnPageRight_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageRight.Click
-        ChangePage(Page + 1)
-    End Sub
-    Private Sub ChangePage(NewPage As Integer)
-        CardPages.IsEnabled = False
-        Page = NewPage
-        FrmMain.BackToTop()
-        Log($"[Download] 数据包切换到第 {Page + 1} 页")
-        RunInThread(Sub()
-                        Thread.Sleep(100) '等待向上滚的动画结束
-                        RunInUi(Sub() CardPages.IsEnabled = True)
-                        Loader.Start()
-                    End Sub)
-    End Sub
-
-#Region "搜索"
-
-    '搜索按钮
-    Private Sub StartNewSearch() Handles BtnSearchRun.Click
-        Page = 0
-        If Loader.ShouldStart(LoaderInput()) Then Storage = New CompProjectStorage '避免连续搜索两次使得 CompProjectStorage 引用丢失(#1311)
-        Loader.Start()
-    End Sub
-    Private Sub EnterTrigger(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyDown, TextSearchVersion.KeyDown
-        If e.Key = Key.Enter Then StartNewSearch()
-    End Sub
-
-    '重置按钮
-    Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click
-        TextSearchName.Text = ""
-        TextSearchVersion.Text = "全部 (也可自行输入)"
-        TextSearchVersion.SelectedIndex = 0
-        ComboSearchSource.SelectedIndex = 0
-        ComboSearchTag.SelectedIndex = 0
-        Loader.LastFinishedTime = 0 '要求强制重新开始
-    End Sub
-
-#End Region
-
-End Class

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

@@ -101,12 +101,12 @@
                 FabricApi_Loaded()
                 FabricApi_Loaded()
                 OptiFabric_Loaded()
                 OptiFabric_Loaded()
                 SelectReload()
                 SelectReload()
+                PanMinecraft.Visibility = Visibility.Collapsed
             End Sub, After:=True),
             End Sub, After:=True),
             AaOpacity(PanSelect, 1 - PanSelect.Opacity, 90, 100),
             AaOpacity(PanSelect, 1 - PanSelect.Opacity, 90, 100),
             AaTranslateX(PanSelect, -CType(PanSelect.RenderTransform, TranslateTransform).X, 200, 100, Ease:=New AniEaseOutFluent(AniEasePower.ExtraStrong)),
             AaTranslateX(PanSelect, -CType(PanSelect.RenderTransform, TranslateTransform).X, 200, 100, Ease:=New AniEaseOutFluent(AniEasePower.ExtraStrong)),
             AaCode(
             AaCode(
             Sub()
             Sub()
-                PanMinecraft.Visibility = Visibility.Collapsed
                 PanBack.IsHitTestVisible = True
                 PanBack.IsHitTestVisible = True
                 '初始化 Binding
                 '初始化 Binding
                 If IsFirstLoaded Then Exit Sub
                 If IsFirstLoaded Then Exit Sub
@@ -1254,9 +1254,9 @@
         '确认版本隔离
         '确认版本隔离
         If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
         If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
            (Setup.Get("LaunchArgumentIndieV2") = 0 OrElse Setup.Get("LaunchArgumentIndieV2") = 2) Then
            (Setup.Get("LaunchArgumentIndieV2") = 0 OrElse Setup.Get("LaunchArgumentIndieV2") = 2) Then
-            If MyMsgBox("你尚未开启版本隔离,这会导致多个版本共用同一个 Mod 文件夹。" & vbCrLf &
-                        "因此游戏可能会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
-                        "推荐在开始下载前,在 设置 → 启动选项 → 版本隔离 中开启版本隔离!", "版本隔离提示", "取消下载", "继续") = 1 Then
+            If MyMsgBox("你尚未开启版本隔离,多个 MC 版本会共用同一个 Mod 文件夹。" & vbCrLf &
+                        "因此,游戏可能会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
+                        "推荐先在 设置 → 启动选项 → 默认版本隔离 中开启版本隔离!", "版本隔离提示", "取消下载", "继续") = 1 Then
                 Exit Sub
                 Exit Sub
             End If
             End If
         End If
         End If

+ 32 - 32
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml

@@ -71,38 +71,38 @@
             <TextBlock Text="社区资源" Margin="13,30,5,4" Opacity="0.6" FontSize="12" />
             <TextBlock Text="社区资源" Margin="13,30,5,4" Opacity="0.6" FontSize="12" />
             <local:MyListItem x:Name="ItemMod" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="11" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod"
             <local:MyListItem x:Name="ItemMod" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="11" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod"
                           LogoScale="0.97" Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z">
                           LogoScale="0.97" Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z">
-            <local:MyListItem.Buttons>
-                <x:Array Type="{x:Type local:MyIconButton}">
-                    <local:MyIconButton Tag="11" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
-                </x:Array>
-            </local:MyListItem.Buttons>
-        </local:MyListItem>
-        <local:MyListItem x:Name="ItemPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="12" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="整合包"
-                          LogoScale="0.98" Logo="M511.488 995.328a128.654222 128.654222 0 0 1-57.116444-13.112889L70.769778 791.808a126.833778 126.833778 0 0 1-70.769778-113.777778V311.608889a126.179556 126.179556 0 0 1 15.36-60.103111V248.604444c1.479111-2.901333 3.356444-5.603556 5.518222-8.021333a127.630222 127.630222 0 0 1 49.891556-42.325333L454.371556 13.368889a128.739556 128.739556 0 0 1 112.981333 0l383.601778 190.407111a126.862222 126.862222 0 0 1 72.049777 113.379556v360.874666a126.805333 126.805333 0 0 1-70.769777 115.939556L568.604444 984.32c-17.92 7.964444-37.461333 11.747556-57.116444 11.008z m42.638222-470.897778v370.204445l360.192-178.545778c14.449778-7.253333 23.552-21.987556 23.438222-38.087111v-335.928889L554.097778 524.430222zM85.248 330.666667v347.335111a42.268444 42.268444 0 0 0 23.438222 38.087111l360.192 178.545778V523.576889L85.248 330.666667zM135.537778 260.835556l375.950222 189.952 137.671111-65.564445L286.435556 188.074667 135.537778 260.864z m245.105778-118.471112l363.576888 197.973334 150.897778-71.480889-365.283555-180.224a42.922667 42.922667 0 0 0-37.518223 0l-111.672888 53.731555z">
-            <local:MyListItem.Buttons>
-                <x:Array Type="{x:Type local:MyIconButton}">
-                    <local:MyIconButton Tag="12" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
-                </x:Array>
-            </local:MyListItem.Buttons>
-        </local:MyListItem>
-        <local:MyListItem x:Name="ItemResourcePack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="13" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="资源包"
-                  LogoScale="0.98" Logo="M913.066667 264.533333l-371.2-209.066666c-25.6-12.8-59.733333-12.8-85.333334 0L89.6 264.533333C34.133333 298.666667 34.133333 379.733333 89.6 413.866667l371.2 209.066666c25.6 12.8 59.733333 12.8 85.333333 0l371.2-209.066666c55.466667-34.133333 55.466667-119.466667-4.266666-149.333334z m-413.866667 281.6L132.266667 337.066667 499.2 128l371.2 209.066667-371.2 209.066666z M46.933333 516.266667c12.8-21.333333 38.4-25.6 59.733334-17.066667l384 221.866667c12.8 8.533333 29.866667 8.533333 42.666666 0l388.266667-217.6c21.333333-12.8 46.933333-4.266667 59.733333 17.066666 12.8 21.333333 4.266667 46.933333-17.066666 59.733334l-388.266667 217.6c-38.4 21.333333-89.6 21.333333-128 0l-384-221.866667c-21.333333-12.8-25.6-38.4-17.066667-59.733333z M106.666667 669.866667c-21.333333-12.8-46.933333-4.266667-59.733334 17.066666-12.8 21.333333-4.266667 46.933333 17.066667 59.733334l388.266667 217.6c38.4 21.333333 85.333333 21.333333 128 0l379.733333-217.6c21.333333-12.8 25.6-38.4 17.066667-59.733334-12.8-21.333333-38.4-25.6-59.733334-17.066666l-379.733333 217.6c-12.8 8.533333-29.866667 8.533333-42.666667 0l-388.266666-217.6z">
-            <local:MyListItem.Buttons>
-                <x:Array Type="{x:Type local:MyIconButton}">
-                    <local:MyIconButton Tag="13" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
-                </x:Array>
-            </local:MyListItem.Buttons>
-        </local:MyListItem>
-        <local:MyListItem x:Name="ItemShader" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="14" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="光影包"
-              LogoScale="0.98" Logo="M640 810.666667 384 810.666667c-25.6 0-42.666667-17.066667-42.666667-42.666667l0-21.333333c0-59.733333-25.6-119.466667-72.533333-166.4C200.533333 512 166.4 422.4 170.666667 328.533333 179.2 149.333333 328.533333 4.266667 507.733333 0L512 0c187.733333 0 341.333333 153.6 341.333333 341.333333 0 89.6-34.133333 179.2-102.4 243.2-46.933333 42.666667-68.266667 102.4-68.266667 162.133333L682.666667 768C682.666667 793.6 665.6 810.666667 640 810.666667zM426.666667 725.333333l170.666667 0c4.266667-76.8 38.4-145.066667 93.866667-204.8C742.4 473.6 768 409.6 768 341.333333c0-140.8-115.2-256-256-256l-4.266667 0C375.466667 89.6 260.266667 196.266667 256 332.8 251.733333 401.066667 281.6 469.333333 328.533333 520.533333 388.266667 580.266667 422.4 652.8 426.666667 725.333333z M512 1024 512 1024c-93.866667 0-170.666667-76.8-170.666667-170.666667l0-85.333333c0-25.6 17.066667-42.666667 42.666667-42.666667l256 0c25.6 0 42.666667 17.066667 42.666667 42.666667l0 85.333333C682.666667 947.2 605.866667 1024 512 1024zM426.666667 810.666667l0 42.666667c0 46.933333 38.4 85.333333 85.333333 85.333333L512 938.666667c46.933333 0 85.333333-38.4 85.333333-85.333333l0-42.666667L426.666667 810.666667z M384 384C358.4 384 341.333333 366.933333 341.333333 341.333333c0-93.866667 76.8-170.666667 170.666667-170.666667 25.6 0 42.666667 17.066667 42.666667 42.666667s-17.066667 42.666667-42.666667 42.666667c-46.933333 0-85.333333 38.4-85.333333 85.333333C426.666667 366.933333 409.6 384 384 384z">
-            <local:MyListItem.Buttons>
-                <x:Array Type="{x:Type local:MyIconButton}">
-                    <local:MyIconButton Tag="14" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
-                </x:Array>
-            </local:MyListItem.Buttons>
-        </local:MyListItem>
-            <local:MyListItem x:Name="ItemDataPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="15" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="数据包"
-              LogoScale="0.98" Logo="M511.488 995.328a128.654222 128.654222 0 0 1-57.116444-13.112889L70.769778 791.808a126.833778 126.833778 0 0 1-70.769778-113.777778V311.608889a126.179556 126.179556 0 0 1 15.36-60.103111V248.604444c1.479111-2.901333 3.356444-5.603556 5.518222-8.021333a127.630222 127.630222 0 0 1 49.891556-42.325333L454.371556 13.368889a128.739556 128.739556 0 0 1 112.981333 0l383.601778 190.407111a126.862222 126.862222 0 0 1 72.049777 113.379556v360.874666a126.805333 126.805333 0 0 1-70.769777 115.939556L568.604444 984.32c-17.92 7.964444-37.461333 11.747556-57.116444 11.008z m42.638222-470.897778v370.204445l360.192-178.545778c14.449778-7.253333 23.552-21.987556 23.438222-38.087111v-335.928889L554.097778 524.430222zM85.248 330.666667v347.335111a42.268444 42.268444 0 0 0 23.438222 38.087111l360.192 178.545778V523.576889L85.248 330.666667zM135.537778 260.835556l375.950222 189.952 137.671111-65.564445L286.435556 188.074667 135.537778 260.864z m245.105778-118.471112l363.576888 197.973334 150.897778-71.480889-365.283555-180.224a42.922667 42.922667 0 0 0-37.518223 0l-111.672888 53.731555z">
+                <local:MyListItem.Buttons>
+                    <x:Array Type="{x:Type local:MyIconButton}">
+                        <local:MyIconButton Tag="11" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
+                    </x:Array>
+                </local:MyListItem.Buttons>
+            </local:MyListItem>
+            <local:MyListItem x:Name="ItemPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="12" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="整合包"
+                          LogoScale="0.98" 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">
+                <local:MyListItem.Buttons>
+                    <x:Array Type="{x:Type local:MyIconButton}">
+                        <local:MyIconButton Tag="12" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
+                    </x:Array>
+                </local:MyListItem.Buttons>
+            </local:MyListItem>
+            <local:MyListItem x:Name="ItemDataPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="13" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="数据包"
+                  LogoScale="0.96" Logo="M445 545c18 0 33 14 33 33v149a182 182 0 1 1-182-182z m282 0a182 182 0 1 1-182 182v-149c0-18 14-33 33-33zM412 611H296a116 116 0 1 0 116 116V611z m315 0H611v116a116 116 0 1 0 116-116zM296 113a182 182 0 0 1 182 182v149a33 33 0 0 1-33 33H296a182 182 0 0 1 0-365z m431 0a182 182 0 0 1 0 365h-149a33 33 0 0 1-33-33V296A182 182 0 0 1 727 113zM296 180a116 116 0 0 0 0 232H412V296c0-62-48-112-109-115z m431 0a116 116 0 0 0-116 116V412h116c62 0 112-48 115-109l0-6a116 116 0 0 0-116-116z">
+                <local:MyListItem.Buttons>
+                    <x:Array Type="{x:Type local:MyIconButton}">
+                        <local:MyIconButton Tag="13" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
+                    </x:Array>
+                </local:MyListItem.Buttons>
+            </local:MyListItem>
+            <local:MyListItem x:Name="ItemResourcePack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="14" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="资源包"
+                  LogoScale="0.81" Logo="M884.4 130.6H140.6c-41.9 0-76 34.1-76 76v613.3c0 41.9 34.1 76 76 76h743.8c41.9 0 76-34.1 76-76V206.6c0-41.9-34.1-76-76-76z m-743.8 72h743.8c2.2 0 4 1.8 4 4v371.3L796 461.7c-21.7-27.3-54.1-43.7-88.8-45-34.7-1.3-68.1 12.7-91.7 38.3L454 630c-2.8 3-7.2 3.5-10.5 1.3l-103-70.3c-31.5-21.5-72.8-22.5-105.3-2.7l-98.6 60.1V206.6c0-2.2 1.8-4 4-4z m743.8 621.3H140.6c-2.2 0-4-1.8-4-4V702.7l136.1-83c8.4-5.1 19.1-4.8 27.2 0.7l103 70.3c15.9 10.8 35.1 15.6 54.2 13.4 19-2.2 36.7-11.2 49.8-25.3l161.6-175c9.5-10.3 22.3-15.7 36.2-15.1 13.9 0.5 26.3 6.8 35.1 17.8l148.7 187v126.3c-0.1 2.3-1.9 4.1-4.1 4.1z M231.8 400.6a69.6 69.6 0 1 0 98.4-98.4 69.6 69.6 0 1 0-98.4 98.4Z">
+                <local:MyListItem.Buttons>
+                    <x:Array Type="{x:Type local:MyIconButton}">
+                        <local:MyIconButton Tag="14" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
+                    </x:Array>
+                </local:MyListItem.Buttons>
+            </local:MyListItem>
+            <local:MyListItem x:Name="ItemShader" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="15" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="光影包"
+                  LogoScale="1.04" Logo="M512 0c25 0 42 17 42 42v85c0 25-17 42-42 42s-42-17-42-42V42c0-25 17-42 42-42zM512 853c25 0 42 17 42 42v85c0 25-17 42-42 42s-42-17-42-42v-85c0-25 17-42 42-42zM209 149c-17-17-42-17-59 0-17 17-17 42 0 59l59 59c17 17 42 17 59 0 17-17 17-42 0-59L209 149zM755 755c17-17 42-17 59 0l59 59c17 17 17 42 0 59s-42 17-59 0l-59-59c-17-17-17-46 0-59zM42 469c-25 0-42 17-42 42s17 42 42 42h85c25 0 42-17 42-42s-17-42-42-42H42zM853 512c0-25 17-42 42-42h85c25 0 42 17 42 42s-17 42-42 42h-85c-25 0-42-17-42-42zM149 814c-17 17-17 42 0 59 17 17 42 17 59 0l59-59c17-17 17-42 0-59-17-17-42-17-59 0l-59 59zM755 268c-17-17-17-42 0-59l59-59c17-17 42-17 59 0s17 42 0 59l-59 59c-17 17-46 17-59 0z M512 213c-166 0-298 132-298 298s132 298 298 298 298-132 298-298-132-298-298-298z m0 512c-119 0-213-93-213-213s93-213 213-213 213 93 213 213-93 213-213 213z">
                 <local:MyListItem.Buttons>
                 <local:MyListItem.Buttons>
                     <x:Array Type="{x:Type local:MyIconButton}">
                     <x:Array Type="{x:Type local:MyIconButton}">
                         <local:MyIconButton Tag="15" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
                         <local:MyIconButton Tag="15" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />

+ 39 - 26
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb

@@ -11,7 +11,7 @@
     ''' <summary>
     ''' <summary>
     ''' 勾选事件改变页面。
     ''' 勾选事件改变页面。
     ''' </summary>
     ''' </summary>
-    Private Sub PageCheck(sender As MyListItem, e As RouteEventArgs) Handles ItemInstall.Check, ItemClient.Check, ItemOptiFine.Check, ItemForge.Check, ItemNeoForge.Check, ItemLiteLoader.Check, ItemMod.Check, ItemFabric.Check, ItemPack.Check, ItemDataPack.Check, ItemShader.Check, ItemResourcePack.Check
+    Private Sub PageCheck(sender As MyListItem, e As RouteEventArgs) Handles ItemInstall.Check, ItemClient.Check, ItemOptiFine.Check, ItemForge.Check, ItemNeoForge.Check, ItemLiteLoader.Check, ItemMod.Check, ItemFabric.Check, ItemPack.Check, ItemResourcePack.Check, ItemShader.Check, ItemDataPack.Check
         '尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0
         '尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0
         '若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False)
         '若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False)
         If sender.Tag IsNot Nothing Then PageChange(Val(sender.Tag))
         If sender.Tag IsNot Nothing Then PageChange(Val(sender.Tag))
@@ -47,15 +47,15 @@
             Case FormMain.PageSubType.DownloadPack
             Case FormMain.PageSubType.DownloadPack
                 If FrmDownloadPack Is Nothing Then FrmDownloadPack = New PageDownloadPack
                 If FrmDownloadPack Is Nothing Then FrmDownloadPack = New PageDownloadPack
                 Return FrmDownloadPack
                 Return FrmDownloadPack
-            Case FormMain.PageSubType.DownloadDataPack
-                If FrmDownloadDataPack Is Nothing Then FrmDownloadDataPack = New PageDownloadDataPack
-                Return FrmDownloadDataPack
-            Case FormMain.PageSubType.DownloadShader
-                If FrmDownloadShader Is Nothing Then FrmDownloadShader = New PageDownloadShader
-                Return FrmDownloadShader
             Case FormMain.PageSubType.DownloadResourcePack
             Case FormMain.PageSubType.DownloadResourcePack
                 If FrmDownloadResourcePack Is Nothing Then FrmDownloadResourcePack = New PageDownloadResourcePack
                 If FrmDownloadResourcePack Is Nothing Then FrmDownloadResourcePack = New PageDownloadResourcePack
                 Return FrmDownloadResourcePack
                 Return FrmDownloadResourcePack
+            Case FormMain.PageSubType.DownloadShader
+                If FrmDownloadShader Is Nothing Then FrmDownloadShader = New PageDownloadShader
+                Return FrmDownloadShader
+            Case FormMain.PageSubType.DownloadDataPack
+                If FrmDownloadDataPack Is Nothing Then FrmDownloadDataPack = New PageDownloadDataPack
+                Return FrmDownloadDataPack
             Case Else
             Case Else
                 Throw New Exception("未知的下载子页面种类:" & ID)
                 Throw New Exception("未知的下载子页面种类:" & ID)
         End Select
         End Select
@@ -119,37 +119,50 @@
                 DlOptiFabricLoader.Start(IsForceRestart:=True)
                 DlOptiFabricLoader.Start(IsForceRestart:=True)
                 ItemInstall.Checked = True
                 ItemInstall.Checked = True
             Case FormMain.PageSubType.DownloadMod
             Case FormMain.PageSubType.DownloadMod
-                PageDownloadMod.Storage = New CompProjectStorage
-                PageDownloadMod.Page = 0
                 CompProjectCache.Clear()
                 CompProjectCache.Clear()
                 CompFilesCache.Clear()
                 CompFilesCache.Clear()
-                If FrmDownloadMod IsNot Nothing Then FrmDownloadMod.PageLoaderRestart()
+                If FrmDownloadMod IsNot Nothing Then
+                    FrmDownloadMod.Content.Storage = New CompProjectStorage
+                    FrmDownloadMod.Content.Page = 0
+                    FrmDownloadMod.PageLoaderRestart()
+                End If
                 ItemMod.Checked = True
                 ItemMod.Checked = True
             Case FormMain.PageSubType.DownloadPack
             Case FormMain.PageSubType.DownloadPack
-                PageDownloadPack.Storage = New CompProjectStorage
-                PageDownloadPack.Page = 0
                 CompProjectCache.Clear()
                 CompProjectCache.Clear()
                 CompFilesCache.Clear()
                 CompFilesCache.Clear()
-                If FrmDownloadPack IsNot Nothing Then FrmDownloadPack.PageLoaderRestart()
+                If FrmDownloadPack IsNot Nothing Then
+                    FrmDownloadPack.Content.Storage = New CompProjectStorage
+                    FrmDownloadPack.Content.Page = 0
+                    FrmDownloadPack.PageLoaderRestart()
+                End If
                 ItemPack.Checked = True
                 ItemPack.Checked = True
-            Case FormMain.PageSubType.DownloadDataPack
-                PageDownloadDataPack.Storage = New CompProjectStorage
-                PageDownloadDataPack.Page = 0
+            Case FormMain.PageSubType.DownloadResourcePack
                 CompProjectCache.Clear()
                 CompProjectCache.Clear()
-                If FrmDownloadDataPack IsNot Nothing Then FrmDownloadDataPack.PageLoaderRestart()
-                ItemDataPack.Checked = True
+                CompFilesCache.Clear()
+                If FrmDownloadResourcePack IsNot Nothing Then
+                    FrmDownloadResourcePack.Content.Storage = New CompProjectStorage
+                    FrmDownloadResourcePack.Content.Page = 0
+                    FrmDownloadResourcePack.PageLoaderRestart()
+                End If
+                ItemResourcePack.Checked = True
             Case FormMain.PageSubType.DownloadShader
             Case FormMain.PageSubType.DownloadShader
-                PageDownloadShader.Storage = New CompProjectStorage
-                PageDownloadShader.Page = 0
                 CompProjectCache.Clear()
                 CompProjectCache.Clear()
-                If FrmDownloadShader IsNot Nothing Then FrmDownloadShader.PageLoaderRestart()
+                CompFilesCache.Clear()
+                If FrmDownloadShader IsNot Nothing Then
+                    FrmDownloadShader.Content.Storage = New CompProjectStorage
+                    FrmDownloadShader.Content.Page = 0
+                    FrmDownloadShader.PageLoaderRestart()
+                End If
                 ItemShader.Checked = True
                 ItemShader.Checked = True
-            Case FormMain.PageSubType.DownloadResourcePack
-                PageDownloadResourcePack.Storage = New CompProjectStorage
-                PageDownloadResourcePack.Page = 0
+            Case FormMain.PageSubType.DownloadDataPack
                 CompProjectCache.Clear()
                 CompProjectCache.Clear()
-                If FrmDownloadResourcePack IsNot Nothing Then FrmDownloadResourcePack.PageLoaderRestart()
-                ItemResourcePack.Checked = True
+                CompFilesCache.Clear()
+                If FrmDownloadDataPack IsNot Nothing Then
+                    FrmDownloadDataPack.Content.Storage = New CompProjectStorage
+                    FrmDownloadDataPack.Content.Page = 0
+                    FrmDownloadDataPack.PageLoaderRestart()
+                End If
+                ItemDataPack.Checked = True
             Case FormMain.PageSubType.DownloadClient
             Case FormMain.PageSubType.DownloadClient
                 DlClientListLoader.Start(IsForceRestart:=True)
                 DlClientListLoader.Start(IsForceRestart:=True)
                 ItemClient.Checked = True
                 ItemClient.Checked = True

+ 0 - 122
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml

@@ -1,122 +0,0 @@
-<local:MyPageRight
-    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-    mc:Ignorable="d" x:Class="PageDownloadMod"
-    PanScroll="{Binding ElementName=PanBack}">
-    <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
-        <StackPanel Orientation="Vertical" Margin="25">
-            <local:MyCard Title="搜索 Mod" Margin="0,0,0,15" x:Name="PanAlways">
-                <StackPanel Margin="25,40,25,15">
-                    <Grid Margin="0,0,0,11" HorizontalAlignment="Stretch">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="1.3*" />
-                            <ColumnDefinition Width="1.2*" />
-                            <ColumnDefinition Width="50" />
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="1*" />
-                        </Grid.ColumnDefinitions>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="28" />
-                            <RowDefinition Height="9" />
-                            <RowDefinition Height="28" />
-                        </Grid.RowDefinitions>
-                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,18,0" />
-                        <local:MyTextBox x:Name="TextSearchName" Grid.Column="1" Grid.ColumnSpan="2" />
-                        <TextBlock VerticalAlignment="Center" Grid.Column="4" HorizontalAlignment="Left" Text="来源" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchSource" Grid.Column="5">
-                            <local:MyComboBoxItem Content="全部" Tag="3" IsSelected="True" />
-                            <local:MyComboBoxItem Content="CurseForge" Tag="1" />
-                            <local:MyComboBoxItem Content="Modrinth" Tag="2" />
-                        </local:MyComboBox>
-                        <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" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
-                            <local:MyComboBoxItem Content="1.21.5" />
-                            <local:MyComboBoxItem Content="1.21.4" />
-                            <local:MyComboBoxItem Content="1.21.1" />
-                            <local:MyComboBoxItem Content="1.20.6" />
-                            <local:MyComboBoxItem Content="1.20.1" />
-                            <local:MyComboBoxItem Content="1.19.4" />
-                            <local:MyComboBoxItem Content="1.19.2" />
-                            <local:MyComboBoxItem Content="1.18.2" />
-                            <local:MyComboBoxItem Content="1.17.1" />
-                            <local:MyComboBoxItem Content="1.16.5" />
-                            <local:MyComboBoxItem Content="1.14.4" />
-                            <local:MyComboBoxItem Content="1.12.2" />
-                            <local:MyComboBoxItem Content="1.10.2" />
-                            <local:MyComboBoxItem Content="1.8.9" />
-                            <local:MyComboBoxItem Content="1.7.10" />
-                        </local:MyComboBox>
-                        <local:MyComboBox x:Name="ComboSearchLoader" Visibility="Collapsed" Grid.Row="2" Grid.Column="2" MaxDropDownHeight="320" Margin="10,0,0,0">
-                            <local:MyComboBoxItem Content="任意 Mod 加载器" IsSelected="True" Tag="0" />
-                            <local:MyComboBoxItem Content="Forge" Tag="1" />
-                            <local:MyComboBoxItem Content="Fabric" Tag="4" />
-                            <local:MyComboBoxItem Content="Quilt" Tag="5" />
-                            <local:MyComboBoxItem Content="NeoForge" Tag="6" />
-                        </local:MyComboBox>
-                        <TextBlock VerticalAlignment="Center" Grid.Column="4" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="5" Grid.Row="2" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Content="全部" Tag="" IsSelected="True" />
-                            <local:MyComboBoxItem Content="世界元素" Tag="406/worldgen" />
-                            <local:MyComboBoxItem Content="生物群系" Tag="407/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="维度" Tag="410/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="矿物与资源" Tag="408/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="天然结构" Tag="409/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="科技" Tag="412/technology" />
-                            <local:MyComboBoxItem Content="管道与物流" Tag="415/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="自动化" Tag="4843/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="能源" Tag="417/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="红石" Tag="4558/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="食物与烹饪" Tag="436/food" />
-                            <local:MyComboBoxItem Content="农业" Tag="416/" Margin="15,0,0,0" />
-                            <local:MyComboBoxItem Content="游戏机制" Tag="/game-mechanics" />
-                            <local:MyComboBoxItem Content="运输" Tag="414/transportation" />
-                            <local:MyComboBoxItem Content="仓储" Tag="420/storage" />
-                            <local:MyComboBoxItem Content="魔法" Tag="419/magic" />
-                            <local:MyComboBoxItem Content="冒险" Tag="422/adventure" />
-                            <local:MyComboBoxItem Content="装饰" Tag="424/decoration" />
-                            <local:MyComboBoxItem Content="生物" Tag="411/mobs" />
-                            <local:MyComboBoxItem Content="装备与工具" Tag="434/equipment" />
-                            <local:MyComboBoxItem Content="性能优化" Tag="/optimization" />
-                            <local:MyComboBoxItem Content="信息显示" Tag="423/" />
-                            <local:MyComboBoxItem Content="服务器" Tag="435/social" />
-                            <local:MyComboBoxItem Content="改良" Tag="5191/utility" />
-                            <local:MyComboBoxItem Content="支持库" Tag="421/library" />
-                        </local:MyComboBox>
-                    </Grid>
-                    <Grid Margin="0,4,0,6" Height="35">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                        </Grid.ColumnDefinitions>
-                        <local:MyButton x:Name="BtnSearchRun" Text="搜索" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
-                        <local:MyButton x:Name="BtnSearchReset" Text="重置条件" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="1" />
-                    </Grid>
-                </StackPanel>
-            </local:MyCard>
-            <StackPanel x:Name="PanContent">
-                <local:MyHint x:Name="HintError" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,结果可能不全。&#xa;请尝试使用 VPN 或加速器以改善网络。" IsWarn="True" Margin="0,0,0,15" />
-                <local:MyCard x:Name="CardProjects" UseAnimation="False">
-                    <StackPanel x:Name="PanProjects" Margin="12" />
-                </local:MyCard>
-                <local:MyCard Margin="0,15,0,0" x:Name="CardPages" HorizontalAlignment="Center">
-                    <StackPanel Orientation="Horizontal" Height="23" Margin="10,7">
-                        <local:MyIconButton x:Name="BtnPageFirst" IsEnabled="False" Opacity="0.2" Margin="0,0.5,5,0.5"
-                            Logo="M496.213333 329.856L315.306667 510.848l180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z m298.666667 0l-180.949333 180.992 180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z" />
-                        <local:MyIconButton x:Name="BtnPageLeft" IsEnabled="False" Opacity="0.2" Margin="0,0,5,0"
-                            Logo="M650.752 278.357333l-241.322667 241.365334 241.322667 241.365333a42.666667 42.666667 0 1 1-60.330667 60.330667l-271.530666-271.530667a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.416-27.648l271.530666-271.530666a42.666667 42.666667 0 0 1 60.330667 60.330666z" />
-                        <TextBlock x:Name="LabPage" Text="1" 
-                                   Margin="8,0,13,0" FontSize="15" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush3}" />
-                        <local:MyIconButton x:Name="BtnPageRight" Margin="0,0,30,0"
-                            Logo="M404.309333 278.357333l241.322667 241.365334-241.322667 241.365333a42.666667 42.666667 0 1 0 60.330667 60.330667l271.530667-271.530667a42.453333 42.453333 0 0 0 11.818666-22.613333l0.597334-5.034667v-5.034667a42.496 42.496 0 0 0-12.416-27.648L464.64 218.026667a42.666667 42.666667 0 0 0-60.330667 60.330666z" />
-                    </StackPanel>
-                </local:MyCard>
-            </StackPanel>
-            <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
-                <local:MyLoading Text="正在获取 Mod 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
-            </local:MyCard>
-        </StackPanel>
-    </local:MyScrollViewer>
-</local:MyPageRight>

+ 0 - 111
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml

@@ -1,111 +0,0 @@
-<local:MyPageRight
-    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-    mc:Ignorable="d" x:Class="PageDownloadPack"
-    PanScroll="{Binding ElementName=PanBack}">
-    <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
-        <StackPanel Orientation="Vertical" Margin="25">
-            <local:MyCard Title="搜索整合包" Margin="0,0,0,15" x:Name="PanAlways">
-                <StackPanel Margin="25,40,25,15">
-                    <Grid Margin="0,0,0,11" HorizontalAlignment="Stretch">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="2.5*" />
-                            <ColumnDefinition Width="50" />
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="1*" />
-                        </Grid.ColumnDefinitions>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="28" />
-                            <RowDefinition Height="9" />
-                            <RowDefinition Height="28" />
-                        </Grid.RowDefinitions>
-                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,18,0" />
-                        <local:MyTextBox x:Name="TextSearchName" Grid.Column="1" />
-                        <TextBlock VerticalAlignment="Center" Grid.Column="3" HorizontalAlignment="Left" Text="来源" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchSource" Grid.Column="4">
-                            <local:MyComboBoxItem Content="全部" Tag="3" IsSelected="True" />
-                            <local:MyComboBoxItem Content="CurseForge" Tag="1" />
-                            <local:MyComboBoxItem Content="Modrinth" Tag="2" />
-                        </local:MyComboBox>
-                        <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" IsEditable="True" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
-                            <local:MyComboBoxItem Content="1.21.5" />
-                            <local:MyComboBoxItem Content="1.21.4" />
-                            <local:MyComboBoxItem Content="1.21.1" />
-                            <local:MyComboBoxItem Content="1.20.6" />
-                            <local:MyComboBoxItem Content="1.20.1" />
-                            <local:MyComboBoxItem Content="1.19.4" />
-                            <local:MyComboBoxItem Content="1.19.2" />
-                            <local:MyComboBoxItem Content="1.18.2" />
-                            <local:MyComboBoxItem Content="1.17.1" />
-                            <local:MyComboBoxItem Content="1.16.5" />
-                            <local:MyComboBoxItem Content="1.14.4" />
-                            <local:MyComboBoxItem Content="1.12.2" />
-                            <local:MyComboBoxItem Content="1.10.2" />
-                            <local:MyComboBoxItem Content="1.8.9" />
-                            <local:MyComboBoxItem Content="1.7.10" />
-                        </local:MyComboBox>
-                        <TextBlock VerticalAlignment="Center" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="4" Grid.Row="2" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
-                            <local:MyComboBoxItem Tag="4484/" Content="多人" />
-                            <local:MyComboBoxItem Tag="/optimization" Content="性能优化" />
-                            <local:MyComboBoxItem Tag="4479/challenging" Content="硬核" />
-                            <local:MyComboBoxItem Tag="4483/combat" Content="战斗" />
-                            <local:MyComboBoxItem Tag="4478/quests" Content="任务" />
-                            <local:MyComboBoxItem Tag="4472/technology" Content="科技" />
-                            <local:MyComboBoxItem Tag="4473/magic" Content="魔法" />
-                            <local:MyComboBoxItem Tag="4475/adventure" Content="冒险" />
-                            <local:MyComboBoxItem Tag="/kitchen-sink" Content="大杂烩" />
-                            <local:MyComboBoxItem Tag="4476/" Content="探索" />
-                            <local:MyComboBoxItem Tag="4477/" Content="小游戏" />
-                            <local:MyComboBoxItem Tag="4471/" Content="科幻" />
-                            <local:MyComboBoxItem Tag="4736/" Content="空岛" />
-                            <local:MyComboBoxItem Tag="5128/" Content="原版改良" />
-                            <local:MyComboBoxItem Tag="4487/" Content="FTB" 
-                                                  ToolTip="由 FTB 官方发布" ToolTipService.HorizontalOffset="70" />
-                            <local:MyComboBoxItem Tag="4480/" Content="基于地图" />
-                            <local:MyComboBoxItem Tag="4481/lightweight" Content="轻量整合" />
-                            <local:MyComboBoxItem Tag="4482/" Content="大型整合" />
-                        </local:MyComboBox>
-                    </Grid>
-                    <Grid Margin="0,4,0,6" 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="BtnSearchRun" Text="搜索" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
-                        <local:MyButton x:Name="BtnSearchReset" Text="重置条件" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="1" />
-                        <local:MyButton x:Name="BtnSearchInstall" Text="安装已有整合包" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="2" 
-                                        ToolTip="在当前选择的 Minecraft 文件夹下安装整合包" ToolTipService.HorizontalOffset="-55" ToolTipService.VerticalOffset="5" />
-                    </Grid>
-                </StackPanel>
-            </local:MyCard>
-            <StackPanel x:Name="PanContent">
-                <local:MyHint x:Name="HintError" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,结果可能不全。&#xa;请尝试使用 VPN 或加速器以改善网络。" IsWarn="True" Margin="0,0,0,15" />
-                <local:MyCard x:Name="CardProjects" UseAnimation="False">
-                    <StackPanel x:Name="PanProjects" Margin="12" />
-                </local:MyCard>
-                <local:MyCard Margin="0,15,0,0" x:Name="CardPages" HorizontalAlignment="Center">
-                    <StackPanel Orientation="Horizontal" Height="23" Margin="10,7">
-                        <local:MyIconButton x:Name="BtnPageFirst" IsEnabled="False" Opacity="0.2" Margin="0,0.5,5,0.5"
-                            Logo="M496.213333 329.856L315.306667 510.848l180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z m298.666667 0l-180.949333 180.992 180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z" />
-                        <local:MyIconButton x:Name="BtnPageLeft" IsEnabled="False" Opacity="0.2" Margin="0,0,5,0"
-                            Logo="M650.752 278.357333l-241.322667 241.365334 241.322667 241.365333a42.666667 42.666667 0 1 1-60.330667 60.330667l-271.530666-271.530667a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.416-27.648l271.530666-271.530666a42.666667 42.666667 0 0 1 60.330667 60.330666z" />
-                        <TextBlock x:Name="LabPage" Text="1" 
-                                   Margin="8,0,13,0" FontSize="15" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush3}" />
-                        <local:MyIconButton x:Name="BtnPageRight" Margin="0,0,30,0"
-                            Logo="M404.309333 278.357333l241.322667 241.365334-241.322667 241.365333a42.666667 42.666667 0 1 0 60.330667 60.330667l271.530667-271.530667a42.453333 42.453333 0 0 0 11.818666-22.613333l0.597334-5.034667v-5.034667a42.496 42.496 0 0 0-12.416-27.648L464.64 218.026667a42.666667 42.666667 0 0 0-60.330667 60.330666z" />
-                    </StackPanel>
-                </local:MyCard>
-            </StackPanel>
-            <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
-                <local:MyLoading Text="正在获取整合包列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
-            </local:MyCard>
-        </StackPanel>
-    </local:MyScrollViewer>
-</local:MyPageRight>

+ 0 - 128
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml.vb

@@ -1,128 +0,0 @@
-Public Class PageDownloadPack
-
-    Public Const PageSize = 40
-
-    '加载器信息
-    Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject ModPack", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
-    Public Shared Storage As New CompProjectStorage
-    Public Shared Page As Integer = 0
-    Private Sub PageDownloadPack_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
-        PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
-        If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
-    End Sub
-    Private Shared Function LoaderInput() As CompProjectRequest
-        Dim Request As New CompProjectRequest(CompType.ModPack, Storage, (Page + 1) * PageSize)
-        If FrmDownloadPack IsNot Nothing Then
-            With Request
-                .SearchText = FrmDownloadPack.TextSearchName.Text
-                .GameVersion = If(FrmDownloadPack.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
-                    If(FrmDownloadPack.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadPack.TextSearchVersion.Text.Contains("w"), FrmDownloadPack.TextSearchVersion.Text, Nothing))
-                .Tag = FrmDownloadPack.ComboSearchTag.SelectedItem.Tag
-                .Source = CType(Val(FrmDownloadPack.ComboSearchSource.SelectedItem.Tag), CompSourceType)
-            End With
-        End If
-        Return Request
-    End Function
-
-    '结果 UI 化
-    Private Sub Load_OnFinish()
-        Try
-            Log($"[Comp] 开始可视化整合包列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
-            '列表项
-            PanProjects.Children.Clear()
-            For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
-                PanProjects.Children.Add(Storage.Results(i).ToCompItem(Loader.Input.GameVersion Is Nothing, True))
-            Next
-            '页码
-            CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
-                                      Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal,
-                                      Visibility.Visible, Visibility.Collapsed)
-            LabPage.Text = Page + 1
-            BtnPageFirst.IsEnabled = Page > 1
-            BtnPageFirst.Opacity = If(Page > 1, 1, 0.2)
-            BtnPageLeft.IsEnabled = Page > 0
-            BtnPageLeft.Opacity = If(Page > 0, 1, 0.2)
-            Dim IsRightEnabled As Boolean = '由于 WPF 的未知 bug,读取到的 IsEnabled 可能是错误的值(#3319)
-                Storage.Results.Count > PageSize * (Page + 1) OrElse
-                Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal
-            BtnPageRight.IsEnabled = IsRightEnabled
-            BtnPageRight.Opacity = If(IsRightEnabled, 1, 0.2)
-            '错误信息
-            If Storage.ErrorMessage Is Nothing Then
-                HintError.Visibility = Visibility.Collapsed
-            Else
-                HintError.Visibility = Visibility.Visible
-                HintError.Text = Storage.ErrorMessage
-            End If
-            '强制返回顶部
-            PanBack.ScrollToTop()
-        Catch ex As Exception
-            Log(ex, "可视化整合包列表出错", LogLevel.Feedback)
-        End Try
-    End Sub
-
-    '自动重试
-    Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
-        Select Case Loader.State
-            Case LoadState.Failed
-                Dim ErrorMessage As String = ""
-                If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
-                If ErrorMessage.Contains("不是有效的 json 文件") Then
-                    Log("[Download] 下载的整合包列表 json 文件损坏,已自动重试", LogLevel.Debug)
-                    PageLoaderRestart()
-                End If
-        End Select
-    End Sub
-
-    '切换页码
-
-    Private Sub BtnPageFirst_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageFirst.Click
-        ChangePage(0)
-    End Sub
-    Private Sub BtnPageLeft_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageLeft.Click
-        ChangePage(Page - 1)
-    End Sub
-    Private Sub BtnPageRight_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageRight.Click
-        ChangePage(Page + 1)
-    End Sub
-    Private Sub ChangePage(NewPage As Integer)
-        CardPages.IsEnabled = False
-        Page = NewPage
-        FrmMain.BackToTop()
-        Log($"[Download] 整合包切换到第 {Page + 1} 页")
-        RunInThread(Sub()
-                        Thread.Sleep(100) '等待向上滚的动画结束
-                        RunInUi(Sub() CardPages.IsEnabled = True)
-                        Loader.Start()
-                    End Sub)
-    End Sub
-
-    Private Sub BtnSearchInstall_Click(sender As Object, e As EventArgs) Handles BtnSearchInstall.Click
-        ModpackInstall()
-    End Sub
-
-#Region "搜索"
-
-    '搜索按钮
-    Private Sub StartNewSearch() Handles BtnSearchRun.Click
-        Page = 0
-        If Loader.ShouldStart(LoaderInput()) Then Storage = New CompProjectStorage '避免连续搜索两次使得 CompProjectStorage 引用丢失(#1311)
-        Loader.Start()
-    End Sub
-    Private Sub EnterTrigger(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyDown, TextSearchVersion.KeyDown
-        If e.Key = Key.Enter Then StartNewSearch()
-    End Sub
-
-    '重置按钮
-    Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click
-        TextSearchName.Text = ""
-        TextSearchVersion.Text = "全部 (也可自行输入)"
-        TextSearchVersion.SelectedIndex = 0
-        ComboSearchSource.SelectedIndex = 0
-        ComboSearchTag.SelectedIndex = 0
-        Loader.LastFinishedTime = 0 '要求强制重新开始
-    End Sub
-
-#End Region
-
-End Class

+ 0 - 126
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadResourcePack.xaml

@@ -1,126 +0,0 @@
-<local:MyPageRight
-    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-    mc:Ignorable="d" x:Class="PageDownloadResourcePack"
-    PanScroll="{Binding ElementName=PanBack}">
-    <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
-        <StackPanel Orientation="Vertical" Margin="25">
-            <local:MyCard Title="搜索资源包" Margin="0,0,0,15" x:Name="PanAlways">
-                <StackPanel Margin="25,40,25,15">
-                    <Grid Margin="0,0,0,11" HorizontalAlignment="Stretch">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="2.5*" />
-                            <ColumnDefinition Width="50" />
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="1*" />
-                        </Grid.ColumnDefinitions>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="28" />
-                            <RowDefinition Height="9" />
-                            <RowDefinition Height="28" />
-                        </Grid.RowDefinitions>
-                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,18,0" />
-                        <local:MyTextBox x:Name="TextSearchName" Grid.Column="1" />
-                        <TextBlock VerticalAlignment="Center" Grid.Column="3" HorizontalAlignment="Left" Text="来源" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchSource" Grid.Column="4">
-                            <local:MyComboBoxItem Content="全部" Tag="3" IsSelected="True" />
-                            <local:MyComboBoxItem Content="CurseForge" Tag="1" />
-                            <local:MyComboBoxItem Content="Modrinth" Tag="2" />
-                        </local:MyComboBox>
-                        <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" IsEditable="True" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
-                            <local:MyComboBoxItem Content="1.20.6" />
-                            <local:MyComboBoxItem Content="1.20.4" />
-                            <local:MyComboBoxItem Content="1.20.1" />
-                            <local:MyComboBoxItem Content="1.19.4" />
-                            <local:MyComboBoxItem Content="1.19.2" />
-                            <local:MyComboBoxItem Content="1.18.2" />
-                            <local:MyComboBoxItem Content="1.17.1" />
-                            <local:MyComboBoxItem Content="1.16.5" />
-                            <local:MyComboBoxItem Content="1.15.2" />
-                            <local:MyComboBoxItem Content="1.14.4" />
-                            <local:MyComboBoxItem Content="1.12.2" />
-                            <local:MyComboBoxItem Content="1.11.2" />
-                            <local:MyComboBoxItem Content="1.10.2" />
-                            <local:MyComboBoxItem Content="1.8.9" />
-                            <local:MyComboBoxItem Content="1.7.10" />
-                        </local:MyComboBox>
-                        <TextBlock VerticalAlignment="Center" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="4" Grid.Row="2" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
-                            <local:MyComboBoxItem Content="8x-" Tag="/8x-" />
-                            <local:MyComboBoxItem Content="16x" Tag="393/16x" />
-                            <local:MyComboBoxItem Content="32x" Tag="394/32x" />
-                            <local:MyComboBoxItem Content="48x" Tag="/48x" />
-                            <local:MyComboBoxItem Content="64x" Tag="395/64x" />
-                            <local:MyComboBoxItem Content="128x" Tag="396/128x" />
-                            <local:MyComboBoxItem Content="256x" Tag="397/256x" />
-                            <local:MyComboBoxItem Content="512x+" Tag="398/512x+" />
-                            <local:MyComboBoxItem Content="声音" Tag="/audio" />
-                            <local:MyComboBoxItem Content="方块" Tag="/blocks" />
-                            <local:MyComboBoxItem Content="战斗" Tag="/combat" />
-                            <local:MyComboBoxItem Content="核心着色器" Tag="/core-shaders" />
-                            <local:MyComboBoxItem Content="Cursed" Tag="/cursed" />
-                            <local:MyComboBoxItem Content="装饰" Tag="/decoration" />
-                            <local:MyComboBoxItem Content="实体" Tag="/entities" />
-                            <local:MyComboBoxItem Content="环境" Tag="/environment" />
-                            <local:MyComboBoxItem Content="装备" Tag="/equipment" />
-                            <local:MyComboBoxItem Content="字体" Tag="/fonts" />
-                            <local:MyComboBoxItem Content="GUI" Tag="/gui" />
-                            <local:MyComboBoxItem Content="物品" Tag="/items" />
-                            <local:MyComboBoxItem Content="本地化" Tag="/locale" />
-                            <local:MyComboBoxItem Content="Modded" Tag="4465/modded" />
-                            <local:MyComboBoxItem Content="模型" Tag="/models" />
-                            <local:MyComboBoxItem Content="写实" Tag="400/realistic" />
-                            <local:MyComboBoxItem Content="扁平" Tag="/simplistic" />
-                            <local:MyComboBoxItem Content="主题" Tag="/themed" />
-                            <local:MyComboBoxItem Content="优化" Tag="/tweaks" />
-                            <local:MyComboBoxItem Content="实用" Tag="/utility" />
-                            <local:MyComboBoxItem Content="类原生" Tag="/vanilla-like" />
-                            <local:MyComboBoxItem Content="动态效果" Tag="404/" />
-                            <local:MyComboBoxItem Content="传统" Tag="403/" />
-                            <local:MyComboBoxItem Content="中世纪" Tag="402/" />
-                            <local:MyComboBoxItem Content="蒸汽朋克" Tag="399/" />
-                            <local:MyComboBoxItem Content="现代" Tag="401/" />
-                            <local:MyComboBoxItem Content="字体包" Tag="5244/" />
-                            <local:MyComboBoxItem Content="含有数据包" Tag="5193/" />
-                            <local:MyComboBoxItem Content="其他" Tag="405/" />
-                        </local:MyComboBox>
-                    </Grid>
-                    <Grid Margin="0,4,0,6" Height="35">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                        </Grid.ColumnDefinitions>
-                        <local:MyButton x:Name="BtnSearchRun" Text="搜索" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
-                        <local:MyButton x:Name="BtnSearchReset" Text="重置条件" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="1" />
-                    </Grid>
-                </StackPanel>
-            </local:MyCard>
-            <StackPanel x:Name="PanContent">
-                <local:MyHint x:Name="HintError" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,结果可能不全。&#xa;请尝试使用 VPN 或加速器以改善网络。" IsWarn="True" Margin="0,0,0,15" />
-                <local:MyCard x:Name="CardProjects" UseAnimation="False">
-                    <StackPanel x:Name="PanProjects" Margin="12" />
-                </local:MyCard>
-                <local:MyCard Margin="0,15,0,0" x:Name="CardPages" HorizontalAlignment="Center">
-                    <StackPanel Orientation="Horizontal" Height="23" Margin="10,7">
-                        <local:MyIconButton x:Name="BtnPageFirst" IsEnabled="False" Opacity="0.2" Margin="0,0.5,5,0.5"
-                            Logo="M496.213333 329.856L315.306667 510.848l180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z m298.666667 0l-180.949333 180.992 180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z" />
-                        <local:MyIconButton x:Name="BtnPageLeft" IsEnabled="False" Opacity="0.2" Margin="0,0,5,0"
-                            Logo="M650.752 278.357333l-241.322667 241.365334 241.322667 241.365333a42.666667 42.666667 0 1 1-60.330667 60.330667l-271.530666-271.530667a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.416-27.648l271.530666-271.530666a42.666667 42.666667 0 0 1 60.330667 60.330666z" />
-                        <TextBlock x:Name="LabPage" Text="1" 
-                                   Margin="8,0,13,0" FontSize="15" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush3}" />
-                        <local:MyIconButton x:Name="BtnPageRight" Margin="0,0,30,0"
-                            Logo="M404.309333 278.357333l241.322667 241.365334-241.322667 241.365333a42.666667 42.666667 0 1 0 60.330667 60.330667l271.530667-271.530667a42.453333 42.453333 0 0 0 11.818666-22.613333l0.597334-5.034667v-5.034667a42.496 42.496 0 0 0-12.416-27.648L464.64 218.026667a42.666667 42.666667 0 0 0-60.330667 60.330666z" />
-                    </StackPanel>
-                </local:MyCard>
-            </StackPanel>
-            <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
-                <local:MyLoading Text="正在获取资源包列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
-            </local:MyCard>
-        </StackPanel>
-    </local:MyScrollViewer>
-</local:MyPageRight>

+ 0 - 124
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadResourcePack.xaml.vb

@@ -1,124 +0,0 @@
-Public Class PageDownloadResourcePack
-
-    Public Const PageSize = 40
-
-    '加载器信息
-    Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject ResourcePack", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
-    Public Shared Storage As New CompProjectStorage
-    Public Shared Page As Integer = 0
-    Private Sub PageDownloadResourcePack_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
-        PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
-        If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
-    End Sub
-    Private Shared Function LoaderInput() As CompProjectRequest
-        Dim Request As New CompProjectRequest(CompType.ResourcePack, Storage, (Page + 1) * PageSize)
-        If FrmDownloadResourcePack IsNot Nothing Then
-            With Request
-                .SearchText = FrmDownloadResourcePack.TextSearchName.Text
-                .GameVersion = If(FrmDownloadResourcePack.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
-                    If(FrmDownloadResourcePack.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadResourcePack.TextSearchVersion.Text.Contains("w"), FrmDownloadResourcePack.TextSearchVersion.Text, Nothing))
-                .Tag = FrmDownloadResourcePack.ComboSearchTag.SelectedItem.Tag
-                .Source = CType(Val(FrmDownloadResourcePack.ComboSearchSource.SelectedItem.Tag), CompSourceType)
-            End With
-        End If
-        Return Request
-    End Function
-
-    '结果 UI 化
-    Private Sub Load_OnFinish()
-        Try
-            Log($"[Comp] 开始可视化资源包列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
-            '列表项
-            PanProjects.Children.Clear()
-            For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
-                PanProjects.Children.Add(Storage.Results(i).ToCompItem(Loader.Input.GameVersion Is Nothing, False))
-            Next
-            '页码
-            CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
-                                      Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal,
-                                      Visibility.Visible, Visibility.Collapsed)
-            LabPage.Text = Page + 1
-            BtnPageFirst.IsEnabled = Page > 1
-            BtnPageFirst.Opacity = If(Page > 1, 1, 0.2)
-            BtnPageLeft.IsEnabled = Page > 0
-            BtnPageLeft.Opacity = If(Page > 0, 1, 0.2)
-            Dim IsRightEnabled As Boolean = '由于 WPF 的未知 bug,读取到的 IsEnabled 可能是错误的值(#3319)
-                Storage.Results.Count > PageSize * (Page + 1) OrElse
-                Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal
-            BtnPageRight.IsEnabled = IsRightEnabled
-            BtnPageRight.Opacity = If(IsRightEnabled, 1, 0.2)
-            '错误信息
-            If Storage.ErrorMessage Is Nothing Then
-                HintError.Visibility = Visibility.Collapsed
-            Else
-                HintError.Visibility = Visibility.Visible
-                HintError.Text = Storage.ErrorMessage
-            End If
-            '强制返回顶部
-            PanBack.ScrollToTop()
-        Catch ex As Exception
-            Log(ex, "可视化资源包列表出错", LogLevel.Feedback)
-        End Try
-    End Sub
-
-    '自动重试
-    Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
-        Select Case Loader.State
-            Case LoadState.Failed
-                Dim ErrorMessage As String = ""
-                If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
-                If ErrorMessage.Contains("不是有效的 json 文件") Then
-                    Log("[Download] 下载的资源包列表 json 文件损坏,已自动重试", LogLevel.Debug)
-                    PageLoaderRestart()
-                End If
-        End Select
-    End Sub
-
-    '切换页码
-
-    Private Sub BtnPageFirst_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageFirst.Click
-        ChangePage(0)
-    End Sub
-    Private Sub BtnPageLeft_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageLeft.Click
-        ChangePage(Page - 1)
-    End Sub
-    Private Sub BtnPageRight_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageRight.Click
-        ChangePage(Page + 1)
-    End Sub
-    Private Sub ChangePage(NewPage As Integer)
-        CardPages.IsEnabled = False
-        Page = NewPage
-        FrmMain.BackToTop()
-        Log($"[Download] 资源包切换到第 {Page + 1} 页")
-        RunInThread(Sub()
-                        Thread.Sleep(100) '等待向上滚的动画结束
-                        RunInUi(Sub() CardPages.IsEnabled = True)
-                        Loader.Start()
-                    End Sub)
-    End Sub
-
-#Region "搜索"
-
-    '搜索按钮
-    Private Sub StartNewSearch() Handles BtnSearchRun.Click
-        Page = 0
-        If Loader.ShouldStart(LoaderInput()) Then Storage = New CompProjectStorage '避免连续搜索两次使得 CompProjectStorage 引用丢失(#1311)
-        Loader.Start()
-    End Sub
-    Private Sub EnterTrigger(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyDown, TextSearchVersion.KeyDown
-        If e.Key = Key.Enter Then StartNewSearch()
-    End Sub
-
-    '重置按钮
-    Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click
-        TextSearchName.Text = ""
-        TextSearchVersion.Text = "全部 (也可自行输入)"
-        TextSearchVersion.SelectedIndex = 0
-        ComboSearchSource.SelectedIndex = 0
-        ComboSearchTag.SelectedIndex = 0
-        Loader.LastFinishedTime = 0 '要求强制重新开始
-    End Sub
-
-#End Region
-
-End Class

+ 0 - 115
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadShader.xaml

@@ -1,115 +0,0 @@
-<local:MyPageRight
-    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-    mc:Ignorable="d" x:Class="PageDownloadShader"
-    PanScroll="{Binding ElementName=PanBack}">
-    <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
-        <StackPanel Orientation="Vertical" Margin="25">
-            <local:MyCard Title="搜索光影包" Margin="0,0,0,15" x:Name="PanAlways">
-                <StackPanel Margin="25,40,25,15">
-                    <Grid Margin="0,0,0,11" HorizontalAlignment="Stretch">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="2.5*" />
-                            <ColumnDefinition Width="50" />
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="1*" />
-                        </Grid.ColumnDefinitions>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="28" />
-                            <RowDefinition Height="9" />
-                            <RowDefinition Height="28" />
-                        </Grid.RowDefinitions>
-                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="名称" Margin="0,0,18,0" />
-                        <local:MyTextBox x:Name="TextSearchName" Grid.Column="1" />
-                        <TextBlock VerticalAlignment="Center" Grid.Column="3" HorizontalAlignment="Left" Text="来源" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchSource" Grid.Column="4">
-                            <local:MyComboBoxItem Content="全部" Tag="3" IsSelected="True" />
-                            <local:MyComboBoxItem Content="CurseForge" Tag="1" />
-                            <local:MyComboBoxItem Content="Modrinth" Tag="2" />
-                        </local:MyComboBox>
-                        <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" IsEditable="True" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
-                            <local:MyComboBoxItem Content="1.20.6" />
-                            <local:MyComboBoxItem Content="1.20.4" />
-                            <local:MyComboBoxItem Content="1.20.1" />
-                            <local:MyComboBoxItem Content="1.19.4" />
-                            <local:MyComboBoxItem Content="1.19.2" />
-                            <local:MyComboBoxItem Content="1.18.2" />
-                            <local:MyComboBoxItem Content="1.17.1" />
-                            <local:MyComboBoxItem Content="1.16.5" />
-                            <local:MyComboBoxItem Content="1.15.2" />
-                            <local:MyComboBoxItem Content="1.14.4" />
-                            <local:MyComboBoxItem Content="1.12.2" />
-                            <local:MyComboBoxItem Content="1.11.2" />
-                            <local:MyComboBoxItem Content="1.10.2" />
-                            <local:MyComboBoxItem Content="1.8.9" />
-                            <local:MyComboBoxItem Content="1.7.10" />
-                        </local:MyComboBox>
-                        <TextBlock VerticalAlignment="Center" Grid.Row="2" Grid.Column="3" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
-                        <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="4" Grid.Row="2" MaxDropDownHeight="320">
-                            <local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
-                            <local:MyComboBoxItem Content="卡通" Tag="/cartoon" />
-                            <local:MyComboBoxItem Content="Cursed" Tag="/cursed" />
-                            <local:MyComboBoxItem Content="幻想" Tag="6554/fantasy" />
-                            <local:MyComboBoxItem Content="写实" Tag="6553/realistic" />
-                            <local:MyComboBoxItem Content="半写实" Tag="/semi-realistic" />
-                            <local:MyComboBoxItem Content="原版风" Tag="6555/vanilla-like" />
-
-                            <local:MyComboBoxItem Content="大气环境" Tag="/atmosphere" />
-                            <local:MyComboBoxItem Content="植被" Tag="/bloom" />
-                            <local:MyComboBoxItem Content="光源着色" Tag="/colored-lighting" />
-                            <local:MyComboBoxItem Content="树叶" Tag="/foliage" />
-                            <local:MyComboBoxItem Content="路径追踪" Tag="/path-tracing" />
-                            <local:MyComboBoxItem Content="PBR" Tag="/pbr" />
-                            <local:MyComboBoxItem Content="反射" Tag="/reflections" />
-                            <local:MyComboBoxItem Content="阴影" Tag="/shadows" />
-
-                            <local:MyComboBoxItem Content="土豆画质" Tag="/potato" />
-                            <local:MyComboBoxItem Content="低性能影响" Tag="/low" />
-                            <local:MyComboBoxItem Content="中性能影响" Tag="/medium" />
-                            <local:MyComboBoxItem Content="高性能影响" Tag="/high" />
-                            <local:MyComboBoxItem Content="极致画质" Tag="/screenshot" />
-
-                            <local:MyComboBoxItem Content="Canvas" Tag="/canvas" />
-                            <local:MyComboBoxItem Content="Iris" Tag="/iris" />
-                            <local:MyComboBoxItem Content="OptiFine" Tag="/optifine" />
-                            <local:MyComboBoxItem Content="原版光影" Tag="/vanilla" />
-                        </local:MyComboBox>
-                    </Grid>
-                    <Grid Margin="0,4,0,6" Height="35">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                            <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
-                        </Grid.ColumnDefinitions>
-                        <local:MyButton x:Name="BtnSearchRun" Text="搜索" MinWidth="140" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
-                        <local:MyButton x:Name="BtnSearchReset" Text="重置条件" MinWidth="140" Padding="13,0" Margin="0,0,20,0" Grid.Column="1" />
-                    </Grid>
-                </StackPanel>
-            </local:MyCard>
-            <StackPanel x:Name="PanContent">
-                <local:MyHint x:Name="HintError" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,结果可能不全。&#xa;请尝试使用 VPN 或加速器以改善网络。" IsWarn="True" Margin="0,0,0,15" />
-                <local:MyCard x:Name="CardProjects" UseAnimation="False">
-                    <StackPanel x:Name="PanProjects" Margin="12" />
-                </local:MyCard>
-                <local:MyCard Margin="0,15,0,0" x:Name="CardPages" HorizontalAlignment="Center">
-                    <StackPanel Orientation="Horizontal" Height="23" Margin="10,7">
-                        <local:MyIconButton x:Name="BtnPageFirst" IsEnabled="False" Opacity="0.2" Margin="0,0.5,5,0.5"
-                            Logo="M496.213333 329.856L315.306667 510.848l180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z m298.666667 0l-180.949333 180.992 180.992 181.077333a42.666667 42.666667 0 1 1-60.330667 60.330667l-211.2-211.2a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.373333-27.648l211.2-211.2a42.666667 42.666667 0 0 1 60.373334 60.330667z" />
-                        <local:MyIconButton x:Name="BtnPageLeft" IsEnabled="False" Opacity="0.2" Margin="0,0,5,0"
-                            Logo="M650.752 278.357333l-241.322667 241.365334 241.322667 241.365333a42.666667 42.666667 0 1 1-60.330667 60.330667l-271.530666-271.530667a42.453333 42.453333 0 0 1-11.818667-22.613333l-0.597333-5.034667v-5.034667a42.496 42.496 0 0 1 12.416-27.648l271.530666-271.530666a42.666667 42.666667 0 0 1 60.330667 60.330666z" />
-                        <TextBlock x:Name="LabPage" Text="1" 
-                                   Margin="8,0,13,0" FontSize="15" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush3}" />
-                        <local:MyIconButton x:Name="BtnPageRight" Margin="0,0,30,0"
-                            Logo="M404.309333 278.357333l241.322667 241.365334-241.322667 241.365333a42.666667 42.666667 0 1 0 60.330667 60.330667l271.530667-271.530667a42.453333 42.453333 0 0 0 11.818666-22.613333l0.597334-5.034667v-5.034667a42.496 42.496 0 0 0-12.416-27.648L464.64 218.026667a42.666667 42.666667 0 0 0-60.330667 60.330666z" />
-                    </StackPanel>
-                </local:MyCard>
-            </StackPanel>
-            <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
-                <local:MyLoading Text="正在获取光影包列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
-            </local:MyCard>
-        </StackPanel>
-    </local:MyScrollViewer>
-</local:MyPageRight>

+ 0 - 122
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadShader.xaml.vb

@@ -1,122 +0,0 @@
-Public Class PageDownloadShader
-
-    Public Const PageSize = 40
-
-    '加载器信息
-    Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject Shader", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
-    Public Shared Storage As New CompProjectStorage
-    Public Shared Page As Integer = 0
-    Private Sub PageDownloadShader_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
-        PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
-        If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
-    End Sub
-    Private Shared Function LoaderInput() As CompProjectRequest
-        Dim Request As New CompProjectRequest(CompType.Shader, Storage, (Page + 1) * PageSize)
-        If FrmDownloadShader IsNot Nothing Then
-            With Request
-                .SearchText = FrmDownloadShader.TextSearchName.Text
-                .GameVersion = If(FrmDownloadShader.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
-                    If(FrmDownloadShader.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadShader.TextSearchVersion.Text.Contains("w"), FrmDownloadShader.TextSearchVersion.Text, Nothing))
-                .Tag = FrmDownloadShader.ComboSearchTag.SelectedItem.Tag
-                .Source = CType(Val(FrmDownloadShader.ComboSearchSource.SelectedItem.Tag), CompSourceType)
-            End With
-        End If
-        Return Request
-    End Function
-
-    '结果 UI 化
-    Private Sub Load_OnFinish()
-        Try
-            Log($"[Comp] 开始可视化光影包列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
-            '列表项
-            PanProjects.Children.Clear()
-            For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
-                PanProjects.Children.Add(Storage.Results(i).ToCompItem(Loader.Input.GameVersion Is Nothing, False))
-            Next
-            '页码
-            CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
-                                      Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal,
-                                      Visibility.Visible, Visibility.Collapsed)
-            LabPage.Text = Page + 1
-            BtnPageFirst.IsEnabled = Page > 1
-            BtnPageFirst.Opacity = If(BtnPageFirst.IsEnabled, 1, 0.2)
-            BtnPageLeft.IsEnabled = Page > 0
-            BtnPageLeft.Opacity = If(BtnPageLeft.IsEnabled, 1, 0.2)
-            BtnPageRight.IsEnabled = Storage.Results.Count > PageSize * (Page + 1) OrElse
-                                     Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal
-            BtnPageRight.Opacity = If(BtnPageRight.IsEnabled, 1, 0.2)
-            '错误信息
-            If Storage.ErrorMessage Is Nothing Then
-                HintError.Visibility = Visibility.Collapsed
-            Else
-                HintError.Visibility = Visibility.Visible
-                HintError.Text = Storage.ErrorMessage
-            End If
-            '强制返回顶部
-            PanBack.ScrollToTop()
-        Catch ex As Exception
-            Log(ex, "可视化光影包列表出错", LogLevel.Feedback)
-        End Try
-    End Sub
-
-    '自动重试
-    Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
-        Select Case Loader.State
-            Case LoadState.Failed
-                Dim ErrorMessage As String = ""
-                If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
-                If ErrorMessage.Contains("不是有效的 JSON 文件") Then
-                    Log("[Download] 下载的光影包列表 JSON 文件损坏,已自动重试", LogLevel.Debug)
-                    PageLoaderRestart()
-                End If
-        End Select
-    End Sub
-
-    '切换页码
-
-    Private Sub BtnPageFirst_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageFirst.Click
-        ChangePage(0)
-    End Sub
-    Private Sub BtnPageLeft_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageLeft.Click
-        ChangePage(Page - 1)
-    End Sub
-    Private Sub BtnPageRight_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageRight.Click
-        ChangePage(Page + 1)
-    End Sub
-    Private Sub ChangePage(NewPage As Integer)
-        CardPages.IsEnabled = False
-        Page = NewPage
-        FrmMain.BackToTop()
-        Log($"[Download] 光影包切换到第 {Page + 1} 页")
-        RunInThread(Sub()
-                        Thread.Sleep(100) '等待向上滚的动画结束
-                        RunInUi(Sub() CardPages.IsEnabled = True)
-                        Loader.Start()
-                    End Sub)
-    End Sub
-
-#Region "搜索"
-
-    '搜索按钮
-    Private Sub StartNewSearch() Handles BtnSearchRun.Click
-        Page = 0
-        If Loader.ShouldStart(LoaderInput()) Then Storage = New CompProjectStorage '避免连续搜索两次使得 CompProjectStorage 引用丢失(#1311)
-        Loader.Start()
-    End Sub
-    Private Sub EnterTrigger(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyDown, TextSearchVersion.KeyDown
-        If e.Key = Key.Enter Then StartNewSearch()
-    End Sub
-
-    '重置按钮
-    Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click
-        TextSearchName.Text = ""
-        TextSearchVersion.Text = "全部 (也可自行输入)"
-        TextSearchVersion.SelectedIndex = 0
-        ComboSearchSource.SelectedIndex = 0
-        ComboSearchTag.SelectedIndex = 0
-        Loader.LastFinishedTime = 0 '要求强制重新开始
-    End Sub
-
-#End Region
-
-End Class

+ 3 - 0
Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb

@@ -125,6 +125,9 @@
                 ElseIf ex.Message.Contains("expired_token") Then
                 ElseIf ex.Message.Contains("expired_token") Then
                     Finished(New Exception("$登录用时太长啦,重新试试吧!"))
                     Finished(New Exception("$登录用时太长啦,重新试试吧!"))
                     Return
                     Return
+                ElseIf ex.Message.Contains("service abuse") Then
+                    Finished(New Exception("$非常抱歉,该账号已被微软封禁,无法登录。"))
+                    Return
                 ElseIf ex.Message.Contains("AADSTS70000") Then '可能不能判 “invalid_grant”,见 #269
                 ElseIf ex.Message.Contains("AADSTS70000") Then '可能不能判 “invalid_grant”,见 #269
                     Finished(New RestartException)
                     Finished(New RestartException)
                     Return
                     Return

+ 30 - 33
Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb

@@ -22,10 +22,10 @@
     End Sub
     End Sub
 #End If
 #End If
 
 
-#Region "自定义主页"
+#Region "主页"
 
 
     ''' <summary>
     ''' <summary>
-    ''' 刷新自定义主页。
+    ''' 刷新主页。
     ''' </summary>
     ''' </summary>
     Private Sub Refresh() Handles Me.Loaded
     Private Sub Refresh() Handles Me.Loaded
         RunInNewThread(
         RunInNewThread(
@@ -35,9 +35,9 @@
                     RefreshReal()
                     RefreshReal()
                 End SyncLock
                 End SyncLock
             Catch ex As Exception
             Catch ex As Exception
-                Log(ex, "加载 PCL 主页自定义信息失败", LogLevel.Msgbox)
+                Log(ex, "加载 PCL 主页自定义信息失败", If(ModeDebug, LogLevel.Msgbox, LogLevel.Hint))
             End Try
             End Try
-        End Sub, $"刷新自定义主页 #{GetUuid()}")
+        End Sub, $"刷新主页 #{GetUuid()}")
     End Sub
     End Sub
     Private Sub RefreshReal()
     Private Sub RefreshReal()
         Dim Content As String = ""
         Dim Content As String = ""
@@ -133,8 +133,8 @@ Download:
     End Sub
     End Sub
     Private RefreshLock As New Object
     Private RefreshLock As New Object
 
 
-    '联网获取自定义主页文件
-    Private OnlineLoader As New LoaderTask(Of String, Integer)("自定义主页获取", AddressOf OnlineLoaderSub) With {.ReloadTimeout = 10 * 60 * 1000}
+    '联网获取主页文件
+    Private OnlineLoader As New LoaderTask(Of String, Integer)("下载主页", AddressOf OnlineLoaderSub) With {.ReloadTimeout = 10 * 60 * 1000}
     Private Sub OnlineLoaderSub(Task As LoaderTask(Of String, Integer))
     Private Sub OnlineLoaderSub(Task As LoaderTask(Of String, Integer))
         Dim Address As String = Task.Input '#3721 中连续触发两次导致内容变化
         Dim Address As String = Task.Input '#3721 中连续触发两次导致内容变化
         Try
         Try
@@ -153,22 +153,22 @@ Download:
             Dim NeedDownload As Boolean = True
             Dim NeedDownload As Boolean = True
             Try
             Try
                 Version = NetGetCodeByRequestOnce(VersionAddress, Timeout:=10000)
                 Version = NetGetCodeByRequestOnce(VersionAddress, Timeout:=10000)
-                If Version.Length > 1000 Then Throw New Exception($"获取的自定义主页版本过长({Version.Length} 字符)")
+                If Version.Length > 1000 Then Throw New Exception($"获取的主页版本过长({Version.Length} 字符)")
                 Dim CurrentVersion As String = Setup.Get("CacheSavedPageVersion")
                 Dim CurrentVersion As String = Setup.Get("CacheSavedPageVersion")
                 If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then
                 If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then
-                    Log($"[Page] 当前缓存的自定义主页已为最新,当前版本:{Version},检查源:{VersionAddress}")
+                    Log($"[Page] 当前缓存的主页已为最新,当前版本:{Version},检查源:{VersionAddress}")
                     NeedDownload = False
                     NeedDownload = False
                 Else
                 Else
-                    Log($"[Page] 需要下载联网自定义主页,当前版本:{Version},检查源:{VersionAddress}")
+                    Log($"[Page] 需要下载联网主页,当前版本:{Version},检查源:{VersionAddress}")
                 End If
                 End If
             Catch exx As Exception
             Catch exx As Exception
-                Log(exx, $"联网获取自定义主页版本失败", LogLevel.Developer)
-                Log($"[Page] 无法检查联网自定义主页版本,将直接下载,检查源:{VersionAddress}")
+                Log(exx, $"联网获取主页版本失败", LogLevel.Developer)
+                Log($"[Page] 无法检查联网主页版本,将直接下载,检查源:{VersionAddress}")
             End Try
             End Try
             '实际下载
             '实际下载
             If NeedDownload Then
             If NeedDownload Then
                 Dim FileContent As String = NetGetCodeByRequestRetry(Address)
                 Dim FileContent As String = NetGetCodeByRequestRetry(Address)
-                Log($"[Page] 已联网下载自定义主页,内容长度:{FileContent.Length},来源:{Address}")
+                Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}")
                 Setup.Set("CacheSavedPageUrl", Address)
                 Setup.Set("CacheSavedPageUrl", Address)
                 Setup.Set("CacheSavedPageVersion", Version)
                 Setup.Set("CacheSavedPageVersion", Version)
                 WriteFile(PathTemp & "Cache\Custom.xaml", FileContent)
                 WriteFile(PathTemp & "Cache\Custom.xaml", FileContent)
@@ -176,20 +176,16 @@ Download:
             '要求刷新
             '要求刷新
             Refresh()
             Refresh()
         Catch ex As Exception
         Catch ex As Exception
-            If Setup.Get("CacheSavedPageVersion") = "" Then
-                Log(ex, $"联网下载自定义主页失败({Address})", LogLevel.Msgbox)
-            Else
-                Log(ex, $"联网下载自定义主页失败({Address})")
-            End If
+            Log(ex, $"下载主页失败({Address})", If(ModeDebug, LogLevel.Msgbox, LogLevel.Hint))
         End Try
         End Try
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
-    ''' 立即强制刷新自定义主页。
+    ''' 立即强制刷新主页。
     ''' 必须在 UI 线程调用。
     ''' 必须在 UI 线程调用。
     ''' </summary>
     ''' </summary>
     Public Sub ForceRefresh() Implements IRefreshable.Refresh
     Public Sub ForceRefresh() Implements IRefreshable.Refresh
-        Log("[Page] 要求强制刷新自定义主页")
+        Log("[Page] 要求强制刷新主页")
         ClearCache()
         ClearCache()
         '实际的刷新
         '实际的刷新
         If FrmMain.PageCurrent.Page = FormMain.PageType.Launch Then
         If FrmMain.PageCurrent.Page = FormMain.PageType.Launch Then
@@ -201,18 +197,18 @@ Download:
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
-    ''' 清空自定义主页缓存信息。
+    ''' 清空主页缓存信息。
     ''' </summary>
     ''' </summary>
     Private Sub ClearCache()
     Private Sub ClearCache()
         LoadedContentHash = -1
         LoadedContentHash = -1
         OnlineLoader.Input = ""
         OnlineLoader.Input = ""
         Setup.Set("CacheSavedPageUrl", "")
         Setup.Set("CacheSavedPageUrl", "")
         Setup.Set("CacheSavedPageVersion", "")
         Setup.Set("CacheSavedPageVersion", "")
-        Log("[Page] 已清空自定义主页缓存")
+        Log("[Page] 已清空主页缓存")
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
-    ''' 从文本内容中加载自定义主页。
+    ''' 从文本内容中加载主页。
     ''' 必须在 UI 线程调用。
     ''' 必须在 UI 线程调用。
     ''' </summary>
     ''' </summary>
     Private Sub LoadContent(Content As String)
     Private Sub LoadContent(Content As String)
@@ -224,27 +220,28 @@ Download:
             '实际加载内容
             '实际加载内容
             PanCustom.Children.Clear()
             PanCustom.Children.Clear()
             If String.IsNullOrWhiteSpace(Content) Then
             If String.IsNullOrWhiteSpace(Content) Then
-                Log($"[Page] 实例化:清空自定义主页 UI,来源为空")
+                Log($"[Page] 实例化:清空主页 UI,来源为空")
                 Return
                 Return
             End If
             End If
             Try
             Try
+                '修改时应同时修改 PageOtherHelpDetail.Init
                 Content = HelpArgumentReplace(Content)
                 Content = HelpArgumentReplace(Content)
                 If Content.Contains("xmlns") Then Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间
                 If Content.Contains("xmlns") Then Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间
                 Content = "<StackPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:sys=""clr-namespace:System;assembly=mscorlib"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:local=""clr-namespace:PCL;assembly=Plain Craft Launcher 2"">" & Content & "</StackPanel>"
                 Content = "<StackPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:sys=""clr-namespace:System;assembly=mscorlib"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:local=""clr-namespace:PCL;assembly=Plain Craft Launcher 2"">" & Content & "</StackPanel>"
-                Log($"[Page] 实例化:加载自定义主页 UI 开始,最终内容长度:{Content.Count}")
+                Log($"[Page] 实例化:加载主页 UI 开始,最终内容长度:{Content.Count}")
                 PanCustom.Children.Add(GetObjectFromXML(Content))
                 PanCustom.Children.Add(GetObjectFromXML(Content))
-            Catch ex As UnauthorizedAccessException
-                Log(ex, "加载失败的自定义主页内容:" & vbCrLf & Content)
-                If MyMsgBox(ex.Message, "加载自定义主页失败", "重试", "取消") = 1 Then
-                    GoTo Refresh '防止 SyncLock 死锁
-                End If
             Catch ex As Exception
             Catch ex As Exception
-                Log(ex, "加载失败的自定义主页内容:" & vbCrLf & Content)
-                If MyMsgBox($"自定义主页内容编写有误,请根据下列错误信息进行检查:{vbCrLf}{GetExceptionSummary(ex)}", "加载自定义主页失败", "重试", "取消") = 1 Then
-                    GoTo Refresh '防止 SyncLock 死锁
+                If ModeDebug Then
+                    Log(ex, "加载失败的主页内容:" & vbCrLf & Content)
+                    If MyMsgBox(If(TypeOf ex Is UnauthorizedAccessException, ex.Message, $"主页内容编写有误,请根据下列错误信息进行检查:{vbCrLf}{GetExceptionSummary(ex)}"),
+                                "加载主页界面失败", "重试", "取消") = 1 Then
+                        GoTo Refresh '防止 SyncLock 死锁
+                    End If
+                Else
+                    Log(ex, "加载主页界面失败", LogLevel.Hint)
                 End If
                 End If
             End Try
             End Try
-            Log($"[Page] 实例化:加载自定义主页 UI 完成")
+            Log($"[Page] 实例化:加载主页 UI 完成")
         End SyncLock
         End SyncLock
         Return
         Return
 Refresh:
 Refresh:

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

@@ -45,7 +45,7 @@ Public Class PageLoginLegacy
         If LoginData.UserName.Trim = "" Then Return "玩家名不能为空!"
         If LoginData.UserName.Trim = "" Then Return "玩家名不能为空!"
         If LoginData.UserName.Contains("""") Then Return "玩家名不能包含英文引号!"
         If LoginData.UserName.Contains("""") Then Return "玩家名不能包含英文引号!"
         If McVersionCurrent IsNot Nothing AndAlso
         If McVersionCurrent IsNot Nothing AndAlso
-           ((McVersionCurrent.Version.McCodeMain = 20 AndAlso McVersionCurrent.Version.McCodeSub >= 3) OrElse McVersionCurrent.Version.McCodeMain > 20) AndAlso
+           (McVersionCurrent.Version.IsStandardVersion AndAlso McVersionCurrent.Version.McVersion >= New Version(1, 20, 3)) AndAlso
            LoginData.UserName.Trim.Length > 16 Then
            LoginData.UserName.Trim.Length > 16 Then
             Return "自 1.20.3 起,玩家名至多只能包含 16 个字符!"
             Return "自 1.20.3 起,玩家名至多只能包含 16 个字符!"
         End If
         End If

+ 6 - 1
Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml

@@ -118,11 +118,13 @@
                         <TextBlock Width="120" Margin="0,1.5" Text="Tong" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Tong" />
                         <TextBlock Width="120" Margin="0,1.5" Text="15158206433" />
                         <TextBlock Width="120" Margin="0,1.5" Text="15158206433" />
                         <TextBlock Width="120" Margin="0,1.5" Text="一抹蓝色和粉色" />
                         <TextBlock Width="120" Margin="0,1.5" Text="一抹蓝色和粉色" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="UcFB" />
                         <TextBlock Width="120" Margin="0,1.5" Text="哦" />
                         <TextBlock Width="120" Margin="0,1.5" Text="哦" />
                         <TextBlock Width="120" Margin="0,1.5" Text="T2222" />
                         <TextBlock Width="120" Margin="0,1.5" Text="T2222" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Toudesu" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Toudesu" />
                         <TextBlock Width="120" Margin="0,1.5" Text="苏利" />
                         <TextBlock Width="120" Margin="0,1.5" Text="苏利" />
                         <TextBlock Width="120" Margin="0,1.5" Text="DW." />
                         <TextBlock Width="120" Margin="0,1.5" Text="DW." />
+                        <TextBlock Width="120" Margin="0,1.5" Text="抛抛不是泡泡" />
                         <TextBlock Width="120" Margin="0,1.5" Text="无名小卒" />
                         <TextBlock Width="120" Margin="0,1.5" Text="无名小卒" />
                         <TextBlock Width="120" Margin="0,1.5" Text="lgl" />
                         <TextBlock Width="120" Margin="0,1.5" Text="lgl" />
                         <TextBlock Width="120" Margin="0,1.5" Text="mk" />
                         <TextBlock Width="120" Margin="0,1.5" Text="mk" />
@@ -187,6 +189,7 @@
                         <TextBlock Width="120" Margin="0,1.5" Text="橘子233" />
                         <TextBlock Width="120" Margin="0,1.5" Text="橘子233" />
                         <TextBlock Width="120" Margin="0,1.5" Text="wyhll" />
                         <TextBlock Width="120" Margin="0,1.5" Text="wyhll" />
                         <TextBlock Width="120" Margin="0,1.5" Text="SiMen_774" />
                         <TextBlock Width="120" Margin="0,1.5" Text="SiMen_774" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Klcos" />
                         <TextBlock Width="120" Margin="0,1.5" Text="pepsi" />
                         <TextBlock Width="120" Margin="0,1.5" Text="pepsi" />
                         <TextBlock Width="120" Margin="0,1.5" Text="FORGE" />
                         <TextBlock Width="120" Margin="0,1.5" Text="FORGE" />
                         <TextBlock Width="120" Margin="0,1.5" Text="李青团" />
                         <TextBlock Width="120" Margin="0,1.5" Text="李青团" />
@@ -197,6 +200,7 @@
                         <TextBlock Width="120" Margin="0,1.5" Text="赤诚之心" />
                         <TextBlock Width="120" Margin="0,1.5" Text="赤诚之心" />
                         <TextBlock Width="120" Margin="0,1.5" Text="藏白" />
                         <TextBlock Width="120" Margin="0,1.5" Text="藏白" />
                         <TextBlock Width="120" Margin="0,1.5" Text="某零子" />
                         <TextBlock Width="120" Margin="0,1.5" Text="某零子" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="WJMAS" />
                         <TextBlock Width="120" Margin="0,1.5" Text="骨头" />
                         <TextBlock Width="120" Margin="0,1.5" Text="骨头" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Starying" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Starying" />
                         <TextBlock Width="120" Margin="0,1.5" Text="钱小穷" />
                         <TextBlock Width="120" Margin="0,1.5" Text="钱小穷" />
@@ -269,6 +273,7 @@
                         <TextBlock Width="120" Margin="0,1.5" Text="梦境之中" />
                         <TextBlock Width="120" Margin="0,1.5" Text="梦境之中" />
                         <TextBlock Width="120" Margin="0,1.5" Text="青枝望月" />
                         <TextBlock Width="120" Margin="0,1.5" Text="青枝望月" />
                         <TextBlock Width="120" Margin="0,1.5" Text="m1nato__" />
                         <TextBlock Width="120" Margin="0,1.5" Text="m1nato__" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="dingwenbo" />
                         <TextBlock Width="120" Margin="0,1.5" Text="法老" />
                         <TextBlock Width="120" Margin="0,1.5" Text="法老" />
                         <TextBlock Width="120" Margin="0,1.5" Text="和十奕" />
                         <TextBlock Width="120" Margin="0,1.5" Text="和十奕" />
                         <TextBlock Width="120" Margin="0,1.5" Text="give" />
                         <TextBlock Width="120" Margin="0,1.5" Text="give" />
@@ -281,7 +286,7 @@
                         <TextBlock Width="120" Margin="0,1.5" Text="灵喻" />
                         <TextBlock Width="120" Margin="0,1.5" Text="灵喻" />
                         <TextBlock Width="120" Margin="0,1.5" Text="_暮霭" />
                         <TextBlock Width="120" Margin="0,1.5" Text="_暮霭" />
                         <TextBlock Width="120" Margin="0,1.5" Text="TylerDeng" />
                         <TextBlock Width="120" Margin="0,1.5" Text="TylerDeng" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="咸鱼汤鱼咸" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="我不在线" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Hugh" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Hugh" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Qiyue" />
                         <TextBlock Width="120" Margin="0,1.5" Text="Qiyue" />
                         <TextBlock Width="120" Margin="0,1.5" Text="CHAKKS" />
                         <TextBlock Width="120" Margin="0,1.5" Text="CHAKKS" />

+ 9 - 6
Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb

@@ -14,17 +14,20 @@
     ''' 根据特定帮助项初始化页面 UI,返回是否成功加载。
     ''' 根据特定帮助项初始化页面 UI,返回是否成功加载。
     ''' </summary>
     ''' </summary>
     Public Function Init(Entry As HelpEntry) As Boolean
     Public Function Init(Entry As HelpEntry) As Boolean
-        Dim FileContent = "<StackPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:local=""clr-namespace:PCL;assembly=Plain Craft Launcher 2"">" & If(Entry.XamlContent, "") & "</StackPanel>"
+        Dim Content = If(Entry.XamlContent, "")
+        If Content = "" Then Throw New Exception("帮助 xaml 文件为空")
         Try
         Try
-            If String.IsNullOrEmpty(Entry.XamlContent) Then Throw New Exception("帮助 xaml 文件为空")
+            '修改时应同时修改 PageLaunchRight.LoadContent
+            Content = HelpArgumentReplace(Content)
+            If Content.Contains("xmlns") Then Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间
+            Content = "<StackPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:sys=""clr-namespace:System;assembly=mscorlib"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:local=""clr-namespace:PCL;assembly=Plain Craft Launcher 2"">" & Content & "</StackPanel>"
             Me.Entry = Entry
             Me.Entry = Entry
             PanCustom.Children.Clear()
             PanCustom.Children.Clear()
-            FileContent = HelpArgumentReplace(FileContent)
-            PanCustom.Children.Add(GetObjectFromXML(FileContent))
+            PanCustom.Children.Add(GetObjectFromXML(Content))
             Return True
             Return True
         Catch ex As Exception
         Catch ex As Exception
-            Log("[System] 自定义信息内容:" & vbCrLf & FileContent)
-            Log(ex, "加载帮助 xaml 文件失败", LogLevel.Msgbox)
+            Log("[System] 自定义信息内容:" & vbCrLf & Content)
+            Log(ex, "加载帮助 XAML 文件失败", LogLevel.Msgbox)
             Return False
             Return False
         End Try
         End Try
     End Function
     End Function

+ 2 - 1
Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb

@@ -118,7 +118,8 @@
         {"ToolHelpChinese", New SetupEntry(True, Source:=SetupSource.Registry)},
         {"ToolHelpChinese", New SetupEntry(True, Source:=SetupSource.Registry)},
         {"ToolDownloadThread", New SetupEntry(63, Source:=SetupSource.Registry)},
         {"ToolDownloadThread", New SetupEntry(63, Source:=SetupSource.Registry)},
         {"ToolDownloadSpeed", New SetupEntry(42, Source:=SetupSource.Registry)},
         {"ToolDownloadSpeed", New SetupEntry(42, Source:=SetupSource.Registry)},
-        {"ToolDownloadVersion", New SetupEntry(0, Source:=SetupSource.Registry)},
+        {"ToolDownloadSource", New SetupEntry(1, Source:=SetupSource.Registry)},
+        {"ToolDownloadVersion", New SetupEntry(1, Source:=SetupSource.Registry)},
         {"ToolDownloadTranslate", New SetupEntry(0, Source:=SetupSource.Registry)},
         {"ToolDownloadTranslate", New SetupEntry(0, Source:=SetupSource.Registry)},
         {"ToolDownloadTranslateV2", New SetupEntry(1, Source:=SetupSource.Registry)},
         {"ToolDownloadTranslateV2", New SetupEntry(1, Source:=SetupSource.Registry)},
         {"ToolDownloadIgnoreQuilt", New SetupEntry(True, Source:=SetupSource.Registry)},
         {"ToolDownloadIgnoreQuilt", New SetupEntry(True, Source:=SetupSource.Registry)},

+ 1 - 1
Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb

@@ -150,7 +150,7 @@
                     ItemLaunch.Checked = True
                     ItemLaunch.Checked = True
                 End If
                 End If
             Case FormMain.PageSubType.SetupUI
             Case FormMain.PageSubType.SetupUI
-                If MyMsgBox("是否要初始化个性化页的所有设置?该操作不可撤销。" & vbCrLf & "(背景图片与音乐、自定义主页等外部文件不会被删除)", "初始化确认",, "取消", IsWarn:=True) = 1 Then
+                If MyMsgBox("是否要初始化个性化页的所有设置?该操作不可撤销。" & vbCrLf & "(背景图片与音乐、主页等外部文件不会被删除)", "初始化确认",, "取消", IsWarn:=True) = 1 Then
                     If IsNothing(FrmSetupUI) Then FrmSetupUI = New PageSetupUI
                     If IsNothing(FrmSetupUI) Then FrmSetupUI = New PageSetupUI
                     FrmSetupUI.Reset()
                     FrmSetupUI.Reset()
                     ItemUI.Checked = True
                     ItemUI.Checked = True

+ 29 - 21
Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml

@@ -15,6 +15,8 @@
                             <ColumnDefinition />
                             <ColumnDefinition />
                         </Grid.ColumnDefinitions>
                         </Grid.ColumnDefinitions>
                         <Grid.RowDefinitions>
                         <Grid.RowDefinitions>
+                            <RowDefinition Height="28" />
+                            <RowDefinition Height="7" />
                             <RowDefinition Height="28" />
                             <RowDefinition Height="28" />
                             <RowDefinition Height="7" />
                             <RowDefinition Height="7" />
                             <RowDefinition Height="27" />
                             <RowDefinition Height="27" />
@@ -22,28 +24,34 @@
                             <RowDefinition Height="Auto" />
                             <RowDefinition Height="Auto" />
                             <RowDefinition Height="Auto" />
                             <RowDefinition Height="Auto" />
                         </Grid.RowDefinitions>
                         </Grid.RowDefinitions>
-                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="版本列表源" Margin="0,0,25,0" />
-                        <local:MyComboBox x:Name="ComboDownloadVersion" Grid.ColumnSpan="2" Tag="ToolDownloadVersion" Grid.Column="1">
-                            <local:MyComboBoxItem Content="尽量使用镜像源(加载快,但版本可能不是最新的)" IsSelected="True" />
-                            <local:MyComboBoxItem Content="仅在官方源加载缓慢时改用镜像源" />
-                            <local:MyComboBoxItem Content="尽量使用官方源(保证版本最新,但加载缓慢)" />
+                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="文件下载源" Margin="0,0,25,0" />
+                        <local:MyComboBox x:Name="ComboDownloadSource" Grid.ColumnSpan="2" Tag="ToolDownloadSource" Grid.Column="1">
+                            <local:MyComboBoxItem Content="尽量使用镜像源" />
+                            <local:MyComboBoxItem Content="优先使用官方源,在加载缓慢时换用镜像源" IsSelected="True" />
+                            <local:MyComboBoxItem Content="尽量使用官方源" />
                         </local:MyComboBox>
                         </local:MyComboBox>
-                        <TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="最大线程数" Margin="0,0,25,0" />
-                        <local:MySlider x:Name="SliderDownloadThread" Grid.Row="2" Tag="ToolDownloadThread" MaxValue="255" Value="63" Grid.Column="1"
+                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="版本列表源" Margin="0,0,25,0" Grid.Row="2" />
+                        <local:MyComboBox x:Name="ComboDownloadVersion" Grid.ColumnSpan="2" Tag="ToolDownloadVersion" Grid.Column="1" Grid.Row="2">
+                            <local:MyComboBoxItem Content="尽量使用镜像源(可能缺少刚刚更新的版本)" />
+                            <local:MyComboBoxItem Content="优先使用官方源,在加载缓慢时换用镜像源" IsSelected="True" />
+                            <local:MyComboBoxItem Content="尽量使用官方源" />
+                        </local:MyComboBox>
+                        <TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="最大线程数" Margin="0,0,25,0" />
+                        <local:MySlider x:Name="SliderDownloadThread" Grid.Row="4" Tag="ToolDownloadThread" MaxValue="255" Value="63" Grid.Column="1"
                                         ToolTip="线程数越多,限速的文件下载越快,但过高的线程数会造成下载时非常严重的卡顿。&#xa;一般而言,64 线程已可以保证足够的下载速度。" />
                                         ToolTip="线程数越多,限速的文件下载越快,但过高的线程数会造成下载时非常严重的卡顿。&#xa;一般而言,64 线程已可以保证足够的下载速度。" />
-                        <TextBlock VerticalAlignment="Center" Grid.Row="3" HorizontalAlignment="Left" Text="速度限制" Margin="0,0,25,0" />
-                        <local:MySlider x:Name="SliderDownloadSpeed" Grid.Row="3" Tag="ToolDownloadSpeed" MaxValue="42" Value="42" Grid.Column="1"
+                        <TextBlock VerticalAlignment="Center" Grid.Row="5" HorizontalAlignment="Left" Text="速度限制" Margin="0,0,25,0" />
+                        <local:MySlider x:Name="SliderDownloadSpeed" Grid.Row="5" Tag="ToolDownloadSpeed" MaxValue="42" Value="42" Grid.Column="1"
                                         ToolTip="设置下载的速度上限,以避免在下载时导致其他需要联网的程序卡死" />
                                         ToolTip="设置下载的速度上限,以避免在下载时导致其他需要联网的程序卡死" />
-                        <TextBlock VerticalAlignment="Top" Grid.Row="4" HorizontalAlignment="Left" Text="目标文件夹" Margin="0,5,25,5" />
-                        <TextBlock Margin="0,5" HorizontalAlignment="Left" Text="请在 启动 → 版本选择 → 文件夹列表 中更改下载目标文件夹。&#xa;在某个文件夹或游戏版本上右键,即可选择打开对应文件夹。" Grid.Row="4" Grid.Column="1" VerticalAlignment="Center" Opacity="0.5" />
-                        <local:MyCheckBox Margin="0,2,0,4" Text="在正版登录时验证 SSL 证书" Grid.Row="5" Height="22" Grid.ColumnSpan="2"
+                        <TextBlock VerticalAlignment="Top" Grid.Row="6" HorizontalAlignment="Left" Text="目标文件夹" Margin="0,5,25,5" />
+                        <TextBlock Margin="0,5" HorizontalAlignment="Left" Text="请在 启动 → 版本选择 → 文件夹列表 中更改下载目标文件夹。&#xa;在某个文件夹或游戏版本上右键,即可选择打开对应文件夹。" Grid.Row="6" Grid.Column="1" VerticalAlignment="Center" Opacity="0.5" />
+                        <local:MyCheckBox Margin="0,2,0,4" Text="在正版登录时验证 SSL 证书" Grid.Row="7" Height="22" Grid.ColumnSpan="2"
                                           x:Name="CheckDownloadCert" Tag="ToolDownloadCert" 
                                           x:Name="CheckDownloadCert" Tag="ToolDownloadCert" 
                                           ToolTip="开启验证可以提高安全性,但可能会导致正版登录失败(见 #3018)。&#xa;若登录因为 “未能为 SSL/TLS 安全通道建立信任关系” 失败,请考虑关闭此选项。" />
                                           ToolTip="开启验证可以提高安全性,但可能会导致正版登录失败(见 #3018)。&#xa;若登录因为 “未能为 SSL/TLS 安全通道建立信任关系” 失败,请考虑关闭此选项。" />
                     </Grid>
                     </Grid>
                 </StackPanel>
                 </StackPanel>
             </local:MyCard>
             </local:MyCard>
-            <local:MyCard Margin="0,0,0,15" Title="Mod 与整合包">
-                <StackPanel Margin="25,37,25,15">
+            <local:MyCard Margin="0,0,0,15" Title="社区资源">
+                <StackPanel Margin="25,37,25,12">
                     <Grid>
                     <Grid>
                         <Grid.ColumnDefinitions>
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
                             <ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
@@ -64,12 +72,12 @@
                         </local:MyComboBox>-->
                         </local:MyComboBox>-->
                         <TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="文件名格式" Margin="0,0,25,0" />
                         <TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="文件名格式" Margin="0,0,25,0" />
                         <local:MyComboBox Grid.Row="0" x:Name="ComboDownloadTranslateV2" Grid.ColumnSpan="2" Tag="ToolDownloadTranslateV2" Grid.Column="1" 
                         <local:MyComboBox Grid.Row="0" x:Name="ComboDownloadTranslateV2" Grid.ColumnSpan="2" Tag="ToolDownloadTranslateV2" Grid.Column="1" 
-                                          ToolTip="下载 Mod 时,Mod 的默认文件名格式">
-                            <local:MyComboBoxItem Content="【遗物】relics-0.1.14" />
-                            <local:MyComboBoxItem Content="[遗物] relics-0.1.14" IsSelected="True" />
-                            <local:MyComboBoxItem Content="遗物-relics-0.1.14" />
-                            <local:MyComboBoxItem Content="relics-0.1.14-遗物" />
-                            <local:MyComboBoxItem Content="relics-0.1.14" />
+                                          ToolTip="下载社区资源时,其默认文件名的格式">
+                            <local:MyComboBoxItem Content="【机械动力】create-1.21.1-6.0.4" />
+                            <local:MyComboBoxItem Content="[机械动力] create-1.21.1-6.0.4" IsSelected="True" />
+                            <local:MyComboBoxItem Content="机械动力-create-1.21.1-6.0.4" />
+                            <local:MyComboBoxItem Content="create-1.21.1-6.0.4-机械动力" />
+                            <local:MyComboBoxItem Content="create-1.21.1-6.0.4" />
                         </local:MyComboBox>
                         </local:MyComboBox>
                         <TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="Mod 管理样式" Margin="0,0,25,0" />
                         <TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="Mod 管理样式" Margin="0,0,25,0" />
                         <local:MyComboBox Grid.Row="2" x:Name="ComboModLocalNameStyle" Grid.ColumnSpan="2" Tag="ToolModLocalNameStyle" Grid.Column="1" 
                         <local:MyComboBox Grid.Row="2" x:Name="ComboModLocalNameStyle" Grid.ColumnSpan="2" Tag="ToolModLocalNameStyle" Grid.Column="1" 
@@ -77,7 +85,7 @@
                             <local:MyComboBoxItem Content="标题显示译名,详情显示文件名" IsSelected="True" />
                             <local:MyComboBoxItem Content="标题显示译名,详情显示文件名" IsSelected="True" />
                             <local:MyComboBoxItem Content="标题显示文件名,详情显示译名" />
                             <local:MyComboBoxItem Content="标题显示文件名,详情显示译名" />
                         </local:MyComboBox>
                         </local:MyComboBox>
-                        <local:MyCheckBox Margin="0,2,0,4" Text="显示 Mod 加载器时忽略 Quilt" Grid.Row="4" Height="22" Grid.ColumnSpan="2"
+                        <local:MyCheckBox Margin="0,2,0,4" Text="在显示 Mod 加载器时忽略 Quilt" Grid.Row="4" Height="22" Grid.ColumnSpan="2"
                                           x:Name="CheckDownloadIgnoreQuilt" Tag="ToolDownloadIgnoreQuilt" />
                                           x:Name="CheckDownloadIgnoreQuilt" Tag="ToolDownloadIgnoreQuilt" />
                     </Grid>
                     </Grid>
                 </StackPanel>
                 </StackPanel>

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

@@ -29,6 +29,7 @@
         '下载
         '下载
         SliderDownloadThread.Value = Setup.Get("ToolDownloadThread")
         SliderDownloadThread.Value = Setup.Get("ToolDownloadThread")
         SliderDownloadSpeed.Value = Setup.Get("ToolDownloadSpeed")
         SliderDownloadSpeed.Value = Setup.Get("ToolDownloadSpeed")
+        ComboDownloadSource.SelectedIndex = Setup.Get("ToolDownloadSource")
         ComboDownloadVersion.SelectedIndex = Setup.Get("ToolDownloadVersion")
         ComboDownloadVersion.SelectedIndex = Setup.Get("ToolDownloadVersion")
         CheckDownloadCert.Checked = Setup.Get("ToolDownloadCert")
         CheckDownloadCert.Checked = Setup.Get("ToolDownloadCert")
 
 
@@ -63,6 +64,7 @@
         Try
         Try
             Setup.Reset("ToolDownloadThread")
             Setup.Reset("ToolDownloadThread")
             Setup.Reset("ToolDownloadSpeed")
             Setup.Reset("ToolDownloadSpeed")
+            Setup.Reset("ToolDownloadSource")
             Setup.Reset("ToolDownloadVersion")
             Setup.Reset("ToolDownloadVersion")
             Setup.Reset("ToolDownloadTranslateV2")
             Setup.Reset("ToolDownloadTranslateV2")
             Setup.Reset("ToolDownloadIgnoreQuilt")
             Setup.Reset("ToolDownloadIgnoreQuilt")
@@ -96,7 +98,7 @@
     Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderDebugAnim.Change, SliderDownloadThread.Change, SliderDownloadSpeed.Change
     Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderDebugAnim.Change, SliderDownloadThread.Change, SliderDownloadSpeed.Change
         If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value)
         If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value)
     End Sub
     End Sub
-    Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboDownloadVersion.SelectionChanged, ComboModLocalNameStyle.SelectionChanged, ComboDownloadTranslateV2.SelectionChanged, ComboSystemUpdate.SelectionChanged, ComboSystemActivity.SelectionChanged
+    Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboDownloadVersion.SelectionChanged, ComboModLocalNameStyle.SelectionChanged, ComboDownloadTranslateV2.SelectionChanged, ComboSystemUpdate.SelectionChanged, ComboSystemActivity.SelectionChanged, ComboDownloadSource.SelectionChanged
         If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex)
         If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex)
     End Sub
     End Sub
     Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextSystemCache.ValidatedTextChanged
     Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextSystemCache.ValidatedTextChanged

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

@@ -422,7 +422,7 @@ Refresh:
                  "3. 点击 刷新主页 按钮,查看主页现在长啥样了。" & vbCrLf &
                  "3. 点击 刷新主页 按钮,查看主页现在长啥样了。" & vbCrLf &
                  vbCrLf &
                  vbCrLf &
                  "你可以在生成教学文件后直接刷新主页,对照着进行修改,更有助于理解。" & vbCrLf &
                  "你可以在生成教学文件后直接刷新主页,对照着进行修改,更有助于理解。" & vbCrLf &
-                 "直接将自定义主页文件拖进 PCL 窗口也可以快捷加载。", "主页自定义教程")
+                 "直接将主页文件拖进 PCL 窗口也可以快捷加载。", "主页自定义教程")
     End Sub
     End Sub
 
 
     '主题
     '主题

+ 0 - 0
Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml → Plain Craft Launcher 2/Pages/PageVersion/MyLocalModItem.xaml


+ 0 - 0
Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb → Plain Craft Launcher 2/Pages/PageVersion/MyLocalModItem.xaml.vb


+ 5 - 4
Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb

@@ -380,7 +380,7 @@ Install:
     ''' 下载 Mod。
     ''' 下载 Mod。
     ''' </summary>
     ''' </summary>
     Private Sub BtnManageDownload_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageDownload.Click, BtnHintDownload.Click
     Private Sub BtnManageDownload_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageDownload.Click, BtnHintDownload.Click
-        PageDownloadMod.TargetVersion = PageVersionLeft.Version '将当前版本设置为筛选器
+        PageComp.TargetVersion = PageVersionLeft.Version '将当前版本设置为筛选器
         FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadMod)
         FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadMod)
     End Sub
     End Sub
 
 
@@ -432,7 +432,7 @@ Install:
 #Region "筛选"
 #Region "筛选"
 
 
     Private _Filter As FilterType = FilterType.All
     Private _Filter As FilterType = FilterType.All
-    Private Property Filter As FilterType
+    Public Property Filter As FilterType
         Get
         Get
             Return _Filter
             Return _Filter
         End Get
         End Get
@@ -454,7 +454,7 @@ Install:
             RefreshUI()
             RefreshUI()
         End Set
         End Set
     End Property
     End Property
-    Private Enum FilterType As Integer
+    Public Enum FilterType As Integer
         All = 0
         All = 0
         Enabled = 1
         Enabled = 1
         Disabled = 2
         Disabled = 2
@@ -808,7 +808,8 @@ Install:
                     .Additional = {ModEntry.Comp, New List(Of String), PageVersionLeft.Version.Version.McName,
                     .Additional = {ModEntry.Comp, New List(Of String), PageVersionLeft.Version.Version.McName,
                         If(PageVersionLeft.Version.Version.HasForge, CompModLoaderType.Forge,
                         If(PageVersionLeft.Version.Version.HasForge, CompModLoaderType.Forge,
                         If(PageVersionLeft.Version.Version.HasNeoForge, CompModLoaderType.NeoForge,
                         If(PageVersionLeft.Version.Version.HasNeoForge, CompModLoaderType.NeoForge,
-                        If(PageVersionLeft.Version.Version.HasFabric, CompModLoaderType.Fabric, CompModLoaderType.Any)))}})
+                        If(PageVersionLeft.Version.Version.HasFabric, CompModLoaderType.Fabric, CompModLoaderType.Any))),
+                        CompType.Mod}})
             Else
             Else
                 '获取信息
                 '获取信息
                 Dim ContentLines As New List(Of String)
                 Dim ContentLines As New List(Of String)

+ 41 - 29
Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj

@@ -195,11 +195,14 @@
     <Compile Include="Controls\MyIconTextButton.xaml.vb">
     <Compile Include="Controls\MyIconTextButton.xaml.vb">
       <DependentUpon>MyIconTextButton.xaml</DependentUpon>
       <DependentUpon>MyIconTextButton.xaml</DependentUpon>
     </Compile>
     </Compile>
+
+
+
     <Compile Include="Modules\Minecraft\ModComp.vb" />
     <Compile Include="Modules\Minecraft\ModComp.vb" />
     <Compile Include="Modules\Minecraft\ModJava.vb" />
     <Compile Include="Modules\Minecraft\ModJava.vb" />
     <Compile Include="Modules\Minecraft\ModMod.vb" />
     <Compile Include="Modules\Minecraft\ModMod.vb" />
     <Compile Include="Modules\Minecraft\ModModpack.vb" />
     <Compile Include="Modules\Minecraft\ModModpack.vb" />
-    <Compile Include="Modules\Minecraft\MyLocalModItem.xaml.vb">
+    <Compile Include="Pages\PageVersion\MyLocalModItem.xaml.vb">
       <DependentUpon>MyLocalModItem.xaml</DependentUpon>
       <DependentUpon>MyLocalModItem.xaml</DependentUpon>
     </Compile>
     </Compile>
     <Compile Include="Modules\ModEvent.vb" />
     <Compile Include="Modules\ModEvent.vb" />
@@ -235,17 +238,26 @@
     <Compile Include="Modules\Reference\CookieWebClient.vb">
     <Compile Include="Modules\Reference\CookieWebClient.vb">
       <SubType>Component</SubType>
       <SubType>Component</SubType>
     </Compile>
     </Compile>
-    <Compile Include="Pages\PageDownload\ModDownloadLib.vb" />
-    <Compile Include="Modules\Minecraft\MyCompItem.xaml.vb">
-      <DependentUpon>MyCompItem.xaml</DependentUpon>
+    <Compile Include="Pages\PageDownload\Comp\PageComp.xaml.vb">
+      <DependentUpon>PageComp.xaml</DependentUpon>
     </Compile>
     </Compile>
-    <Compile Include="Pages\PageDownload\PageDownloadDataPack.xaml.vb">
+    <Compile Include="Pages\PageDownload\Comp\PageDownloadDataPack.xaml.vb">
       <DependentUpon>PageDownloadDataPack.xaml</DependentUpon>
       <DependentUpon>PageDownloadDataPack.xaml</DependentUpon>
     </Compile>
     </Compile>
-    <Compile Include="Pages\PageDownload\PageDownloadResourcePack.xaml.vb">
+    <Compile Include="Pages\PageDownload\Comp\PageDownloadPack.xaml.vb">
+      <DependentUpon>PageDownloadPack.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Pages\PageDownload\Comp\PageDownloadShader.xaml.vb">
+      <DependentUpon>PageDownloadShader.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Pages\PageDownload\Comp\PageDownloadResourcePack.xaml.vb">
       <DependentUpon>PageDownloadResourcePack.xaml</DependentUpon>
       <DependentUpon>PageDownloadResourcePack.xaml</DependentUpon>
     </Compile>
     </Compile>
-    <Compile Include="Pages\PageDownload\PageDownloadMod.xaml.vb">
+    <Compile Include="Pages\PageDownload\ModDownloadLib.vb" />
+    <Compile Include="Pages\PageDownload\Comp\MyCompItem.xaml.vb">
+      <DependentUpon>MyCompItem.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Pages\PageDownload\Comp\PageDownloadMod.xaml.vb">
       <DependentUpon>PageDownloadMod.xaml</DependentUpon>
       <DependentUpon>PageDownloadMod.xaml</DependentUpon>
     </Compile>
     </Compile>
     <Compile Include="Pages\PageDownload\PageDownloadFabric.xaml.vb">
     <Compile Include="Pages\PageDownload\PageDownloadFabric.xaml.vb">
@@ -254,18 +266,12 @@
     <Compile Include="Pages\PageDownload\PageDownloadInstall.xaml.vb">
     <Compile Include="Pages\PageDownload\PageDownloadInstall.xaml.vb">
       <DependentUpon>PageDownloadInstall.xaml</DependentUpon>
       <DependentUpon>PageDownloadInstall.xaml</DependentUpon>
     </Compile>
     </Compile>
-    <Compile Include="Pages\PageDownload\PageDownloadCompDetail.xaml.vb">
+    <Compile Include="Pages\PageDownload\Comp\PageDownloadCompDetail.xaml.vb">
       <DependentUpon>PageDownloadCompDetail.xaml</DependentUpon>
       <DependentUpon>PageDownloadCompDetail.xaml</DependentUpon>
     </Compile>
     </Compile>
     <Compile Include="Pages\PageDownload\PageDownloadNeoForge.xaml.vb">
     <Compile Include="Pages\PageDownload\PageDownloadNeoForge.xaml.vb">
       <DependentUpon>PageDownloadNeoForge.xaml</DependentUpon>
       <DependentUpon>PageDownloadNeoForge.xaml</DependentUpon>
     </Compile>
     </Compile>
-    <Compile Include="Pages\PageDownload\PageDownloadPack.xaml.vb">
-      <DependentUpon>PageDownloadPack.xaml</DependentUpon>
-    </Compile>
-    <Compile Include="Pages\PageDownload\PageDownloadShader.xaml.vb">
-      <DependentUpon>PageDownloadShader.xaml</DependentUpon>
-    </Compile>
     <Compile Include="Pages\PageLaunch\MyMsgLogin.xaml.vb">
     <Compile Include="Pages\PageLaunch\MyMsgLogin.xaml.vb">
       <DependentUpon>MyMsgLogin.xaml</DependentUpon>
       <DependentUpon>MyMsgLogin.xaml</DependentUpon>
     </Compile>
     </Compile>
@@ -495,23 +501,36 @@
       <DependentUpon>FormMain.xaml</DependentUpon>
       <DependentUpon>FormMain.xaml</DependentUpon>
       <SubType>Code</SubType>
       <SubType>Code</SubType>
     </Compile>
     </Compile>
-    <Page Include="Modules\Minecraft\MyLocalModItem.xaml">
+
+    <Page Include="Pages\PageVersion\MyLocalModItem.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Pages\PageDownload\Comp\MyCompItem.xaml">
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
     </Page>
     </Page>
-    <Page Include="Modules\Minecraft\MyCompItem.xaml">
+    <Page Include="Pages\PageDownload\Comp\PageComp.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Pages\PageDownload\Comp\PageDownloadDataPack.xaml">
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
     </Page>
     </Page>
-    <Page Include="Pages\PageDownload\PageDownloadDataPack.xaml">
+    <Page Include="Pages\PageDownload\Comp\PageDownloadPack.xaml">
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
     </Page>
     </Page>
-    <Page Include="Pages\PageDownload\PageDownloadResourcePack.xaml">
+    <Page Include="Pages\PageDownload\Comp\PageDownloadShader.xaml">
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
     </Page>
     </Page>
-    <Page Include="Pages\PageDownload\PageDownloadMod.xaml">
+    <Page Include="Pages\PageDownload\Comp\PageDownloadResourcePack.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Pages\PageDownload\Comp\PageDownloadMod.xaml">
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
     </Page>
     </Page>
@@ -523,7 +542,7 @@
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
     </Page>
     </Page>
-    <Page Include="Pages\PageDownload\PageDownloadCompDetail.xaml">
+    <Page Include="Pages\PageDownload\Comp\PageDownloadCompDetail.xaml">
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
     </Page>
     </Page>
@@ -531,14 +550,6 @@
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
     </Page>
     </Page>
-    <Page Include="Pages\PageDownload\PageDownloadPack.xaml">
-      <SubType>Designer</SubType>
-      <Generator>MSBuild:Compile</Generator>
-    </Page>
-    <Page Include="Pages\PageDownload\PageDownloadShader.xaml">
-      <Generator>MSBuild:Compile</Generator>
-      <SubType>Designer</SubType>
-    </Page>
     <Page Include="Pages\PageLaunch\MyMsgLogin.xaml">
     <Page Include="Pages\PageLaunch\MyMsgLogin.xaml">
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
@@ -946,6 +957,7 @@
     <Resource Include="Images\Heads\MCBBS.png" />
     <Resource Include="Images\Heads\MCBBS.png" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Resource Include="Images\Blocks\NeoForge.png" />
     <Resource Include="Images\Blocks\NeoForge.png" />
@@ -958,4 +970,4 @@
     <None Include="Resources\libwebp64.dll" />
     <None Include="Resources\libwebp64.dll" />
   </ItemGroup>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
-</Project>
+</Project>

+ 2 - 2
Plain Craft Launcher 2/Resources/Custom.xaml

@@ -299,11 +299,11 @@
     </StackPanel>
     </StackPanel>
 </local:MyCard>
 </local:MyCard>
 
 
-<local:MyCard Title="进阶:联网自定义主页" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
+<local:MyCard Title="进阶:联网主页" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
     <StackPanel Margin="25,40,23,15">
     <StackPanel Margin="25,40,23,15">
         <local:MyHint Margin="0,0,0,10" Text="以下特性于 PCL 2.6.5 (299) 加入,不适用于更早版本的 PCL。" IsWarn="False" />
         <local:MyHint Margin="0,0,0,10" Text="以下特性于 PCL 2.6.5 (299) 加入,不适用于更早版本的 PCL。" IsWarn="False" />
         <TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
         <TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
-                    Text="如果你在尝试制作联网更新的自定义主页,可以查看下方的 GitHub 讨论页。&#xa;你可以根据其中的介绍为主页添加版本号检查以节省流量,也可以通过检查 Referer 和 User Agent 来确定对方的 PCL 版本。" />
+                    Text="如果你在尝试制作联网更新的主页,可以查看下方的 GitHub 讨论页。&#xa;你可以根据其中的介绍为主页添加版本号检查以节省流量,也可以通过检查 Referer 和 User Agent 来确定对方的 PCL 版本。" />
         <local:MyButton Margin="0,0,0,8" Height="35" HorizontalAlignment="Center" Padding="20,0,20,0"
         <local:MyButton Margin="0,0,0,8" Height="35" HorizontalAlignment="Center" Padding="20,0,20,0"
                     Text="打开 GitHub 讨论页" EventType="打开网页" EventData="https://github.com/Hex-Dragon/PCL2/discussions/2528" />
                     Text="打开 GitHub 讨论页" EventType="打开网页" EventData="https://github.com/Hex-Dragon/PCL2/discussions/2528" />
     </StackPanel>
     </StackPanel>