龙腾猫跃 2 лет назад
Родитель
Сommit
7b0e925748
47 измененных файлов с 1185 добавлено и 1180 удалено
  1. 6 26
      Plain Craft Launcher 2/Controls/MyCard.vb
  2. 7 7
      Plain Craft Launcher 2/Controls/MyPageRight.vb
  3. 18 5
      Plain Craft Launcher 2/FormMain.xaml.vb
  4. 72 67
      Plain Craft Launcher 2/Modules/Base/ModBase.vb
  5. 11 15
      Plain Craft Launcher 2/Modules/Base/ModNet.vb
  6. 5 4
      Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
  7. 2 2
      Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
  8. 179 327
      Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
  9. 25 28
      Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
  10. 4 5
      Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
  11. 46 40
      Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
  12. 13 9
      Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
  13. 12 8
      Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
  14. 8 1
      Plain Craft Launcher 2/Modules/ModEvent.vb
  15. 7 8
      Plain Craft Launcher 2/Modules/ModMusic.vb
  16. 1 0
      Plain Craft Launcher 2/Modules/ModSecret.vb
  17. 2 2
      Plain Craft Launcher 2/My Project/AssemblyInfo.vb
  18. 176 186
      Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
  19. 1 1
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadClient.xaml.vb
  20. 21 19
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb
  21. 2 2
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadForge.xaml.vb
  22. 2 1
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml
  23. 85 91
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
  24. 0 1
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml
  25. 26 22
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb
  26. 1 1
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLiteLoader.xaml.vb
  27. 1 0
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
  28. 13 10
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb
  29. 5 7
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml
  30. 10 30
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml.vb
  31. 2 6
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb
  32. 1 0
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
  33. 7 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml.vb
  34. 1 1
      Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
  35. 11 11
      Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
  36. 9 8
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb
  37. 304 131
      Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
  38. 6 6
      Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb
  39. 6 26
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb
  40. 7 3
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb
  41. 4 2
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
  42. 1 1
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionModDisabled.xaml
  43. 15 11
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml.vb
  44. 17 17
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml
  45. 4 5
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb
  46. 14 7
      Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj
  47. 15 15
      Plain Craft Launcher 2/Resources/Custom.xaml

+ 6 - 26
Plain Craft Launcher 2/Controls/MyCard.vb

@@ -98,21 +98,13 @@
         '排序
         '排序
         Select Case Type
         Select Case Type
             Case 3
             Case 3
-                Stack.Tag = Sort(CType(Stack.Tag, List(Of DlOptiFineListEntry)), Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
-                                                                                     Return VersionSortBoolean(Left.NameDisplay, Right.NameDisplay)
-                                                                                 End Function)
+                Stack.Tag = Sort(CType(Stack.Tag, List(Of DlOptiFineListEntry)), Function(a, b) VersionSortBoolean(a.NameDisplay, b.NameDisplay))
             Case 4, 10
             Case 4, 10
-                Stack.Tag = Sort(CType(Stack.Tag, List(Of DlLiteLoaderListEntry)), Function(Left As DlLiteLoaderListEntry, Right As DlLiteLoaderListEntry) As Boolean
-                                                                                       Return VersionSortBoolean(Left.Inherit, Right.Inherit)
-                                                                                   End Function)
+                Stack.Tag = Sort(CType(Stack.Tag, List(Of DlLiteLoaderListEntry)), Function(a, b) VersionSortBoolean(a.Inherit, b.Inherit))
             Case 6
             Case 6
-                Stack.Tag = Sort(CType(Stack.Tag, List(Of DlForgeVersionEntry)), Function(Left As DlForgeVersionEntry, Right As DlForgeVersionEntry) As Boolean
-                                                                                     Return VersionSortBoolean(Left.Version, Right.Version)
-                                                                                 End Function)
+                Stack.Tag = Sort(CType(Stack.Tag, List(Of DlForgeVersionEntry)), Function(a, b) a.Version > b.Version)
             Case 8, 9
             Case 8, 9
-                Stack.Tag = Sort(CType(Stack.Tag, List(Of CompFile)), Function(Left As CompFile, Right As CompFile) As Boolean
-                                                                          Return Left.ReleaseDate > Right.ReleaseDate
-                                                                      End Function)
+                Stack.Tag = Sort(CType(Stack.Tag, List(Of CompFile)), Function(a, b) a.ReleaseDate > b.ReleaseDate)
         End Select
         End Select
         '控件转换
         '控件转换
         Select Case Type
         Select Case Type
@@ -128,16 +120,6 @@
                 ForgeDownloadListItemPreload(Stack, Stack.Tag, AddressOf ForgeSave_Click, True)
                 ForgeDownloadListItemPreload(Stack, Stack.Tag, AddressOf ForgeSave_Click, True)
             Case 8
             Case 8
                 CompFilesCardPreload(Stack, Stack.Tag)
                 CompFilesCardPreload(Stack, Stack.Tag)
-            Case 13
-                Dim LoadingPickaxe As New MyLoading With {.Text = "正在获取版本列表", .Margin = New Thickness(5)}
-                Dim Loader = New LoaderTask(Of String, List(Of DlNeoForgeVersionEntry))("DlNeoForgeVersion Main", AddressOf DlNeoForgeVersionMain)
-                LoadingPickaxe.State = Loader
-                Loader.Start(Stack.Tag)
-                AddHandler LoadingPickaxe.StateChanged, AddressOf FrmDownloadNeoForge.NeoForge_StateChanged
-                AddHandler LoadingPickaxe.Click, AddressOf FrmDownloadNeoForge.NeoForge_Click
-                Stack.Children.Add(LoadingPickaxe)
-            Case 14
-                NeoForgeDownloadListItemPreload(Stack, Stack.Tag, AddressOf NeoForgeSave_Click, True)
         End Select
         End Select
         '实现控件虚拟化
         '实现控件虚拟化
         For Each Data As Object In Stack.Tag
         For Each Data As Object In Stack.Tag
@@ -154,9 +136,8 @@
                 Case 6
                 Case 6
                     Stack.Children.Add(ForgeDownloadListItem(Data, AddressOf ForgeSave_Click, True))
                     Stack.Children.Add(ForgeDownloadListItem(Data, AddressOf ForgeSave_Click, True))
                 Case 7
                 Case 7
-                    Stack.Children.Add(McDownloadListItem(Data, Sub(sender, e) '不能使用 AddressOf,这导致了 #535,原因完全不明,疑似是编译器 Bug
-                                                                    FrmDownloadInstall.MinecraftSelected(sender, e)
-                                                                End Sub, False))
+                    '不能使用 AddressOf,这导致了 #535,原因完全不明,疑似是编译器 Bug
+                    Stack.Children.Add(McDownloadListItem(Data, Sub(sender, e) FrmDownloadInstall.MinecraftSelected(sender, e), False))
                 Case 8
                 Case 8
                     If CType(Stack.Tag, List(Of CompFile)).Distinct(Function(a, b) a.DisplayName = b.DisplayName).Count <>
                     If CType(Stack.Tag, List(Of CompFile)).Distinct(Function(a, b) a.DisplayName = b.DisplayName).Count <>
                        CType(Stack.Tag, List(Of CompFile)).Count Then
                        CType(Stack.Tag, List(Of CompFile)).Count Then
@@ -182,7 +163,6 @@
                 Case 12
                 Case 12
                     Stack.Children.Add(FabricDownloadListItem(CType(Data, JObject), AddressOf FrmDownloadInstall.Fabric_Selected))
                     Stack.Children.Add(FabricDownloadListItem(CType(Data, JObject), AddressOf FrmDownloadInstall.Fabric_Selected))
                 Case 13
                 Case 13
-                Case 14
                     Stack.Children.Add(NeoForgeDownloadListItem(Data, AddressOf NeoForgeSave_Click, True))
                     Stack.Children.Add(NeoForgeDownloadListItem(Data, AddressOf NeoForgeSave_Click, True))
                 Case Else
                 Case Else
                     Log("未知的虚拟化种类:" & Type, LogLevel.Feedback)
                     Log("未知的虚拟化种类:" & Type, LogLevel.Feedback)

+ 7 - 7
Plain Craft Launcher 2/Controls/MyPageRight.vb

@@ -74,13 +74,13 @@
         '添加结束 Invoke
         '添加结束 Invoke
         If FinishedInvoke IsNot Nothing Then
         If FinishedInvoke IsNot Nothing Then
             AddHandler RealLoader.PreviewFinish,
             AddHandler RealLoader.PreviewFinish,
-                Sub()
-                    Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ContentExit
-                        Thread.Sleep(10) '不在退出动画时执行 UI 线程操作,避免退出动画被重置
-                    Loop
-                    RunInUiWait(Sub() FinishedInvoke(RealLoader))
-                    Thread.Sleep(20) '由于大量初始化控件会导致掉帧,延迟触发 State 改变事件
-                End Sub
+            Sub()
+                Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ContentExit
+                    Thread.Sleep(10) '不在退出动画时执行 UI 线程操作,避免退出动画被重置
+                Loop
+                RunInUiWait(Sub() FinishedInvoke(RealLoader))
+                Thread.Sleep(20) '由于大量初始化控件会导致掉帧,延迟触发 State 改变事件
+            End Sub
         End If
         End If
         AddHandler RealLoader.OnStateChangedUi, Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) RunInUi(Sub() PageLoaderState(Loader, NewState, OldState))
         AddHandler RealLoader.OnStateChangedUi, Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) RunInUi(Sub() PageLoaderState(Loader, NewState, OldState))
         '隐藏 UI
         '隐藏 UI

+ 18 - 5
Plain Craft Launcher 2/FormMain.xaml.vb

@@ -10,6 +10,13 @@ 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 < 326 Then 'Release 2.7.4
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "会自动隐藏明显不可用的自动安装选项"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化正版登录流程和 MC 性能"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复正版登录时弹出脚本错误提示的 Bug"))
+            FeatureCount += 17
+            BugCount += 19
+        End If
         If LastVersion < 323 Then 'Release 2.7.3
         If LastVersion < 323 Then 'Release 2.7.3
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "添加 启动游戏前进行内存优化 设置"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "添加 启动游戏前进行内存优化 设置"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化 MC 性能"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化 MC 性能"))
@@ -108,6 +115,12 @@ Public Class FormMain
         '3:BUG+ IMP* FEAT-
         '3:BUG+ IMP* FEAT-
         '2:BUG* IMP-
         '2:BUG* IMP-
         '1:BUG-
         '1:BUG-
+        If LastVersion < 327 Then 'Snapshot 2.8.0
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "NeoForge 兼容与自动安装"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持编译、运行 PCL 开源代码"))
+            FeatureCount += 11
+            BugCount += 14
+        End If
         If LastVersion < 325 Then 'Snapshot 2.7.4
         If LastVersion < 325 Then 'Snapshot 2.7.4
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "会自动隐藏明显不可用的自动安装选项"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "会自动隐藏明显不可用的自动安装选项"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化正版登录流程和 MC 性能"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化正版登录流程和 MC 性能"))
@@ -1019,11 +1032,11 @@ Install:
         DownloadClient = 4
         DownloadClient = 4
         DownloadOptiFine = 5
         DownloadOptiFine = 5
         DownloadForge = 6
         DownloadForge = 6
-        DownloadNeoForge = 13
-        DownloadFabric = 7
-        DownloadLiteLoader = 8
-        DownloadMod = 10
-        DownloadPack = 11
+        DownloadNeoForge = 7
+        DownloadFabric = 8
+        DownloadLiteLoader = 9
+        DownloadMod = 11
+        DownloadPack = 12
         SetupLaunch = 0
         SetupLaunch = 0
         SetupUI = 1
         SetupUI = 1
         SetupSystem = 2
         SetupSystem = 2

+ 72 - 67
Plain Craft Launcher 2/Modules/Base/ModBase.vb

@@ -11,12 +11,12 @@ Public Module ModBase
 #Region "声明"
 #Region "声明"
 
 
     '下列版本信息由更新器自动修改
     '下列版本信息由更新器自动修改
-    Public Const VersionBaseName As String = "2.7.4" '不含分支前缀的显示用版本名
-    Public Const VersionStandardCode As String = "2.7.4." & VersionBranchCode '标准格式的四段式版本号
+    Public Const VersionBaseName As String = "2.8.0" '不含分支前缀的显示用版本名
+    Public Const VersionStandardCode As String = "2.8.0." & VersionBranchCode '标准格式的四段式版本号
 #If BETA Then
 #If BETA Then
-    Public Const VersionCode As Integer = 323 'Release
+    Public Const VersionCode As Integer = 326 'Release
 #Else
 #Else
-    Public Const VersionCode As Integer = 325 'Snapshot
+    Public Const VersionCode As Integer = 327 'Snapshot
 #End If
 #End If
     '自动生成的版本信息
     '自动生成的版本信息
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -2065,15 +2065,16 @@ NextElement:
     ''' 在新的工作线程中执行代码。
     ''' 在新的工作线程中执行代码。
     ''' </summary>
     ''' </summary>
     Public Function RunInNewThread(Action As Action, Name As String, Optional Priority As ThreadPriority = ThreadPriority.Normal) As Thread
     Public Function RunInNewThread(Action As Action, Name As String, Optional Priority As ThreadPriority = ThreadPriority.Normal) As Thread
-        Dim th As New Thread(Sub()
-                                 Try
-                                     Action()
-                                 Catch ex As ThreadInterruptedException
-                                     Log(Name & ":线程已中止")
-                                 Catch ex As Exception
-                                     Log(ex, Name & ":线程执行失败", LogLevel.Feedback)
-                                 End Try
-                             End Sub) With {.Name = Name, .Priority = Priority}
+        Dim th As New Thread(
+        Sub()
+            Try
+                Action()
+            Catch ex As ThreadInterruptedException
+                Log(Name & ":线程已中止")
+            Catch ex As Exception
+                Log(ex, Name & ":线程执行失败", LogLevel.Feedback)
+            End Try
+        End Sub) With {.Name = Name, .Priority = Priority}
         th.Start()
         th.Start()
         Return th
         Return th
     End Function
     End Function
@@ -2186,8 +2187,9 @@ NextElement:
     ''' </summary>
     ''' </summary>
     Public Sub OpenWebsite(Url As String)
     Public Sub OpenWebsite(Url As String)
         Try
         Try
-            ' 允许 Minecraft 基岩版的 URLScheme (#3985)
-            If Not Url.StartsWithF("http", True) Or Not Url.StartsWithF("minecraft://") Then Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!")
+            If Not Url.StartsWithF("http", True) AndAlso Not Url.StartsWithF("minecraft://", True) Then
+                Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!")
+            End If
             Log("[System] 正在打开网页:" & Url)
             Log("[System] 正在打开网页:" & Url)
             Process.Start(Url)
             Process.Start(Url)
         Catch ex As Exception
         Catch ex As Exception
@@ -2212,25 +2214,27 @@ NextElement:
     ''' 设置剪贴板。将在另一线程运行,且不会抛出异常。
     ''' 设置剪贴板。将在另一线程运行,且不会抛出异常。
     ''' </summary>
     ''' </summary>
     Public Sub ClipboardSet(Text As String, Optional ShowSuccessHint As Boolean = True)
     Public Sub ClipboardSet(Text As String, Optional ShowSuccessHint As Boolean = True)
-        RunInThread(Sub()
-                        Dim RetryCount As Integer = 0
+        RunInThread(
+        Sub()
+            Dim RetryCount As Integer = 0
 Retry:
 Retry:
-                        Try
-                            RunInUi(Sub()
-                                        My.Computer.Clipboard.Clear()
-                                        My.Computer.Clipboard.SetText(Text)
-                                    End Sub)
-                        Catch ex As Exception
-                            RetryCount += 1
-                            If RetryCount <= 5 Then
-                                Thread.Sleep(20)
-                                GoTo Retry
-                            Else
-                                Log(ex, "可能由于剪贴板被其他程序占用,文本复制失败", LogLevel.Hint)
-                            End If
-                        End Try
-                        If ShowSuccessHint Then Hint("已成功复制!", HintType.Finish)
-                    End Sub)
+            Try
+                RunInUi(
+                Sub()
+                    My.Computer.Clipboard.Clear()
+                    My.Computer.Clipboard.SetText(Text)
+                End Sub)
+            Catch ex As Exception
+                RetryCount += 1
+                If RetryCount <= 5 Then
+                    Thread.Sleep(20)
+                    GoTo Retry
+                Else
+                    Log(ex, "可能由于剪贴板被其他程序占用,文本复制失败", LogLevel.Hint)
+                End If
+            End Try
+            If ShowSuccessHint Then Hint("已成功复制!", HintType.Finish)
+        End Sub)
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
@@ -2449,39 +2453,40 @@ Retry:
     Private LogList As New StringBuilder
     Private LogList As New StringBuilder
     Private LogWritter As StreamWriter
     Private LogWritter As StreamWriter
     Public Sub LogStart()
     Public Sub LogStart()
-        RunInNewThread(Sub()
-                           Dim IsInitSuccess As Boolean = True
-                           Try
-                               For i = 4 To 1 Step -1
-                                   If File.Exists(Path & "PCL\Log" & i & ".txt") Then
-                                       If File.Exists(Path & "PCL\Log" & (i + 1) & ".txt") Then File.Delete(Path & "PCL\Log" & (i + 1) & ".txt")
-                                       CopyFile(Path & "PCL\Log" & i & ".txt", Path & "PCL\Log" & (i + 1) & ".txt")
-                                   End If
-                               Next
-                               File.Create(Path & "PCL\Log1.txt").Dispose()
-                           Catch ex As IOException
-                               IsInitSuccess = False
-                               Hint("可能同时开启了多个 PCL,程序可能会出现未知问题!", HintType.Critical)
-                               Log(ex, "日志初始化失败(疑似文件占用问题)")
-                           Catch ex As Exception
-                               IsInitSuccess = False
-                               Log(ex, "日志初始化失败", LogLevel.Hint)
-                           End Try
-                           Try
-                               LogWritter = New StreamWriter(Path & "PCL\Log1.txt", True) With {.AutoFlush = True}
-                           Catch ex As Exception
-                               LogWritter = Nothing
-                               Log(ex, "日志写入失败", LogLevel.Hint)
-                           End Try
-                           While True
-                               If IsInitSuccess Then
-                                   LogFlush()
-                               Else
-                                   LogList = New StringBuilder '清空 LogList 避免内存爆炸
-                               End If
-                               Thread.Sleep(50)
-                           End While
-                       End Sub, "Log Writer", ThreadPriority.Lowest)
+        RunInNewThread(
+        Sub()
+            Dim IsInitSuccess As Boolean = True
+            Try
+                For i = 4 To 1 Step -1
+                    If File.Exists(Path & "PCL\Log" & i & ".txt") Then
+                        If File.Exists(Path & "PCL\Log" & (i + 1) & ".txt") Then File.Delete(Path & "PCL\Log" & (i + 1) & ".txt")
+                        CopyFile(Path & "PCL\Log" & i & ".txt", Path & "PCL\Log" & (i + 1) & ".txt")
+                    End If
+                Next
+                File.Create(Path & "PCL\Log1.txt").Dispose()
+            Catch ex As IOException
+                IsInitSuccess = False
+                Hint("可能同时开启了多个 PCL,程序可能会出现未知问题!", HintType.Critical)
+                Log(ex, "日志初始化失败(疑似文件占用问题)")
+            Catch ex As Exception
+                IsInitSuccess = False
+                Log(ex, "日志初始化失败", LogLevel.Hint)
+            End Try
+            Try
+                LogWritter = New StreamWriter(Path & "PCL\Log1.txt", True) With {.AutoFlush = True}
+            Catch ex As Exception
+                LogWritter = Nothing
+                Log(ex, "日志写入失败", LogLevel.Hint)
+            End Try
+            While True
+                If IsInitSuccess Then
+                    LogFlush()
+                Else
+                    LogList = New StringBuilder '清空 LogList 避免内存爆炸
+                End If
+                Thread.Sleep(50)
+            End While
+        End Sub, "Log Writer", ThreadPriority.Lowest)
     End Sub
     End Sub
     Private ReadOnly LogFlushLock As New Object '防止外部调用 LogFlush 时同时输出多次日志
     Private ReadOnly LogFlushLock As New Object '防止外部调用 LogFlush 时同时输出多次日志
     Public Sub LogFlush()
     Public Sub LogFlush()
@@ -2714,4 +2719,4 @@ Retry:
 
 
 #End Region
 #End Region
 
 
-End Module
+End Module

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

@@ -341,14 +341,15 @@ Retry:
         Dim RequestEx As Exception = Nothing
         Dim RequestEx As Exception = Nothing
         Dim FailCount As Integer = 0
         Dim FailCount As Integer = 0
         For i = 1 To RequestCount
         For i = 1 To RequestCount
-            Dim th As New Thread(Sub()
-                                     Try
-                                         RequestResult = NetRequestOnce(Url, Method, Data, ContentType, 30000, Headers)
-                                     Catch ex As Exception
-                                         FailCount += 1
-                                         RequestEx = ex
-                                     End Try
-                                 End Sub)
+            Dim th As New Thread(
+            Sub()
+                Try
+                    RequestResult = NetRequestOnce(Url, Method, Data, ContentType, 30000, Headers)
+                Catch ex As Exception
+                    FailCount += 1
+                    RequestEx = ex
+                End Try
+            End Sub)
             th.Start()
             th.Start()
             Threads.Add(th)
             Threads.Add(th)
             Thread.Sleep(i * 250)
             Thread.Sleep(i * 250)
@@ -382,7 +383,7 @@ RequestFinished:
         Dim Resp As WebResponse = Nothing
         Dim Resp As WebResponse = Nothing
         Dim Req As HttpWebRequest
         Dim Req As HttpWebRequest
         Try
         Try
-            Req = WebRequest.Create(New Uri(Url))
+            Req = WebRequest.Create(Url)
             Req.Method = Method
             Req.Method = Method
             Dim SendData As Byte()
             Dim SendData As Byte()
             If TypeOf Data Is Byte() Then
             If TypeOf Data Is Byte() Then
@@ -1859,15 +1860,10 @@ Retry:
                 Try
                 Try
                     While True
                     While True
                         Thread.Sleep(20)
                         Thread.Sleep(20)
-                        '若已完成,则清空
-                        If Id = 0 AndAlso FileRemain = 0 AndAlso Files.Any() Then
-                            SyncLock LockFiles
-                                Files.Clear()
-                            End SyncLock
-                        End If
                         '获取文件列表
                         '获取文件列表
                         Dim AllFiles As List(Of NetFile)
                         Dim AllFiles As List(Of NetFile)
                         SyncLock LockFiles
                         SyncLock LockFiles
+                            If Id = 0 AndAlso FileRemain = 0 AndAlso Files.Any() Then Files.Clear() '若已完成,则清空
                             AllFiles = Files.Values.ToList()
                             AllFiles = Files.Values.ToList()
                         End SyncLock
                         End SyncLock
                         Dim WaitingFiles As New List(Of NetFile)
                         Dim WaitingFiles As New List(Of NetFile)

+ 5 - 4
Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb

@@ -355,12 +355,12 @@
                     ModLoaders = New List(Of CompModLoaderType)
                     ModLoaders = New List(Of CompModLoaderType)
                     For Each Category In Data("categories").Select(Function(t) t.ToString)
                     For Each Category In Data("categories").Select(Function(t) t.ToString)
                         Select Case Category
                         Select Case Category
-                        '加载器
+                            '加载器
                             Case "forge" : ModLoaders.Add(CompModLoaderType.Forge)
                             Case "forge" : ModLoaders.Add(CompModLoaderType.Forge)
                             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
+                            'Mod
                             Case "worldgen" : Tags.Add("世界元素")
                             Case "worldgen" : Tags.Add("世界元素")
                             Case "technology" : Tags.Add("科技")
                             Case "technology" : Tags.Add("科技")
                             Case "food" : Tags.Add("食物/烹饪")
                             Case "food" : Tags.Add("食物/烹饪")
@@ -376,7 +376,7 @@
                             Case "social" : Tags.Add("服务器")
                             Case "social" : Tags.Add("服务器")
                             Case "utility" : 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 "optimization" : Tags.Add("性能优化")
                             Case "challenging" : Tags.Add("硬核")
                             Case "challenging" : Tags.Add("硬核")
@@ -387,7 +387,7 @@
                             Case "adventure" : Tags.Add("冒险")
                             Case "adventure" : Tags.Add("冒险")
                             Case "kitchen-sink" : Tags.Add("烹饪")
                             Case "kitchen-sink" : Tags.Add("烹饪")
                             Case "lightweight" : Tags.Add("轻量")
                             Case "lightweight" : Tags.Add("轻量")
-                                'FUTURE: Res
+                            'FUTURE: Res
                         End Select
                         End Select
                     Next
                     Next
                     If Not Tags.Any() Then Tags.Add("杂项")
                     If Not Tags.Any() Then Tags.Add("杂项")
@@ -1320,6 +1320,7 @@ Retry:
                     Dim RawLoaders As List(Of String) = Data("loaders").Select(Function(v) v.ToString).ToList
                     Dim RawLoaders As List(Of String) = Data("loaders").Select(Function(v) v.ToString).ToList
                     ModLoaders = New List(Of CompModLoaderType)
                     ModLoaders = New List(Of CompModLoaderType)
                     If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge)
                     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("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric)
                     If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
                     If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
 #End Region
 #End Region

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

@@ -697,8 +697,8 @@ NextStack:
                     "forge", "setup", "block", "model", "mixin", "event", "unimi", "netty", "world",
                     "forge", "setup", "block", "model", "mixin", "event", "unimi", "netty", "world",
                     "gitlab", "common", "server", "config", "loader", "launch", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events",
                     "gitlab", "common", "server", "config", "loader", "launch", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events",
                     "preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content", "systems", "modules", "service",
                     "preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content", "systems", "modules", "service",
-                    "fastutil", "optifine", "internal", "platform", "override", "fabricmc",
-                    "injection", "listeners", "scheduler", "minecraft", "transformer", "transformers", "universal", "multipart", "minecraftforge", "blockentity", "spongepowered", "electronwill"
+                    "fastutil", "optifine", "internal", "platform", "override", "fabricmc", "neoforge",
+                    "injection", "listeners", "scheduler", "minecraft", "transformer", "transformers", "neoforged", "universal", "multipart", "minecraftforge", "blockentity", "spongepowered", "electronwill"
                    }.Contains(Word.ToLower) Then Continue For
                    }.Contains(Word.ToLower) Then Continue For
                 PossibleWords.Add(Word.Trim)
                 PossibleWords.Add(Word.Trim)
             Next
             Next

+ 179 - 327
Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb

@@ -220,7 +220,7 @@
             End If
             End If
             Setup.Set("ToolUpdateSnapshotLast", If(Version, "Nothing"))
             Setup.Set("ToolUpdateSnapshotLast", If(Version, "Nothing"))
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("版本列表解析失败", ex)
+            Throw New Exception("Minecraft 官方源版本列表解析失败", ex)
         End Try
         End Try
     End Sub
     End Sub
     ''' <summary>
     ''' <summary>
@@ -237,7 +237,7 @@
             '返回
             '返回
             Loader.Output = New DlClientListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Json}
             Loader.Output = New DlClientListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Json}
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("版本列表解析失败(" & Json.ToString & ")", ex)
+            Throw New Exception("Minecraft BMCLAPI 版本列表解析失败(" & Json.ToString & ")", ex)
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -288,6 +288,7 @@
         ''' </summary>
         ''' </summary>
         Public Value As List(Of DlOptiFineListEntry)
         Public Value As List(Of DlOptiFineListEntry)
     End Structure
     End Structure
+
     Public Class DlOptiFineListEntry
     Public Class DlOptiFineListEntry
         ''' <summary>
         ''' <summary>
         ''' 显示名称,已去除 HD_U 字样,如“1.12.2 C8”。
         ''' 显示名称,已去除 HD_U 字样,如“1.12.2 C8”。
@@ -359,29 +360,33 @@
     Private Sub DlOptiFineListOfficialMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
     Private Sub DlOptiFineListOfficialMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
         Dim Result As String = NetGetCodeByClient("https://optifine.net/downloads", Encoding.Default)
         Dim Result As String = NetGetCodeByClient("https://optifine.net/downloads", Encoding.Default)
         If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
         If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
-        '获取所有版本信息
-        Dim Forge As List(Of String) = RegexSearch(Result, "(?<=colForge'>)[^<]*")
-        Dim ReleaseTime As List(Of String) = RegexSearch(Result, "(?<=colDate'>)[^<]+")
-        Dim Name As List(Of String) = RegexSearch(Result, "(?<=OptiFine_)[0-9A-Za-z_.]+(?=.jar"")")
-        If Not ReleaseTime.Count = Name.Count Then Throw New Exception("版本与发布时间数据无法对应")
-        If Not Forge.Count = Name.Count Then Throw New Exception("版本与 Forge 兼容数据无法对应")
-        If ReleaseTime.Count < 10 Then Throw New Exception("获取到的版本数量不足(" & Result & ")")
-        '转化为列表输出
-        Dim Versions As New List(Of DlOptiFineListEntry)
-        For i = 0 To ReleaseTime.Count - 1
-            Name(i) = Name(i).Replace("_", " ")
-            Dim Entry As New DlOptiFineListEntry With {
-                         .NameDisplay = Name(i).Replace("HD U ", "").Replace(".0 ", " "),
-                         .ReleaseTime = Join({ReleaseTime(i).Split(".")(2), ReleaseTime(i).Split(".")(1), ReleaseTime(i).Split(".")(0)}, "/"),
-                         .IsPreview = Name(i).ContainsF("pre", True),
-                         .Inherit = Name(i).ToString.Split(" ")(0),
-                         .NameFile = If(Name(i).ContainsF("pre", True), "preview_", "") & "OptiFine_" & Name(i).Replace(" ", "_") & ".jar",
-                         .RequiredForgeVersion = Forge(i).Replace("Forge ", "").Replace("#", "")}
-            If Entry.RequiredForgeVersion.Contains("N/A") Then Entry.RequiredForgeVersion = Nothing
-            Entry.NameVersion = Entry.Inherit & "-OptiFine_" & Name(i).ToString.Replace(" ", "_").Replace(Entry.Inherit & "_", "")
-            Versions.Add(Entry)
-        Next
-        Loader.Output = New DlOptiFineListResult With {.IsOfficial = True, .SourceName = "OptiFine 官方源", .Value = Versions}
+        Try
+            '获取所有版本信息
+            Dim Forge As List(Of String) = RegexSearch(Result, "(?<=colForge'>)[^<]*")
+            Dim ReleaseTime As List(Of String) = RegexSearch(Result, "(?<=colDate'>)[^<]+")
+            Dim Name As List(Of String) = RegexSearch(Result, "(?<=OptiFine_)[0-9A-Za-z_.]+(?=.jar"")")
+            If Not ReleaseTime.Count = Name.Count Then Throw New Exception("版本与发布时间数据无法对应")
+            If Not Forge.Count = Name.Count Then Throw New Exception("版本与 Forge 兼容数据无法对应")
+            If ReleaseTime.Count < 10 Then Throw New Exception("获取到的版本数量不足(" & Result & ")")
+            '转化为列表输出
+            Dim Versions As New List(Of DlOptiFineListEntry)
+            For i = 0 To ReleaseTime.Count - 1
+                Name(i) = Name(i).Replace("_", " ")
+                Dim Entry As New DlOptiFineListEntry With {
+                             .NameDisplay = Name(i).Replace("HD U ", "").Replace(".0 ", " "),
+                             .ReleaseTime = Join({ReleaseTime(i).Split(".")(2), ReleaseTime(i).Split(".")(1), ReleaseTime(i).Split(".")(0)}, "/"),
+                             .IsPreview = Name(i).ContainsF("pre", True),
+                             .Inherit = Name(i).ToString.Split(" ")(0),
+                             .NameFile = If(Name(i).ContainsF("pre", True), "preview_", "") & "OptiFine_" & Name(i).Replace(" ", "_") & ".jar",
+                             .RequiredForgeVersion = Forge(i).Replace("Forge ", "").Replace("#", "")}
+                If Entry.RequiredForgeVersion.Contains("N/A") Then Entry.RequiredForgeVersion = Nothing
+                Entry.NameVersion = Entry.Inherit & "-OptiFine_" & Name(i).ToString.Replace(" ", "_").Replace(Entry.Inherit & "_", "")
+                Versions.Add(Entry)
+            Next
+            Loader.Output = New DlOptiFineListResult With {.IsOfficial = True, .SourceName = "OptiFine 官方源", .Value = Versions}
+        Catch ex As Exception
+            Throw New Exception("OptiFine 官方源版本列表解析失败(" & Result & ")", ex)
+        End Try
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
@@ -407,7 +412,7 @@
             Next
             Next
             Loader.Output = New DlOptiFineListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Versions}
             Loader.Output = New DlOptiFineListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Versions}
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("版本列表解析失败(" & Json.ToString & ")", ex)
+            Throw New Exception("OptiFine BMCLAPI 版本列表解析失败(" & Json.ToString & ")", ex)
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -485,15 +490,61 @@
 
 
 #Region "DlForgeVersion | Forge 版本列表"
 #Region "DlForgeVersion | Forge 版本列表"
 
 
-    Public Class DlForgeVersionEntry
+    Public MustInherit Class DlForgelikeEntry
+        Public IsNeoForge As Boolean
         ''' <summary>
         ''' <summary>
-        ''' 完整的版本名,如 “14.22.1.2478”。
+        ''' 加载器名称。Forge 或 NeoForge。
         ''' </summary>
         ''' </summary>
-        Public Version As String
+        Public ReadOnly Property LoaderName As String
+            Get
+                Return If(IsNeoForge, "NeoForge", "Forge")
+            End Get
+        End Property
+        ''' <summary>
+        ''' 文件扩展名。不以小数点开头。
+        ''' </summary>
+        Public ReadOnly Property FileExtension As String
+            Get
+                If IsNeoForge Then
+                    Return "jar"
+                Else
+                    Return If(CType(Me, DlForgeVersionEntry).Category = "installer", "jar", "zip")
+                End If
+            End Get
+        End Property
+        ''' <summary>
+        ''' Forge:MC 版本是否小于 1.13。
+        ''' NeoForge:MC 版本是否为 1.20.1。
+        ''' </summary>
+        Public ReadOnly Property IsLegacy As Boolean
+            Get
+                '虽然很抽象,但确实可以这样判断
+                'Forge:1.13+ 的版本号首位都大于 20
+                'NeoForge:1.20.1 的版本号首位人为规定为 19 开头
+                Return Version.Major < 20
+            End Get
+        End Property
+        ''' <summary>
+        ''' 标准化后的版本号,仅可用于比较与排序。
+        ''' 格式:Major.Minor.Build.Revision
+        ''' Forge:如 “50.1.9.0”(最后一位固定为 0)、“14.22.1.2478”(Legacy)。
+        ''' NeoForge:如 “20.4.30.0”(最后一位固定为 0)、“19.47.1.99”(Legacy:第一位固定为 19)。
+        ''' </summary>
+        Public Version As Version
+        ''' <summary>
+        ''' 可对玩家显示的非格式化版本名。
+        ''' Forge:如 “50.1.9”、“14.22.1.2478”(Legacy)。
+        ''' NeoForge:如 “20.4.30-beta”、“47.1.99”(Legacy)。
+        ''' </summary>
+        Public VersionName As String
         ''' <summary>
         ''' <summary>
         ''' 对应的 Minecraft 版本,如“1.12.2”。
         ''' 对应的 Minecraft 版本,如“1.12.2”。
         ''' </summary>
         ''' </summary>
         Public Inherit As String
         Public Inherit As String
+    End Class
+
+    Public Class DlForgeVersionEntry
+        Inherits DlForgelikeEntry
         ''' <summary>
         ''' <summary>
         ''' 发布时间,格式为“yyyy/MM/dd HH:mm”。
         ''' 发布时间,格式为“yyyy/MM/dd HH:mm”。
         ''' </summary>
         ''' </summary>
@@ -511,58 +562,21 @@
         ''' </summary>
         ''' </summary>
         Public Category As String
         Public Category As String
         ''' <summary>
         ''' <summary>
-        ''' 版本分支。若无分支则为 Nothing。
-        ''' </summary>
-        Public Branch As String = Nothing
-        ''' <summary>
-        ''' 是否为新版 Forge。(即为 Minecraft 1.13+)
-        ''' </summary>
-        Public ReadOnly Property IsNewType As Boolean
-            Get
-                Return Version.Split(".")(0) >= 20
-            End Get
-        End Property
-        ''' <summary>
-        ''' 构建数。
-        ''' </summary>
-        Public ReadOnly Property Build As Integer
-            Get
-                Dim Version = Me.Version.Split(".")
-                If Version(0) < 15 Then
-                    Return Version(Version.Count - 1)
-                Else
-                    Return Version(Version.Count - 1) + 10000
-                End If
-            End Get
-        End Property
-        ''' <summary>
         ''' 用于下载的文件版本名。可能在 Version 的基础上添加了分支。
         ''' 用于下载的文件版本名。可能在 Version 的基础上添加了分支。
         ''' </summary>
         ''' </summary>
-        Public ReadOnly Property FileVersion As String
-            Get
-                Return Version & If(Branch Is Nothing, "", "-" & Branch)
-            End Get
-        End Property
-        ''' <summary>
-        ''' 即将下载的文件全名。
-        ''' </summary>
-        Public ReadOnly Property FileName As String
-            Get
-                Return "forge-" & Inherit & "-" & FileVersion & "-" & Category & "." & FileSuffix
-            End Get
-        End Property
-        ''' <summary>
-        ''' 文件扩展名。
-        ''' </summary>
-        Public ReadOnly Property FileSuffix As String
-            Get
-                If Category = "installer" Then
-                    Return "jar"
-                Else
-                    Return "zip"
-                End If
-            End Get
-        End Property
+        Public FileVersion As String
+
+        Public Sub New(Version As String, Branch As String, Inherit As String)
+            '司马版本的特殊处理
+            If Version = "11.15.1.2318" OrElse Version = "11.15.1.1902" OrElse Version = "11.15.1.1890" Then Branch = "1.8.9"
+            If Branch Is Nothing AndAlso Inherit = "1.7.10" AndAlso Version.Split(".")(3) >= 1300 Then Branch = "1.7.10"
+            '为 DlForgelikeEntry 提供所有信息
+            IsNeoForge = False
+            VersionName = Version
+            Me.Version = New Version(Version)
+            Me.Inherit = Inherit
+            FileVersion = Version & If(Branch Is Nothing, "", "-" & Branch)
+        End Sub
     End Class
     End Class
 
 
     ''' <summary>
     ''' <summary>
@@ -620,8 +634,6 @@
                     '分支获取
                     '分支获取
                     Dim Branch As String = RegexSeek(VersionCode, $"(?<=-{Name}-)[^-""]+(?=-[a-z]+.[a-z]{{3}})")
                     Dim Branch As String = RegexSeek(VersionCode, $"(?<=-{Name}-)[^-""]+(?=-[a-z]+.[a-z]{{3}})")
                     If String.IsNullOrWhiteSpace(Branch) Then Branch = Nothing
                     If String.IsNullOrWhiteSpace(Branch) Then Branch = Nothing
-                    If Name = "11.15.1.2318" OrElse Name = "11.15.1.1902" OrElse Name = "11.15.1.1890" Then Branch = "1.8.9"
-                    If Branch Is Nothing AndAlso Inherit = "1.7.10" AndAlso Name.Split(".")(3) >= 1300 Then Branch = "1.7.10"
                     '发布时间获取
                     '发布时间获取
                     Dim ReleaseTimeOriginal = RegexSeek(VersionCode, "(?<=""download-time"" title="")[^""]+")
                     Dim ReleaseTimeOriginal = RegexSeek(VersionCode, "(?<=""download-time"" title="")[^""]+")
                     Dim ReleaseTimeSplit = ReleaseTimeOriginal.Split(" -:".ToCharArray) '原格式:"2021-02-15 03:24:02"
                     Dim ReleaseTimeSplit = ReleaseTimeOriginal.Split(" -:".ToCharArray) '原格式:"2021-02-15 03:24:02"
@@ -651,13 +663,13 @@
                         Continue For
                         Continue For
                     End If
                     End If
                     '添加进列表
                     '添加进列表
-                    Versions.Add(New DlForgeVersionEntry With {.Category = Category, .Version = Name, .IsRecommended = IsRecommended, .Hash = MD5.Trim(vbCr, vbLf), .Inherit = Inherit, .ReleaseTime = ReleaseTime, .Branch = Branch})
+                    Versions.Add(New DlForgeVersionEntry(Name, Branch, Inherit) With {.Category = Category, .IsRecommended = IsRecommended, .Hash = MD5.Trim(vbCr, vbLf), .ReleaseTime = ReleaseTime})
                 Catch ex As Exception
                 Catch ex As Exception
-                    Throw New Exception("版本信息提取失败(" & VersionCode & ")", ex)
+                    Throw New Exception("Forge 官方源版本信息提取失败(" & VersionCode & ")", ex)
                 End Try
                 End Try
             Next
             Next
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("版本列表解析失败(" & Result & ")", ex)
+            Throw New Exception("Forge 官方源版本列表解析失败(" & Result & ")", ex)
         End Try
         End Try
         If Not Versions.Any() Then Throw New Exception("没有可用版本")
         If Not Versions.Any() Then Throw New Exception("没有可用版本")
         Loader.Output = Versions
         Loader.Output = Versions
@@ -700,20 +712,17 @@
                     End Select
                     End Select
                 Next
                 Next
                 '获取 Entry
                 '获取 Entry
-                Dim Inherit As String = Loader.Input
                 Dim Branch As String = Token("branch")
                 Dim Branch As String = Token("branch")
                 Dim Name As String = Token("version")
                 Dim Name As String = Token("version")
-                If Name = "11.15.1.2318" OrElse Name = "11.15.1.1902" OrElse Name = "11.15.1.1890" Then Branch = "1.8.9"
-                If Branch Is Nothing AndAlso Inherit = "1.7.10" AndAlso Name.Split(".")(3) >= 1300 Then Branch = "1.7.10"
                 '基础信息获取
                 '基础信息获取
-                Dim Entry = New DlForgeVersionEntry With {.Hash = Hash, .Category = Category, .Version = Name, .Branch = Branch, .Inherit = Inherit, .IsRecommended = Recommended = Name}
+                Dim Entry = New DlForgeVersionEntry(Name, Branch, Loader.Input) With {.Hash = Hash, .Category = Category, .IsRecommended = Recommended = Name}
                 Dim TimeSplit = Token("modified").ToString.Split("-"c, "T"c, ":"c, "."c, " "c, "/"c)
                 Dim TimeSplit = Token("modified").ToString.Split("-"c, "T"c, ":"c, "."c, " "c, "/"c)
                 Entry.ReleaseTime = Token("modified").ToObject(Of Date).ToLocalTime.ToString("yyyy'/'MM'/'dd HH':'mm")
                 Entry.ReleaseTime = Token("modified").ToObject(Of Date).ToLocalTime.ToString("yyyy'/'MM'/'dd HH':'mm")
                 '添加项
                 '添加项
                 Versions.Add(Entry)
                 Versions.Add(Entry)
             Next
             Next
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("版本列表解析失败(" & Json.ToString & ")", ex)
+            Throw New Exception("Forge BMCLAPI 版本列表解析失败(" & Json.ToString & ")", ex)
         End Try
         End Try
         If Not Versions.Any() Then Throw New Exception("没有可用版本")
         If Not Versions.Any() Then Throw New Exception("没有可用版本")
         Loader.Output = Versions
         Loader.Output = Versions
@@ -721,7 +730,7 @@
 
 
 #End Region
 #End Region
 
 
-#Region "DlNeoForgeList | NeoForge Minecraft 版本列表"
+#Region "DlNeoForgeList | NeoForge 版本列表"
 
 
     Public Structure DlNeoForgeListResult
     Public Structure DlNeoForgeListResult
         ''' <summary>
         ''' <summary>
@@ -733,11 +742,47 @@
         ''' </summary>
         ''' </summary>
         Public IsOfficial As Boolean
         Public IsOfficial As Boolean
         ''' <summary>
         ''' <summary>
-        ''' 获取到的数据。
+        ''' 所有版本的列表。已经按从新到老排序。
         ''' </summary>
         ''' </summary>
-        Public Value As List(Of String)
+        Public Value As List(Of DlNeoForgeListEntry)
     End Structure
     End Structure
 
 
+    Public Class DlNeoForgeListEntry
+        Inherits DlForgelikeEntry
+        ''' <summary>
+        ''' 是否是 Beta 版。
+        ''' </summary>
+        Public IsBeta As Boolean
+        ''' <summary>
+        ''' API 使用的原始版本字符串,如 “20.4.30-beta”、“1.20.1-47.1.99”(Legacy)。
+        ''' </summary>
+        Public ApiName As String
+        ''' <summary>
+        ''' 文件在官网的基础地址,不包含后缀。
+        ''' </summary>
+        Public ReadOnly Property UrlBase As String
+            Get
+                Dim PackageName As String = If(IsLegacy, "forge", "neoforge")
+                Return $"https://maven.neoforged.net/releases/net/neoforged/{PackageName}/{ApiName}/{PackageName}-{ApiName}"
+            End Get
+        End Property
+
+        Public Sub New(ApiName As String)
+            IsNeoForge = True
+            Me.ApiName = ApiName
+            IsBeta = ApiName.Contains("beta")
+            If ApiName.Contains("1.20.1") Then '1.20.1-47.1.99
+                VersionName = ApiName.Replace("1.20.1-", "")
+                Version = New Version("19." & VersionName)
+                Inherit = "1.20.1"
+            Else '20.4.30-beta
+                VersionName = ApiName
+                Version = New Version(ApiName.Before("-"))
+                Inherit = $"1.{Version.Major}" & If(Version.Minor = 0, "", "." & Version.Minor)
+            End If
+        End Sub
+    End Class
+
     ''' <summary>
     ''' <summary>
     ''' NeoForge 版本列表,主加载器。
     ''' NeoForge 版本列表,主加载器。
     ''' </summary>
     ''' </summary>
@@ -767,241 +812,47 @@
     ''' </summary>
     ''' </summary>
     Public DlNeoForgeListOfficialLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Official", AddressOf DlNeoForgeListOfficialMain)
     Public DlNeoForgeListOfficialLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Official", AddressOf DlNeoForgeListOfficialMain)
     Private Sub DlNeoForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
     Private Sub DlNeoForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
-        Dim ResultLatest As String
-        Dim VersionsJArray As JArray
-        Try
-            ResultLatest = NetGetCodeByDownload("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge", UseBrowserUserAgent:=True, IsJson:=True)
-        Catch ex As Exception
-            If GetExceptionSummary(ex).Contains("(404)") Then
-                Throw New Exception("没有可用版本")
-            Else
-                Throw
-            End If
-        End Try
-        If ResultLatest.Length < 50 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
-        VersionsJArray = GetJson(ResultLatest)("versions")
-        Dim Versions As New List(Of String)
-        Versions.Add("1.20.1")
+        '获取版本列表 JSON
+        Dim ResultLatest As String = NetGetCodeByDownload("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge", UseBrowserUserAgent:=True, IsJson:=True)
+        Dim ResultLegacy As String = NetGetCodeByDownload("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge", UseBrowserUserAgent:=True, IsJson:=True)
+        If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
+        '解析
         Try
         Try
-            For Each Token As String In VersionsJArray
-                Dim Version As String = Token.Replace("neoforge-", "")
-                Dim Inherit As String = $"1.{Version.Split(".")(0)}.{Token.Split(".")(1)}"
-                If Inherit.EndsWith(".0") Then Inherit = Inherit.Replace(".0", "")
-                Versions.Add(Inherit)
-            Next
-            Versions = Versions.Distinct().ToList()
+            Loader.Output = New DlNeoForgeListResult With {.IsOfficial = True, .SourceName = "NeoForge 官方源",
+                .Value = GetNeoForgeEntries(ResultLatest, ResultLegacy)}
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, LogLevel.Feedback)
+            Throw New Exception("NeoForge 官方源版本列表解析失败(" & ResultLatest & vbCrLf & vbCrLf & ResultLegacy & ")", ex)
         End Try
         End Try
-        If Not Versions.Any() Then Throw New Exception("没有可用版本")
-        Loader.Output = New DlNeoForgeListResult With {.IsOfficial = True, .SourceName = "NeoForge 官方源", .Value = Versions}
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
     ''' NeoForge 版本列表,BMCLAPI。
     ''' NeoForge 版本列表,BMCLAPI。
     ''' </summary>
     ''' </summary>
-    Public DlNeoForgeListBmclapiLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Bmclapi", AddressOf DlNeoForgeListBmclapiMain)
-    Private Sub DlNeoForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
-        Dim ResultLatest As String
-        Dim VersionsJArray As JArray
-        Try
-            ResultLatest = NetGetCodeByDownload("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/neoforge", UseBrowserUserAgent:=True, IsJson:=True)
-        Catch ex As Exception
-            If GetExceptionSummary(ex).Contains("(404)") Then
-                Throw New Exception("没有可用版本")
-            Else
-                Throw
-            End If
-        End Try
-        If ResultLatest.Length < 50 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
-        VersionsJArray = GetJson(ResultLatest)("name")
-        Dim Versions As New List(Of String)
-        Versions.Add("1.20.1")
-        Try
-            For Each Token As String In VersionsJArray("name")
-                Dim Version As String = Token.Replace("neoforge-", "")
-                Dim Inherit As String = $"1.{Version.Split(".")(0)}.{Token.Split(".")(1)}"
-                If Inherit.EndsWith(".0") Then Inherit = Inherit.Replace(".0", "")
-                Versions.Add(Inherit)
-            Next
-            Versions = Versions.Distinct().ToList()
-        Catch ex As Exception
-            Log(ex, LogLevel.Feedback)
-        End Try
-        If Not Versions.Any() Then Throw New Exception("没有可用版本")
-        Loader.Output = New DlNeoForgeListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Versions}
-    End Sub
-#End Region
-
-#Region "DlNeoForgeVersion | NeoForge 版本列表"
-
-    Public Class DlNeoForgeVersionEntry
-        ''' <summary>
-        ''' 完整的版本名,如 “neoforge-20.4.30-beta”。
-        ''' </summary>
-        Public VersionName As String
-        ''' <summary>
-        ''' 对应的 Minecraft 版本,如“1.20.4”。
-        ''' </summary>
-        Public Inherit As String
-        ''' <summary>
-        ''' 是否是 Beta 版。若未提供则默认为 False。
-        ''' </summary>
-        Public IsBeta As Boolean = False
-        ''' <summary>
-        ''' 标准的版本号,如 “20.4.30”。
-        ''' </summary>
-        Public VersionCode As String
-        Public Structure DlNeoForgeListResult
-            ''' <summary>
-            ''' 数据来源名称,如“Official”,“BMCLAPI”。
-            ''' </summary>
-            Public SourceName As String
-            ''' <summary>
-            ''' 是否为官方的实时数据。
-            ''' </summary>
-            Public IsOfficial As Boolean
-            ''' <summary>
-            ''' 获取到的数据。
-            ''' </summary>
-            Public Value As JObject
-        End Structure
-        ''' <summary>
-        ''' 即将下载的文件全名。
-        ''' </summary>
-        Public ReadOnly Property FileName As String
-            Get
-                If VersionCode.StartsWith("47.") Then 'NeoForge 1.20.1 的版本命名有些特殊...
-                    Return "forge-" & "1.20.1" & "-" & VersionCode & If(IsBeta, "-beta", "") & "-" & "installer" & "." & "jar"
-                Else
-                    Return "neoforge-" & VersionCode & If(IsBeta, "-beta", "") & "-" & "installer" & "." & "jar"
-                End If
-            End Get
-        End Property
-        ''' <summary>
-        ''' 文件扩展名
-        ''' </summary>
-        Public ReadOnly Property FileSuffix As String = ".jar"
-    End Class
-    ''' <summary>
-    ''' NeoForge 版本列表,主加载器。
-    ''' </summary>
-    Public Sub DlNeoForgeVersionMain(Loader As LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)))
-        Dim DlNeoForgeVersionOfficialLoader As New LoaderTask(Of String, List(Of DlNeoForgeVersionEntry))("DlNeoForgeVersion Official", AddressOf DlNeoForgeVersionOfficialMain)
-        Dim DlNeoForgeVersionBmclapiLoader As New LoaderTask(Of String, List(Of DlNeoForgeVersionEntry))("DlNeoForgeVersion Bmclapi", AddressOf DlNeoForgeVersionBmclapiMain)
-        Select Case Setup.Get("ToolDownloadVersion")
-            Case 0
-                DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)) From {
-                    New KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)(DlNeoForgeVersionBmclapiLoader, 30),
-                    New KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)(DlNeoForgeVersionOfficialLoader, 60)
-                }, Loader.IsForceRestarting)
-            Case 1
-                DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)) From {
-                    New KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)(DlNeoForgeVersionOfficialLoader, 5),
-                    New KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)(DlNeoForgeVersionBmclapiLoader, 35)
-                }, Loader.IsForceRestarting)
-            Case Else
-                DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)) From {
-                    New KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)(DlNeoForgeVersionOfficialLoader, 60),
-                    New KeyValuePair(Of LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)), Integer)(DlNeoForgeVersionBmclapiLoader, 60)
-                }, Loader.IsForceRestarting)
-        End Select
-    End Sub
-
-    ''' <summary>
-    ''' NeoForge 版本列表,官方源。
-    ''' </summary>
-    Public Sub DlNeoForgeVersionOfficialMain(Loader As LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)))
-        Dim ResultLatest As String
-        Dim ResultLegacy As String
+    Public DlNeoForgeListBmclapiLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Bmclapi", AddressOf DlNeoForgeListOfficialMain)
+    Public Sub DlNeoForgeVersionBmclapiMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
+        '获取版本列表 JSON
+        Dim ResultLatest As String = NetGetCodeByDownload("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/neoforge", UseBrowserUserAgent:=True, IsJson:=True)
+        Dim ResultLegacy As String = NetGetCodeByDownload("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/forge", UseBrowserUserAgent:=True, IsJson:=True)
+        If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
+        '解析
         Try
         Try
-            ResultLatest = NetGetCodeByDownload("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge", UseBrowserUserAgent:=True, IsJson:=True)
-            ResultLegacy = NetGetCodeByDownload("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge", UseBrowserUserAgent:=True, IsJson:=True)
+            Loader.Output = New DlNeoForgeListResult With {.IsOfficial = True, .SourceName = "BMCLAPI",
+                .Value = GetNeoForgeEntries(ResultLatest, ResultLegacy)}
         Catch ex As Exception
         Catch ex As Exception
-            If GetExceptionSummary(ex).Contains("(404)") Then
-                Throw New Exception("没有可用版本")
-            Else
-                Throw
-            End If
+            Throw New Exception("NeoForge BMCLAPI 版本列表解析失败(" & ResultLatest & vbCrLf & vbCrLf & ResultLegacy & ")", ex)
         End Try
         End Try
-        If ResultLatest.Length < 50 AndAlso ResultLegacy.Length < 50 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
-        Dim ResultLatestJson As JObject = GetJson(ResultLatest)
-        Dim ResultLegacyJson As JObject = GetJson(ResultLegacy)
-        Dim VersionsJArray As JArray
-        Dim IsLegacyNeo As Boolean = False
-        If Loader.Input IsNot Nothing AndAlso Loader.Input.ToString().Contains("1.20.1") Then
-            VersionsJArray = ResultLegacyJson("versions")
-            IsLegacyNeo = True
-        Else
-            VersionsJArray = ResultLatestJson("versions")
-        End If
-        Dim Versions As New List(Of DlNeoForgeVersionEntry)
-        Try
-            For Each Token As String In VersionsJArray
-                Dim StdVersion As String
-                Dim IsBeta As Boolean
-                Dim rawVersion As String = Token
-                If rawVersion.Contains("-beta") Then
-                    StdVersion = Token.Replace("neoforge-", "").Replace("-beta", "").Replace("1.20.1-", "")
-                    IsBeta = True
-                Else
-                    StdVersion = Token.Replace("neoforge-", "").Replace("1.20.1-", "")
-                    IsBeta = False
-                End If
-                Dim Inherit As String = $"1.{StdVersion.Split(".")(0)}.{StdVersion.Split(".")(1)}"
-                If Inherit.EndsWithF(".0") Then Inherit.Remove(Inherit.LastIndexOfF(".0"), 1)
-                Inherit = If(IsLegacyNeo, "1.20.1", Inherit)
-                Dim Entry = New DlNeoForgeVersionEntry
-                If Loader.Input IsNot Nothing Then
-                    If IsLegacyNeo OrElse Inherit.Contains(Loader.Input.ToString().Replace("1.", "")) Then
-                        Entry = New DlNeoForgeVersionEntry With {.VersionName = rawVersion, .Inherit = Inherit, .IsBeta = IsBeta, .VersionCode = StdVersion}
-                        Versions.Add(Entry)
-                    End If
-                Else
-                    Entry = New DlNeoForgeVersionEntry With {.VersionName = rawVersion, .Inherit = Inherit, .IsBeta = IsBeta, .VersionCode = StdVersion}
-                    Versions.Add(Entry)
-                End If
-            Next
-        Catch ex As Exception
-            Log(ex, LogLevel.Feedback)
-        End Try
-        If Not Versions.Any() Then Throw New Exception("没有可用版本")
-        Dim VersionsArray = Versions.ToList()
-        VersionsArray.Reverse()
-        Loader.Output = VersionsArray
     End Sub
     End Sub
 
 
-    ''' <summary>
-    ''' NeoForge 版本列表,BMCLAPI。
-    ''' </summary>
-    Public Sub DlNeoForgeVersionBmclapiMain(Loader As LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)))
-        Dim Json As JArray = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/neoforge/list/" & Loader.Input, IsJson:=True)
-        Dim Versions As New List(Of DlNeoForgeVersionEntry)
-        Try
-            For Each Token As JObject In Json
-                Dim StdVersion As String
-                Dim IsBeta As Boolean
-                Dim rawVersion As String = Token("rawVersion")
-                If rawVersion.Contains("-beta") Then
-                    StdVersion = Token("version").ToString().Replace("neoforge-", "").Replace("-beta", "").Replace("1.20.1-", "")
-                    IsBeta = True
-                Else
-                    StdVersion = Token("version").ToString().Replace("neoforge-", "").Replace("1.20.1-", "")
-                    IsBeta = False
-                End If
-                Dim Inherit As String = Token("mcversion")
-                Dim Entry = New DlNeoForgeVersionEntry With {.VersionName = rawVersion, .Inherit = Inherit, .IsBeta = IsBeta, .VersionCode = StdVersion}
-                Versions.Add(Entry)
-            Next
-        Catch ex As Exception
-            MyMsgBox(ex.ToString(), "错误")
-            Throw New Exception("版本列表解析失败(" & Json.ToString & ")", ex)
-        End Try
+    Private Function GetNeoForgeEntries(LatestJson As String, LatestLegacyJson As String) As List(Of DlNeoForgeListEntry)
+        Dim VersionNames = RegexSearch(LatestLegacyJson & LatestJson,
+            "(?<="")(1\.20\.1-)?\d+\.\d+\.\d+(-beta)?(?="")") '我寻思直接正则就行.jpg
+        Dim Versions = VersionNames.
+            Where(Function(name) name <> "47.1.82"). '这个版本虽然在版本列表中,但不能下载
+            Select(Function(name) New DlNeoForgeListEntry(name)).ToList
         If Not Versions.Any() Then Throw New Exception("没有可用版本")
         If Not Versions.Any() Then Throw New Exception("没有可用版本")
-        Dim VersionsArray = Versions.ToList()
-        VersionsArray.Reverse()
-        Loader.Output = VersionsArray
-    End Sub
+        Versions = Versions.OrderByDescending(Function(a) a.Version).ToList
+        Return Versions
+    End Function
 
 
 #End Region
 #End Region
 
 
@@ -1025,6 +876,7 @@
         ''' </summary>
         ''' </summary>
         Public OfficialError As Exception
         Public OfficialError As Exception
     End Structure
     End Structure
+
     Public Class DlLiteLoaderListEntry
     Public Class DlLiteLoaderListEntry
         ''' <summary>
         ''' <summary>
         ''' 实际的文件名,如“liteloader-installer-1.12-00-SNAPSHOT.jar”。
         ''' 实际的文件名,如“liteloader-installer-1.12-00-SNAPSHOT.jar”。
@@ -1104,7 +956,7 @@
             Next
             Next
             Loader.Output = New DlLiteLoaderListResult With {.IsOfficial = True, .SourceName = "LiteLoader 官方源", .Value = Versions}
             Loader.Output = New DlLiteLoaderListResult With {.IsOfficial = True, .SourceName = "LiteLoader 官方源", .Value = Versions}
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("版本列表解析失败(" & Result.ToString & ")", ex)
+            Throw New Exception("LiteLoader 官方源版本列表解析失败(" & Result.ToString & ")", ex)
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -1132,7 +984,7 @@
             Next
             Next
             Loader.Output = New DlLiteLoaderListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Versions}
             Loader.Output = New DlLiteLoaderListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Versions}
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("版本列表解析失败(" & Result.ToString & ")", ex)
+            Throw New Exception("LiteLoader BMCLAPI 版本列表解析失败(" & Result.ToString & ")", ex)
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -1190,7 +1042,7 @@
             If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
             If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
             Loader.Output = Output
             Loader.Output = Output
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("列表解析失败(" & Result.ToString & ")", ex)
+            Throw New Exception("Fabric 官方源版本列表解析失败(" & Result.ToString & ")", ex)
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -1205,7 +1057,7 @@
             If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
             If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
             Loader.Output = Output
             Loader.Output = Output
         Catch ex As Exception
         Catch ex As Exception
-            Throw New Exception("列表解析失败(" & Result.ToString & ")", ex)
+            Throw New Exception("Fabric BMCLAPI 版本列表解析失败(" & Result.ToString & ")", ex)
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -1228,25 +1080,25 @@
     Public Function DlSourceResourceGet(MojangBase As String) As String()
     Public Function DlSourceResourceGet(MojangBase As String) As String()
         MojangBase = MojangBase.Replace("http://resources.download.minecraft.net", "https://resources.download.minecraft.net")
         MojangBase = MojangBase.Replace("http://resources.download.minecraft.net", "https://resources.download.minecraft.net")
         Return {
         Return {
-                MojangBase.Replace("https://piston-data.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"),
-                MojangBase
-               }
+            MojangBase.Replace("https://piston-data.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"),
+            MojangBase
+        }
     End Function
     End Function
 
 
     Public Function DlSourceLibraryGet(MojangBase As String) As String()
     Public Function DlSourceLibraryGet(MojangBase As String) As String()
         Return {
         Return {
-                MojangBase.Replace("https://piston-data.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"),
-                MojangBase.Replace("https://piston-data.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"),
-                MojangBase
-               }
+            MojangBase.Replace("https://piston-data.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"),
+            MojangBase.Replace("https://piston-data.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"),
+            MojangBase
+        }
     End Function
     End Function
 
 
     Public Function DlSourceLauncherOrMetaGet(MojangBase As String) As String()
     Public Function DlSourceLauncherOrMetaGet(MojangBase As String) As String()
         If MojangBase Is Nothing Then Throw New Exception("无对应的 json 下载地址")
         If MojangBase Is Nothing Then Throw New Exception("无对应的 json 下载地址")
         Return {
         Return {
-                MojangBase.Replace("https://piston-data.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://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com"),
-                MojangBase
-               }
+            MojangBase.Replace("https://piston-data.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://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com"),
+            MojangBase
+        }
     End Function
     End Function
 
 
     Private Sub DlSourceLoader(Of InputType, OutputType)(MainLoader As LoaderTask(Of InputType, OutputType),
     Private Sub DlSourceLoader(Of InputType, OutputType)(MainLoader As LoaderTask(Of InputType, OutputType),

+ 25 - 28
Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb

@@ -1,18 +1,6 @@
 Public Module ModJava
 Public Module ModJava
     Public JavaListCacheVersion As Integer = 6
     Public JavaListCacheVersion As Integer = 6
 
 
-    ''' <summary>
-    ''' 用于在搜索 Java 时进行关键词检测。
-    ''' </summary>
-    Public ReadOnly SearchEntryWords As List(Of String) =
-        New List(Of String) From {"java", "jdk", "env", "环境", "run", "软件", "jre", "mc",
-        "soft", "cache", "temp", "corretto", "roaming", "users", "craft", "program", "世界", "net",
-        "游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", "client", "整合",
-        "应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot",
-        "runtime", "x86", "x64", "forge", "原版", "optifine", "官方", "启动", "hmcl", "mod", "高清",
-        "download", "launch", "程序", "path", "version", "baka", "pcl", "zulu", "local", "packages",
-        "4297127d64ec6", "国服", "网易", "ext", "netease", "1.", "启动"}
-
     ''' <summary>
     ''' <summary>
     ''' 目前所有可用的 Java。
     ''' 目前所有可用的 Java。
     ''' </summary>
     ''' </summary>
@@ -252,21 +240,25 @@
             Dim UserJava As JavaEntry = Nothing
             Dim UserJava As JavaEntry = Nothing
 
 
             '获取版本独立设置中指定的 Java
             '获取版本独立设置中指定的 Java
-            If RelatedVersion IsNot Nothing AndAlso Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion).ToString.StartsWithF("{") Then
-                Try
-                    UserJava = JavaEntry.FromJson(GetJson(Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion)))
-                    UserJava.Check()
-                Catch ex As ThreadInterruptedException
-                    Throw
-                Catch ex As Exception
-                    UserJava = Nothing
-                    Setup.Reset("VersionArgumentJavaSelect", Version:=RelatedVersion)
-                    Log(ex, "版本独立设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint)
-                End Try
+            Dim VersionSelect As String = ""
+            If RelatedVersion IsNot Nothing Then
+                VersionSelect = Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion)
+                If VersionSelect.StartsWithF("{") Then
+                    Try
+                        UserJava = JavaEntry.FromJson(GetJson(VersionSelect))
+                        UserJava.Check()
+                    Catch ex As ThreadInterruptedException
+                        Throw
+                    Catch ex As Exception
+                        UserJava = Nothing
+                        Setup.Reset("VersionArgumentJavaSelect", Version:=RelatedVersion)
+                        Log(ex, "版本独立设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint)
+                    End Try
+                End If
             End If
             End If
 
 
             '获取全局设置中指定的 Java
             '获取全局设置中指定的 Java
-            If UserJava Is Nothing AndAlso Setup.Get("LaunchArgumentJavaSelect") <> "" Then
+            If UserJava Is Nothing AndAlso VersionSelect <> "" AndAlso Setup.Get("LaunchArgumentJavaSelect") <> "" Then
                 Try
                 Try
                     UserJava = JavaEntry.FromJson(GetJson(Setup.Get("LaunchArgumentJavaSelect")))
                     UserJava = JavaEntry.FromJson(GetJson(Setup.Get("LaunchArgumentJavaSelect")))
                     UserJava.Check()
                     UserJava.Check()
@@ -677,13 +669,18 @@ Wait:
             '若该目录有 Java,则加入结果
             '若该目录有 Java,则加入结果
             If File.Exists(Path & "javaw.exe") Then Results(Path) = Source
             If File.Exists(Path & "javaw.exe") Then Results(Path) = Source
             '查找其下的所有文件夹
             '查找其下的所有文件夹
+            Dim Keywords = {"java", "jdk", "env", "环境", "run", "软件", "jre", "mc", "dragon",
+                            "soft", "cache", "temp", "corretto", "roaming", "users", "craft", "program", "世界", "net",
+                            "游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", "client", "整合",
+                            "应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot",
+                            "runtime", "x86", "x64", "forge", "原版", "optifine", "官方", "启动", "hmcl", "mod", "高清",
+                            "download", "launch", "程序", "path", "version", "baka", "pcl", "zulu", "local", "packages",
+                            "4297127d64ec6", "国服", "网易", "ext", "netease", "1.", "启动"}
             For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories
             For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories
                 If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接
                 If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接
                 Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).ToLower '用于搜索的字符串
                 Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).ToLower '用于搜索的字符串
-                If IsFullSearch OrElse
-                        FolderInfo.Parent.Name.ToLower = "users" OrElse
-                        SearchEntryWords.Any(Function(word) SearchEntry.Contains(word)) OrElse '进行关键词检测
-                        SearchEntry = "bin" Then
+                If IsFullSearch OrElse FolderInfo.Parent.Name.ToLower = "users" OrElse
+                   Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then
                     JavaSearchFolder(FolderInfo, Results, Source)
                     JavaSearchFolder(FolderInfo, Results, Source)
                 End If
                 End If
             Next
             Next

+ 4 - 5
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb

@@ -113,19 +113,18 @@ Public Module ModLaunch
                 New LoaderTask(Of Process, Integer)("等待游戏窗口出现", AddressOf McLaunchWait) With {.ProgressWeight = 1},
                 New LoaderTask(Of Process, Integer)("等待游戏窗口出现", AddressOf McLaunchWait) With {.ProgressWeight = 1},
                 New LoaderTask(Of Integer, Integer)("结束处理", AddressOf McLaunchEnd) With {.ProgressWeight = 1}
                 New LoaderTask(Of Integer, Integer)("结束处理", AddressOf McLaunchEnd) With {.ProgressWeight = 1}
             }
             }
-
             '内存优化
             '内存优化
             Select Case Setup.Get("VersionRamOptimize", Version:=McVersionCurrent)
             Select Case Setup.Get("VersionRamOptimize", Version:=McVersionCurrent)
                 Case 0 '全局
                 Case 0 '全局
-                    If Setup.Get("LaunchArgumentRam") Then
+                    If Setup.Get("LaunchArgumentRam") Then '使用全局设置
                         CType(Loaders(2), LoaderCombo(Of String)).Block = False
                         CType(Loaders(2), LoaderCombo(Of String)).Block = False
                         Loaders.Insert(3, New LoaderTask(Of Integer, Integer)("内存优化", AddressOf McLaunchMemoryOptimize) With {.ProgressWeight = 30})
                         Loaders.Insert(3, New LoaderTask(Of Integer, Integer)("内存优化", AddressOf McLaunchMemoryOptimize) With {.ProgressWeight = 30})
                     End If
                     End If
                 Case 1 '开启
                 Case 1 '开启
                     CType(Loaders(2), LoaderCombo(Of String)).Block = False
                     CType(Loaders(2), LoaderCombo(Of String)).Block = False
                     Loaders.Insert(3, New LoaderTask(Of Integer, Integer)("内存优化", AddressOf McLaunchMemoryOptimize) With {.ProgressWeight = 30})
                     Loaders.Insert(3, New LoaderTask(Of Integer, Integer)("内存优化", AddressOf McLaunchMemoryOptimize) With {.ProgressWeight = 30})
+                Case 2 '关闭
             End Select
             End Select
-
             Dim LaunchLoader As New LoaderCombo(Of Object)("Minecraft 启动", Loaders) With {.Show = False}
             Dim LaunchLoader As New LoaderCombo(Of Object)("Minecraft 启动", Loaders) With {.Show = False}
             If McLoginLoader.State = LoadState.Finished Then McLoginLoader.State = LoadState.Waiting '要求重启登录主加载器,它会自行决定是否启动副加载器
             If McLoginLoader.State = LoadState.Finished Then McLoginLoader.State = LoadState.Waiting '要求重启登录主加载器,它会自行决定是否启动副加载器
             '等待加载器执行并更新 UI
             '等待加载器执行并更新 UI
@@ -1081,8 +1080,8 @@ SystemBrowser:
             Case 4
             Case 4
                 '自定义
                 '自定义
                 Do Until McSkinSex(Uuid) = If(Setup.Get("LaunchSkinSlim"), "Alex", "Steve")
                 Do Until McSkinSex(Uuid) = If(Setup.Get("LaunchSkinSlim"), "Alex", "Steve")
-                    If Uuid.EndsWithF("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
-                    Uuid = Mid(Uuid, 1, 32 - 5) & (Long.Parse(Right(Uuid, 5), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X").PadLeft(5, "0")
+                    If Uuid.EndsWithF("FFFFF") Then Uuid = Uuid.Substring(0, 27) & "00000"
+                    Uuid = Uuid.Substring(0, 27) & (Long.Parse(Uuid.Substring(27), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X").PadLeft(5, "0")
                 Loop
                 Loop
         End Select
         End Select
         Return Uuid
         Return Uuid

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

@@ -151,7 +151,7 @@ Public Module ModMinecraft
 
 
 #Region "版本处理"
 #Region "版本处理"
 
 
-    Public Const McVersionCacheVersion As Integer = 29
+    Public Const McVersionCacheVersion As Integer = 30
 
 
     Private _McVersionCurrent As McVersion
     Private _McVersionCurrent As McVersion
     Private _McVersionLast = 0 '为 0 以保证与 Nothing 不相同,使得 UI 显示可以正常初始化
     Private _McVersionLast = 0 '为 0 以保证与 Nothing 不相同,使得 UI 显示可以正常初始化
@@ -715,8 +715,8 @@ Recheck:
                         'OptiFine
                         'OptiFine
                         If RealJson.Contains("optifine") Then
                         If RealJson.Contains("optifine") Then
                             State = McVersionState.OptiFine
                             State = McVersionState.OptiFine
-                            Version.OptiFineVersion = If(RegexSeek(RealJson, "(?<=HD_U_)[^"":/]+"), "未知版本")
                             Version.HasOptiFine = True
                             Version.HasOptiFine = True
+                            Version.OptiFineVersion = If(RegexSeek(RealJson, "(?<=HD_U_)[^"":/]+"), "未知版本")
                         End If
                         End If
                         'LiteLoader
                         'LiteLoader
                         If RealJson.Contains("liteloader") Then
                         If RealJson.Contains("liteloader") Then
@@ -727,22 +727,20 @@ Recheck:
                         'FUTURE: [Quilt 支持] 确认这里的玩意儿对不对
                         '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.FabricVersion = If(RegexSeek(RealJson, "(?<=(net.fabricmc:fabric-loader:)|(org.quiltmc:quilt-loader:))[0-9\.]+(\+build.[0-9]+)?"), "未知版本").Replace("+build", "")
                             Version.HasFabric = True
                             Version.HasFabric = True
-                        ElseIf RealJson.Contains("minecraftforge") AndAlso Not RealJson.Contains("neoforge") Then
+                            Version.FabricVersion = If(RegexSeek(RealJson, "(?<=(net.fabricmc:fabric-loader:)|(org.quiltmc:quilt-loader:))[0-9\.]+(\+build.[0-9]+)?"), "未知版本").Replace("+build", "")
+                        ElseIf RealJson.Contains("minecraftforge") AndAlso Not RealJson.Contains("net.neoforge") Then
                             State = McVersionState.Forge
                             State = McVersionState.Forge
+                            Version.HasForge = True
                             Version.ForgeVersion = RegexSeek(RealJson, "(?<=forge:[0-9\.]+(_pre[0-9]*)?\-)[0-9\.]+")
                             Version.ForgeVersion = RegexSeek(RealJson, "(?<=forge:[0-9\.]+(_pre[0-9]*)?\-)[0-9\.]+")
                             If Version.ForgeVersion Is Nothing Then Version.ForgeVersion = RegexSeek(RealJson, "(?<=net\.minecraftforge:minecraftforge:)[0-9\.]+")
                             If Version.ForgeVersion Is Nothing Then Version.ForgeVersion = RegexSeek(RealJson, "(?<=net\.minecraftforge:minecraftforge:)[0-9\.]+")
                             If Version.ForgeVersion Is Nothing Then Version.ForgeVersion = If(RegexSeek(RealJson, "(?<=net\.minecraftforge:fmlloader:[0-9\.]+-)[0-9\.]+"), "未知版本")
                             If Version.ForgeVersion Is Nothing Then Version.ForgeVersion = If(RegexSeek(RealJson, "(?<=net\.minecraftforge:fmlloader:[0-9\.]+-)[0-9\.]+"), "未知版本")
-                            Version.HasForge = True
-                        ElseIf RealJson.Contains("neoforge") Then    '1.20.1 NeoForge Json 内信息不同,为了方便直接截断 orgeVersion;这里的实现比较抽象,正则我写不会
-                            State = McVersionState.NeoForge          '1.20.1 Json 标识:"--fml.forgeVersion"     1.20.1 以上 Json 标识:"--fml.neoForgeVersion"
-                            Dim JsonStr1() As String = RealJson.Replace(" ", "").Split("orgeVersion""," & vbCrLf & """")
-                            Dim JsonStr2() As String = JsonStr1(1).Split("""")
-                            Version.NeoForgeVersion = JsonStr2(0)
-                            If Version.NeoForgeVersion Is Nothing Then Version.NeoForgeVersion = RegexSeek(RealJson, "(?<=orgeVersion"",)[0-9\.]+")
-                            If Version.NeoForgeVersion Is Nothing Then Version.NeoForgeVersion = If(RegexSeek(RealJson, "(?<=net\.minecraftforge:fmlloader:[0-9\.]+-)[0-9\.]+"), "未知版本")
+                        ElseIf RealJson.Contains("net.neoforge") Then
+                            '1.20.1 JSON 范例:"--fml.forgeVersion", "47.1.99"
+                            '1.20.2+ JSON 范例:"--fml.neoForgeVersion", "20.6.119-beta"
+                            State = McVersionState.NeoForge
                             Version.HasNeoForge = True
                             Version.HasNeoForge = True
+                            Version.NeoForgeVersion = If(RegexSeek(RealJson, "(?<=orgeVersion"",[^""]*?"")[^""]+(?="",)"), "未知版本")
                         End If
                         End If
                         Version.IsApiLoaded = True
                         Version.IsApiLoaded = True
                 End Select
                 End Select
@@ -987,7 +985,7 @@ ExitDataLoad:
                             ElseIf SubVersions.Length = 3 Then
                             ElseIf SubVersions.Length = 3 Then
                                 _SortCode = Val(SubVersions(0)) * 1000000 + Val(SubVersions(1)) * 10000 + Val(SubVersions(2))
                                 _SortCode = Val(SubVersions(0)) * 1000000 + Val(SubVersions(1)) * 10000 + Val(SubVersions(2))
                             Else
                             Else
-                                Throw New Exception(If(HasForge, "无效的 Forge 版本:" & ForgeVersion, "无效的 NeoForge 版本:" & NeoForgeVersion))
+                                Throw New Exception("无效的 Neo/Forge 版本:" & ForgeVersion)
                             End If
                             End If
                         ElseIf HasOptiFine Then
                         ElseIf HasOptiFine Then
                             If OptiFineVersion = "未知版本" Then Return 0
                             If OptiFineVersion = "未知版本" Then Return 0
@@ -1433,7 +1431,7 @@ OnLoaded:
             End Function)
             End Function)
         End If
         End If
 
 
-        'API 版本:优先按版本排序,此后【先放 Fabric,再放 Forge,再放 NeoForge(按版本号从高到低排序),最后放 LiteLoader(按名称排序)】
+        'API 版本:优先按版本排序,此后【先放 Fabric,再放 Neo/Forge(按版本号从高到低排序),最后放 LiteLoader(按名称排序)】
         If ResultVersionList.ContainsKey(McVersionCardType.API) Then
         If ResultVersionList.ContainsKey(McVersionCardType.API) Then
             ResultVersionList(McVersionCardType.API) = Sort(ResultVersionList(McVersionCardType.API),
             ResultVersionList(McVersionCardType.API) = Sort(ResultVersionList(McVersionCardType.API),
             Function(Left As McVersion, Right As McVersion)
             Function(Left As McVersion, Right As McVersion)
@@ -1443,10 +1441,10 @@ OnLoaded:
                 Else
                 Else
                     If Left.Version.HasFabric Xor Right.Version.HasFabric Then
                     If Left.Version.HasFabric Xor Right.Version.HasFabric Then
                         Return Left.Version.HasFabric
                         Return Left.Version.HasFabric
-                    ElseIf Left.Version.HasForge Xor Right.Version.HasForge Then
-                        Return Left.Version.HasForge
                     ElseIf Left.Version.HasNeoForge Xor Right.Version.HasNeoForge Then
                     ElseIf Left.Version.HasNeoForge Xor Right.Version.HasNeoForge Then
                         Return Left.Version.HasNeoForge
                         Return Left.Version.HasNeoForge
+                    ElseIf Left.Version.HasForge Xor Right.Version.HasForge Then
+                        Return Left.Version.HasForge
                     ElseIf Not Left.Version.SortCode <> Right.Version.SortCode Then
                     ElseIf Not Left.Version.SortCode <> Right.Version.SortCode Then
                         Return Left.Version.SortCode > Right.Version.SortCode
                         Return Left.Version.SortCode > Right.Version.SortCode
                     Else
                     Else
@@ -1677,7 +1675,7 @@ OnLoaded:
                 Return _Url
                 Return _Url
             End Get
             End Get
             Set(value As String)
             Set(value As String)
-                '孤儿 Forge 作者喜欢把没有的 URL 写个空字符串
+                '孤儿 Forge 作者喜欢把没有 URL 的写个空字符串
                 _Url = If(String.IsNullOrWhiteSpace(value), Nothing, value)
                 _Url = If(String.IsNullOrWhiteSpace(value), Nothing, value)
             End Set
             End Set
         End Property
         End Property
@@ -1694,15 +1692,6 @@ OnLoaded:
             End Get
             End Get
         End Property
         End Property
         ''' <summary>
         ''' <summary>
-        ''' 原 Json 中 Name 项最后一部分的版本号。
-        ''' </summary>
-        Public ReadOnly Property Version As String
-            Get
-                Dim Splited = OriginalName.Split(":")
-                Return Splited(Splited.Count - 1)
-            End Get
-        End Property
-        ''' <summary>
         ''' 原 Json 中的 Name 项。
         ''' 原 Json 中的 Name 项。
         ''' </summary>
         ''' </summary>
         Public OriginalName As String
         Public OriginalName As String
@@ -1783,7 +1772,7 @@ OnLoaded:
                 '根据 Inherit 获取最深层版本
                 '根据 Inherit 获取最深层版本
                 Dim OriginalVersion As McVersion = Version
                 Dim OriginalVersion As McVersion = Version
                 '1.17+ 的 Forge 不寻找 Inherit
                 '1.17+ 的 Forge 不寻找 Inherit
-                If Not (Version.Version.HasForge AndAlso Version.Version.McCodeMain >= 17) Then
+                If Not ((Version.Version.HasForge OrElse Version.Version.HasNeoForge) AndAlso Version.Version.McCodeMain >= 17) Then
                     Do Until OriginalVersion.InheritVersion = ""
                     Do Until OriginalVersion.InheritVersion = ""
                         If OriginalVersion.InheritVersion = OriginalVersion.Name Then Exit Do
                         If OriginalVersion.InheritVersion = OriginalVersion.Name Then Exit Do
                         OriginalVersion = New McVersion(PathMcFolder & "versions\" & OriginalVersion.InheritVersion & "\")
                         OriginalVersion = New McVersion(PathMcFolder & "versions\" & OriginalVersion.InheritVersion & "\")
@@ -1868,13 +1857,14 @@ OnLoaded:
                 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"),
-                                                       .Url = If(RootUrl, Library("downloads")("artifact")("url")),
-                                                       .LocalPath = If(Library("downloads")("artifact")("path") Is Nothing, McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder), CustomMcFolder & "libraries\" & Library("downloads")("artifact")("path").ToString.Replace("/", "\")),
-                                                       .Size = Val(Library("downloads")("artifact")("size").ToString),
-                                                       .IsNatives = False,
-                                                       .SHA1 = Library("downloads")("artifact")("sha1")?.ToString})
+                            .IsJumpLoader = IsJumpLoader,
+                            .OriginalName = Library("name"),
+                            .Url = If(RootUrl, Library("downloads")("artifact")("url")),
+                            .LocalPath = If(Library("downloads")("artifact")("path") Is Nothing, McLibGet(Library("name"),
+                                CustomMcFolder:=CustomMcFolder), CustomMcFolder & "libraries\" & Library("downloads")("artifact")("path").ToString.Replace("/", "\")),
+                            .Size = Val(Library("downloads")("artifact")("size").ToString),
+                            .IsNatives = False,
+                            .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 {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing})
                     End If
                     End If
@@ -1908,15 +1898,25 @@ OnLoaded:
 
 
         '去重
         '去重
         Dim ResultArray As New Dictionary(Of String, McLibToken)
         Dim ResultArray As New Dictionary(Of String, McLibToken)
+        Dim GetVersion =
+        Function(Token As McLibToken) As String
+            '测试例:
+            'D:\Minecraft\test\libraries\net\neoforged\mergetool\2.0.0\mergetool-2.0.0-api.jar
+            'D:\Minecraft\test\libraries\org\apache\commons\commons-collections4\4.2\commons-collections4-4.2.jar
+            'D:\Minecraft\test\libraries\com\google\guava\guava\31.1-jre\guava-31.1-jre.jar
+            Return GetFolderNameFromPath(GetPathFromFullPath(Token.LocalPath))
+        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 & BasicArray(i).IsJumpLoader.ToString
             If ResultArray.ContainsKey(Key) Then
             If ResultArray.ContainsKey(Key) Then
-                If BasicArray(i).Version <> ResultArray(Key).Version AndAlso KeepSameNameDifferentVersionResult Then
-                    Log($"[Minecraft] 发现疑似重复的支持库:{BasicArray(i)} 与 {ResultArray(Key)}")
+                Dim BasicArrayVersion As String = GetVersion(BasicArray(i))
+                Dim ResultArrayVersion As String = GetVersion(ResultArray(Key))
+                If BasicArrayVersion <> ResultArrayVersion AndAlso KeepSameNameDifferentVersionResult Then
+                    Log($"[Minecraft] 发现疑似重复的支持库:{BasicArray(i)} ({BasicArrayVersion}) 与 {ResultArray(Key)} ({ResultArrayVersion})")
                     ResultArray.Add(Key & GetUuid(), BasicArray(i))
                     ResultArray.Add(Key & GetUuid(), BasicArray(i))
                 Else
                 Else
-                    Log($"[Minecraft] 发现重复的支持库:{BasicArray(i)} 与 {ResultArray(Key)},已忽略其中之一")
-                    If VersionSortBoolean(BasicArray(i).Version, ResultArray(Key).Version) Then
+                    Log($"[Minecraft] 发现重复的支持库:{BasicArray(i)} ({BasicArrayVersion}) 与 {ResultArray(Key)} ({ResultArrayVersion}),已忽略其中之一")
+                    If VersionSortBoolean(BasicArrayVersion, ResultArrayVersion) Then
                         ResultArray(Key) = BasicArray(i)
                         ResultArray(Key) = BasicArray(i)
                     End If
                     End If
                 End If
                 End If
@@ -1976,6 +1976,7 @@ OnLoaded:
                 End If
                 End If
             End If
             End If
         End If
         End If
+
         'Authlib-Injector 文件
         'Authlib-Injector 文件
         If Setup.Get("VersionServerLogin", Version:=Version) = 4 OrElse
         If Setup.Get("VersionServerLogin", Version:=Version) = 4 OrElse
            (PageLinkHiper.HiperState = LoadState.Finished AndAlso Setup.Get("LoginType") = McLoginType.Legacy) Then 'HiPer 登录转接
            (PageLinkHiper.HiperState = LoadState.Finished AndAlso Setup.Get("LoginType") = McLoginType.Legacy) Then 'HiPer 登录转接
@@ -2025,8 +2026,13 @@ OnLoaded:
             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") Then Urls = DlSourceLauncherOrMetaGet(Token.Url).ToList() 'Mappings
-                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"))
+                If Token.Url.Contains("launcher.mojang.com/v1/objects") Then
+                    Urls = DlSourceLauncherOrMetaGet(Token.Url).ToList() 'Mappings
+                End If
+                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"))
+                End If
             End If
             End If
             If Token.LocalPath.Contains("transformer-discovery-service") Then
             If Token.LocalPath.Contains("transformer-discovery-service") Then
                 'Transformer 文件释放
                 'Transformer 文件释放

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

@@ -887,7 +887,7 @@ Finished:
                 ModList.Add(ModEntry)
                 ModList.Add(ModEntry)
                 '读取 Comp 缓存
                 '读取 Comp 缓存
                 If ModEntry.State = McMod.McModState.Unavaliable Then Continue For
                 If ModEntry.State = McMod.McModState.Unavaliable Then Continue For
-                Dim CacheKey = ModEntry.ModrinthHash & PageVersionLeft.Version.Version.McName
+                Dim CacheKey = ModEntry.ModrinthHash & PageVersionLeft.Version.Version.McName & GetTargetModLoaders().Join("")
                 If Cache.ContainsKey(CacheKey) Then
                 If Cache.ContainsKey(CacheKey) Then
                     ModEntry.FromJson(Cache(CacheKey))
                     ModEntry.FromJson(Cache(CacheKey))
                     '如果缓存中的信息在 6 小时以内更新过,则无需重新获取
                     '如果缓存中的信息在 6 小时以内更新过,则无需重新获取
@@ -923,20 +923,15 @@ Finished:
             Throw
             Throw
         End Try
         End Try
     End Sub
     End Sub
-
     '联网加载 Mod 详情
     '联网加载 Mod 详情
-    Private Const LocalModCacheVersion As Integer = 4
+    Private Const LocalModCacheVersion As Integer = 5
     Public McModDetailLoader As New LoaderTask(Of KeyValuePair(Of List(Of McMod), JObject), Integer)("Mod List Detail Loader", AddressOf McModDetailLoad)
     Public McModDetailLoader As New LoaderTask(Of KeyValuePair(Of List(Of McMod), JObject), Integer)("Mod List Detail Loader", AddressOf McModDetailLoad)
     Private Sub McModDetailLoad(Loader As LoaderTask(Of KeyValuePair(Of List(Of McMod), JObject), Integer))
     Private Sub McModDetailLoad(Loader As LoaderTask(Of KeyValuePair(Of List(Of McMod), JObject), Integer))
         Dim Mods As List(Of McMod) = Loader.Input.Key
         Dim Mods As List(Of McMod) = Loader.Input.Key
         Dim Cache As JObject = Loader.Input.Value
         Dim Cache As JObject = Loader.Input.Value
         '获取作为检查目标的加载器和版本
         '获取作为检查目标的加载器和版本
         Dim TargetMcVersion As McVersionInfo = PageVersionLeft.Version.Version
         Dim TargetMcVersion As McVersionInfo = PageVersionLeft.Version.Version
-        Dim ModLoaders As New List(Of CompModLoaderType)
-        If TargetMcVersion.HasForge Then ModLoaders.Add(CompModLoaderType.Forge)
-        If TargetMcVersion.HasFabric Then ModLoaders.Add(CompModLoaderType.Fabric)
-        If TargetMcVersion.HasLiteLoader Then ModLoaders.Add(CompModLoaderType.LiteLoader)
-        If Not ModLoaders.Any() Then ModLoaders.AddRange({CompModLoaderType.Forge, CompModLoaderType.Fabric, CompModLoaderType.LiteLoader, CompModLoaderType.Quilt})
+        Dim ModLoaders = GetTargetModLoaders()
         Dim McVersion = TargetMcVersion.McName
         Dim McVersion = TargetMcVersion.McName
         '暂不向下扩展检查的 MC 小版本
         '暂不向下扩展检查的 MC 小版本
         '例如:Mod 在更新 1.16.5 后,对早期的 1.16.2 版本发布了修补补丁,这会导致 PCL 将 1.16.5 版本的 Mod 降级到 1.16.2
         '例如:Mod 在更新 1.16.5 后,对早期的 1.16.2 版本发布了修补补丁,这会导致 PCL 将 1.16.5 版本的 Mod 降级到 1.16.2
@@ -1136,10 +1131,19 @@ Finished:
         If Not Mods.Any() Then Exit Sub
         If Not Mods.Any() Then Exit Sub
         For Each Entry In Mods 'TODO: Bookshelf 的 Logo 会在两个网站间横跳
         For Each Entry In Mods 'TODO: Bookshelf 的 Logo 会在两个网站间横跳
             Entry.CompLoaded = SucceedThreadCount = 2
             Entry.CompLoaded = SucceedThreadCount = 2
-            Cache(Entry.ModrinthHash & McVersion) = Entry.ToJson()
+            Cache(Entry.ModrinthHash & McVersion & ModLoaders.Join("")) = Entry.ToJson()
         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)))
     End Sub
     End Sub
+    Private Function GetTargetModLoaders() As List(Of CompModLoaderType)
+        Dim ModLoaders As New List(Of CompModLoaderType)
+        If PageVersionLeft.Version.Version.HasForge Then ModLoaders.Add(CompModLoaderType.Forge)
+        If PageVersionLeft.Version.Version.HasNeoForge Then ModLoaders.Add(CompModLoaderType.NeoForge)
+        If PageVersionLeft.Version.Version.HasFabric Then ModLoaders.Add(CompModLoaderType.Fabric)
+        If PageVersionLeft.Version.Version.HasLiteLoader Then ModLoaders.Add(CompModLoaderType.LiteLoader)
+        If Not ModLoaders.Any() Then ModLoaders.AddRange({CompModLoaderType.Forge, CompModLoaderType.NeoForge, CompModLoaderType.Fabric, CompModLoaderType.LiteLoader, CompModLoaderType.Quilt})
+        Return ModLoaders
+    End Function
 
 
 #If DEBUG Then
 #If DEBUG Then
     ''' <summary>
     ''' <summary>

+ 12 - 8
Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb

@@ -281,19 +281,23 @@ Retry:
                     '建立 CompFile
                     '建立 CompFile
                     Dim File As New CompFile(ModJson, CompType.Mod)
                     Dim File As New CompFile(ModJson, CompType.Mod)
                     If Not File.Available Then Continue For
                     If Not File.Available Then Continue For
-                    '根据 modules 和文件名后缀判断是资源包还是 Mod
-                    Dim IsResourcePack As Boolean
+                    '根据 modules 和文件名后缀判断资源类型
+                    Dim TargetFolder As String
                     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
-                        IsResourcePack =
-                            (Not ModuleNames.Contains("META-INF")) AndAlso (Not ModuleNames.Contains("mcmod.info")) AndAlso '不包含 META-INF 或 mcmod.info
-                            ModuleNames.Contains("pack.mcmeta") AndAlso '包含 pack.mcmeta
-                            (Not File.FileName.EndsWithF(".jar", True)) '文件后缀不是 .jar
+                        If ModuleNames.Contains("META-INF") OrElse ModuleNames.Contains("mcmod.info") OrElse
+                           File.FileName.EndsWithF(".jar", True) Then
+                            TargetFolder = "mods"
+                        ElseIf ModuleNames.Contains("pack.mcmeta") Then
+                            TargetFolder = "resourcepacks"
+                        Else
+                            TargetFolder = "shaderpacks"
+                        End If
                     Else
                     Else
-                        IsResourcePack = False
+                        TargetFolder = "mods"
                     End If
                     End If
                     '实际的添加
                     '实际的添加
-                    FileList.Add(Id, File.ToNetFile($"{PathMcFolder}versions\{VersionName}\{If(IsResourcePack, "resourcepacks", "mods")}\"))
+                    FileList.Add(Id, File.ToNetFile($"{PathMcFolder}versions\{VersionName}\{TargetFolder}\"))
                     Task.Progress += 1 / (1 + ModList.Count)
                     Task.Progress += 1 / (1 + ModList.Count)
                 Next
                 Next
                 Task.Output = FileList.Values.ToList
                 Task.Output = FileList.Values.ToList

+ 8 - 1
Plain Craft Launcher 2/Modules/ModEvent.vb

@@ -43,7 +43,14 @@
                                 End Sub)
                                 End Sub)
 
 
                 Case "启动游戏"
                 Case "启动游戏"
-                    If Data(0) = "\current" Then Data(0) = McVersionCurrent.Name
+                    If Data(0) = "\current" Then
+                        If McVersionCurrent Is Nothing Then
+                            Hint("请先选择一个 Minecraft 版本!", HintType.Critical)
+                            Exit Sub
+                        Else
+                            Data(0) = McVersionCurrent.Name
+                        End If
+                    End If
                     If McLaunchStart(New McLaunchOptions With
                     If McLaunchStart(New McLaunchOptions With
                                      {.ServerIp = If(Data.Length >= 2, Data(1), Nothing), .Version = New McVersion(Data(0))}) Then
                                      {.ServerIp = If(Data.Length >= 2, Data(1), Nothing), .Version = New McVersion(Data(0))}) Then
                         Hint("正在启动 " & Data(0) & "……")
                         Hint("正在启动 " & Data(0) & "……")

+ 7 - 8
Plain Craft Launcher 2/Modules/ModMusic.vb

@@ -69,23 +69,24 @@
                         Else
                         Else
                             '有背景音乐
                             '有背景音乐
                             FrmMain.BtnExtraMusic.Show = True
                             FrmMain.BtnExtraMusic.Show = True
-
-                            Dim ToolTipText As String = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
+                            Dim ToolTipText As String
                             If MusicState = MusicStates.Pause Then
                             If MusicState = MusicStates.Pause Then
                                 FrmMain.BtnExtraMusic.Logo = Logo.IconPlay
                                 FrmMain.BtnExtraMusic.Logo = Logo.IconPlay
                                 FrmMain.BtnExtraMusic.LogoScale = 0.8
                                 FrmMain.BtnExtraMusic.LogoScale = 0.8
+                                ToolTipText = "已暂停:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
                                 If MusicAllList.Count > 1 Then
                                 If MusicAllList.Count > 1 Then
-                                    ToolTipText += vbCrLf & "左键播放,右键播放下一曲。"
+                                    ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。"
                                 Else
                                 Else
-                                    ToolTipText += vbCrLf & "左键播放,右键从头重新播放。"
+                                    ToolTipText += vbCrLf & "左键恢复播放,右键重新从头播放。"
                                 End If
                                 End If
                             Else
                             Else
                                 FrmMain.BtnExtraMusic.Logo = Logo.IconMusic
                                 FrmMain.BtnExtraMusic.Logo = Logo.IconMusic
                                 FrmMain.BtnExtraMusic.LogoScale = 1
                                 FrmMain.BtnExtraMusic.LogoScale = 1
+                                ToolTipText = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
                                 If MusicAllList.Count > 1 Then
                                 If MusicAllList.Count > 1 Then
                                     ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。"
                                     ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。"
                                 Else
                                 Else
-                                    ToolTipText += vbCrLf & "左键暂停,右键从头重新播放。"
+                                    ToolTipText += vbCrLf & "左键暂停,右键重新从头播放。"
                                 End If
                                 End If
                             End If
                             End If
                             FrmMain.BtnExtraMusic.ToolTip = ToolTipText
                             FrmMain.BtnExtraMusic.ToolTip = ToolTipText
@@ -123,16 +124,14 @@
     ''' </summary>
     ''' </summary>
     Public Sub MusicControlNext()
     Public Sub MusicControlNext()
         If MusicAllList.Count = 1 Then
         If MusicAllList.Count = 1 Then
-            'Hint("播放列表中仅有一首歌曲!")
             MusicStartPlay(MusicCurrent)
             MusicStartPlay(MusicCurrent)
             Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Finish)
             Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Finish)
-            MusicRefreshUI()
         Else
         Else
             Dim Address As String = DequeueNextMusicAddress()
             Dim Address As String = DequeueNextMusicAddress()
             MusicStartPlay(Address)
             MusicStartPlay(Address)
             Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish)
             Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish)
-            MusicRefreshUI()
         End If
         End If
+        MusicRefreshUI()
     End Sub
     End Sub
 
 
 #End Region
 #End Region

+ 1 - 0
Plain Craft Launcher 2/Modules/ModSecret.vb

@@ -252,6 +252,7 @@ Friend Module ModSecret
         Return False
         Return False
     End Function
     End Function
     Public Function DonateCodeInput() As Boolean?
     Public Function DonateCodeInput() As Boolean?
+        Return Nothing
     End Function
     End Function
 
 
 #End Region
 #End Region

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

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

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

@@ -1005,38 +1005,40 @@ Retry:
 
 
 #End Region
 #End Region
 
 
-#Region "Forge / NeoForge 下载"
+#Region "Forgelike 下载"
 
 
-    Public Sub McDownloadForge(IsNeo As Boolean, Optional DownloadForgeInfo As DlForgeVersionEntry = Nothing, Optional DownloadNeoInfo As DlNeoForgeVersionEntry = Nothing)
-        Dim DownloadInfo = If(IsNeo, DownloadNeoInfo, DownloadForgeInfo)
+    Public Sub McDownloadForgelike(Info As DlForgelikeEntry)
         '老版本提示
         '老版本提示
-        If DownloadInfo.Category = "client" Then
-            If MyMsgBox("该 Forge 版本过于古老,PCL 暂不支持该版本的自动安装。" & vbCrLf &
-                        "若你仍然希望继续,PCL 将把安装程序下载到你指定的位置,但不会进行安装。",
-                        "版本过老", "继续", "取消") = 1 Then
-                McDownloadForgeSave(IsNeo, DownloadInfo)
+        If Not Info.IsNeoForge Then
+            Dim ForgeInfo As DlForgeVersionEntry = Info
+            If ForgeInfo.Category = "client" Then
+                If MyMsgBox("该 Forge 版本过于古老,PCL 暂不支持该版本的自动安装。" & vbCrLf &
+                            "若你仍然希望继续,PCL 将把安装程序下载到你指定的位置,但不会进行安装。",
+                            "版本过老", "继续", "取消") = 1 Then
+                    McDownloadForgelikeSave(Info)
+                End If
+                Exit Sub
             End If
             End If
-            Exit Sub
-        End If
-        If DownloadInfo.Category = "universal" OrElse DownloadInfo.Inherit.StartsWithF("1.5") Then '对该版本自动安装的支持将在之后加入
-            If MyMsgBox("该 Forge 版本过于古老,PCL 暂不支持该版本的自动安装。" & vbCrLf &
-                        "若你仍然希望继续,PCL 将把安装程序下载到你指定的位置,但不会进行安装。",
-                        "版本过老", "继续", "取消") = 1 Then
-                McDownloadForgeSave(IsNeo, DownloadInfo)
+            If ForgeInfo.Category = "universal" OrElse ForgeInfo.Inherit.StartsWithF("1.5") Then
+                If MyMsgBox("该 Forge 版本过于古老,PCL 暂不支持该版本的自动安装。" & vbCrLf &
+                            "若你仍然希望继续,PCL 将把安装程序下载到你指定的位置,但不会进行安装。",
+                            "版本过老", "继续", "取消") = 1 Then
+                    McDownloadForgelikeSave(Info)
+                End If
+                Exit Sub
             End If
             End If
-            Exit Sub
         End If
         End If
         '初始化参数
         '初始化参数
-        Dim Id As String = DownloadInfo.Inherit & $"-{If(IsNeo, "neo", "")}forge-" & DownloadInfo.Version
-        Dim Target As String = PathTemp & $"Cache\Code\{If(IsNeo, "Neo", "")}ForgeInstall-" & DownloadInfo.Version & "_" & GetUuid() & "." & DownloadInfo.FileSuffix
-        Dim VersionFolder As String = PathMcFolder & "versions\" & Id & "\"
-        Dim DisplayName As String = $"{If(IsNeo, "Neo", "")}Forge " & DownloadInfo.Inherit & " - " & DownloadInfo.Version
+        Dim McVersionName As String = $"{Info.Inherit}-{Info.LoaderName.ToLower}-{Info.VersionName}"
+        Dim TempFolder As String = $"{PathTemp}Cache\Code\{Info.LoaderName}Install-{Info.Version}_{GetUuid()}.{Info.FileExtension}"
+        Dim McVersionFolder As String = $"{PathMcFolder}versions\{McVersionName}\"
+        Dim DisplayName As String = $"{Info.LoaderName} {Info.Inherit} - {Info.VersionName}"
         Try
         Try
 
 
             '重复任务检查
             '重复任务检查
             SyncLock LoaderTaskbarLock
             SyncLock LoaderTaskbarLock
                 For i = 0 To LoaderTaskbar.Count - 1
                 For i = 0 To LoaderTaskbar.Count - 1
-                    If LoaderTaskbar(i).Name = DisplayName & " 下载" Then
+                    If LoaderTaskbar(i).Name = Info.LoaderName & " 下载" Then
                         Hint("该版本正在下载中!", HintType.Critical)
                         Hint("该版本正在下载中!", HintType.Critical)
                         Exit Sub
                         Exit Sub
                     End If
                     End If
@@ -1044,37 +1046,39 @@ Retry:
             End SyncLock
             End SyncLock
 
 
             '已有版本检查
             '已有版本检查
-            If File.Exists(VersionFolder & Id & ".json") Then
-                If MyMsgBox("版本 " & Id & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 json 和 jar 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
-                    File.Delete(VersionFolder & Id & ".jar")
-                    File.Delete(VersionFolder & Id & ".json")
+            If File.Exists(McVersionFolder & McVersionName & ".json") Then
+                If MyMsgBox("版本 " & McVersionName & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 json 和 jar 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
+                    File.Delete(McVersionFolder & McVersionName & ".jar")
+                    File.Delete(McVersionFolder & McVersionName & ".json")
                 Else
                 Else
                     Exit Sub
                     Exit Sub
                 End If
                 End If
             End If
             End If
 
 
             '启动
             '启动
-            Dim Loader As New LoaderCombo(Of String)(DisplayName & " 下载", McDownloadForgeLoader(IsNeo, DownloadInfo.Version, DownloadInfo.Inherit, DownloadInfo)) With {.OnStateChanged = AddressOf McInstallState}
-            Loader.Start(VersionFolder)
+            Dim Loader As New LoaderCombo(Of String)(Info.LoaderName & " 下载",
+                McDownloadForgelikeLoader(Info.IsNeoForge, If(Info.IsNeoForge, CType(Info, DlNeoForgeListEntry).ApiName, Info.VersionName), Info.Inherit, Info)) With
+                {.OnStateChanged = AddressOf McInstallState}
+            Loader.Start(McVersionFolder)
             LoaderTaskbarAdd(Loader)
             LoaderTaskbarAdd(Loader)
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.Ribble()
             FrmMain.BtnExtraDownload.Ribble()
 
 
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, $"开始 {If(IsNeo, "Neo", "")}Forge 下载失败", LogLevel.Feedback)
+            Log(ex, $"开始 {Info.LoaderName} 下载失败", LogLevel.Feedback)
         Finally
         Finally
             '删除安装包
             '删除安装包
             Try
             Try
-                If File.Exists(Target) Then File.Delete(Target)
+                If File.Exists(TempFolder) Then File.Delete(TempFolder)
             Catch
             Catch
             End Try
             End Try
         End Try
         End Try
     End Sub
     End Sub
-    Public Sub McDownloadForgeSave(IsNeo As Boolean, Optional DownloadForgeInfo As DlForgeVersionEntry = Nothing, Optional DownloadNeoInfo As DlNeoForgeVersionEntry = Nothing)
-        Dim DownloadInfo = If(IsNeo, DownloadNeoInfo, DownloadForgeInfo)
+    Public Sub McDownloadForgelikeSave(Info As DlForgelikeEntry)
         Try
         Try
-            Dim Target As String = SelectAs("选择保存位置", DownloadInfo.FileName, $"{If(IsNeo, "Neo", "")}Forge 文件 (*." & DownloadInfo.FileSuffix & ")|*." & DownloadInfo.FileSuffix)
-            Dim DisplayName As String = $"{If(IsNeo, "Neo", "")}Forge " & DownloadInfo.Inherit & " - " & If(IsNeo, DownloadInfo.VersionCode, DownloadInfo.Version)
+            Dim Target As String = SelectAs("选择保存位置", $"{Info.LoaderName}-{Info.Inherit}-{Info.VersionName}.{Info.FileExtension}",
+                                            $"{Info.LoaderName} 安装器 (*.{Info.FileExtension})|*.{Info.FileExtension}")
+            Dim DisplayName As String = $"{Info.LoaderName} {Info.Inherit} - {Info.VersionName}"
             If Not Target.Contains("\") Then Exit Sub
             If Not Target.Contains("\") Then Exit Sub
 
 
             '重复任务检查
             '重复任务检查
@@ -1087,50 +1091,41 @@ Retry:
                 Next
                 Next
             End SyncLock
             End SyncLock
 
 
-            '构造步骤加载器
-            Dim Loaders As New List(Of LoaderBase)
             '获取下载地址
             '获取下载地址
-            If IsNeo Then
+            Dim Files As New List(Of NetFile)
+            If Info.IsNeoForge Then
                 'NeoForge
                 'NeoForge
-                Loaders.Add(New LoaderTask(Of DlNeoForgeVersionEntry, List(Of NetFile))("获取下载地址",
-                Sub(Task As LoaderTask(Of DlNeoForgeVersionEntry, List(Of NetFile)))
-                    Dim Files As New List(Of NetFile)
-                    Dim IsLegacyNeo As Boolean = DownloadInfo.VersionCode.StartsWith("47.")
-                    Files.Add(New NetFile({
-                        $"https://bmclapi2.bangbang93.com/maven/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}",
-                        $"https://maven.neoforged.net/releases/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}"
-                    }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=If(IsNeo, Nothing, DownloadInfo.Hash))))
-                    Task.Output = Files
-                End Sub) With {.ProgressWeight = 0.1, .Show = False})
+                Dim Neo As DlNeoForgeListEntry = Info
+                Dim Url As String = Neo.UrlBase & "-installer.jar"
+                Files.Add(New NetFile({
+                    Url.Replace("maven.neoforged.net/releases", "bmclapi2.bangbang93.com/maven"), Url
+                }, Target, New FileChecker(MinSize:=64 * 1024)))
             Else
             Else
                 'Forge
                 'Forge
-                Loaders.Add(New LoaderTask(Of DlForgeVersionEntry, List(Of NetFile))("获取下载地址",
-                Sub(Task As LoaderTask(Of DlForgeVersionEntry, List(Of NetFile)))
-                    Dim Files As New List(Of NetFile)
-                    Files.Add(New NetFile({
-                        "https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
-                        "https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
-                    }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=If(IsNeo, Nothing, DownloadInfo.Hash))))
-                    Task.Output = Files
-                End Sub) With {.ProgressWeight = 0.1, .Show = False})
+                Dim Forge As DlForgeVersionEntry = Info
+                Files.Add(New NetFile({
+                    $"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/{Forge.Inherit}-{Forge.FileVersion}/forge-{Forge.Inherit}-{Forge.FileVersion}-{Forge.Category}.{Forge.FileExtension}",
+                    $"https://files.minecraftforge.net/maven/net/minecraftforge/forge/{Forge.Inherit}-{Forge.FileVersion}/forge-{Forge.Inherit}-{Forge.FileVersion}-{Forge.Category}.{Forge.FileExtension}"
+                }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=Forge.Hash)))
             End If
             End If
-            '下载
-            Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile)) With {.ProgressWeight = 6})
+
+            '构造加载器
+            Dim Loaders As New List(Of LoaderBase)
+            Loaders.Add(New LoaderDownload("下载主文件", Files) With {.ProgressWeight = 6})
 
 
             '启动
             '启动
-            Dim Loader = If(IsNeo, New LoaderCombo(Of DlNeoForgeVersionEntry)(DisplayName & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave},
-                New LoaderCombo(Of DlForgeVersionEntry)(DisplayName & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave})
-            Loader.Start(DownloadInfo)
+            Dim Loader = New LoaderCombo(Of DlForgelikeEntry)(DisplayName & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
+            Loader.Start(Info)
             LoaderTaskbarAdd(Loader)
             LoaderTaskbarAdd(Loader)
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.Ribble()
             FrmMain.BtnExtraDownload.Ribble()
 
 
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, $"开始 {If(IsNeo, "Neo", "")}Forge 下载失败", LogLevel.Feedback)
+            Log(ex, $"开始 {Info.LoaderName} 安装器下载失败", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
 
 
-    Private Sub ForgeInjector(Target As String, Task As LoaderTask(Of Boolean, Boolean), McFolder As String, UseJavaWrapper As Boolean, IsNeoForge As Boolean)
+    Private Sub ForgelikeInjector(Target As String, Task As LoaderTask(Of Boolean, Boolean), McFolder As String, UseJavaWrapper As Boolean, IsNeoForge As Boolean)
         '选择 Java
         '选择 Java
         Dim Java As JavaEntry
         Dim Java As JavaEntry
         SyncLock JavaLock
         SyncLock JavaLock
@@ -1185,7 +1180,7 @@ Retry:
                             Else
                             Else
                                 LastResults.Enqueue(e.Data)
                                 LastResults.Enqueue(e.Data)
                                 If LastResults.Count > 100 Then LastResults.Dequeue()
                                 If LastResults.Count > 100 Then LastResults.Dequeue()
-                                ForgeInjectorLine(e.Data, Task)
+                                ForgelikeInjectorLine(e.Data, Task)
                             End If
                             End If
                         Catch ex As ObjectDisposedException
                         Catch ex As ObjectDisposedException
                         Catch ex As Exception
                         Catch ex As Exception
@@ -1208,7 +1203,7 @@ Retry:
                             Else
                             Else
                                 LastResults.Enqueue(e.Data)
                                 LastResults.Enqueue(e.Data)
                                 If LastResults.Count > 100 Then LastResults.Dequeue()
                                 If LastResults.Count > 100 Then LastResults.Dequeue()
-                                ForgeInjectorLine(e.Data, Task)
+                                ForgelikeInjectorLine(e.Data, Task)
                             End If
                             End If
                         Catch ex As ObjectDisposedException
                         Catch ex As ObjectDisposedException
                         Catch ex As Exception
                         Catch ex As Exception
@@ -1246,7 +1241,7 @@ Retry:
             End Using
             End Using
         End SyncLock
         End SyncLock
     End Sub
     End Sub
-    Private Sub ForgeInjectorLine(Content As String, Task As LoaderTask(Of Boolean, Boolean))
+    Private Sub ForgelikeInjectorLine(Content As String, Task As LoaderTask(Of Boolean, Boolean))
         If Content.StartsWithF("  Data") OrElse Content.StartsWithF("  Slim") Then
         If Content.StartsWithF("  Data") OrElse Content.StartsWithF("  Slim") Then
             If ModeDebug Then Log("[Installer] " & Content)
             If ModeDebug Then Log("[Installer] " & Content)
         ElseIf Content.StartsWithF("  Reading patch ") Then
         ElseIf Content.StartsWithF("  Reading patch ") Then
@@ -1292,87 +1287,85 @@ Retry:
     End Sub
     End Sub
 
 
     ''' <summary>
     ''' <summary>
-    ''' 获取下载某个 Forge / NeoForge 版本的加载器列表。
+    ''' 获取下载某个 Forgelike 版本的加载器列表。
     ''' </summary>
     ''' </summary>
-    Private Function McDownloadForgeLoader(IsNeo As Boolean, Version As String, Inherit As String, Optional DownloadForgeInfo As DlForgeVersionEntry = Nothing, Optional DownloadNeoInfo As DlNeoForgeVersionEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
+    Private Function McDownloadForgelikeLoader(IsNeoForge As Boolean, Version As String, Inherit As String, Optional Info As DlForgelikeEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
 
 
         '参数初始化
         '参数初始化
-        Dim DownloadInfo = If(IsNeo, DownloadNeoInfo, DownloadForgeInfo)
-        If IsNeo Then '兜底,有的时候 DownloadInfo 可能是空的
-            If DownloadNeoInfo Is Nothing Then
-                DownloadInfo = New DlNeoForgeVersionEntry With {.VersionName = Version}
-                Version = Version.Replace("neoforge-", "").Replace("-beta", "").Replace("1.20.1-", "")
-                DownloadInfo.VersionCode = Version
-                If Version.Contains("-beta") Then DownloadInfo.IsBeta = True
+        McFolder = If(McFolder, PathMcFolder)
+        If IsNeoForge AndAlso Info Is Nothing Then
+            '需要传入 API Name,但整合包版本可能不以 1.20.1- 开头,所以需要进行特别处理
+            If Inherit = "1.20.1" AndAlso Not Version.StartsWithF("1.20.1-") Then
+                Info = New DlNeoForgeListEntry("1.20.1-" & Version)
             Else
             Else
-                DownloadInfo = DownloadNeoInfo
-                Version = DownloadInfo.VersionCode
+                Info = New DlNeoForgeListEntry(Version)
             End If
             End If
-        Else
-            DownloadInfo = DownloadForgeInfo
         End If
         End If
-        McFolder = If(McFolder, PathMcFolder)
-        If Not IsNeo AndAlso Version.StartsWithF("1.") AndAlso Version.Contains("-") Then
+        If Not IsNeoForge AndAlso Version.StartsWithF("1.") AndAlso Version.Contains("-") Then
             '类似 1.19.3-41.2.8 格式,优先使用 Version 中要求的版本而非 Inherit(例如 1.19.3 却使用了 1.19 的 Forge)
             '类似 1.19.3-41.2.8 格式,优先使用 Version 中要求的版本而非 Inherit(例如 1.19.3 却使用了 1.19 的 Forge)
             Inherit = Version.Before("-")
             Inherit = Version.Before("-")
             Version = Version.After("-")
             Version = Version.After("-")
         End If
         End If
-        Dim LoaderName As String = If(IsNeo, "NeoForge", "Forge")
+        Dim LoaderName As String = If(IsNeoForge, "NeoForge", "Forge")
         Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
         Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
-        Dim Id As String = If(IsNeo, DownloadInfo.VersionName, Inherit & "-forge-" & Version)
-        Dim InstallerAddress As String = PathTemp & $"Cache\Code\{LoaderName}Install-" & Version & "_" & RandomInteger(0, 100000)
-        Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
-        Dim DisplayName As String = $"{LoaderName} " & Inherit & " - " & Version
+        Dim InstallerAddress As String = $"{PathTemp}Cache\Code\{LoaderName}Install-{Version}_{RandomInteger(0, 100000)}"
+        Dim VersionName As String = If(IsNeoForge, "neoforge-" & Version.Replace("1.20.1-", ""), "forge-" & Version)
+        Dim VersionFolder As String = $"{McFolder}versions\{VersionName}\"
+        Log($"[Download] Forgelike 安装目标版本文件夹:{VersionFolder}")
+        Dim DisplayName As String = $"{LoaderName} {Inherit} - {Version}"
         Dim Loaders As New List(Of LoaderBase)
         Dim Loaders As New List(Of LoaderBase)
-        Dim LibVersionFolder As String = PathMcFolder & "versions\" & Id & "\" '作为 Lib 文件目标的版本文件夹
+        Dim LibVersionFolder As String = $"{PathMcFolder}versions\{VersionName}\" '作为 Lib 文件目标的版本文件夹
 
 
-        '获取下载信息
-        If DownloadInfo Is Nothing Then
+        '获取 Forge 下载信息
+        If Info Is Nothing Then
             Loaders.Add(New LoaderTask(Of String, String)($"获取 {LoaderName} 详细信息",
             Loaders.Add(New LoaderTask(Of String, String)($"获取 {LoaderName} 详细信息",
             Sub(Task As LoaderTask(Of String, String))
             Sub(Task As LoaderTask(Of String, String))
-                '获取 Forge / NeoForge 版本列表
-                Dim ForgeLoader = If(IsNeo, New LoaderTask(Of String, List(Of DlNeoForgeVersionEntry))("McDownloadNeoForgeLoader " & Inherit, AddressOf DlNeoForgeVersionMain), New LoaderTask(Of String, List(Of DlForgeVersionEntry))("McDownloadForgeLoader " & Inherit, AddressOf DlForgeVersionMain))
+                '获取 Forge 对应 MC 版本列表
+                Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("McDownloadForgeLoader " & Inherit, AddressOf DlForgeVersionMain)
                 ForgeLoader.WaitForExit(Inherit)
                 ForgeLoader.WaitForExit(Inherit)
                 Task.Progress = 0.8
                 Task.Progress = 0.8
                 '查找对应版本
                 '查找对应版本
                 For Each ForgeVersion In ForgeLoader.Output
                 For Each ForgeVersion In ForgeLoader.Output
-                    If ForgeVersion.Version = Version Then
-                        DownloadInfo = ForgeVersion
+                    If VersionSortInteger(ForgeVersion.Version.ToString, Version) = 0 Then
+                        Info = ForgeVersion
                         Exit Sub
                         Exit Sub
                     End If
                     End If
                 Next
                 Next
                 Throw New Exception($"未能找到 {LoaderName} " & Inherit & "-" & Version & " 的详细信息!")
                 Throw New Exception($"未能找到 {LoaderName} " & Inherit & "-" & Version & " 的详细信息!")
             End Sub) With {.ProgressWeight = 3})
             End Sub) With {.ProgressWeight = 3})
         End If
         End If
-        '下载 Forge / NeoForge 主文件
+        '下载 Forgelike 主文件
         Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"准备下载 {LoaderName}",
         Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"准备下载 {LoaderName}",
-            Sub(Task As LoaderTask(Of String, List(Of NetFile)))
-                '启动依赖版本的下载
-                If ClientDownloadLoader Is Nothing Then
-                    If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
-                    ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, Inherit)
-                End If
-                '添加主文件
-                Dim Files
-                If IsNeo Then 'NeoForge
-                    Dim IsLegacyNeo As Boolean = DownloadInfo.VersionCode.StartsWith("47.")
-                    Files = New List(Of NetFile) From {New NetFile({
-                        $"https://bmclapi2.bangbang93.com/maven/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}",
-                        $"https://maven.neoforged.net/releases/net/neoforged/{If(IsLegacyNeo, "", "neo")}forge/{If(IsLegacyNeo, "1.20.1-", "")}{DownloadInfo.VersionCode}{If(DownloadInfo.IsBeta, "-beta", "")}/{DownloadInfo.FileName}"
-                    }, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=If(IsNeo, Nothing, DownloadInfo.Hash)))}
-                Else 'Forge
-                    Files = New List(Of NetFile) From {New NetFile({
-                    "https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
-                    "https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
-                }, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=If(IsNeo, Nothing, DownloadInfo.Hash)))}
-                End If
-                Task.Output = Files
-            End Sub) With {.ProgressWeight = 0.5, .Show = False})
+        Sub(Task As LoaderTask(Of String, List(Of NetFile)))
+            '启动依赖版本的下载
+            If ClientDownloadLoader Is Nothing Then
+                If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
+                ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, Inherit)
+            End If
+            '添加主文件下载
+            Dim Files As New List(Of NetFile)
+            If Info.IsNeoForge Then
+                'NeoForge
+                Dim Neo As DlNeoForgeListEntry = Info
+                Dim Url As String = Neo.UrlBase & "-installer.jar"
+                Files.Add(New NetFile({
+                    Url.Replace("maven.neoforged.net/releases", "bmclapi2.bangbang93.com/maven"), Url
+                }, InstallerAddress, New FileChecker(MinSize:=64 * 1024)))
+            Else
+                'Forge
+                Dim Forge As DlForgeVersionEntry = Info
+                Files.Add(New NetFile({
+                    $"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/{Forge.Inherit}-{Forge.FileVersion}/forge-{Forge.Inherit}-{Forge.FileVersion}-{Forge.Category}.{Forge.FileExtension}",
+                    $"https://files.minecraftforge.net/maven/net/minecraftforge/forge/{Forge.Inherit}-{Forge.FileVersion}/forge-{Forge.Inherit}-{Forge.FileVersion}-{Forge.Category}.{Forge.FileExtension}"
+                }, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=Forge.Hash)))
+            End If
+            Task.Output = Files
+        End Sub) With {.ProgressWeight = 0.5, .Show = False})
         Loaders.Add(New LoaderDownload($"下载 {LoaderName} 主文件", New List(Of NetFile)) With {.ProgressWeight = 9})
         Loaders.Add(New LoaderDownload($"下载 {LoaderName} 主文件", New List(Of NetFile)) With {.ProgressWeight = 9})
 
 
         '安装(仅在新版安装时需要原版 Jar)
         '安装(仅在新版安装时需要原版 Jar)
-        If Version.Before(".") >= 20 Then
-            Log($"[Download] 检测为{If(IsNeo, " Neo", "新版 ")}Forge:" & Version)
+        If IsNeoForge OrElse Version.Before(".") >= 20 Then
+            Log($"[Download] 检测为{If(IsNeoForge, " Neo", "新版 ")}Forge:" & Version)
             Dim Libs As List(Of McLibToken) = Nothing
             Dim Libs As List(Of McLibToken) = Nothing
             Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"分析 {LoaderName} 支持库文件",
             Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"分析 {LoaderName} 支持库文件",
             Sub(Task As LoaderTask(Of String, List(Of NetFile)))
             Sub(Task As LoaderTask(Of String, List(Of NetFile)))
@@ -1400,10 +1393,10 @@ Retry:
                         Log("[Download] 需要下载 Mappings:" & Address)
                         Log("[Download] 需要下载 Mappings:" & Address)
                     End If
                     End If
                     Task.Progress = 0.8
                     Task.Progress = 0.8
-                    '去除其中的原始 Forge / NeoForge 项
+                    '去除其中的原始 Forgelike 项
                     For i = 0 To Libs.Count - 1
                     For i = 0 To Libs.Count - 1
-                        If Libs(i).LocalPath.EndsWithF($"{If(IsNeo, "neo", "")}forge-" & Inherit & "-" & Version & ".jar") OrElse
-                                                                                                      Libs(i).LocalPath.EndsWithF("forge-" & Inherit & "-" & Version & "-client.jar") Then
+                        If Libs(i).LocalPath.EndsWithF($"{LoaderName.ToLower}-{Inherit}-{Version}.jar") OrElse
+                           Libs(i).LocalPath.EndsWithF($"{LoaderName.ToLower}-{Inherit}-{Version}-client.jar") Then
                             Log($"[Download] 已从待下载 {LoaderName} 支持库中移除:" & Libs(i).LocalPath, LogLevel.Debug)
                             Log($"[Download] 已从待下载 {LoaderName} 支持库中移除:" & Libs(i).LocalPath, LogLevel.Debug)
                             Libs.RemoveAt(i)
                             Libs.RemoveAt(i)
                             Exit For
                             Exit For
@@ -1411,7 +1404,7 @@ Retry:
                     Next
                     Next
                     Task.Output = McLibFixFromLibToken(Libs, PathMcFolder)
                     Task.Output = McLibFixFromLibToken(Libs, PathMcFolder)
                 Catch ex As Exception
                 Catch ex As Exception
-                    Throw New Exception($"获取{If(IsNeo, " Neo", "新版 ")}Forge 支持库列表失败", ex)
+                    Throw New Exception($"获取{If(IsNeoForge, " Neo", "新版 ")}Forge 支持库列表失败", ex)
                 Finally
                 Finally
                     '释放文件
                     '释放文件
                     If Installer IsNot Nothing Then Installer.Dispose()
                     If Installer IsNot Nothing Then Installer.Dispose()
@@ -1420,7 +1413,7 @@ Retry:
             Loaders.Add(New LoaderDownload($"下载 {LoaderName} 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 12})
             Loaders.Add(New LoaderDownload($"下载 {LoaderName} 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 12})
             Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)($"获取 {LoaderName} 支持库文件",
             Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)($"获取 {LoaderName} 支持库文件",
             Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
             Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
-#Region "Forge / NeoForge 文件"
+#Region "Forgelike 文件"
                 If IsCustomFolder Then
                 If IsCustomFolder Then
                     For Each LibFile As McLibToken In Libs
                     For Each LibFile As McLibToken In Libs
                         Dim RealPath As String = LibFile.LocalPath.Replace(PathMcFolder, McFolder)
                         Dim RealPath As String = LibFile.LocalPath.Replace(PathMcFolder, McFolder)
@@ -1436,8 +1429,8 @@ Retry:
                 '等待原版文件下载完成
                 '等待原版文件下载完成
                 If ClientDownloadLoader Is Nothing Then Exit Sub
                 If ClientDownloadLoader Is Nothing Then Exit Sub
                 Dim TargetLoaders As List(Of LoaderBase) =
                 Dim TargetLoaders As List(Of LoaderBase) =
-                                                                                ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
-                                                                                Where(Function(l) l.State <> LoadState.Finished).ToList
+                    ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
+                    Where(Function(l) l.State <> LoadState.Finished).ToList()
                 If TargetLoaders.Any Then Log($"[Download] {LoaderName} 安装正在等待原版文件下载完成")
                 If TargetLoaders.Any Then Log($"[Download] {LoaderName} 安装正在等待原版文件下载完成")
                 Do While TargetLoaders.Any AndAlso Not Task.IsAborted
                 Do While TargetLoaders.Any AndAlso Not Task.IsAborted
                     TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
                     TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
@@ -1458,14 +1451,13 @@ Retry:
                 End SyncLock
                 End SyncLock
 #End Region
 #End Region
             End Sub) With {.ProgressWeight = 0.1, .Show = False})
             End Sub) With {.ProgressWeight = 0.1, .Show = False})
-            Loaders.Add(New LoaderTask(Of Boolean, Boolean)(If(IsNeo, "安装 NeoForge", "安装 Forge(方式 A)"),
+            Loaders.Add(New LoaderTask(Of Boolean, Boolean)(If(IsNeoForge, "安装 NeoForge", "安装 Forge(方式 A)"),
             Sub(Task As LoaderTask(Of Boolean, Boolean))
             Sub(Task As LoaderTask(Of Boolean, Boolean))
                 Dim Installer As ZipArchive = Nothing
                 Dim Installer As ZipArchive = Nothing
                 Try
                 Try
-                    Log($"[Download] 开始进行{If(IsNeo, " Neo", "新版方式 ")}Forge 安装:" & InstallerAddress)
+                    Log($"[Download] 开始进行 Forgelike 安装:" & InstallerAddress)
                     '记录当前文件夹列表(在新建目标文件夹之前)
                     '记录当前文件夹列表(在新建目标文件夹之前)
-                    Dim OldList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.
-                                                                        Select(Function(i) i.FullName).ToList()
+                    Dim OldList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.Select(Function(i) i.FullName).ToList()
                     '解压并获取信息
                     '解压并获取信息
                     Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
                     Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
                     Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
                     Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
@@ -1483,7 +1475,7 @@ Retry:
                         WriteFile(PathTemp & "Cache\forge_installer.jar", GetResources("ForgeInstaller"))
                         WriteFile(PathTemp & "Cache\forge_installer.jar", GetResources("ForgeInstaller"))
                         Task.Progress = 0.06
                         Task.Progress = 0.06
                         '运行注入器
                         '运行注入器
-                        ForgeInjector(InstallerAddress, Task, McFolder, UseJavaWrapper, False)
+                        ForgelikeInjector(InstallerAddress, Task, McFolder, UseJavaWrapper, IsNeoForge)
                         Task.Progress = 0.97
                         Task.Progress = 0.97
                     Catch ex As Exception
                     Catch ex As Exception
                         If UseJavaWrapper Then
                         If UseJavaWrapper Then
@@ -1500,11 +1492,13 @@ Retry:
                     If DeltaList.Count > 1 Then
                     If DeltaList.Count > 1 Then
                         '它可能和 OptiFine 安装同时运行,导致增加的文件不止一个(这导致了 #151)
                         '它可能和 OptiFine 安装同时运行,导致增加的文件不止一个(这导致了 #151)
                         '也可能是因为 Forge 安装器的 Bug,生成了一个名字错误的文件夹,所以需要检查文件夹是否为空
                         '也可能是因为 Forge 安装器的 Bug,生成了一个名字错误的文件夹,所以需要检查文件夹是否为空
-                        DeltaList = DeltaList.Where(Function(l) l.Name.Contains($"{If(IsNeo, "neo", "")}forge") AndAlso l.EnumerateFiles.Any).ToList
+                        DeltaList = DeltaList.Where(Function(l) l.Name.ContainsF("forge", True) AndAlso l.EnumerateFiles.Any).ToList
                     End If
                     End If
-                    If DeltaList.Count = 1 Then '如果没有新增文件夹,那么预测的文件夹名就是正确的
+                    If DeltaList.Count = 1 Then
+                        '如果没有新增文件夹,那么预测的文件夹名就是正确的
+                        '如果只新增 1 个文件夹,那么拷贝 json 文件
                         Dim JsonFile As FileInfo = DeltaList(0).EnumerateFiles.First()
                         Dim JsonFile As FileInfo = DeltaList(0).EnumerateFiles.First()
-                        WriteFile(VersionFolder & Id & ".json", ReadFile(JsonFile.FullName))
+                        WriteFile(VersionFolder & VersionName & ".json", ReadFile(JsonFile.FullName))
                     End If
                     End If
                     '新建 mods 文件夹
                     '新建 mods 文件夹
                     Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
                     Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
@@ -1522,7 +1516,7 @@ Retry:
             End Sub) With {.ProgressWeight = 10})
             End Sub) With {.ProgressWeight = 10})
         Else
         Else
             Log("[Download] 检测为非新版 Forge:" & Version)
             Log("[Download] 检测为非新版 Forge:" & Version)
-            Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 Forge(方式 B)",
+            Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)($"安装 {LoaderName}(方式 B)",
             Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
             Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
                 Dim Installer As ZipArchive = Nothing
                 Dim Installer As ZipArchive = Nothing
                 Try
                 Try
@@ -1535,12 +1529,12 @@ Retry:
                     Directory.CreateDirectory(VersionFolder)
                     Directory.CreateDirectory(VersionFolder)
                     Task.Progress = 0.5
                     Task.Progress = 0.5
                     If Json("install") Is Nothing Then
                     If Json("install") Is Nothing Then
-                        '中版格式
-                        Log("[Download] 进行中版方式安装:" & InstallerAddress)
+                        '中版:Legacy 方式 1
+                        Log("[Download] 开始进行 Forge 安装,Legacy 方式 1:" & InstallerAddress)
                         '建立 Json 文件
                         '建立 Json 文件
                         Dim JsonVersion As JObject = GetJson(ReadFile(Installer.GetEntry(Json("json").ToString.TrimStart("/")).Open))
                         Dim JsonVersion As JObject = GetJson(ReadFile(Installer.GetEntry(Json("json").ToString.TrimStart("/")).Open))
-                        JsonVersion("id") = Id
-                        WriteFile(VersionFolder & Id & ".json", JsonVersion.ToString)
+                        JsonVersion("id") = VersionName
+                        WriteFile(VersionFolder & VersionName & ".json", JsonVersion.ToString)
                         Task.Progress = 0.6
                         Task.Progress = 0.6
                         '解压支持库文件
                         '解压支持库文件
                         Installer.Dispose()
                         Installer.Dispose()
@@ -1548,17 +1542,17 @@ Retry:
                         CopyDirectory(InstallerAddress & "_unrar\maven\", McFolder & "libraries\")
                         CopyDirectory(InstallerAddress & "_unrar\maven\", McFolder & "libraries\")
                         DeleteDirectory(InstallerAddress & "_unrar\")
                         DeleteDirectory(InstallerAddress & "_unrar\")
                     Else
                     Else
-                        '旧版格式
-                        Log("[Download] 进行旧版方式安装:" & InstallerAddress)
+                        '旧版:Legacy 方式 2
+                        Log("[Download] 开始进行 Forge 安装,Legacy 方式 2:" & InstallerAddress)
                         '解压 Jar 文件
                         '解压 Jar 文件
                         Dim JarAddress As String = McLibGet(Json("install")("path"), CustomMcFolder:=McFolder)
                         Dim JarAddress As String = McLibGet(Json("install")("path"), CustomMcFolder:=McFolder)
                         If File.Exists(JarAddress) Then File.Delete(JarAddress)
                         If File.Exists(JarAddress) Then File.Delete(JarAddress)
                         WriteFile(JarAddress, Installer.GetEntry(Json("install")("filePath")).Open)
                         WriteFile(JarAddress, Installer.GetEntry(Json("install")("filePath")).Open)
                         Task.Progress = 0.9
                         Task.Progress = 0.9
                         '建立 Json 文件
                         '建立 Json 文件
-                        Json("versionInfo")("id") = Id
+                        Json("versionInfo")("id") = VersionName
                         If Json("versionInfo")("inheritsFrom") Is Nothing Then CType(Json("versionInfo"), JObject).Add("inheritsFrom", Inherit)
                         If Json("versionInfo")("inheritsFrom") Is Nothing Then CType(Json("versionInfo"), JObject).Add("inheritsFrom", Inherit)
-                        WriteFile(VersionFolder & Id & ".json", Json("versionInfo").ToString)
+                        WriteFile(VersionFolder & VersionName & ".json", Json("versionInfo").ToString)
                     End If
                     End If
                     '新建 mods 文件夹
                     '新建 mods 文件夹
                     Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
                     Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
@@ -1589,16 +1583,16 @@ Retry:
 
 
 #Region "Forge 下载菜单"
 #Region "Forge 下载菜单"
 
 
-    Public Sub ForgeDownloadListItemPreload(Stack As StackPanel, Entrys As List(Of DlForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
+    Public Sub ForgeDownloadListItemPreload(Stack As StackPanel, Entries As List(Of DlForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
         '获取推荐版本与最新版本
         '获取推荐版本与最新版本
         Dim FreshVersion As DlForgeVersionEntry = Nothing
         Dim FreshVersion As DlForgeVersionEntry = Nothing
-        If Entrys.Any Then
-            FreshVersion = Entrys(0)
+        If Entries.Any Then
+            FreshVersion = Entries(0)
         Else
         Else
             Log("[System] 未找到可用的 Forge 版本", LogLevel.Debug)
             Log("[System] 未找到可用的 Forge 版本", LogLevel.Debug)
         End If
         End If
         Dim RecommendedVersion As DlForgeVersionEntry = Nothing
         Dim RecommendedVersion As DlForgeVersionEntry = Nothing
-        For Each Entry In Entrys
+        For Each Entry In Entries
             If Entry.IsRecommended Then RecommendedVersion = Entry
             If Entry.IsRecommended Then RecommendedVersion = Entry
         Next
         Next
         '若推荐版本与最新版本为同一版本,则仅显示推荐版本
         '若推荐版本与最新版本为同一版本,则仅显示推荐版本
@@ -1615,15 +1609,14 @@ Retry:
             Stack.Children.Add(Fresh)
             Stack.Children.Add(Fresh)
         End If
         End If
         '添加间隔
         '添加间隔
-        Stack.Children.Add(New TextBlock With {.Text = "全部版本 (" & Entrys.Count & ")", .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 13, 0, 4)})
+        Stack.Children.Add(New TextBlock With {.Text = "全部版本 (" & Entries.Count & ")", .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 13, 0, 4)})
     End Sub
     End Sub
     Public Function ForgeDownloadListItem(Entry As DlForgeVersionEntry, OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) As MyListItem
     Public Function ForgeDownloadListItem(Entry As DlForgeVersionEntry, OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) As MyListItem
         '建立控件
         '建立控件
         Dim NewItem As New MyListItem With {
         Dim NewItem As New MyListItem With {
-            .Title = Entry.Version, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
-            .Info = If(Entry.ReleaseTime = "",
-                If(ModeDebug, "种类:" & Entry.Category & If(Entry.Branch Is Nothing, "", ",开发分支:" & Entry.Branch), ""),
-                "发布于 " & Entry.ReleaseTime & If(ModeDebug, ",种类:" & Entry.Category & If(Entry.Branch Is Nothing, "", ",开发分支:" & Entry.Branch), "")),
+            .Title = Entry.VersionName, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
+            .Info = {If(Entry.ReleaseTime = "", "", "发布于 " & Entry.ReleaseTime), If(ModeDebug, "种类:" & Entry.Category, "")}.
+                Where(Function(d) d <> "").Join(","),
             .Logo = PathImage & "Blocks/Anvil.png"
             .Logo = PathImage & "Blocks/Anvil.png"
         }
         }
         AddHandler NewItem.Click, OnClick
         AddHandler NewItem.Click, OnClick
@@ -1666,7 +1659,7 @@ Retry:
         Else
         Else
             Version = sender.Parent.Parent.Tag
             Version = sender.Parent.Parent.Tag
         End If
         End If
-        OpenWebsite("https://files.minecraftforge.net/maven/net/minecraftforge/forge/" & Version.Inherit & "-" & Version.Version & "/forge-" & Version.Inherit & "-" & Version.Version & "-changelog.txt")
+        OpenWebsite($"https://files.minecraftforge.net/maven/net/minecraftforge/forge/{Version.Inherit}-{Version.VersionName}/forge-{Version.Inherit}-{Version.VersionName}-changelog.txt")
     End Sub
     End Sub
     Public Sub ForgeSave_Click(sender As Object, e As RoutedEventArgs)
     Public Sub ForgeSave_Click(sender As Object, e As RoutedEventArgs)
         Dim Version As DlForgeVersionEntry
         Dim Version As DlForgeVersionEntry
@@ -1677,7 +1670,7 @@ Retry:
         Else
         Else
             Version = sender.Parent.Parent.Tag
             Version = sender.Parent.Parent.Tag
         End If
         End If
-        McDownloadForgeSave(False, DownloadForgeInfo:=Version)
+        McDownloadForgelikeSave(Version)
     End Sub
     End Sub
 
 
 #End Region
 #End Region
@@ -1741,19 +1734,17 @@ Retry:
 
 
 #Region "NeoForge 下载菜单"
 #Region "NeoForge 下载菜单"
 
 
-    Public Sub NeoForgeDownloadListItemPreload(Stack As StackPanel, Entrys As List(Of DlNeoForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
+    Public Sub NeoForgeDownloadListItemPreload(Stack As StackPanel, Entries As List(Of DlNeoForgeListEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
         '获取最新稳定版和测试版
         '获取最新稳定版和测试版
-        Dim FreshStableVersion As DlNeoForgeVersionEntry = Nothing
-        Dim FreshBetaVersion As DlNeoForgeVersionEntry = Nothing
-        If Entrys.Any Then
-            Dim VersionsArray = Entrys.ToList()
-            VersionsArray.Reverse()
-            For Each Entry In VersionsArray
+        Dim FreshStableVersion As DlNeoForgeListEntry = Nothing
+        Dim FreshBetaVersion As DlNeoForgeListEntry = Nothing
+        If Entries.Any() Then
+            For Each Entry In Entries.ToList()
                 If Entry.IsBeta Then
                 If Entry.IsBeta Then
-                    FreshBetaVersion = Entry
+                    If FreshBetaVersion Is Nothing Then FreshBetaVersion = Entry
                 Else
                 Else
-                    If Entry.VersionCode.Contains("47.1.82") Then Continue For
                     FreshStableVersion = Entry
                     FreshStableVersion = Entry
+                    Exit For
                 End If
                 End If
             Next
             Next
         Else
         Else
@@ -1762,22 +1753,22 @@ Retry:
         '显示各个版本
         '显示各个版本
         If FreshStableVersion IsNot Nothing Then
         If FreshStableVersion IsNot Nothing Then
             Dim Fresh = NeoForgeDownloadListItem(FreshStableVersion, OnClick, IsSaveOnly)
             Dim Fresh = NeoForgeDownloadListItem(FreshStableVersion, OnClick, IsSaveOnly)
-            Fresh.Info = "最新版" & If(Fresh.Info = "", "", "," & Fresh.Info)
+            Fresh.Info = If(Fresh.Info = "", "最新稳定版", "最新" & Fresh.Info)
             Stack.Children.Add(Fresh)
             Stack.Children.Add(Fresh)
         End If
         End If
         If FreshBetaVersion IsNot Nothing Then
         If FreshBetaVersion IsNot Nothing Then
             Dim Fresh = NeoForgeDownloadListItem(FreshBetaVersion, OnClick, IsSaveOnly)
             Dim Fresh = NeoForgeDownloadListItem(FreshBetaVersion, OnClick, IsSaveOnly)
-            Fresh.Info = "最新版" & If(Fresh.Info = "", "", "," & Fresh.Info)
+            Fresh.Info = If(Fresh.Info = "", "最新测试版", "最新" & Fresh.Info)
             Stack.Children.Add(Fresh)
             Stack.Children.Add(Fresh)
         End If
         End If
         '添加间隔
         '添加间隔
-        Stack.Children.Add(New TextBlock With {.Text = "全部版本 (" & Entrys.Count & ")", .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 13, 0, 4)})
+        Stack.Children.Add(New TextBlock With {.Text = "全部版本 (" & Entries.Count & ")", .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 13, 0, 4)})
     End Sub
     End Sub
-    Public Function NeoForgeDownloadListItem(Entry As DlNeoForgeVersionEntry, OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) As MyListItem
+    Public Function NeoForgeDownloadListItem(Info As DlNeoForgeListEntry, OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) As MyListItem
         '建立控件
         '建立控件
         Dim NewItem As New MyListItem With {
         Dim NewItem As New MyListItem With {
-            .Title = If(Entry.IsBeta, Entry.VersionCode & "-beta", Entry.VersionCode), .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
-            .Info = If(Entry.IsBeta, "测试版", "稳定版"),
+            .Title = Info.VersionName, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Info,
+            .Info = If(Info.IsBeta, "测试版", "稳定版"),
             .Logo = PathImage & "Blocks/NeoForge.png"
             .Logo = PathImage & "Blocks/NeoForge.png"
         }
         }
         AddHandler NewItem.Click, OnClick
         AddHandler NewItem.Click, OnClick
@@ -1812,26 +1803,26 @@ Retry:
         sender.Buttons = {BtnInfo}
         sender.Buttons = {BtnInfo}
     End Sub
     End Sub
     Private Sub NeoForgeLog_Click(sender As Object, e As RoutedEventArgs)
     Private Sub NeoForgeLog_Click(sender As Object, e As RoutedEventArgs)
-        Dim Version As DlNeoForgeVersionEntry
+        Dim Info As DlNeoForgeListEntry
         If sender.Tag IsNot Nothing Then
         If sender.Tag IsNot Nothing Then
-            Version = sender.Tag
+            Info = sender.Tag
         ElseIf sender.Parent.Tag IsNot Nothing Then
         ElseIf sender.Parent.Tag IsNot Nothing Then
-            Version = sender.Parent.Tag
+            Info = sender.Parent.Tag
         Else
         Else
-            Version = sender.Parent.Parent.Tag
+            Info = sender.Parent.Parent.Tag
         End If
         End If
-        OpenWebsite("https://maven.neoforged.net/releases/net/neoforged/neoforge/" & Version.VersionCode & "/" & Version.VersionName & "-changelog.txt")
+        OpenWebsite(Info.UrlBase & "-changelog.txt")
     End Sub
     End Sub
     Public Sub NeoForgeSave_Click(sender As Object, e As RoutedEventArgs)
     Public Sub NeoForgeSave_Click(sender As Object, e As RoutedEventArgs)
-        Dim Version As DlNeoForgeVersionEntry
+        Dim Info As DlNeoForgeListEntry
         If sender.Tag IsNot Nothing Then
         If sender.Tag IsNot Nothing Then
-            Version = sender.Tag
+            Info = sender.Tag
         ElseIf sender.Parent.Tag IsNot Nothing Then
         ElseIf sender.Parent.Tag IsNot Nothing Then
-            Version = sender.Parent.Tag
+            Info = sender.Parent.Tag
         Else
         Else
-            Version = sender.Parent.Parent.Tag
+            Info = sender.Parent.Parent.Tag
         End If
         End If
-        McDownloadForgeSave(True, DownloadNeoInfo:=Version)
+        McDownloadForgelikeSave(Info)
     End Sub
     End Sub
 
 
 #End Region
 #End Region
@@ -2009,7 +2000,7 @@ Retry:
         ''' <summary>
         ''' <summary>
         ''' 欲下载的 NeoForge。
         ''' 欲下载的 NeoForge。
         ''' </summary>
         ''' </summary>
-        Public NeoForgeEntry As DlNeoForgeVersionEntry = Nothing
+        Public NeoForgeEntry As DlNeoForgeListEntry = Nothing
 
 
         ''' <summary>
         ''' <summary>
         ''' 欲下载的 Fabric Loader 版本名。
         ''' 欲下载的 Fabric Loader 版本名。
@@ -2111,7 +2102,7 @@ Retry:
     Public Function McInstallLoader(Request As McInstallRequest, Optional DontFixLibraries As Boolean = False) As List(Of LoaderBase)
     Public Function McInstallLoader(Request As McInstallRequest, Optional DontFixLibraries As Boolean = False) As List(Of LoaderBase)
         '获取缓存目录
         '获取缓存目录
         Dim PathInstallTemp As String
         Dim PathInstallTemp As String
-        If PathTemp.Contains(" ") AndAlso (Request.ForgeEntry IsNot Nothing OrElse Request.NeoForgeEntry IsNot Nothing) Then
+        If PathTemp.Contains(" ") AndAlso (Request.OptiFineEntry IsNot Nothing OrElse Request.ForgeEntry IsNot Nothing OrElse Request.NeoForgeEntry IsNot Nothing) Then
             PathInstallTemp = OsDrive & "ProgramData\PCL\Install\"
             PathInstallTemp = OsDrive & "ProgramData\PCL\Install\"
         Else
         Else
             PathInstallTemp = PathTemp & "Install\"
             PathInstallTemp = PathTemp & "Install\"
@@ -2146,11 +2137,11 @@ Retry:
         End If
         End If
         If Request.OptiFineEntry IsNot Nothing Then OptiFineFolder = TempMcFolder & "versions\" & Request.OptiFineEntry.NameVersion
         If Request.OptiFineEntry IsNot Nothing Then OptiFineFolder = TempMcFolder & "versions\" & Request.OptiFineEntry.NameVersion
         Dim ForgeFolder As String = Nothing
         Dim ForgeFolder As String = Nothing
-        If Request.ForgeEntry IsNot Nothing Then Request.ForgeVersion = If(Request.ForgeVersion, Request.ForgeEntry.Version)
+        If Request.ForgeEntry IsNot Nothing Then Request.ForgeVersion = If(Request.ForgeVersion, Request.ForgeEntry.VersionName)
         If Request.ForgeVersion IsNot Nothing Then ForgeFolder = TempMcFolder & "versions\" & Request.MinecraftName & "-forge-" & Request.ForgeVersion
         If Request.ForgeVersion IsNot Nothing Then ForgeFolder = TempMcFolder & "versions\" & Request.MinecraftName & "-forge-" & Request.ForgeVersion
         Dim NeoForgeFolder As String = Nothing
         Dim NeoForgeFolder As String = Nothing
         If Request.NeoForgeEntry IsNot Nothing Then Request.NeoForgeVersion = If(Request.NeoForgeVersion, Request.NeoForgeEntry.VersionName)
         If Request.NeoForgeEntry IsNot Nothing Then Request.NeoForgeVersion = If(Request.NeoForgeVersion, Request.NeoForgeEntry.VersionName)
-        If Request.NeoForgeVersion IsNot Nothing Then NeoForgeFolder = TempMcFolder & "versions\" & If(Request.NeoForgeVersion.StartsWithF("1.20.1") OrElse Request.NeoForgeVersion.StartsWithF("47."), "1.20.1-forge-", "") & Request.NeoForgeVersion.Replace("1.20.1-forge-", "").Replace("1.20.1-", "")
+        If Request.NeoForgeVersion IsNot Nothing Then NeoForgeFolder = TempMcFolder & "versions\neoforge-" & Request.NeoForgeVersion
         Dim FabricFolder As String = Nothing
         Dim FabricFolder As String = Nothing
         If Request.FabricVersion IsNot Nothing Then FabricFolder = TempMcFolder & "versions\fabric-loader-" & Request.FabricVersion & "-" & Request.MinecraftName
         If Request.FabricVersion IsNot Nothing Then FabricFolder = TempMcFolder & "versions\fabric-loader-" & Request.FabricVersion & "-" & Request.MinecraftName
         Dim LiteLoaderFolder As String = Nothing
         Dim LiteLoaderFolder As String = Nothing
@@ -2168,7 +2159,6 @@ Retry:
         If OptiFineFolder IsNot Nothing Then Log("[Download] OptiFine 缓存:" & OptiFineFolder)
         If OptiFineFolder IsNot Nothing Then Log("[Download] OptiFine 缓存:" & OptiFineFolder)
         If ForgeFolder IsNot Nothing Then Log("[Download] Forge 缓存:" & ForgeFolder)
         If ForgeFolder IsNot Nothing Then Log("[Download] Forge 缓存:" & ForgeFolder)
         If NeoForgeFolder IsNot Nothing Then Log("[Download] NeoForge 缓存:" & NeoForgeFolder)
         If NeoForgeFolder IsNot Nothing Then Log("[Download] NeoForge 缓存:" & NeoForgeFolder)
-        If Request.NeoForgeVersion IsNot Nothing Then Log("[Download] NeoForge 版本:" & Request.NeoForgeVersion)
         If FabricFolder IsNot Nothing Then Log("[Download] Fabric 缓存:" & FabricFolder)
         If FabricFolder IsNot Nothing Then Log("[Download] Fabric 缓存:" & FabricFolder)
         If LiteLoaderFolder IsNot Nothing Then Log("[Download] LiteLoader 缓存:" & LiteLoaderFolder)
         If LiteLoaderFolder IsNot Nothing Then Log("[Download] LiteLoader 缓存:" & LiteLoaderFolder)
         Log("[Download] 对应的原版版本:" & Request.MinecraftName)
         Log("[Download] 对应的原版版本:" & Request.MinecraftName)
@@ -2203,11 +2193,11 @@ Retry:
         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, McDownloadForgeLoader(False, Request.ForgeVersion, Request.MinecraftName, Request.ForgeEntry, , TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) 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, Request.MinecraftName, Request.ForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) 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, McDownloadForgeLoader(True, Request.NeoForgeVersion, Request.MinecraftName, , Request.NeoForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) 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, Request.MinecraftName, Request.NeoForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) 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
@@ -2227,7 +2217,7 @@ Retry:
             End Sub) With {.ProgressWeight = 2, .Block = True})
             End Sub) With {.ProgressWeight = 2, .Block = True})
         '补全文件
         '补全文件
         If Not DontFixLibraries AndAlso
         If Not DontFixLibraries AndAlso
-        (Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.Before(".") >= 20) OrElse (Request.NeoForgeVersion IsNot Nothing) OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing) Then
+        (Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.Before(".") >= 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(OutputFolder))) With {.ProgressWeight = 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(OutputFolder))) 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})
@@ -2335,7 +2325,7 @@ Retry:
         End If
         End If
 #End Region
 #End Region
 
 
-#Region "处理 Json 文件"
+#Region "处理 JSON 文件"
         '获取 minecraftArguments
         '获取 minecraftArguments
         Dim AllArguments As String =
         Dim AllArguments As String =
             If(MinecraftJson("minecraftArguments"), " ").ToString & " " &
             If(MinecraftJson("minecraftArguments"), " ").ToString & " " &

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

@@ -87,7 +87,7 @@
                 PanMain.Children.Add(NewCard)
                 PanMain.Children.Add(NewCard)
             Next
             Next
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, "可视化版本列表出错", LogLevel.Feedback)
+            Log(ex, "可视化 MC 版本列表出错", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
 
 

+ 21 - 19
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb

@@ -177,17 +177,18 @@
                 End Sub) With {.ProgressWeight = 0.1})
                 End Sub) With {.ProgressWeight = 0.1})
 
 
             '启动
             '启动
-            Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = Sub(MyLoader)
-                                                                                                      Select Case MyLoader.State
-                                                                                                          Case LoadState.Failed
-                                                                                                              Hint(MyLoader.Name & "失败:" & GetExceptionSummary(MyLoader.Error), HintType.Critical)
-                                                                                                          Case LoadState.Aborted
-                                                                                                              Hint(MyLoader.Name & "已取消!", HintType.Info)
-                                                                                                          Case LoadState.Loading
-                                                                                                              Exit Sub '不重新加载版本列表
-                                                                                                      End Select
-                                                                                                      McInstallFailedClearFolder(MyLoader)
-                                                                                                  End Sub}
+            Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged =
+            Sub(MyLoader)
+                Select Case MyLoader.State
+                    Case LoadState.Failed
+                        Hint(MyLoader.Name & "失败:" & GetExceptionSummary(MyLoader.Error), HintType.Critical)
+                    Case LoadState.Aborted
+                        Hint(MyLoader.Name & "已取消!", HintType.Info)
+                    Case LoadState.Loading
+                        Exit Sub '不重新加载版本列表
+                End Select
+                McInstallFailedClearFolder(MyLoader)
+            End Sub}
             Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
             Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
             LoaderTaskbarAdd(Loader)
             LoaderTaskbarAdd(Loader)
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.ShowRefresh()
@@ -197,7 +198,7 @@
             Log(ex, "下载资源整合包失败", LogLevel.Feedback)
             Log(ex, "下载资源整合包失败", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
-    'Mod 下载;整合包另存为
+    '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
@@ -211,10 +212,10 @@
                     '获取 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 '从文件中获取
-                        AllowForge = File.ModLoaders.Contains(CompModLoaderType.Forge)
+                        AllowForge = File.ModLoaders.Contains(CompModLoaderType.Forge) OrElse File.ModLoaders.Contains(CompModLoaderType.NeoForge)
                         AllowFabric = File.ModLoaders.Contains(CompModLoaderType.Fabric)
                         AllowFabric = File.ModLoaders.Contains(CompModLoaderType.Fabric)
                     ElseIf Project.ModLoaders.Any Then '从工程中获取
                     ElseIf Project.ModLoaders.Any Then '从工程中获取
-                        AllowForge = Project.ModLoaders.Contains(CompModLoaderType.Forge)
+                        AllowForge = Project.ModLoaders.Contains(CompModLoaderType.Forge) OrElse File.ModLoaders.Contains(CompModLoaderType.NeoForge)
                         AllowFabric = Project.ModLoaders.Contains(CompModLoaderType.Fabric)
                         AllowFabric = Project.ModLoaders.Contains(CompModLoaderType.Fabric)
                     End If
                     End If
                     If AllowForge IsNot Nothing AndAlso Not AllowForge AndAlso
                     If AllowForge IsNot Nothing AndAlso Not AllowForge AndAlso
@@ -230,7 +231,7 @@
                         If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso
                         If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso
                            Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v.Split(".")(1) = Version.Version.McCodeMain.ToString) Then Return False
                            Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v.Split(".")(1) = Version.Version.McCodeMain.ToString) Then Return False
                         If AllowForge Is Nothing OrElse AllowFabric Is Nothing Then Return True
                         If AllowForge Is Nothing OrElse AllowFabric Is Nothing Then Return True
-                        If AllowForge AndAlso Version.Version.HasForge Then Return True
+                        If AllowForge AndAlso (Version.Version.HasForge OrElse Version.Version.HasNeoForge) Then Return True
                         If AllowFabric AndAlso Version.Version.HasFabric Then Return True
                         If AllowFabric AndAlso Version.Version.HasFabric Then Return True
                         Return False
                         Return False
                     End Function
                     End Function
@@ -260,10 +261,11 @@
                                 Log("[Comp] 由于当前版本不兼容,使用当前的 MC 文件夹作为默认下载位置")
                                 Log("[Comp] 由于当前版本不兼容,使用当前的 MC 文件夹作为默认下载位置")
                             End If
                             End If
                         Else '选择 Mod 数量最多的版本
                         Else '选择 Mod 数量最多的版本
-                            Dim SelectedVersion = SuitableVersions.OrderBy(Function(v)
-                                                                               Dim Info As New DirectoryInfo(v.PathIndie & "mods\")
-                                                                               Return If(Info.Exists, Info.GetFiles().Length, -1)
-                                                                           End Function).LastOrDefault()
+                            Dim SelectedVersion = SuitableVersions.OrderBy(
+                            Function(v)
+                                Dim Info As New DirectoryInfo(v.PathIndie & "mods\")
+                                Return If(Info.Exists, Info.GetFiles().Length, -1)
+                            End Function).LastOrDefault()
                             DefaultFolder = SelectedVersion.PathIndie & "mods\"
                             DefaultFolder = SelectedVersion.PathIndie & "mods\"
                             Directory.CreateDirectory(DefaultFolder)
                             Directory.CreateDirectory(DefaultFolder)
                             Log("[Comp] 使用适合的游戏版本作为默认下载位置(" & SelectedVersion.Name & ")")
                             Log("[Comp] 使用适合的游戏版本作为默认下载位置(" & SelectedVersion.Name & ")")

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

@@ -33,7 +33,7 @@
             '    PanMain.Children.Insert(0, CardWarn)
             '    PanMain.Children.Insert(0, CardWarn)
             'End If
             'End If
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, "可视化版本列表出错", LogLevel.Feedback)
+            Log(ex, "可视化 Forge 版本列表出错", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -56,7 +56,7 @@
     End Sub
     End Sub
 
 
     Public Sub DownloadStart(sender As MyListItem, e As Object)
     Public Sub DownloadStart(sender As MyListItem, e As Object)
-        McDownloadForge(sender.Tag)
+        McDownloadForgelike(sender.Tag)
     End Sub
     End Sub
 
 
     '介绍栏
     '介绍栏

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

@@ -20,6 +20,7 @@
                         <StackPanel Margin="25,37,25,15">
                         <StackPanel Margin="25,37,25,15">
                             <local:MyHint Text="你尚未选择安装 Fabric API,这会导致大多数 Mod 无法使用!" Margin="0,1,0,7" x:Name="HintFabricAPI" IsWarn="True" />
                             <local:MyHint Text="你尚未选择安装 Fabric API,这会导致大多数 Mod 无法使用!" Margin="0,1,0,7" x:Name="HintFabricAPI" IsWarn="True" />
                             <local:MyHint Text="你尚未选择安装 OptiFabric,这会导致 OptiFine 无法使用!" Margin="0,1,0,7" x:Name="HintOptiFabric" IsWarn="True" />
                             <local:MyHint Text="你尚未选择安装 OptiFabric,这会导致 OptiFine 无法使用!" Margin="0,1,0,7" x:Name="HintOptiFabric" IsWarn="True" />
+                            <local:MyHint Text="安装结束后,请在 Mod 下载中搜索 OptiFabric Origins 并下载,否则 OptiFine 会无法使用!" Margin="0,1,0,7" x:Name="HintOptiFabricOld" IsWarn="False" />
                             <local:MyHint Text="OptiFine 与一部分 Mod 的兼容性不佳,请谨慎安装。" Margin="0,1,0,7" x:Name="HintModOptiFine" IsWarn="False" />
                             <local:MyHint Text="OptiFine 与一部分 Mod 的兼容性不佳,请谨慎安装。" Margin="0,1,0,7" x:Name="HintModOptiFine" IsWarn="False" />
                             <Grid Margin="0,0,0,11">
                             <Grid Margin="0,0,0,11">
                                 <Grid.ColumnDefinitions>
                                 <Grid.ColumnDefinitions>
@@ -94,7 +95,7 @@
                         </Grid>
                         </Grid>
                         <Grid x:Name="BtnNeoForgeClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
                         <Grid x:Name="BtnNeoForgeClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
                             <Path x:Name="BtnNeoForgeClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
                             <Path x:Name="BtnNeoForgeClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
-                    Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
+                                  Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
                         </Grid>
                         </Grid>
                     </local:MyCard>
                     </local:MyCard>
                     <local:MyCard Title="Fabric" Height="40" Margin="0,15,0,0" x:Name="CardFabric" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
                     <local:MyCard Title="Fabric" Height="40" Margin="0,15,0,0" x:Name="CardFabric" IsSwaped="True" CanSwap="True" SwapLogoRight="True">

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

@@ -10,6 +10,7 @@
         DlOptiFineListLoader.Start()
         DlOptiFineListLoader.Start()
         DlLiteLoaderListLoader.Start()
         DlLiteLoaderListLoader.Start()
         DlFabricListLoader.Start()
         DlFabricListLoader.Start()
+        DlNeoForgeListLoader.Start()
 
 
         '重载预览
         '重载预览
         TextSelectName.ValidateRules = New ObjectModel.Collection(Of Validate) From {New ValidateFolderName(PathMcFolder & "versions")}
         TextSelectName.ValidateRules = New ObjectModel.Collection(Of Validate) From {New ValidateFolderName(PathMcFolder & "versions")}
@@ -26,6 +27,7 @@
         LoadLiteLoader.State = DlLiteLoaderListLoader
         LoadLiteLoader.State = DlLiteLoaderListLoader
         LoadFabric.State = DlFabricListLoader
         LoadFabric.State = DlFabricListLoader
         LoadFabricApi.State = DlFabricApiLoader
         LoadFabricApi.State = DlFabricApiLoader
+        LoadNeoForge.State = DlNeoForgeListLoader
         LoadOptiFabric.State = DlOptiFabricLoader
         LoadOptiFabric.State = DlOptiFabricLoader
     End Sub
     End Sub
 
 
@@ -74,13 +76,6 @@
             ForgeLoader.Start(SelectedMinecraftId)
             ForgeLoader.Start(SelectedMinecraftId)
         End If
         End If
 
 
-        '启动 NeoForge 加载
-        If SelectedMinecraftId.StartsWith("1.") AndAlso Int(SelectedMinecraftId.Split(".")(1)) > 19 Then
-            Dim NeoForgeLoader = New LoaderTask(Of String, List(Of DlNeoForgeVersionEntry))("DlNeoForgeVersion " & SelectedMinecraftId, AddressOf DlNeoForgeVersionMain)
-            LoadNeoForge.State = NeoForgeLoader
-            NeoForgeLoader.Start(SelectedMinecraftId)
-        End If
-
         '启动 Fabric API、OptiFabric 加载
         '启动 Fabric API、OptiFabric 加载
         DlFabricApiLoader.Start()
         DlFabricApiLoader.Start()
         DlOptiFabricLoader.Start()
         DlOptiFabricLoader.Start()
@@ -88,34 +83,36 @@
         AniStart({
         AniStart({
             AaOpacity(PanMinecraft, -PanMinecraft.Opacity, 100, 10),
             AaOpacity(PanMinecraft, -PanMinecraft.Opacity, 100, 10),
             AaTranslateX(PanMinecraft, -50 - CType(PanMinecraft.RenderTransform, TranslateTransform).X, 110, 10),
             AaTranslateX(PanMinecraft, -50 - CType(PanMinecraft.RenderTransform, TranslateTransform).X, 110, 10),
-            AaCode(Sub()
-                       PanBack.ScrollToHome()
-                       TextSelectName.Validate()
-                       OptiFine_Loaded()
-                       LiteLoader_Loaded()
-                       Forge_Loaded()
-                       NeoForge_Loaded()
-                       Fabric_Loaded()
-                       FabricApi_Loaded()
-                       OptiFabric_Loaded()
-                       SelectReload()
-                   End Sub, After:=True),
+            AaCode(
+            Sub()
+                PanBack.ScrollToHome()
+                TextSelectName.Validate()
+                OptiFine_Loaded()
+                LiteLoader_Loaded()
+                Forge_Loaded()
+                NeoForge_Loaded()
+                Fabric_Loaded()
+                FabricApi_Loaded()
+                OptiFabric_Loaded()
+                SelectReload()
+            End Sub, After:=True),
             AaOpacity(PanSelect, 1 - PanSelect.Opacity, 250, 150),
             AaOpacity(PanSelect, 1 - PanSelect.Opacity, 250, 150),
             AaTranslateX(PanSelect, -CType(PanSelect.RenderTransform, TranslateTransform).X, 500, 150, Ease:=New AniEaseOutBack(AniEasePower.Weak)),
             AaTranslateX(PanSelect, -CType(PanSelect.RenderTransform, TranslateTransform).X, 500, 150, Ease:=New AniEaseOutBack(AniEasePower.Weak)),
-            AaCode(Sub()
-                       PanMinecraft.Visibility = Visibility.Collapsed
-                       PanBack.IsHitTestVisible = True
-                       '初始化 Binding
-                       If IsFirstLoaded Then Exit Sub
-                       IsFirstLoaded = True
-                       BtnOptiFineClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFine.MainTextBlock, .Mode = BindingMode.OneWay})
-                       BtnLiteLoaderClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardLiteLoader.MainTextBlock, .Mode = BindingMode.OneWay})
-                       BtnForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardForge.MainTextBlock, .Mode = BindingMode.OneWay})
-                       BtnNeoForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardNeoForge.MainTextBlock, .Mode = BindingMode.OneWay})
-                       BtnFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabric.MainTextBlock, .Mode = BindingMode.OneWay})
-                       BtnFabricApiClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabricApi.MainTextBlock, .Mode = BindingMode.OneWay})
-                       BtnOptiFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFabric.MainTextBlock, .Mode = BindingMode.OneWay})
-                   End Sub,, True)
+            AaCode(
+            Sub()
+                PanMinecraft.Visibility = Visibility.Collapsed
+                PanBack.IsHitTestVisible = True
+                '初始化 Binding
+                If IsFirstLoaded Then Exit Sub
+                IsFirstLoaded = True
+                BtnOptiFineClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFine.MainTextBlock, .Mode = BindingMode.OneWay})
+                BtnLiteLoaderClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardLiteLoader.MainTextBlock, .Mode = BindingMode.OneWay})
+                BtnForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardForge.MainTextBlock, .Mode = BindingMode.OneWay})
+                BtnNeoForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardNeoForge.MainTextBlock, .Mode = BindingMode.OneWay})
+                BtnFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabric.MainTextBlock, .Mode = BindingMode.OneWay})
+                BtnFabricApiClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabricApi.MainTextBlock, .Mode = BindingMode.OneWay})
+                BtnOptiFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFabric.MainTextBlock, .Mode = BindingMode.OneWay})
+            End Sub,, True)
         }, "FrmDownloadInstall SelectPageSwitch", True)
         }, "FrmDownloadInstall SelectPageSwitch", True)
     End Sub
     End Sub
     Public Sub ExitSelectPage()
     Public Sub ExitSelectPage()
@@ -224,7 +221,7 @@
     End Sub
     End Sub
 
 
     'NeoForge
     'NeoForge
-    Private SelectedNeoForge As DlNeoForgeVersionEntry = Nothing
+    Private SelectedNeoForge As DlNeoForgeListEntry = Nothing
     Private Sub SetNeoForgeInfoShow(IsShow As String)
     Private Sub SetNeoForgeInfoShow(IsShow As String)
         If PanNeoForgeInfo.Tag = IsShow Then Exit Sub
         If PanNeoForgeInfo.Tag = IsShow Then Exit Sub
         PanNeoForgeInfo.Tag = IsShow
         PanNeoForgeInfo.Tag = IsShow
@@ -368,13 +365,14 @@
         Else
         Else
             BtnForgeClear.Visibility = Visibility.Visible
             BtnForgeClear.Visibility = Visibility.Visible
             ImgForge.Visibility = Visibility.Visible
             ImgForge.Visibility = Visibility.Visible
-            LabForge.Text = SelectedForge.Version
+            LabForge.Text = SelectedForge.VersionName
             LabForge.Foreground = ColorGray1
             LabForge.Foreground = ColorGray1
         End If
         End If
         'NeoForge
         'NeoForge
         If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) <= 19 Then
         If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) <= 19 Then
             CardNeoForge.Visibility = Visibility.Collapsed
             CardNeoForge.Visibility = Visibility.Collapsed
         Else
         Else
+            CardNeoForge.Visibility = Visibility.Visible
             Dim NeoForgeError As String = LoadNeoForgeGetError()
             Dim NeoForgeError As String = LoadNeoForgeGetError()
             CardNeoForge.MainSwap.Visibility = If(NeoForgeError Is Nothing, Visibility.Visible, Visibility.Collapsed)
             CardNeoForge.MainSwap.Visibility = If(NeoForgeError Is Nothing, Visibility.Visible, Visibility.Collapsed)
             If NeoForgeError IsNot Nothing Then CardNeoForge.IsSwaped = True
             If NeoForgeError IsNot Nothing Then CardNeoForge.IsSwaped = True
@@ -387,7 +385,7 @@
             Else
             Else
                 BtnNeoForgeClear.Visibility = Visibility.Visible
                 BtnNeoForgeClear.Visibility = Visibility.Visible
                 ImgNeoForge.Visibility = Visibility.Visible
                 ImgNeoForge.Visibility = Visibility.Visible
-                LabNeoForge.Text = SelectedNeoForge.VersionCode & If(SelectedNeoForge.IsBeta, "-beta", "")
+                LabNeoForge.Text = SelectedNeoForge.VersionName
                 LabNeoForge.Foreground = ColorGray1
                 LabNeoForge.Foreground = ColorGray1
             End If
             End If
         End If
         End If
@@ -461,9 +459,16 @@
             HintFabricAPI.Visibility = Visibility.Collapsed
             HintFabricAPI.Visibility = Visibility.Collapsed
         End If
         End If
         If SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso SelectedOptiFabric Is Nothing Then
         If SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso SelectedOptiFabric Is Nothing Then
-            HintOptiFabric.Visibility = Visibility.Visible
+            If SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15") Then
+                HintOptiFabric.Visibility = Visibility.Collapsed
+                HintOptiFabricOld.Visibility = Visibility.Visible
+            Else
+                HintOptiFabric.Visibility = Visibility.Visible
+                HintOptiFabricOld.Visibility = Visibility.Collapsed
+            End If
         Else
         Else
             HintOptiFabric.Visibility = Visibility.Collapsed
             HintOptiFabric.Visibility = Visibility.Collapsed
+            HintOptiFabricOld.Visibility = Visibility.Collapsed
         End If
         End If
         If SelectedMinecraftId.Contains("1.") AndAlso Val(SelectedMinecraftId.Split(".")(1)) >= 16 AndAlso SelectedOptiFine IsNot Nothing AndAlso
         If SelectedMinecraftId.Contains("1.") AndAlso Val(SelectedMinecraftId.Split(".")(1)) >= 16 AndAlso SelectedOptiFine IsNot Nothing AndAlso
            (SelectedForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) Then
            (SelectedForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) Then
@@ -500,10 +505,10 @@
             Name += "-Fabric " & SelectedFabric.Replace("+build", "")
             Name += "-Fabric " & SelectedFabric.Replace("+build", "")
         End If
         End If
         If SelectedForge IsNot Nothing Then
         If SelectedForge IsNot Nothing Then
-            Name += "-Forge_" & SelectedForge.Version
+            Name += "-Forge_" & SelectedForge.VersionName
         End If
         End If
         If SelectedNeoForge IsNot Nothing Then
         If SelectedNeoForge IsNot Nothing Then
-            Name += "-NeoForge_" & SelectedNeoForge.VersionCode & If(SelectedNeoForge.IsBeta, "-beta", "")
+            Name += "-NeoForge_" & SelectedNeoForge.VersionName
         End If
         End If
         If SelectedLiteLoader IsNot Nothing Then
         If SelectedLiteLoader IsNot Nothing Then
             Name += "-LiteLoader"
             Name += "-LiteLoader"
@@ -522,10 +527,10 @@
             Info += ", Fabric " & SelectedFabric.Replace("+build", "")
             Info += ", Fabric " & SelectedFabric.Replace("+build", "")
         End If
         End If
         If SelectedForge IsNot Nothing Then
         If SelectedForge IsNot Nothing Then
-            Info += ", Forge " & SelectedForge.Version
+            Info += ", Forge " & SelectedForge.VersionName
         End If
         End If
         If SelectedNeoForge IsNot Nothing Then
         If SelectedNeoForge IsNot Nothing Then
-            Info += ", NeoForge " & SelectedNeoForge.VersionCode & If(SelectedNeoForge.IsBeta, "-beta", "")
+            Info += ", NeoForge " & SelectedNeoForge.VersionName
         End If
         End If
         If SelectedLiteLoader IsNot Nothing Then
         If SelectedLiteLoader IsNot Nothing Then
             Info += ", LiteLoader"
             Info += ", LiteLoader"
@@ -683,6 +688,7 @@
     ''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
     ''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
     ''' </summary>
     ''' </summary>
     Private Function LoadOptiFineGetError() As String
     Private Function LoadOptiFineGetError() As String
+        If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
         If LoadOptiFine Is Nothing OrElse LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
         If LoadOptiFine Is Nothing OrElse LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
         If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFine.State, Object).Error.Message
         If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFine.State, Object).Error.Message
         '检查 Forge 1.13 - 1.14.3:全部不兼容
         '检查 Forge 1.13 - 1.14.3:全部不兼容
@@ -718,10 +724,11 @@
     Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
     Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
         If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
         If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
         If OptiFine.RequiredForgeVersion Is Nothing Then Return False '不兼容 Forge
         If OptiFine.RequiredForgeVersion Is Nothing Then Return False '不兼容 Forge
-        Return (OptiFine.RequiredForgeVersion.Contains(".") AndAlso 'XX.X.XXX
-                VersionSortInteger(Forge.Version, OptiFine.RequiredForgeVersion) >= 0) OrElse
-               (Not OptiFine.RequiredForgeVersion.Contains(".") AndAlso '#XXXX
-                Forge.Version.After(".") >= OptiFine.RequiredForgeVersion)
+        If OptiFine.RequiredForgeVersion.Contains(".") Then 'XX.X.XXX
+            Return VersionSortInteger(Forge.Version.ToString, OptiFine.RequiredForgeVersion) >= 0
+        Else 'XXXX
+            Return Forge.Version.Revision >= OptiFine.RequiredForgeVersion
+        End If
     End Function
     End Function
 
 
     '限制展开
     '限制展开
@@ -744,11 +751,12 @@
             Next
             Next
             If Not Versions.Any() Then Exit Sub
             If Not Versions.Any() Then Exit Sub
             '排序
             '排序
-            Versions = Sort(Versions, Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
-                                          If Not Left.IsPreview AndAlso Right.IsPreview Then Return True
-                                          If Left.IsPreview AndAlso Not Right.IsPreview Then Return False
-                                          Return VersionSortBoolean(Left.NameDisplay, Right.NameDisplay)
-                                      End Function)
+            Versions = Sort(Versions,
+            Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
+                If Not Left.IsPreview AndAlso Right.IsPreview Then Return True
+                If Left.IsPreview AndAlso Not Right.IsPreview Then Return False
+                Return VersionSortBoolean(Left.NameDisplay, Right.NameDisplay)
+            End Function)
             '可视化
             '可视化
             PanOptiFine.Children.Clear()
             PanOptiFine.Children.Clear()
             For Each Version In Versions
             For Each Version In Versions
@@ -791,7 +799,6 @@
         If LoadLiteLoader Is Nothing OrElse LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
         If LoadLiteLoader Is Nothing OrElse LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
         If LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadLiteLoader.State, Object).Error.Message
         If LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadLiteLoader.State, Object).Error.Message
         For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
         For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
-            If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
             If Version.Inherit = SelectedMinecraftId Then Return Nothing
             If Version.Inherit = SelectedMinecraftId Then Return Nothing
         Next
         Next
         Return "没有可用版本"
         Return "没有可用版本"
@@ -892,16 +899,15 @@
             If SelectedMinecraftId <> Loader.Input Then Exit Sub
             If SelectedMinecraftId <> Loader.Input Then Exit Sub
             If Loader.State <> LoadState.Finished Then Exit Sub
             If Loader.State <> LoadState.Finished Then Exit Sub
             '获取要显示的版本
             '获取要显示的版本
-            Dim Versions As New List(Of DlForgeVersionEntry)
-            Versions.AddRange(Loader.Output) '复制数组,以免 Output 在实例化后变空
+            Dim Versions = Loader.Output.ToList '复制数组,以免 Output 在实例化后变空
             If Not Loader.Output.Any() Then Exit Sub
             If Not Loader.Output.Any() Then Exit Sub
             PanForge.Children.Clear()
             PanForge.Children.Clear()
-            Versions = Sort(Versions, Function(a, b) New Version(a.Version) > New Version(b.Version)).
-                       Where(Function(v)
-                                 If v.Category = "universal" OrElse v.Category = "client" Then Return False '跳过无法自动安装的版本
-                                 If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, v) Then Return False
-                                 Return True
-                             End Function).ToList
+            Versions = Sort(Versions, Function(a, b) a.Version > b.Version).Where(
+            Function(v)
+                If v.Category = "universal" OrElse v.Category = "client" Then Return False '跳过无法自动安装的版本
+                If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, v) Then Return False
+                Return True
+            End Function).ToList()
             ForgeDownloadListItemPreload(PanForge, Versions, AddressOf Forge_Selected, False)
             ForgeDownloadListItemPreload(PanForge, Versions, AddressOf Forge_Selected, False)
             For Each Version In Versions
             For Each Version In Versions
                 PanForge.Children.Add(ForgeDownloadListItem(Version, AddressOf Forge_Selected, False))
                 PanForge.Children.Add(ForgeDownloadListItem(Version, AddressOf Forge_Selected, False))
@@ -936,25 +942,16 @@
     ''' </summary>
     ''' </summary>
     Private Function LoadNeoForgeGetError() As String
     Private Function LoadNeoForgeGetError() As String
         If Not SelectedMinecraftId.StartsWith("1.") Then Return "没有可用版本"
         If Not SelectedMinecraftId.StartsWith("1.") Then Return "没有可用版本"
-        If Not LoadNeoForge.State.IsLoader Then Return "正在获取版本列表……"
-        Dim Loader As LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)) = LoadNeoForge.State
-        If SelectedMinecraftId <> Loader.Input Then Return "正在获取版本列表……"
-        If Loader.State = LoadState.Loading Then Return "正在获取版本列表……"
-        If Loader.State = LoadState.Failed Then
-            Dim ErrorMessage As String = Loader.Error.Message
-            If ErrorMessage.Contains("没有可用版本") Then
-                Return "没有可用版本"
-            Else
-                Return "获取版本列表失败:" & ErrorMessage
-            End If
-        End If
-        If Loader.State <> LoadState.Finished Then Return "获取版本列表失败:未知错误,状态为 " & GetStringFromEnum(Loader.State)
-        For Each Version In Loader.Output
-            If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
-            If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
+        If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
+        If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
+        If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
+        If LoadNeoForge Is Nothing OrElse LoadNeoForge.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
+        If LoadNeoForge.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadNeoForge.State, Object).Error.Message
+        If DlNeoForgeListLoader.Output.Value.Any(Function(v) v.Inherit = SelectedMinecraftId) Then
             Return Nothing
             Return Nothing
-        Next
-        Return False
+        Else
+            Return "没有可用版本"
+        End If
     End Function
     End Function
 
 
     '限制展开
     '限制展开
@@ -965,18 +962,14 @@
     ''' <summary>
     ''' <summary>
     ''' 尝试重新可视化 NeoForge 版本列表。
     ''' 尝试重新可视化 NeoForge 版本列表。
     ''' </summary>
     ''' </summary>
-    Private Sub NeoForge_Loaded() Handles LoadForge.StateChanged
+    Private Sub NeoForge_Loaded() Handles LoadNeoForge.StateChanged
         Try
         Try
-            If Not LoadNeoForge.State.IsLoader Then Exit Sub
-            Dim Loader As LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)) = LoadNeoForge.State
-            If SelectedMinecraftId <> Loader.Input Then Exit Sub
-            If Loader.State <> LoadState.Finished Then Exit Sub
-            '获取要显示的版本
-            Dim Versions As New List(Of DlNeoForgeVersionEntry)
-            Versions.AddRange(Loader.Output) '复制数组,以免 Output 在实例化后变空
-            If Not Loader.Output.Any() Then Exit Sub
+            '获取版本列表
+            If DlNeoForgeListLoader.State <> LoadState.Finished Then Exit Sub
+            Dim Versions = DlNeoForgeListLoader.Output.Value.Where(Function(v) v.Inherit = SelectedMinecraftId).ToList
+            If Not Versions.Any() Then Exit Sub
+            '可视化
             PanNeoForge.Children.Clear()
             PanNeoForge.Children.Clear()
-
             NeoForgeDownloadListItemPreload(PanNeoForge, Versions, AddressOf NeoForge_Selected, False)
             NeoForgeDownloadListItemPreload(PanNeoForge, Versions, AddressOf NeoForge_Selected, False)
             For Each Version In Versions
             For Each Version In Versions
                 PanNeoForge.Children.Add(NeoForgeDownloadListItem(Version, AddressOf NeoForge_Selected, False))
                 PanNeoForge.Children.Add(NeoForgeDownloadListItem(Version, AddressOf NeoForge_Selected, False))
@@ -1013,9 +1006,8 @@
         If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabric.State, Object).Error.Message
         If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabric.State, Object).Error.Message
         For Each Version As JObject In DlFabricListLoader.Output.Value("game")
         For Each Version As JObject In DlFabricListLoader.Output.Value("game")
             If Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") Then
             If Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") Then
-                If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
                 If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
                 If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
-                'If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
+                If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
                 Return Nothing
                 Return Nothing
             End If
             End If
         Next
         Next
@@ -1202,6 +1194,7 @@
     ''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
     ''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
     ''' </summary>
     ''' </summary>
     Private Function LoadOptiFabricGetError() As String
     Private Function LoadOptiFabricGetError() As String
+        If SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15") Then Return "不兼容老版本 Fabric,请手动下载 OptiFabric Origins"
         If LoadOptiFabric Is Nothing OrElse LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
         If LoadOptiFabric Is Nothing OrElse LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
         If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFabric.State, Object).Error.Message
         If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFabric.State, Object).Error.Message
         If DlOptiFabricLoader.Output Is Nothing Then
         If DlOptiFabricLoader.Output Is Nothing Then
@@ -1247,7 +1240,8 @@
                 PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
                 PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
             Next
             Next
             '自动选择 OptiFabric
             '自动选择 OptiFabric
-            If Not AutoSelectedOptiFabric Then
+            If Not AutoSelectedOptiFabric AndAlso
+                Not (SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15")) Then '1.14~15 不自动选择
                 AutoSelectedOptiFabric = True
                 AutoSelectedOptiFabric = True
                 Log($"[Download] 已自动选择 OptiFabric:{CType(PanOptiFabric.Children(0), MyListItem).Title}")
                 Log($"[Download] 已自动选择 OptiFabric:{CType(PanOptiFabric.Children(0), MyListItem).Title}")
                 OptiFabric_Selected(PanOptiFabric.Children(0), Nothing)
                 OptiFabric_Selected(PanOptiFabric.Children(0), Nothing)
@@ -1279,7 +1273,7 @@
     End Sub
     End Sub
     Private Sub BtnSelectStart_Click() Handles BtnSelectStart.Click
     Private Sub BtnSelectStart_Click() Handles BtnSelectStart.Click
         '确认版本隔离
         '确认版本隔离
-        If (SelectedForge IsNot Nothing OrElse SelectedFabric IsNot Nothing OrElse SelectedNeoForge IsNot Nothing) AndAlso
+        If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
            (Setup.Get("LaunchArgumentIndie") = 0 OrElse Setup.Get("LaunchArgumentIndie") = 2) Then
            (Setup.Get("LaunchArgumentIndie") = 0 OrElse Setup.Get("LaunchArgumentIndie") = 2) Then
             If MyMsgBox("你尚未开启版本隔离,这会导致多个 MC 共用同一个 Mod 文件夹。" & vbCrLf &
             If MyMsgBox("你尚未开启版本隔离,这会导致多个 MC 共用同一个 Mod 文件夹。" & vbCrLf &
                         "因此在切换 MC 版本时,MC 会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
                         "因此在切换 MC 版本时,MC 会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml


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

@@ -72,17 +72,19 @@
         FrmMain.PageRight = Target
         FrmMain.PageRight = Target
         CType(FrmMain.PanMainRight.Child, MyPageRight).PageOnExit()
         CType(FrmMain.PanMainRight.Child, MyPageRight).PageOnExit()
         AniStart({
         AniStart({
-                         AaCode(Sub()
-                                    CType(FrmMain.PanMainRight.Child, MyPageRight).PageOnForceExit()
-                                    FrmMain.PanMainRight.Child = FrmMain.PageRight
-                                    FrmMain.PageRight.Opacity = 0
-                                End Sub, 130),
-                         AaCode(Sub()
-                                    '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
-                                    FrmMain.PageRight.Opacity = 1
-                                    FrmMain.PageRight.PageOnEnter()
-                                End Sub, 30, True)
-                     }, "PageLeft PageChange")
+            AaCode(
+            Sub()
+                CType(FrmMain.PanMainRight.Child, MyPageRight).PageOnForceExit()
+                FrmMain.PanMainRight.Child = FrmMain.PageRight
+                FrmMain.PageRight.Opacity = 0
+            End Sub, 130),
+            AaCode(
+            Sub()
+                '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
+                FrmMain.PageRight.Opacity = 1
+                FrmMain.PageRight.PageOnEnter()
+            End Sub, 30, True)
+        }, "PageLeft PageChange")
     End Sub
     End Sub
 
 
 #End Region
 #End Region
@@ -163,11 +165,12 @@
         ItemForge.Visibility = Visibility.Visible
         ItemForge.Visibility = Visibility.Visible
         ItemNeoForge.Visibility = Visibility.Visible
         ItemNeoForge.Visibility = Visibility.Visible
         ItemLiteLoader.Visibility = Visibility.Visible
         ItemLiteLoader.Visibility = Visibility.Visible
-        RunInThread(Sub()
-                        Thread.Sleep(20)
-                        RunInUiWait(Sub() ItemClient.SetChecked(True, True, True))
-                        AniControlEnabled -= 1
-                    End Sub)
+        RunInThread(
+        Sub()
+            Thread.Sleep(20)
+            RunInUiWait(Sub() ItemClient.SetChecked(True, True, True))
+            AniControlEnabled -= 1
+        End Sub)
     End Sub
     End Sub
     '折叠手动安装
     '折叠手动安装
     Private Sub LabHand_Click(sender As Object, e As MouseButtonEventArgs) Handles LabHand.MouseLeftButtonUp
     Private Sub LabHand_Click(sender As Object, e As MouseButtonEventArgs) Handles LabHand.MouseLeftButtonUp
@@ -178,15 +181,16 @@
         LabHand.Visibility = Visibility.Collapsed
         LabHand.Visibility = Visibility.Collapsed
         ItemClient.Visibility = Visibility.Collapsed
         ItemClient.Visibility = Visibility.Collapsed
         ItemOptiFine.Visibility = Visibility.Collapsed
         ItemOptiFine.Visibility = Visibility.Collapsed
+        ItemNeoForge.Visibility = Visibility.Collapsed
         ItemFabric.Visibility = Visibility.Collapsed
         ItemFabric.Visibility = Visibility.Collapsed
         ItemForge.Visibility = Visibility.Collapsed
         ItemForge.Visibility = Visibility.Collapsed
-        ItemNeoForge.Visibility = Visibility.Collapsed
         ItemLiteLoader.Visibility = Visibility.Collapsed
         ItemLiteLoader.Visibility = Visibility.Collapsed
-        RunInThread(Sub()
-                        Thread.Sleep(20)
-                        RunInUiWait(Sub() ItemInstall.SetChecked(True, True, True))
-                        AniControlEnabled -= 1
-                    End Sub)
+        RunInThread(
+        Sub()
+            Thread.Sleep(20)
+            RunInUiWait(Sub() ItemInstall.SetChecked(True, True, True))
+            AniControlEnabled -= 1
+        End Sub)
     End Sub
     End Sub
 
 
 End Class
 End Class

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

@@ -38,7 +38,7 @@
                 PanMain.Children.Add(NewCard)
                 PanMain.Children.Add(NewCard)
             Next
             Next
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, "可视化版本列表出错", LogLevel.Feedback)
+            Log(ex, "可视化 LiteLoader 版本列表出错", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
 
 

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

@@ -33,6 +33,7 @@
                         <TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" />
                         <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: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="全部 (也可自行输入)" IsSelected="True" />
+                            <local:MyComboBoxItem Content="1.21" />
                             <local:MyComboBoxItem Content="1.20.6" />
                             <local:MyComboBoxItem Content="1.20.6" />
                             <local:MyComboBoxItem Content="1.20.4" />
                             <local:MyComboBoxItem Content="1.20.4" />
                             <local:MyComboBoxItem Content="1.20.1" />
                             <local:MyComboBoxItem Content="1.20.1" />

+ 13 - 10
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb

@@ -40,12 +40,14 @@
                                       Visibility.Visible, Visibility.Collapsed)
                                       Visibility.Visible, Visibility.Collapsed)
             LabPage.Text = Page + 1
             LabPage.Text = Page + 1
             BtnPageFirst.IsEnabled = Page > 1
             BtnPageFirst.IsEnabled = Page > 1
-            BtnPageFirst.Opacity = If(BtnPageFirst.IsEnabled, 1, 0.2)
+            BtnPageFirst.Opacity = If(Page > 1, 1, 0.2)
             BtnPageLeft.IsEnabled = Page > 0
             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)
+            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
             If Storage.ErrorMessage Is Nothing Then
                 HintError.Visibility = Visibility.Collapsed
                 HintError.Visibility = Visibility.Collapsed
@@ -89,11 +91,12 @@
         Page = NewPage
         Page = NewPage
         FrmMain.BackToTop()
         FrmMain.BackToTop()
         Log($"[Download] Mod 切换到第 {Page + 1} 页")
         Log($"[Download] Mod 切换到第 {Page + 1} 页")
-        RunInThread(Sub()
-                        Thread.Sleep(100) '等待向上滚的动画结束
-                        RunInUi(Sub() CardPages.IsEnabled = True)
-                        Loader.Start()
-                    End Sub)
+        RunInThread(
+        Sub()
+            Thread.Sleep(100) '等待向上滚的动画结束
+            RunInUi(Sub() CardPages.IsEnabled = True)
+            Loader.Start()
+        End Sub)
     End Sub
     End Sub
 
 
 #Region "搜索"
 #Region "搜索"

+ 5 - 7
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml

@@ -8,22 +8,20 @@
         <StackPanel Orientation="Vertical" Margin="5">
         <StackPanel Orientation="Vertical" Margin="5">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="NeoForge 简介" x:Name="CardTip">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="NeoForge 简介" x:Name="CardTip">
                 <StackPanel Margin="25,40,15,20">
                 <StackPanel Margin="25,40,15,20">
-                    <TextBlock Margin="0,0,0,11" Text="NeoForge 是新版 Minecraft 下的 Mod 加载器,你需要先安装它才能安装各种 NeoForge 模组。&#xa;本页面提供 NeoForge 安装器下载,在下载后你需要手动打开安装器进行安装。" TextWrapping="Wrap" />
+                    <TextBlock Margin="0,0,0,11" Text="NeoForge 是 Minecraft 1.19+ 的 Mod 加载器,你需要先安装它才能安装各种 NeoForge 模组。&#xa;本页面提供 NeoForge 安装器下载,在下载后你需要手动打开安装器进行安装。" TextWrapping="Wrap" />
                     <Grid Height="35">
                     <Grid Height="35">
                         <Grid.ColumnDefinitions>
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
                             <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
                         </Grid.ColumnDefinitions>
                         </Grid.ColumnDefinitions>
-                        <local:MyButton x:Name="BtnWeb" Grid.Column="0" MinWidth="140" Text="打开官网" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
+                        <local:MyButton x:Name="BtnWeb" Grid.Column="0" MinWidth="140" Text="打开官网" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight"
+                                        EventType="打开网页" EventData="https://neoforged.net/" />
                     </Grid>
                     </Grid>
                 </StackPanel>
                 </StackPanel>
             </local:MyCard>
             </local:MyCard>
-            <!--<local:MyCard x:Name="CardVersions" Margin="20,15,20,20" Title="版本列表">
-                <StackPanel x:Name="PanVersions" Margin="20,40,18,20" />
-            </local:MyCard>-->
             <StackPanel Name="PanMain" Margin="20,15,20,5" Grid.IsSharedSizeScope="True" />
             <StackPanel Name="PanMain" Margin="20,15,20,5" Grid.IsSharedSizeScope="True" />
-            <local:MyCard HorizontalAlignment="Center" Margin="40,50" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
+            <local:MyCard HorizontalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
                 <local:MyLoading Text="正在获取 NeoForge 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
                 <local:MyLoading Text="正在获取 NeoForge 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
             </local:MyCard>
             </local:MyCard>
         </StackPanel>
         </StackPanel>
     </local:MyScrollViewer>
     </local:MyScrollViewer>
-</local:MyPageRight>
+</local:MyPageRight>

+ 10 - 30
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadNeoForge.xaml.vb

@@ -10,12 +10,17 @@
     Private Sub Load_OnFinish()
     Private Sub Load_OnFinish()
         '结果数据化
         '结果数据化
         Try
         Try
-            Dim Versions = Sort(DlNeoForgeListLoader.Output.Value, AddressOf VersionSortBoolean)
+            '归类
+            Dim Dict = DlNeoForgeListLoader.Output.Value.GroupBy(Function(d) d.Inherit).OrderByDescending(Function(g) g.Key).
+                ToDictionary(Function(g) g.Key, Function(g) g.ToList())
+            '清空当前
             PanMain.Children.Clear()
             PanMain.Children.Clear()
-            For Each Version As String In Versions
+            '转化为 UI
+            For Each Pair As KeyValuePair(Of String, List(Of DlNeoForgeListEntry)) In Dict
+                If Not Pair.Value.Any() Then Continue For
                 '增加卡片
                 '增加卡片
-                Dim NewCard As New MyCard With {.Title = Version.Replace("_p", " P"), .Margin = New Thickness(0, 0, 0, 15), .SwapType = 13}
-                Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Version}
+                Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 13}
+                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
                 NewCard.IsSwaped = True
                 NewCard.IsSwaped = True
@@ -25,30 +30,5 @@
             Log(ex, "可视化 NeoForge 版本列表出错", LogLevel.Feedback)
             Log(ex, "可视化 NeoForge 版本列表出错", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
-    Public Sub NeoForge_StateChanged(sender As MyLoading, newState As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState)
-        If newState <> MyLoading.MyLoadingState.Stop Then Exit Sub
 
 
-        Dim Card As MyCard = CType(sender.Parent, FrameworkElement).Parent
-        Dim Loader As LoaderTask(Of String, List(Of DlNeoForgeVersionEntry)) = sender.State
-        '载入列表
-        Card.SwapControl.Children.Clear()
-        Card.SwapControl.Tag = Loader.Output
-        Card.SwapType = 14
-        Card.StackInstall()
-    End Sub
-    Public Sub NeoForge_Click(sender As MyLoading, e As MouseButtonEventArgs)
-        If sender.State.LoadingState = MyLoading.MyLoadingState.Error Then
-            CType(sender.State, LoaderTask(Of String, List(Of DlNeoForgeVersionEntry))).Start(IsForceRestart:=True)
-        End If
-    End Sub
-    Private Sub NeoForge_Selected(sender As MyListItem, e As EventArgs)
-        McDownloadForgeSave(True, sender.Tag)
-    End Sub
-    Public Sub DownloadStart(sender As MyListItem, e As Object)
-        McDownloadForge(True, sender.Tag)
-    End Sub
-    Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
-        OpenWebsite("https://neoforged.net/")
-    End Sub
-
-End Class
+End Class

+ 2 - 6
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb

@@ -13,7 +13,7 @@
             '归类
             '归类
             Dim Dict As New Dictionary(Of String, List(Of DlOptiFineListEntry))
             Dim Dict As New Dictionary(Of String, List(Of DlOptiFineListEntry))
             Dict.Add("快照版本", New List(Of DlOptiFineListEntry))
             Dict.Add("快照版本", New List(Of DlOptiFineListEntry))
-            For VersionCode As Integer = 30 To 0 Step -1
+            For VersionCode As Integer = 50 To 0 Step -1
                 Dict.Add("1." & VersionCode, New List(Of DlOptiFineListEntry))
                 Dict.Add("1." & VersionCode, New List(Of DlOptiFineListEntry))
             Next
             Next
             For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
             For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
@@ -42,14 +42,10 @@
                 PanMain.Children.Add(NewCard)
                 PanMain.Children.Add(NewCard)
             Next
             Next
         Catch ex As Exception
         Catch ex As Exception
-            Log(ex, "可视化版本列表出错", LogLevel.Feedback)
+            Log(ex, "可视化 OptiFine 版本列表出错", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
 
 
-    Public Sub DownloadStart(sender As MyListItem, e As Object)
-        McDownloadOptiFine(sender.Tag)
-    End Sub
-
     Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
     Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
         OpenWebsite("https://www.optifine.net/")
         OpenWebsite("https://www.optifine.net/")
     End Sub
     End Sub

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

@@ -32,6 +32,7 @@
                         <TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" />
                         <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:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="1" IsEditable="True" MaxDropDownHeight="320">
                             <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
                             <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
+                            <local:MyComboBoxItem Content="1.21" />
                             <local:MyComboBoxItem Content="1.20.6" />
                             <local:MyComboBoxItem Content="1.20.6" />
                             <local:MyComboBoxItem Content="1.20.4" />
                             <local:MyComboBoxItem Content="1.20.4" />
                             <local:MyComboBoxItem Content="1.20.1" />
                             <local:MyComboBoxItem Content="1.20.1" />

+ 7 - 5
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml.vb

@@ -39,12 +39,14 @@
                                       Visibility.Visible, Visibility.Collapsed)
                                       Visibility.Visible, Visibility.Collapsed)
             LabPage.Text = Page + 1
             LabPage.Text = Page + 1
             BtnPageFirst.IsEnabled = Page > 1
             BtnPageFirst.IsEnabled = Page > 1
-            BtnPageFirst.Opacity = If(BtnPageFirst.IsEnabled, 1, 0.2)
+            BtnPageFirst.Opacity = If(Page > 1, 1, 0.2)
             BtnPageLeft.IsEnabled = Page > 0
             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)
+            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
             If Storage.ErrorMessage Is Nothing Then
                 HintError.Visibility = Visibility.Collapsed
                 HintError.Visibility = Visibility.Collapsed

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

@@ -241,7 +241,7 @@ Retry:
                             {"Translator-Chinese", "Crowdin 中文翻译者披风"}, {"Translator", "Crowdin 翻译者披风"}, {"Cobalt", "Cobalt 披风"},
                             {"Translator-Chinese", "Crowdin 中文翻译者披风"}, {"Translator", "Crowdin 翻译者披风"}, {"Cobalt", "Cobalt 披风"},
                             {"Vanilla", "原版披风"}, {"Minecon2011", "Minecon 2011 参与者披风"}, {"Minecon2012", "Minecon 2012 参与者披风"},
                             {"Vanilla", "原版披风"}, {"Minecon2011", "Minecon 2011 参与者披风"}, {"Minecon2012", "Minecon 2012 参与者披风"},
                             {"Minecon2013", "Minecon 2013 参与者披风"}, {"Minecon2015", "Minecon 2015 参与者披风"}, {"Minecon2016", "Minecon 2016 参与者披风"},
                             {"Minecon2013", "Minecon 2013 参与者披风"}, {"Minecon2015", "Minecon 2015 参与者披风"}, {"Minecon2016", "Minecon 2016 参与者披风"},
-                            {"Cherry Blossom", "樱花披风"}, {"15th Anniversary", "15 周年纪念披风"}, {"Purple Heart", "紫色心形披风"}, {"Follower's","追随者披风"}
+                            {"Cherry Blossom", "樱花披风"}, {"15th Anniversary", "15 周年纪念披风"}, {"Purple Heart", "紫色心形披风"}, {"Follower's", "追随者披风"}
                         }
                         }
                         Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}}
                         Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}}
                         For Each Cape In SkinData("capes")
                         For Each Cape In SkinData("capes")

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

@@ -27,15 +27,16 @@
     ''' 刷新自定义主页。
     ''' 刷新自定义主页。
     ''' </summary>
     ''' </summary>
     Private Sub Refresh() Handles Me.Loaded
     Private Sub Refresh() Handles Me.Loaded
-        RunInNewThread(Sub()
-                           Try
-                               SyncLock RefreshLock
-                                   RefreshReal()
-                               End SyncLock
-                           Catch ex As Exception
-                               Log(ex, "加载 PCL 主页自定义信息失败", LogLevel.Msgbox)
-                           End Try
-                       End Sub, $"刷新自定义主页 #{GetUuid()}")
+        RunInNewThread(
+        Sub()
+            Try
+                SyncLock RefreshLock
+                    RefreshReal()
+                End SyncLock
+            Catch ex As Exception
+                Log(ex, "加载 PCL 主页自定义信息失败", LogLevel.Msgbox)
+            End Try
+        End Sub, $"刷新自定义主页 #{GetUuid()}")
     End Sub
     End Sub
     Private Sub RefreshReal()
     Private Sub RefreshReal()
         Dim Content As String = ""
         Dim Content As String = ""
@@ -155,7 +156,6 @@ Download:
             Else
             Else
                 Log(ex, $"联网下载自定义主页失败({Address})")
                 Log(ex, $"联网下载自定义主页失败({Address})")
             End If
             End If
-            Address = ""
         End Try
         End Try
     End Sub
     End Sub
 
 
@@ -204,7 +204,7 @@ Download:
             End If
             End If
             Content = "<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"">" & Content & "</StackPanel>"
             Content = "<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"">" & Content & "</StackPanel>"
             Content = HelpArgumentReplace(Content)
             Content = HelpArgumentReplace(Content)
-            Log($"[Page] 实例化:加载自定义主页 UI,最终内容长度:{Content.Count}")
+            Log($"[Page] 实例化:加载自定义主页 UI 开始,最终内容长度:{Content.Count}")
             Try
             Try
                 PanCustom.Children.Add(GetObjectFromXML(Content))
                 PanCustom.Children.Add(GetObjectFromXML(Content))
             Catch ex As Exception
             Catch ex As Exception

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

@@ -39,14 +39,15 @@
     Public Shared Function GetLoginData() As McLoginMs
     Public Shared Function GetLoginData() As McLoginMs
         If FrmLoginMs Is Nothing Then Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName")}
         If FrmLoginMs Is Nothing Then Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName")}
         Dim Result As McLoginMs = Nothing
         Dim Result As McLoginMs = Nothing
-        RunInUiWait(Sub()
-                        If FrmLoginMs.ComboAccounts.SelectedIndex = 0 Then
-                            Result = New McLoginMs
-                        Else
-                            Dim Item As MyListItem = FrmLoginMs.ComboAccounts.SelectedItem
-                            Result = New McLoginMs With {.OAuthRefreshToken = Item.Tag, .UserName = Item.Title}
-                        End If
-                    End Sub)
+        RunInUiWait(
+        Sub()
+            If FrmLoginMs.ComboAccounts.SelectedIndex = 0 Then
+                Result = New McLoginMs
+            Else
+                Dim Item As MyListItem = FrmLoginMs.ComboAccounts.SelectedItem
+                Result = New McLoginMs With {.OAuthRefreshToken = Item.Tag, .UserName = Item.Title}
+            End If
+        End Sub)
         Return Result
         Return Result
     End Function
     End Function
     ''' <summary>
     ''' <summary>

+ 304 - 131
Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml

@@ -104,139 +104,312 @@
             </local:MyCard>
             </local:MyCard>
             <local:MyCard Margin="0,0,0,15" Title="赞助者">
             <local:MyCard Margin="0,0,0,15" Title="赞助者">
                 <StackPanel Margin="25,40,10,20">
                 <StackPanel Margin="25,40,10,20">
-                    <TextBlock HorizontalAlignment="Left" Text="以下是 2024 年 4 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
+                    <TextBlock HorizontalAlignment="Left" Text="以下是 2024 年 5~6 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
                     <WrapPanel Margin="0,0,0,10">
                     <WrapPanel Margin="0,0,0,10">
-                        <TextBlock Width="120" Margin="0,1.5" Text="道士师傅" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="狗群主群狗" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Alioth陳" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="shyzysa" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="死んだライオン" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="mc沙漠之狐隆帅" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="123456胡杨" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="香蕉风味" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="毛哥" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="leon" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="clnb" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="123" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="lihaoran0313" />
-                        <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="皓垣Faraway" />
-                        <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="Akn123" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Dfkeit" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="CloudLonngLee" />
-                        <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="loner..?" />
+                        <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="Petrichor" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="一只可爱的frisk啊" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="luvFwt" />
+                        <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="ADerAQi" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="van" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Eterfrusa" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="kpocc07" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="觉莫" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="我是DGHSFG" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="lhw0616" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="2DGIRL" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="雨猫霖" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Grazie" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="鲲鹏roc" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="皮皮苏" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="哆啦哆啦" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="serendipity" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="W-Qi" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="tenneidp" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="叢沄" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="jian_ke" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="ZHypocrite" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="浑荀" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="yoo-ovo" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="洛梓风anemo" />
+                        <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="FSAH217" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="炽绪" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="JUBEYsl" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="阿祺27" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="江上数峰青" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="ECHO" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="路易斯" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="别曹曹了" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Szy" />
+                        <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="臻榛搸殝" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="GT" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="夜也" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="is步行街" />
-                        <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="SYF" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="帝王尬笑" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="DarkKCat" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="我将如闪电般归来" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="TSLOLY" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="JackX" />
-                        <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="颐葭" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Vaincre_VV" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="小明爱睡觉" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="YHLin" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="翁yy" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="午睡不爱睡觉" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="tanglin" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Quittskii" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="W2erty" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Chris_Dream" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="sanrenxin" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="BBK" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="京北的洋" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="喵木仔" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="abstudio" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="洛惜惜缘" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="熊心万花镜" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="tianguaren" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="bitlogi" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="彬彬爆" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="超爱小辣椒" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Kkigoo" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="于书墨" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="御坂1354号" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="t7fihb8" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="44.5GB" />
-                        <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="LING-DIAN" />
-                        <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="我的神a啊" />
-                        <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="zzyd" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="御影" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Xephyrs" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Sovtheia" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="CRANK" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="本太子的作业满天飞" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="超级无敌旋风小猪猪" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="泽希尔·S+" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="erliang_ya" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="明酱酱" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="玐煲粥" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="The_follow" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="王八" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="joker" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="north-cool" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="JJ" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="小石" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="XiaomQ928" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Fly with You!!" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="海上乘鲸客" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="miku" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="小雯" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="woainad" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="wqaycm" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="白豆" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Alex" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="大地风暴" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="曾and田某人" />
-                        <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="ElliottZChan" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="沐子冷落" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="_Blessing" />
-                        <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="n3v3r" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="七星灯" />
-                        <TextBlock Width="120" Margin="0,1.5" Text="Theia" />
-
+                        <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="Z." />
+                        <TextBlock Width="120" Margin="0,1.5" Text="芝惑鱼" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="MegnaAegwynn " />
+                        <TextBlock Width="120" Margin="0,1.5" Text="DJLD" />
+                        <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="1899年的提拉米苏" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="bzwm" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="GhaMZz" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="雪游" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="奇怪的大土豆" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Moonlight-池绾" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="fusocietyck" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="爬爬鸡" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="山千海千" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="氿离Yoi" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="如风沐烟" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="一条博子" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="m1679" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="snow" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="3瓶奶茶" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Elkanah_" />
+                        <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="EnsoNani" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Ann.Midnight" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="郁子恒是FW" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="ZIHE_kk" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="文八" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="寂月星落" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Writer_DaMao" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="gwd233" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Sutvh" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="崔东山" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Botaiii" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="凛仙子D-" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="MooFaH" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="嘿哈吼" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="下山吃肉的兔子" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="warship" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="木落微雨" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="杨阳baby" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="白茶" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="路过一下的尘垒" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="counterea" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="雨中盛开的花朵" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="珊瑚宫心海" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="luner" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="时崎王罪丶" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Nicht" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="冰薇" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Archetto" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="蓝冰之刃" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Baguette" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="KenshenLove" />
+                        <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="acac" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="瑞风" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="xiankeQAQ" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="BDUCK" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="fuaglove" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="prprprrrpop" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="YOCE" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="忹." />
+                        <TextBlock Width="120" Margin="0,1.5" Text="夜青" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="橘糸侑You" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="薇克波顿" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="夂冬螽" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Colitary" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Harm_b10ck" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="乆月" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Kaoukala" />
+                        <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="Awfrlu+" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Lava_drop_" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="? *???* ?" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Gwynsur" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="许淼淼" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="waneng0807" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="安anLa" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="MQDCB" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="我dnmd" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="猫舍旁边有恶犬" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="yk" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Cik-z" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="胡桃不是桃丫" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="陌白" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="C418" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="醉梦仙露" />
+                        <TextBlock Width="240" Margin="0,1.5" Text="Re.从零开始跟猪鲨鲨恋爱" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="玄?" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="olwlm" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="XiaoLe_SH" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="龙大炮" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="陆阿藏" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="lo" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="七夜英理" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="lizi" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="范德Fa" />
+                        <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="间铃" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="瀧柳" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="IRasciblebh" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="15183318101" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="LALALA" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="大香蕉" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Another0" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="丢天帝" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="魔法喵酱" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="wshilaoliu" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="PangDaHusky" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="qi_lu" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="LetvGodyan" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Amo" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="liang" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="baijillys" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="栗悟飯とカメハメ波" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="姜路扬" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="LuluPipi" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Atuo" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="泳圈鼬用攀瀑" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="EWD" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="孟然君" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="num61" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Elysia_mc" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Wehrmacht" />
+                        <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="Jking" />
+                        <TextBlock Width="240" Margin="0,1.5" Text="抖音搜索:清凉夏日一只瓜" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="HEARLEY" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="woaini_awa" />
+                        <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="zzc" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="w?z?r?y" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="havoc" />
+                        <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="BBQ" />
+                        <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="10000cituitui" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Television" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="......" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="LONG11" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="OP仙人" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="陌音依矢—笠风" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="kinno_mc" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Avid" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="brimobe" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Momoki" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="徐小疯" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="我爱龙猫!!!" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="233" />
+                        <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="pumpkin" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Solaray3" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="m1a0w0" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="懿轩" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="圆圆xyz" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="EchoLong" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="光与影的对白" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="AptS:1547" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="中转站" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="情猫" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="胡桃Mahero" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Ew_o" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="叽里呱啦" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="MHNIO" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="小洺" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="龙儿" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="ccll48" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Ling7844" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="不会写网名的屑" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Aresposeidon1124" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="钻石Daiyamondo" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="七月无风" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="YuTian" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="csleep" />
+                        <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="青绵kipilu" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="IWI_Margarita" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="小林カンナ" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="TD-Clotys" />
+                        <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="Celery" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="简称FV" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="飞翔的PUMA" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="123456。?" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="heitong_shu" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Lan" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="sanjuou" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="芙芙" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="zyc11230170" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="TOUHOULUO" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="在下雾切" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="exusiai2357" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="???" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="润煌Ricardo" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="无风" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="缘花乐" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="Willian" />
+                        <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="Wolfgang_233" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="小螺浩" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="rtoe332" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="lliiooll" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="QFwushang" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="竹翼" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="没差" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="用户13223" />
+                        <TextBlock Width="120" Margin="0,1.5" Text="猫羽喵" />
                     </WrapPanel>
                     </WrapPanel>
                     <Grid Height="35">
                     <Grid Height="35">
                         <Grid.ColumnDefinitions>
                         <Grid.ColumnDefinitions>

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

@@ -38,23 +38,23 @@
                         CardName = "常规版本"
                         CardName = "常规版本"
                     Case McVersionCardType.API
                     Case McVersionCardType.API
                         Dim IsForgeExists As Boolean = False
                         Dim IsForgeExists As Boolean = False
-                        Dim IsNeoExists As Boolean = False
+                        Dim IsNeoForgeExists As Boolean = False
                         Dim IsFabricExists As Boolean = False
                         Dim IsFabricExists As Boolean = False
                         Dim IsLiteExists As Boolean = False
                         Dim IsLiteExists As Boolean = False
                         For Each Version As McVersion In Card.Value
                         For Each Version As McVersion In Card.Value
                             If Version.Version.HasFabric Then IsFabricExists = True
                             If Version.Version.HasFabric Then IsFabricExists = True
                             If Version.Version.HasLiteLoader Then IsLiteExists = True
                             If Version.Version.HasLiteLoader Then IsLiteExists = True
                             If Version.Version.HasForge Then IsForgeExists = True
                             If Version.Version.HasForge Then IsForgeExists = True
-                            If Version.Version.HasNeoForge Then IsNeoExists = True
+                            If Version.Version.HasNeoForge Then IsNeoForgeExists = True
                         Next
                         Next
-                        If If(IsLiteExists, 1, 0) + If(IsForgeExists, 1, 0) + If(IsFabricExists, 1, 0) + If(IsNeoExists, 1, 0) > 1 Then
+                        If If(IsLiteExists, 1, 0) + If(IsForgeExists, 1, 0) + If(IsFabricExists, 1, 0) + If(IsNeoForgeExists, 1, 0) > 1 Then
                             CardName = "可安装 Mod"
                             CardName = "可安装 Mod"
                         ElseIf IsForgeExists Then
                         ElseIf IsForgeExists Then
                             CardName = "Forge 版本"
                             CardName = "Forge 版本"
+                        ElseIf IsNeoForgeExists Then
+                            CardName = "NeoForge 版本"
                         ElseIf IsLiteExists Then
                         ElseIf IsLiteExists Then
                             CardName = "LiteLoader 版本"
                             CardName = "LiteLoader 版本"
-                        ElseIf IsNeoExists Then
-                            CardName = "NeoForge 版本"
                         Else
                         Else
                             CardName = "Fabric 版本"
                             CardName = "Fabric 版本"
                         End If
                         End If
@@ -214,8 +214,8 @@
         FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
         FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
     End Sub
     End Sub
 
 
+    '修改此代码时,同时修改 PageVersionOverall 中的代码
     Public Shared Sub DeleteVersion(Item As MyListItem, Version As McVersion)
     Public Shared Sub DeleteVersion(Item As MyListItem, Version As McVersion)
-        '修改此代码时,同时修改 PageVersionOverall 中的代码
         Try
         Try
             Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
             Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
             Dim IsHintIndie As Boolean = Version.State <> McVersionState.Error AndAlso Version.PathIndie <> PathMcFolder
             Dim IsHintIndie As Boolean = Version.State <> McVersionState.Error AndAlso Version.PathIndie <> PathMcFolder

+ 6 - 26
Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb

@@ -206,10 +206,8 @@
             SliderRamCustom.MaxValue = Math.Floor((RamTotal - 1.5) / 0.5) + 12
             SliderRamCustom.MaxValue = Math.Floor((RamTotal - 1.5) / 0.5) + 12
         ElseIf RamTotal <= 16 Then
         ElseIf RamTotal <= 16 Then
             SliderRamCustom.MaxValue = Math.Floor((RamTotal - 8) / 1) + 25
             SliderRamCustom.MaxValue = Math.Floor((RamTotal - 8) / 1) + 25
-        ElseIf RamTotal <= 32 Then
-            SliderRamCustom.MaxValue = Math.Floor((RamTotal - 16) / 2) + 33
         Else
         Else
-            SliderRamCustom.MaxValue = Math.Min(Math.Floor((RamTotal - 32) / 4) + 41, 49)
+            SliderRamCustom.MaxValue = Math.Min(Math.Floor((RamTotal - 16) / 2) + 33, 41)
         End If
         End If
         '设置文本
         '设置文本
         LabRamGame.Text = If(RamGame = Math.Floor(RamGame), RamGame & ".0", RamGame) & " GB" &
         LabRamGame.Text = If(RamGame = Math.Floor(RamGame), RamGame & ".0", RamGame) & " GB" &
@@ -259,7 +257,6 @@
         End If
         End If
         If RamTextLeft <> Left Then
         If RamTextLeft <> Left Then
             RamTextLeft = Left
             RamTextLeft = Left
-            'If AniControlEnabled = 0 Then
             Select Case Left
             Select Case Left
                 Case 0
                 Case 0
                     AniStart({
                     AniStart({
@@ -280,22 +277,6 @@
                             AaOpacity(LabRamUsedTitle, 0.7 - LabRamUsedTitle.Opacity, 100)
                             AaOpacity(LabRamUsedTitle, 0.7 - LabRamUsedTitle.Opacity, 100)
                         }, "SetupLaunch Ram TextLeft")
                         }, "SetupLaunch Ram TextLeft")
             End Select
             End Select
-            'Else
-            '    Select Case Left
-            '        Case 0
-            '            LabRamUsed.Opacity = 0
-            '            LabRamTotal.Opacity = 0
-            '            LabRamUsedTitle.Opacity = 0
-            '        Case 1
-            '            LabRamUsed.Opacity = 1
-            '            LabRamTotal.Opacity = 0
-            '            LabRamUsedTitle.Opacity = 0.7
-            '        Case 2
-            '            LabRamUsed.Opacity = 1
-            '            LabRamTotal.Opacity = 1
-            '            LabRamUsedTitle.Opacity = 0.7
-            '    End Select
-            'End If
         End If
         End If
         '右侧
         '右侧
         Dim Right As Integer
         Dim Right As Integer
@@ -404,15 +385,14 @@ PreFin:
                 RamGive = (Value - 12) * 0.5 + 1.5
                 RamGive = (Value - 12) * 0.5 + 1.5
             ElseIf Value <= 33 Then
             ElseIf Value <= 33 Then
                 RamGive = (Value - 25) * 1 + 8
                 RamGive = (Value - 25) * 1 + 8
-            ElseIf Value <= 41 Then
-                RamGive = (Value - 33) * 2 + 16
             Else
             Else
-                RamGive = (Value - 41) * 4 + 32
+                RamGive = (Value - 33) * 2 + 16
             End If
             End If
         End If
         End If
         '若使用 32 位 Java,则限制为 1G
         '若使用 32 位 Java,则限制为 1G
         If If(Is32BitJava, Not JavaIs64Bit(If(UseVersionJavaSetup, Version, Nothing))) Then RamGive = Math.Min(1, RamGive)
         If If(Is32BitJava, Not JavaIs64Bit(If(UseVersionJavaSetup, Version, Nothing))) Then RamGive = Math.Min(1, RamGive)
-        Return RamGive
+        '封顶 32G
+        Return Math.Min(32, RamGive)
     End Function
     End Function
 
 
 #End Region
 #End Region
@@ -557,8 +537,8 @@ PreFin:
     Private Sub CheckArgumentRam_Change() Handles CheckArgumentRam.Change
     Private Sub CheckArgumentRam_Change() Handles CheckArgumentRam.Change
         If AniControlEnabled <> 0 Then Exit Sub
         If AniControlEnabled <> 0 Then Exit Sub
         If Not CheckArgumentRam.Checked Then Return
         If Not CheckArgumentRam.Checked Then Return
-        If MyMsgBox("内存优化耗时较长,这会拖慢游戏的启动过程,建议仅在电脑内存不充裕时开启此选项。" & vbCrLf &
-                    "如果你在使用机械硬盘,这还可能会导致一小段时间的严重卡顿。" &
+        If MyMsgBox("内存优化会显著延长启动耗时,建议仅在内存不足时开启。" & vbCrLf &
+                    "如果你在使用机械硬盘,这还可能导致一小段时间的严重卡顿。" &
                     If(IsAdmin(), "", $"{vbCrLf}{vbCrLf}每次启动游戏,PCL 都需要申请管理员权限以进行内存优化。{vbCrLf}若想自动授予权限,可以右键 PCL,打开 属性 → 兼容性 → 以管理员身份运行此程序。"),
                     If(IsAdmin(), "", $"{vbCrLf}{vbCrLf}每次启动游戏,PCL 都需要申请管理员权限以进行内存优化。{vbCrLf}若想自动授予权限,可以右键 PCL,打开 属性 → 兼容性 → 以管理员身份运行此程序。"),
                     "提醒", "确定", "取消") = 2 Then
                     "提醒", "确定", "取消") = 2 Then
             CheckArgumentRam.Checked = False
             CheckArgumentRam.Checked = False

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

@@ -41,8 +41,8 @@
         '设置解锁
         '设置解锁
         If Not RadioLauncherTheme8.IsEnabled Then LabLauncherTheme8Copy.ToolTip = "累积赞助达到 ¥23.33 后,在爱发电私信发送【解锁码】以解锁。" & vbCrLf & "右键打开赞助页面,如果觉得 PCL 做得还不错就支持一下吧 =w=!"
         If Not RadioLauncherTheme8.IsEnabled Then LabLauncherTheme8Copy.ToolTip = "累积赞助达到 ¥23.33 后,在爱发电私信发送【解锁码】以解锁。" & vbCrLf & "右键打开赞助页面,如果觉得 PCL 做得还不错就支持一下吧 =w=!"
         RadioLauncherTheme8.ToolTip = "累积赞助达到 ¥23.33 后,在爱发电私信发送【解锁码】以解锁"
         RadioLauncherTheme8.ToolTip = "累积赞助达到 ¥23.33 后,在爱发电私信发送【解锁码】以解锁"
-        If Not RadioLauncherTheme9.IsEnabled Then LabLauncherTheme9Copy.ToolTip = "· 反馈一个 Bug,在 Issue 标记为 [已完成] 后回复 Issue 要求解锁(右键打开反馈页面)" & vbCrLf & "· 向帮助库提交 Pull Request,在龙猫合并后解锁"
-        RadioLauncherTheme9.ToolTip = "· 反馈一个 Bug,在反馈标记为 [完成] 后回复 Issue 要求解锁" & vbCrLf & "· 向帮助库提交 Pull Request,在龙猫合并后解锁"
+        If Not RadioLauncherTheme9.IsEnabled Then LabLauncherTheme9Copy.ToolTip = "· 反馈一个 Bug,在标记为 [完成] 后回复识别码要求解锁(右键打开反馈页面)" & vbCrLf & "· 提交一个 Pull Request,在合并后回复识别码要求解锁"
+        RadioLauncherTheme9.ToolTip = "· 反馈一个 Bug,在标记为 [完成] 后回复识别码要求解锁" & vbCrLf & "· 提交一个 Pull Request,在合并后回复识别码要求解锁"
         '极客蓝的处理在 ThemeCheck 中
         '极客蓝的处理在 ThemeCheck 中
 
 
     End Sub
     End Sub
@@ -83,7 +83,11 @@
             MusicRefreshUI()
             MusicRefreshUI()
 
 
             '主页
             '主页
-            ComboCustomPreset.SelectedIndex = Setup.Get("UiCustomPreset")
+            Try
+                ComboCustomPreset.SelectedIndex = Setup.Get("UiCustomPreset")
+            Catch
+                Setup.Reset("UiCustomPreset")
+            End Try
             CType(FindName("RadioCustomType" & Setup.Load("UiCustomType")), MyRadioBox).Checked = True
             CType(FindName("RadioCustomType" & Setup.Load("UiCustomType")), MyRadioBox).Checked = True
             TextCustomNet.Text = Setup.Get("UiCustomNet")
             TextCustomNet.Text = Setup.Get("UiCustomNet")
 
 

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

@@ -607,8 +607,10 @@
             If ModEntry.Comp IsNot Nothing Then
             If ModEntry.Comp IsNot Nothing Then
                 '跳转到 Mod 下载页面
                 '跳转到 Mod 下载页面
                 FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
                 FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
-                                   .Additional = {ModEntry.Comp, New List(Of String), PageVersionLeft.Version.Version.McName,
-                                   If(PageVersionLeft.Version.Version.HasForge, CompModLoaderType.Forge, If(PageVersionLeft.Version.Version.HasFabric, CompModLoaderType.Fabric, CompModLoaderType.Any))}})
+                    .Additional = {ModEntry.Comp, New List(Of String), PageVersionLeft.Version.Version.McName,
+                        If(PageVersionLeft.Version.Version.HasForge, CompModLoaderType.Forge,
+                        If(PageVersionLeft.Version.Version.HasNeoForge, CompModLoaderType.NeoForge,
+                        If(PageVersionLeft.Version.Version.HasFabric, CompModLoaderType.Fabric, CompModLoaderType.Any)))}})
             Else
             Else
                 '获取信息
                 '获取信息
                 Dim ContentLines As New List(Of String)
                 Dim ContentLines As New List(Of String)

+ 1 - 1
Plain Craft Launcher 2/Pages/PageVersion/PageVersionModDisabled.xaml

@@ -22,7 +22,7 @@
             </Grid.ColumnDefinitions>
             </Grid.ColumnDefinitions>
             <TextBlock Grid.Row="0" Grid.ColumnSpan="4" Margin="0,0,0,9" HorizontalAlignment="Center" Text="该版本不可使用 Mod" FontSize="19" UseLayoutRounding="True" SnapsToDevicePixels="True" Foreground="{DynamicResource ColorBrush3}" />
             <TextBlock Grid.Row="0" Grid.ColumnSpan="4" Margin="0,0,0,9" HorizontalAlignment="Center" Text="该版本不可使用 Mod" FontSize="19" UseLayoutRounding="True" SnapsToDevicePixels="True" Foreground="{DynamicResource ColorBrush3}" />
             <Rectangle Grid.Row="1" Grid.ColumnSpan="4" HorizontalAlignment="Stretch" Height="2" Fill="{DynamicResource ColorBrush3}" />
             <Rectangle Grid.Row="1" Grid.ColumnSpan="4" HorizontalAlignment="Stretch" Height="2" Fill="{DynamicResource ColorBrush3}" />
-            <TextBlock Grid.Row="2" Grid.ColumnSpan="4" Margin="10,15,10,5" Text="你需要先安装 Forge、NeoForge 或 Fabric 等 Mod 加载器才能使用 Mod,请在下载页面重新安装这些版本。&#xa;如果你已经安装过了 Mod 加载器,那么你很可能选择了错误的版本,请点击版本选择按钮切换版本,并注意 Forge 在版本选择列表中的图标为铁砧,NeoForge 的图标为狐狸,Fabric 的图标为丝绸。" TextWrapping="Wrap" />
+            <TextBlock Grid.Row="2" Grid.ColumnSpan="4" Margin="10,15,10,5" Text="你需要先安装 Forge、Fabric 等 Mod 加载器才能使用 Mod,请在下载页面安装这些版本。&#xa;如果你已经安装过了 Mod 加载器,那么你很可能选择了错误的版本,请点击版本选择按钮切换版本。" TextWrapping="Wrap" />
             <local:MyButton Grid.Row="3" Grid.Column="1" Height="35" HorizontalAlignment="Center" x:Name="BtnDownload" MinWidth="140" Text="转到下载页面" Margin="10,10,10,0" Padding="13,0" ColorType="Highlight" />
             <local:MyButton Grid.Row="3" Grid.Column="1" Height="35" HorizontalAlignment="Center" x:Name="BtnDownload" MinWidth="140" Text="转到下载页面" Margin="10,10,10,0" Padding="13,0" ColorType="Highlight" />
             <local:MyButton Grid.Row="3" Grid.Column="2" Height="35" HorizontalAlignment="Center" x:Name="BtnVersion" MinWidth="140" Text="版本选择" Margin="10,10,10,0" Padding="13,0" />
             <local:MyButton Grid.Row="3" Grid.Column="2" Height="35" HorizontalAlignment="Center" x:Name="BtnVersion" MinWidth="140" Text="版本选择" Margin="10,10,10,0" Padding="13,0" />
         </Grid>
         </Grid>

+ 15 - 11
Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml.vb

@@ -127,6 +127,8 @@
             '重命名主文件夹
             '重命名主文件夹
             My.Computer.FileSystem.RenameDirectory(OldPath, TempName)
             My.Computer.FileSystem.RenameDirectory(OldPath, TempName)
             My.Computer.FileSystem.RenameDirectory(TempPath, NewName)
             My.Computer.FileSystem.RenameDirectory(TempPath, NewName)
+            '清理 ini 缓存
+            IniClearCache(PageVersionLeft.Version.Path & "PCL\Setup.ini")
             '遍历重命名所有文件与文件夹
             '遍历重命名所有文件与文件夹
             For Each Entry As DirectoryInfo In New DirectoryInfo(NewPath).EnumerateDirectories
             For Each Entry As DirectoryInfo In New DirectoryInfo(NewPath).EnumerateDirectories
                 If Not Entry.Name.Contains(OldName) Then Continue For
                 If Not Entry.Name.Contains(OldName) Then Continue For
@@ -292,16 +294,17 @@
             End SyncLock
             End SyncLock
             '启动
             '启动
             Dim Loader As New LoaderCombo(Of String)(PageVersionLeft.Version.Name & " 文件补全", DlClientFix(PageVersionLeft.Version, True, AssetsIndexExistsBehaviour.AlwaysDownload, False))
             Dim Loader As New LoaderCombo(Of String)(PageVersionLeft.Version.Name & " 文件补全", DlClientFix(PageVersionLeft.Version, True, AssetsIndexExistsBehaviour.AlwaysDownload, False))
-            Loader.OnStateChanged = Sub()
-                                        Select Case Loader.State
-                                            Case LoadState.Finished
-                                                Hint(Loader.Name & "成功!", HintType.Finish)
-                                            Case LoadState.Failed
-                                                Hint(Loader.Name & "失败:" & GetExceptionSummary(Loader.Error), HintType.Critical)
-                                            Case LoadState.Aborted
-                                                Hint(Loader.Name & "已取消!", HintType.Info)
-                                        End Select
-                                    End Sub
+            Loader.OnStateChanged =
+            Sub()
+                Select Case Loader.State
+                    Case LoadState.Finished
+                        Hint(Loader.Name & "成功!", HintType.Finish)
+                    Case LoadState.Failed
+                        Hint(Loader.Name & "失败:" & GetExceptionSummary(Loader.Error), HintType.Critical)
+                    Case LoadState.Aborted
+                        Hint(Loader.Name & "已取消!", HintType.Info)
+                End Select
+            End Sub
             Loader.Start(PageVersionLeft.Version.Name)
             Loader.Start(PageVersionLeft.Version.Name)
             LoaderTaskbarAdd(Loader)
             LoaderTaskbarAdd(Loader)
             FrmMain.BtnExtraDownload.ShowRefresh()
             FrmMain.BtnExtraDownload.ShowRefresh()
@@ -312,8 +315,8 @@
     End Sub
     End Sub
 
 
     '删除版本
     '删除版本
+    '修改此代码时,同时修改 PageSelectRight 中的代码
     Private Sub BtnManageDelete_Click(sender As Object, e As EventArgs) Handles BtnManageDelete.Click
     Private Sub BtnManageDelete_Click(sender As Object, e As EventArgs) Handles BtnManageDelete.Click
-        '修改此代码时,同时修改 PageSelectRight 中的代码
         Try
         Try
             Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
             Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
             Dim IsHintIndie As Boolean = PageVersionLeft.Version.State <> McVersionState.Error AndAlso PageVersionLeft.Version.PathIndie <> PathMcFolder
             Dim IsHintIndie As Boolean = PageVersionLeft.Version.State <> McVersionState.Error AndAlso PageVersionLeft.Version.PathIndie <> PathMcFolder
@@ -321,6 +324,7 @@
                         If(IsHintIndie, vbCrLf & "由于该版本开启了版本隔离,删除版本时该版本对应的存档、资源包、Mod 等文件也将被一并删除!", ""),
                         If(IsHintIndie, vbCrLf & "由于该版本开启了版本隔离,删除版本时该版本对应的存档、资源包、Mod 等文件也将被一并删除!", ""),
                         "版本删除确认", , "取消",, IsHintIndie OrElse IsShiftPressed)
                         "版本删除确认", , "取消",, IsHintIndie OrElse IsShiftPressed)
                 Case 1
                 Case 1
+                    IniClearCache(PageVersionLeft.Version.Path & "PCL\Setup.ini")
                     If IsShiftPressed Then
                     If IsShiftPressed Then
                         DeleteDirectory(PageVersionLeft.Version.Path)
                         DeleteDirectory(PageVersionLeft.Version.Path)
                         Hint("版本 " & PageVersionLeft.Version.Name & " 已永久删除!", HintType.Finish)
                         Hint("版本 " & PageVersionLeft.Version.Name & " 已永久删除!", HintType.Finish)

+ 17 - 17
Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml

@@ -77,6 +77,22 @@
                         <local:MySlider Grid.Row="3" Grid.Column="1" IsEnabled="False" x:Name="SliderRamCustom" Tag="VersionRamCustom" MaxValue="49" Value="13" />
                         <local:MySlider Grid.Row="3" Grid.Column="1" IsEnabled="False" x:Name="SliderRamCustom" Tag="VersionRamCustom" MaxValue="49" Value="13" />
                         <!--<local:MyTextBox Grid.Row="2" Grid.Column="3" Width="100" VerticalAlignment="Center" Margin="30,0,0,0" Text="2048 MB" />-->
                         <!--<local:MyTextBox Grid.Row="2" Grid.Column="3" Width="100" VerticalAlignment="Center" Margin="30,0,0,0" Text="2048 MB" />-->
                     </Grid>
                     </Grid>
+                    <Grid Margin="0,5,0,0">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="Auto" />
+                            <ColumnDefinition Width="Auto" />
+                            <ColumnDefinition />
+                        </Grid.ColumnDefinitions>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="28" />
+                        </Grid.RowDefinitions>
+                        <TextBlock Margin="0,6,30,0" Text="启动游戏前进行内存优化" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" />
+                        <local:MyComboBox x:Name="ComboRamOptimize" Margin="10,0,0,0" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="2" Tag="VersionRamOptimize">
+                            <local:MyComboBoxItem Content="使用全局设置" IsSelected="True" />
+                            <local:MyComboBoxItem Content="开启" />
+                            <local:MyComboBoxItem Content="关闭" />
+                        </local:MyComboBox>
+                    </Grid>
                     <Grid x:Name="PanRamDisplay" Margin="0,11,2,0" SnapsToDevicePixels="True" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1">
                     <Grid x:Name="PanRamDisplay" Margin="0,11,2,0" SnapsToDevicePixels="True" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1">
                         <Grid.ColumnDefinitions>
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition x:Name="ColumnRamUsed" Width="4.7*"/>
                             <ColumnDefinition x:Name="ColumnRamUsed" Width="4.7*"/>
@@ -106,22 +122,6 @@
                         </StackPanel>
                         </StackPanel>
                         <TextBlock Grid.Row="2" x:Name="LabRamGame" Text="2.5 GB" Grid.ColumnSpan="3" TextTrimming="None" Margin="2,3,0,0" FontSize="16" Foreground="Black" HorizontalAlignment="Left" />
                         <TextBlock Grid.Row="2" x:Name="LabRamGame" Text="2.5 GB" Grid.ColumnSpan="3" TextTrimming="None" Margin="2,3,0,0" FontSize="16" Foreground="Black" HorizontalAlignment="Left" />
                     </Grid>
                     </Grid>
-                    <Grid Margin="0,15,0,0">
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition Width="Auto" />
-                            <ColumnDefinition />
-                        </Grid.ColumnDefinitions>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="28" />
-                        </Grid.RowDefinitions>
-                        <TextBlock Margin="0,6,0,0" Text="启动游戏前进行内存优化" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" />
-                        <local:MyComboBox x:Name="ComboRamOptimize" Margin="10,0,0,0" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="2" Tag="VersionRamOptimize">
-                            <local:MyComboBoxItem Content="使用全局设置" IsSelected="True" />
-                            <local:MyComboBoxItem Content="开启" />
-                            <local:MyComboBoxItem Content="关闭" />
-                        </local:MyComboBox>
-                    </Grid>
                 </StackPanel>
                 </StackPanel>
             </local:MyCard>
             </local:MyCard>
             <local:MyCard x:Name="CardServer" Margin="0,0,0,15" Title="服务器">
             <local:MyCard x:Name="CardServer" Margin="0,0,0,15" Title="服务器">
@@ -226,4 +226,4 @@
             </local:MyCard>
             </local:MyCard>
         </StackPanel>
         </StackPanel>
     </local:MyScrollViewer>
     </local:MyScrollViewer>
-</local:MyPageRight>
+</local:MyPageRight>

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

@@ -165,10 +165,8 @@
             SliderRamCustom.MaxValue = Math.Floor((RamTotal - 1.5) / 0.5) + 12
             SliderRamCustom.MaxValue = Math.Floor((RamTotal - 1.5) / 0.5) + 12
         ElseIf RamTotal <= 16 Then
         ElseIf RamTotal <= 16 Then
             SliderRamCustom.MaxValue = Math.Floor((RamTotal - 8) / 1) + 25
             SliderRamCustom.MaxValue = Math.Floor((RamTotal - 8) / 1) + 25
-        ElseIf RamTotal <= 32 Then
-            SliderRamCustom.MaxValue = Math.Floor((RamTotal - 16) / 2) + 33
         Else
         Else
-            SliderRamCustom.MaxValue = Math.Min(Math.Floor((RamTotal - 32) / 4) + 41, 49)
+            SliderRamCustom.MaxValue = Math.Min(Math.Floor((RamTotal - 16) / 2) + 33, 41)
         End If
         End If
         '设置文本
         '设置文本
         LabRamGame.Text = If(RamGame = Math.Floor(RamGame), RamGame & ".0", RamGame) & " GB" &
         LabRamGame.Text = If(RamGame = Math.Floor(RamGame), RamGame & ".0", RamGame) & " GB" &
@@ -356,12 +354,13 @@ PreFin:
             ElseIf Value <= 41 Then
             ElseIf Value <= 41 Then
                 RamGive = (Value - 33) * 2 + 16
                 RamGive = (Value - 33) * 2 + 16
             Else
             Else
-                RamGive = (Value - 41) * 4 + 32
+                RamGive = (Value - 33) * 2 + 16
             End If
             End If
         End If
         End If
         '若使用 32 位 Java,则限制为 1G
         '若使用 32 位 Java,则限制为 1G
         If If(Is32BitJava, Not JavaIs64Bit(PageVersionLeft.Version)) Then RamGive = Math.Min(1, RamGive)
         If If(Is32BitJava, Not JavaIs64Bit(PageVersionLeft.Version)) Then RamGive = Math.Min(1, RamGive)
-        Return RamGive
+        '封顶 32G
+        Return Math.Min(32, RamGive)
     End Function
     End Function
 
 
 #End Region
 #End Region

+ 14 - 7
Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj

@@ -185,6 +185,9 @@
     <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" />
@@ -229,9 +232,6 @@
     <Compile Include="Modules\Minecraft\MyCompItem.xaml.vb">
     <Compile Include="Modules\Minecraft\MyCompItem.xaml.vb">
       <DependentUpon>MyCompItem.xaml</DependentUpon>
       <DependentUpon>MyCompItem.xaml</DependentUpon>
     </Compile>
     </Compile>
-    <Compile Include="Pages\PageDownload\PageDownloadNeoForge.xaml.vb">
-      <DependentUpon>PageDownloadNeoForge.xaml</DependentUpon>
-    </Compile>
     <Compile Include="Pages\PageDownload\PageDownloadMod.xaml.vb">
     <Compile Include="Pages\PageDownload\PageDownloadMod.xaml.vb">
       <DependentUpon>PageDownloadMod.xaml</DependentUpon>
       <DependentUpon>PageDownloadMod.xaml</DependentUpon>
     </Compile>
     </Compile>
@@ -244,6 +244,9 @@
     <Compile Include="Pages\PageDownload\PageDownloadCompDetail.xaml.vb">
     <Compile Include="Pages\PageDownload\PageDownloadCompDetail.xaml.vb">
       <DependentUpon>PageDownloadCompDetail.xaml</DependentUpon>
       <DependentUpon>PageDownloadCompDetail.xaml</DependentUpon>
     </Compile>
     </Compile>
+    <Compile Include="Pages\PageDownload\PageDownloadNeoForge.xaml.vb">
+      <DependentUpon>PageDownloadNeoForge.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Pages\PageDownload\PageDownloadPack.xaml.vb">
     <Compile Include="Pages\PageDownload\PageDownloadPack.xaml.vb">
       <DependentUpon>PageDownloadPack.xaml</DependentUpon>
       <DependentUpon>PageDownloadPack.xaml</DependentUpon>
     </Compile>
     </Compile>
@@ -469,6 +472,7 @@
       <DependentUpon>FormMain.xaml</DependentUpon>
       <DependentUpon>FormMain.xaml</DependentUpon>
       <SubType>Code</SubType>
       <SubType>Code</SubType>
     </Compile>
     </Compile>
+
     <Page Include="Modules\Minecraft\MyLocalModItem.xaml">
     <Page Include="Modules\Minecraft\MyLocalModItem.xaml">
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
@@ -477,10 +481,6 @@
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
     </Page>
     </Page>
-    <Page Include="Pages\PageDownload\PageDownloadNeoForge.xaml">
-      <Generator>MSBuild:Compile</Generator>
-      <SubType>Designer</SubType>
-    </Page>
     <Page Include="Pages\PageDownload\PageDownloadMod.xaml">
     <Page Include="Pages\PageDownload\PageDownloadMod.xaml">
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
@@ -497,6 +497,10 @@
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
     </Page>
     </Page>
+    <Page Include="Pages\PageDownload\PageDownloadNeoForge.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Pages\PageDownload\PageDownloadPack.xaml">
     <Page Include="Pages\PageDownload\PageDownloadPack.xaml">
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
@@ -922,6 +926,9 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Resource Include="Images\Heads\MCBBS.png" />
     <Resource Include="Images\Heads\MCBBS.png" />
+  </ItemGroup>
+  <ItemGroup>
+
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Resource Include="Images\Blocks\NeoForge.png" />
     <Resource Include="Images\Blocks\NeoForge.png" />

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

@@ -79,11 +79,11 @@
         <TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
         <TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
                     Text="在 EventData 后面添加一条竖线(|),竖线后填写服务器 IP,即可在启动该版本的同时自动进入服务器。" />
                     Text="在 EventData 后面添加一条竖线(|),竖线后填写服务器 IP,即可在启动该版本的同时自动进入服务器。" />
 		<local:MyButton Margin="0,4,0,0" Width="250" Height="35"
 		<local:MyButton Margin="0,4,0,0" Width="250" Height="35"
-                    Text="启动 1.12.2 并进入 Hypixel" EventType="启动游戏" EventData="1.12.2|mc.hypixel.net" ToolTip="服务器 IP:mc.hypixel.net" />
+                    Text="启动 1.20.1 并进入 Hypixel" EventType="启动游戏" EventData="1.20.1|mc.hypixel.net" ToolTip="服务器 IP:mc.hypixel.net" />
 		<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
 		<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
                     Text="在 EventData 中填写 \current,表示启动当前被选中的游戏版本,同样可以在后面填写服务器 IP。" />
                     Text="在 EventData 中填写 \current,表示启动当前被选中的游戏版本,同样可以在后面填写服务器 IP。" />
 		<local:MyButton Margin="0,4,0,10" Width="250" Height="35"
 		<local:MyButton Margin="0,4,0,10" Width="250" Height="35"
-                    Text="启动当前选中版本并进入 Hypixel" EventType="启动游戏" EventData="\current|mc.hypixel.net" ToolTip="服务器 IP:mc.hypixel.net" />
+                    Text="启动当前选中版本并进入 Hypixel" EventType="启动游戏" EventData="\current|mc.hypixel.net" ToolTip="启动当前版本" />
 	</StackPanel>
 	</StackPanel>
 </local:MyCard>
 </local:MyCard>
 
 
@@ -184,30 +184,30 @@
         <TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
         <TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
                     Text="PCL 内置了一些 Minecraft 方块与物品图片,可以直接使用。"/>
                     Text="PCL 内置了一些 Minecraft 方块与物品图片,可以直接使用。"/>
 		<StackPanel Orientation="Horizontal" Margin="10,8,0,15" Height="30">
 		<StackPanel Orientation="Horizontal" Margin="10,8,0,15" Height="30">
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/CommandBlock.png"/>
 			<!-- 命令方块 -->
 			<!-- 命令方块 -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Cobblestone.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/CommandBlock.png"/>
 			<!-- 圆石 -->
 			<!-- 圆石 -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/GoldBlock.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Cobblestone.png"/>
 			<!-- 金块 -->
 			<!-- 金块 -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Grass.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/GoldBlock.png"/>
 			<!-- 草方块 -->
 			<!-- 草方块 -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/GrassPath.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Grass.png"/>
 			<!-- 草径 -->
 			<!-- 草径 -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Anvil.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/GrassPath.png"/>
 			<!-- 铁砧 -->
 			<!-- 铁砧 -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/RedstoneBlock.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Anvil.png"/>
 			<!-- 红石块 -->
 			<!-- 红石块 -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/RedstoneLampOn.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/RedstoneBlock.png"/>
 			<!-- 红石灯(亮) -->
 			<!-- 红石灯(亮) -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/RedstoneLampOff.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/RedstoneLampOn.png"/>
 			<!-- 红石灯(灭) -->
 			<!-- 红石灯(灭) -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Egg.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/RedstoneLampOff.png"/>
 			<!-- 鸡蛋 -->
 			<!-- 鸡蛋 -->
-			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Fabric.png"/>
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Egg.png"/>
 			<!-- 布料(Fabric 图标) -->
 			<!-- 布料(Fabric 图标) -->
-      <Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/NeoForge.png"/>
-      <!-- 狐狸(NeoForge 图标) -->
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/Fabric.png"/>
+			<!-- 狐狸(NeoForge 图标) -->
+			<Image Width="30" Margin="5,0,0,0" Source="pack://application:,,,/images/Blocks/NeoForge.png"/>
 		</StackPanel>
 		</StackPanel>
         <TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
         <TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
                     Text="使用时,将上方对应行的 Source 复制到 MyListItem 的 Logo 属性处即可。"/>
                     Text="使用时,将上方对应行的 Source 复制到 MyListItem 的 Logo 属性处即可。"/>

Некоторые файлы не были показаны из-за большого количества измененных файлов