龙腾猫跃 2 лет назад
Родитель
Сommit
fb4386952d
43 измененных файлов с 549 добавлено и 645 удалено
  1. 12 0
      Plain Craft Launcher 2/Controls/MyPageRight.vb
  2. 22 67
      Plain Craft Launcher 2/FormMain.xaml.vb
  3. 5 5
      Plain Craft Launcher 2/Modules/Base/ModBase.vb
  4. 1 0
      Plain Craft Launcher 2/Modules/Base/ModNet.vb
  5. 50 43
      Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
  6. 4 4
      Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
  7. 17 56
      Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
  8. 40 43
      Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
  9. 2 1
      Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
  10. 27 20
      Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml.vb
  11. 27 20
      Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb
  12. 3 3
      Plain Craft Launcher 2/My Project/AssemblyInfo.vb
  13. 34 35
      Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
  14. 5 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadClient.xaml
  15. 4 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadClient.xaml.vb
  16. 5 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml
  17. 5 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadFabric.xaml
  18. 5 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadForge.xaml
  19. 5 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml
  20. 2 2
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
  21. 5 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLiteLoader.xaml
  22. 6 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
  23. 5 1
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb
  24. 5 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml
  25. 5 5
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
  26. 90 86
      Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
  27. 5 6
      Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml
  28. 1 0
      Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
  29. 1 1
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml
  30. 0 5
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb
  31. 5 5
      Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml
  32. 6 6
      Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml
  33. 5 5
      Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml
  34. 6 6
      Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml
  35. 4 4
      Plain Craft Launcher 2/Pages/PageSelectRight.xaml
  36. 6 6
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml
  37. 5 5
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml
  38. 8 8
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml
  39. 5 5
      Plain Craft Launcher 2/Pages/PageSpeedRight.xaml
  40. 8 11
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml
  41. 81 124
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
  42. 6 6
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml
  43. 6 6
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml

+ 12 - 0
Plain Craft Launcher 2/Controls/MyPageRight.vb

@@ -2,6 +2,18 @@
     Inherits AdornerDecorator
     Inherits AdornerDecorator
     Public PageUuid As Integer = GetUuid()
     Public PageUuid As Integer = GetUuid()
 
 
+    '“返回顶部” 按钮检测的滚动区域
+    Public Property PanScroll As MyScrollViewer
+        Get
+            Return GetValue(PanScrollProperty)
+        End Get
+        Set(value As MyScrollViewer)
+            SetValue(PanScrollProperty, value)
+        End Set
+    End Property
+    Private Shared ReadOnly PanScrollProperty =
+        DependencyProperty.Register("PanScroll", GetType(MyScrollViewer), GetType(MyPageRight), New PropertyMetadata(Nothing))
+
     '当前状态
     '当前状态
     Public Enum PageStates
     Public Enum PageStates
         Empty '默认状态,页面全空
         Empty '默认状态,页面全空

+ 22 - 67
Plain Craft Launcher 2/FormMain.xaml.vb

@@ -1,5 +1,4 @@
 Imports System.ComponentModel
 Imports System.ComponentModel
-Imports System.Runtime.InteropServices
 
 
 Public Class FormMain
 Public Class FormMain
 
 
@@ -11,6 +10,11 @@ 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 < 313 Then 'Release 2.6.13
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法启动 Forge 1.18.3+ 的 Bug"))
+            FeatureCount += 6
+            BugCount += 10
+        End If
         If LastVersion < 311 Then 'Release 2.6.12
         If LastVersion < 311 Then 'Release 2.6.12
             FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面将显示 Mod 的中文名、图标、标签等信息"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面将显示 Mod 的中文名、图标、标签等信息"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "从 Mod 管理页面查看 Mod 信息时会跳转到其下载详情页面"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "从 Mod 管理页面查看 Mod 信息时会跳转到其下载详情页面"))
@@ -119,30 +123,17 @@ Public Class FormMain
             FeatureCount += 4
             FeatureCount += 4
             BugCount += 4
             BugCount += 4
         End If
         End If
-        If LastVersion < 255 Then 'Release 2.2.14
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法启动 Minecraft 1.19-Pre1 的 Bug"))
-            FeatureCount += 5
-            BugCount += 3
-        End If
-        If LastVersion < 253 Then 'Release 2.2.13
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持在安装菜单中直接安装 OptiFabric"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持调整 Mod 文件名中中文译名的位置"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "崩溃分析优化,支持分析更多 Forge 相关的崩溃"))
-            FeatureCount += 13
-            BugCount += 27
-        End If
-        If LastVersion < 250 Then 'Release 2.2.11
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持将 Mod 文件拖入窗口进行安装"))
-            If LastVersion = 246 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法使用中文搜索 Mod 的 Bug"))
-            FeatureCount += 8
-            BugCount += 33
-        End If
 #Else
 #Else
         '5:          FEAT+
         '5:          FEAT+
         '4:     IMP+ FEAT*
         '4:     IMP+ FEAT*
         '3:BUG+ IMP* FEAT-
         '3:BUG+ IMP* FEAT-
         '2:BUG* IMP-
         '2:BUG* IMP-
         '1:BUG-
         '1:BUG-
+        If LastVersion < 312 Then 'Snapshot 2.6.13
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法启动 Forge 1.18.3+ 的 Bug"))
+            FeatureCount += 6
+            BugCount += 10
+        End If
         If LastVersion < 310 Then 'Snapshot 2.6.12
         If LastVersion < 310 Then 'Snapshot 2.6.12
             If LastVersion = 309 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod 管理页面添加启用、禁用单个 Mod 的快捷按钮"))
             If LastVersion = 309 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod 管理页面添加启用、禁用单个 Mod 的快捷按钮"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法安装 Forge 1.18.3+ 的 Bug"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法安装 Forge 1.18.3+ 的 Bug"))
@@ -322,28 +313,6 @@ Public Class FormMain
             FeatureCount += 4
             FeatureCount += 4
             BugCount += 4
             BugCount += 4
         End If
         End If
-        If LastVersion < 256 Then 'Snapshot 2.2.14
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法启动 Minecraft 1.19-Pre1 的 Bug"))
-            FeatureCount += 5
-            BugCount += 3
-        End If
-        If LastVersion < 254 Then 'Snapshot 2.2.13
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持调整 Mod 文件名中中文译名的位置"))
-            FeatureCount += 3
-            BugCount += 17
-        End If
-        If LastVersion < 252 Then 'Snapshot 2.2.12
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持在安装菜单中直接安装 OptiFabric"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "崩溃分析优化,支持分析更多 Forge 相关的崩溃"))
-            If LastVersion = 251 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复同时安装 Forge 和 OptiFine 时 OptiFine 无效的 Bug"))
-            FeatureCount += 10
-            BugCount += 10
-        End If
-        If LastVersion < 251 Then 'Snapshot 2.2.11
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持将 Mod 文件拖入窗口进行安装"))
-            FeatureCount += 2
-            BugCount += 16
-        End If
 #End If
 #End If
         '整理更新日志文本
         '整理更新日志文本
         Dim ContentList As New List(Of String)
         Dim ContentList As New List(Of String)
@@ -402,6 +371,13 @@ Public Class FormMain
         '加载 UI
         '加载 UI
         InitializeComponent()
         InitializeComponent()
         Opacity = 0
         Opacity = 0
+        ''开启管理员权限下的文件拖拽,但下列代码也没用(#2531)
+        'If IsAdmin() Then
+        '    Log("[Start] PCL 正以管理员权限运行")
+        '    ChangeWindowMessageFilter(&H233, 1)
+        '    ChangeWindowMessageFilter(&H4A, 1)
+        '    ChangeWindowMessageFilter(&H49, 1)
+        'End If
         '切换到首页
         '切换到首页
         If Not IsNothing(FrmLaunchLeft.Parent) Then FrmLaunchLeft.SetValue(ContentPresenter.ContentProperty, Nothing)
         If Not IsNothing(FrmLaunchLeft.Parent) Then FrmLaunchLeft.SetValue(ContentPresenter.ContentProperty, Nothing)
         If Not IsNothing(FrmLaunchRight.Parent) Then FrmLaunchRight.SetValue(ContentPresenter.ContentProperty, Nothing)
         If Not IsNothing(FrmLaunchRight.Parent) Then FrmLaunchRight.SetValue(ContentPresenter.ContentProperty, Nothing)
@@ -510,25 +486,11 @@ Public Class FormMain
                            Catch ex As Exception
                            Catch ex As Exception
                                Log(ex, "清理自动更新文件失败")
                                Log(ex, "清理自动更新文件失败")
                            End Try
                            End Try
-                           '开启管理员权限下的文件拖拽,但下列代码也没用(#2531)
-                           If IsAdmin() Then
-                               Log("[System] PCL 正以管理员权限运行")
-                               Dim changeInfo As New ChangeFilter
-                               changeInfo.cbSize = Marshal.SizeOf(changeInfo)
-                               ChangeWindowMessageFilterEx(Handle, &H233, 1, changeInfo)
-                               ChangeWindowMessageFilterEx(Handle, &H4A, 1, changeInfo)
-                               ChangeWindowMessageFilterEx(Handle, &H49, 1, changeInfo)
-                           End If
                        End Sub, "Start Loader", ThreadPriority.Lowest)
                        End Sub, "Start Loader", ThreadPriority.Lowest)
 
 
         Log("[Start] 第三阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
         Log("[Start] 第三阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
     End Sub
     End Sub
-    <StructLayout(LayoutKind.Sequential)>
-    Public Structure ChangeFilter
-        Public cbSize As UInteger
-        Public ExtStatus As UInteger
-    End Structure
-    Private Declare Function ChangeWindowMessageFilterEx Lib "user32.dll" (hwnd As IntPtr, message As UInteger, action As UInteger, changeInfo As ChangeFilter) As Boolean
+    'Private Declare Function ChangeWindowMessageFilter Lib "user32.dll" (message As Integer, action As Integer) As Boolean
     '根据打开次数触发的事件
     '根据打开次数触发的事件
     Private Sub RunCountSub()
     Private Sub RunCountSub()
         Setup.Set("SystemCount", Setup.Get("SystemCount") + 1)
         Setup.Set("SystemCount", Setup.Get("SystemCount") + 1)
@@ -1618,17 +1580,10 @@ Install:
         Return RealScroll IsNot Nothing AndAlso RealScroll.Visibility = Visibility.Visible AndAlso RealScroll.VerticalOffset > Height + If(BtnExtraBack.Show, 0, 700)
         Return RealScroll IsNot Nothing AndAlso RealScroll.Visibility = Visibility.Visible AndAlso RealScroll.VerticalOffset > Height + If(BtnExtraBack.Show, 0, 700)
     End Function
     End Function
     Private Function BtnExtraBack_GetRealChild() As MyScrollViewer
     Private Function BtnExtraBack_GetRealChild() As MyScrollViewer
-        If PanMainRight.Child Is Nothing Then Return Nothing
-        Dim RightChild = CType(PanMainRight.Child, AdornerDecorator).Child
-        If RightChild Is Nothing Then
-            Return Nothing
-        ElseIf TypeOf RightChild Is MyScrollViewer Then
-            Return RightChild
-        ElseIf TypeOf RightChild Is Grid AndAlso TypeOf CType(RightChild, Grid).Children(0) Is MyScrollViewer Then
-            Return CType(RightChild, Grid).Children(0)
-        Else
-            Return Nothing
-        End If
+        If PanMainRight.Child Is Nothing OrElse TypeOf PanMainRight.Child IsNot MyPageRight Then Return Nothing
+        Dim Scroll = CType(PanMainRight.Child, MyPageRight).PanScroll
+        If Scroll Is Nothing OrElse Scroll.Visibility <> Visibility.Visible Then Return Nothing
+        Return Scroll
     End Function
     End Function
 
 
 #End Region
 #End Region

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

@@ -11,12 +11,12 @@ Public Module ModBase
 #Region "声明"
 #Region "声明"
 
 
     '下列版本信息由更新器自动修改
     '下列版本信息由更新器自动修改
-    Public Const VersionBaseName As String = "2.6.12" '不含分支前缀的显示用版本名
-    Public Const VersionStandardCode As String = "2.6.12." & VersionBranchCode '标准格式的四段式版本号
+    Public Const VersionBaseName As String = "2.6.13" '不含分支前缀的显示用版本名
+    Public Const VersionStandardCode As String = "2.6.13." & VersionBranchCode '标准格式的四段式版本号
 #If BETA Then
 #If BETA Then
-    Public Const VersionCode As Integer = 308 'Release
+    Public Const VersionCode As Integer = 313 'Release
 #Else
 #Else
-    Public Const VersionCode As Integer = 310 'Snapshot
+    Public Const VersionCode As Integer = 312 'Snapshot
 #End If
 #End If
     '自动生成的版本信息
     '自动生成的版本信息
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -1819,7 +1819,7 @@ NextElement:
     ''' 获取格式类似于“11:08:52.037”的当前时间的字符串。
     ''' 获取格式类似于“11:08:52.037”的当前时间的字符串。
     ''' </summary>
     ''' </summary>
     Public Function GetTimeNow() As String
     Public Function GetTimeNow() As String
-        Return Date.Now.ToString("HH:mm:ss.fff")
+        Return Date.Now.ToString("HH':'mm':'ss'.'fff")
     End Function
     End Function
     ''' <summary>
     ''' <summary>
     ''' 获取系统运行时间(毫秒),保证为正 Long 且大于 1,但可能突变减小。
     ''' 获取系统运行时间(毫秒),保证为正 Long 且大于 1,但可能突变减小。

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

@@ -273,6 +273,7 @@ RequestFinished:
                 Client.Headers(HttpRequestHeader.Referer) = "http://" & VersionCode & ".pcl2.server/"
                 Client.Headers(HttpRequestHeader.Referer) = "http://" & VersionCode & ".pcl2.server/"
                 Client.DownloadFile(Url, LocalFile)
                 Client.DownloadFile(Url, LocalFile)
             Catch ex As Exception
             Catch ex As Exception
+                File.Delete(LocalFile)
                 Throw New WebException("直接下载文件失败(" & Url & ")。", ex)
                 Throw New WebException("直接下载文件失败(" & Url & ")。", ex)
             End Try
             End Try
         End Using
         End Using

+ 50 - 43
Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb

@@ -20,6 +20,7 @@
         Forge = 1
         Forge = 1
         Fabric = 4
         Fabric = 4
         Quilt = 5
         Quilt = 5
+        NeoForge = 6
     End Enum
     End Enum
     <Flags> Public Enum CompSourceType
     <Flags> Public Enum CompSourceType
         CurseForge = 1
         CurseForge = 1
@@ -258,14 +259,7 @@
                     Website = Data("links")("websiteUrl").ToString.TrimEnd("/")
                     Website = Data("links")("websiteUrl").ToString.TrimEnd("/")
                     LastUpdate = Data("dateReleased") '#1194
                     LastUpdate = Data("dateReleased") '#1194
                     DownloadCount = Data("downloadCount")
                     DownloadCount = Data("downloadCount")
-                    'Logo
-                    If Data("logo").Count > 0 Then
-                        If GetPixelSize(1) > 1.25 Then
-                            LogoUrl = Data("logo")("thumbnailUrl").ToString '使用 256x256 图标
-                        Else
-                            LogoUrl = Data("logo")("thumbnailUrl").ToString.Replace("/256/256/", "/64/64/") '使用 64x64 图标
-                        End If
-                    End If
+                    If Data("logo").Count > 0 Then LogoUrl = Data("logo")("thumbnailUrl")
                     'FileIndexes / GameVersions
                     'FileIndexes / GameVersions
                     Dim Files = If(CType(Data("latestFilesIndexes"), JArray), New JArray).
                     Dim Files = If(CType(Data("latestFilesIndexes"), JArray), New JArray).
                                 Where(Function(i) i("gameVersion").ToString.Contains("1."))
                                 Where(Function(i) i("gameVersion").ToString.Contains("1."))
@@ -371,6 +365,7 @@
                             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)
                         'Mod
                         'Mod
                             Case "worldgen" : Tags.Add("世界元素")
                             Case "worldgen" : Tags.Add("世界元素")
                             Case "technology" : Tags.Add("科技")
                             Case "technology" : Tags.Add("科技")
@@ -442,21 +437,34 @@
                 GameVersionDescription = "未知"
                 GameVersionDescription = "未知"
             Else
             Else
                 Dim SpaVersions As New List(Of String)
                 Dim SpaVersions As New List(Of String)
-                For i = 0 To GameVersions.Count - 1
+                Dim IsOld As Boolean = False
+                For i = 0 To GameVersions.Count - 1 '版本号一定为降序
+                    '获取当前连续的版本号段
                     Dim StartVersion As Integer = GameVersions(i), EndVersion As Integer = GameVersions(i)
                     Dim StartVersion As Integer = GameVersions(i), EndVersion As Integer = GameVersions(i)
-                    For ii = i + 1 To GameVersions.Count - 1
-                        If GameVersions(ii) = EndVersion - 1 Then
-                            EndVersion = GameVersions(ii)
-                            i = ii
-                        Else
+                    If StartVersion < 10 Then '如果支持新版本,则不显示 1.9-
+                        If SpaVersions.Any() AndAlso Not IsOld Then
                             Exit For
                             Exit For
+                        Else
+                            IsOld = True
                         End If
                         End If
+                    End If
+                    For ii = i + 1 To GameVersions.Count - 1
+                        If GameVersions(ii) <> EndVersion - 1 Then Exit For
+                        EndVersion = GameVersions(ii)
+                        i = ii
                     Next
                     Next
+                    '将版本号段转为描述文本
                     If StartVersion = EndVersion Then
                     If StartVersion = EndVersion Then
                         SpaVersions.Add("1." & StartVersion)
                         SpaVersions.Add("1." & StartVersion)
                     ElseIf McVersionHighest > -1 AndAlso StartVersion >= McVersionHighest Then
                     ElseIf McVersionHighest > -1 AndAlso StartVersion >= McVersionHighest Then
-                        SpaVersions.Add("1." & EndVersion & "+")
-                    ElseIf EndVersion <= 7 Then
+                        If EndVersion <= 10 Then
+                            SpaVersions.Clear()
+                            SpaVersions.Add("全版本")
+                            Exit For
+                        Else
+                            SpaVersions.Add("1." & EndVersion & "+")
+                        End If
+                    ElseIf EndVersion <= 10 Then
                         SpaVersions.Add("1." & StartVersion & "-")
                         SpaVersions.Add("1." & StartVersion & "-")
                         Exit For
                         Exit For
                     ElseIf StartVersion - EndVersion = 1 Then
                     ElseIf StartVersion - EndVersion = 1 Then
@@ -467,6 +475,28 @@
                 Next
                 Next
                 GameVersionDescription = SpaVersions.Join(", ")
                 GameVersionDescription = SpaVersions.Join(", ")
             End If
             End If
+            '获取 Mod 加载器描述
+            Dim ModLoaderDescriptionFull As String, ModLoaderDescriptionPart As String
+            Select Case ModLoaders.Count
+                Case 0
+                    ModLoaderDescriptionFull = "未知"
+                    ModLoaderDescriptionPart = ""
+                Case 1
+                    ModLoaderDescriptionFull = "仅 " & ModLoaders.Single.ToString
+                    ModLoaderDescriptionPart = ModLoaders.Single.ToString
+                Case 2, 3
+                    If Setup.Get("ToolDownloadIgnoreQuilt") AndAlso
+                       ModLoaders.Contains(CompModLoaderType.Forge) AndAlso ModLoaders.Contains(CompModLoaderType.Fabric) Then
+                        ModLoaderDescriptionFull = "任意"
+                        ModLoaderDescriptionPart = ""
+                    Else
+                        ModLoaderDescriptionFull = ModLoaders.Join(" / ")
+                        ModLoaderDescriptionPart = ModLoaders.Join(" / ")
+                    End If
+                Case Else
+                    ModLoaderDescriptionFull = "任意"
+                    ModLoaderDescriptionPart = ""
+            End Select
             '实例化 UI
             '实例化 UI
             Dim NewItem As New MyCompItem With {.Tag = Me, .Logo = GetControlLogo()}
             Dim NewItem As New MyCompItem With {.Tag = Me, .Logo = GetControlLogo()}
             Dim Title = GetControlTitle(True)
             Dim Title = GetControlTitle(True)
@@ -488,37 +518,13 @@
                 NewItem.ColumnVersion3.Width = New GridLength(0)
                 NewItem.ColumnVersion3.Width = New GridLength(0)
             ElseIf ShowMcVersionDesc AndAlso ShowMcVersionDesc Then
             ElseIf ShowMcVersionDesc AndAlso ShowMcVersionDesc Then
                 '全部显示
                 '全部显示
-                Dim ModLoaderDesc As String = If(ModLoaders.Count > 0 AndAlso ModLoaders.Count < 3 AndAlso
-                        Not (Type = CompType.Mod AndAlso Setup.Get("ToolDownloadIgnoreQuilt") AndAlso ModLoaders.Contains(CompModLoaderType.Forge) AndAlso ModLoaders.Contains(CompModLoaderType.Fabric)),
-                        ModLoaders.Join(" / ") & " ", "")
-                Dim VersionDesc As String = If(GameVersionDescription = "1.7+", "全版本", GameVersionDescription)
-                NewItem.LabVersion.Text = ModLoaderDesc & VersionDesc
+                NewItem.LabVersion.Text = If(ModLoaderDescriptionPart = "", "", ModLoaderDescriptionPart & " ") & GameVersionDescription
             ElseIf ShowMcVersionDesc Then
             ElseIf ShowMcVersionDesc Then
                 '仅显示版本
                 '仅显示版本
-                NewItem.LabVersion.Text = If(GameVersionDescription = "1.7+", "全版本", GameVersionDescription)
+                NewItem.LabVersion.Text = GameVersionDescription
             Else
             Else
                 '仅显示 Mod 加载器
                 '仅显示 Mod 加载器
-                Select Case ModLoaders.Count
-                    Case 0
-                        NewItem.LabVersion.Text = "未知"
-                    Case 1
-                        NewItem.LabVersion.Text = If(Type = CompType.Mod, "仅 ", "") & ModLoaders(0).ToString
-                    Case 2
-                        If Type = CompType.Mod Then
-                            NewItem.LabVersion.Text =
-                                If(Not (Setup.Get("ToolDownloadIgnoreQuilt") AndAlso
-                                ModLoaders.Contains(CompModLoaderType.Forge) AndAlso ModLoaders.Contains(CompModLoaderType.Fabric)),
-                                ModLoaders.Join(" / "), "任意")
-                        Else
-                            NewItem.LabVersion.Text = ModLoaders.Join(" / ")
-                        End If
-                    Case 3
-                        If Type = CompType.Mod Then
-                            NewItem.LabVersion.Text = "任意"
-                        Else
-                            NewItem.LabVersion.Text = ModLoaders.Join(" / ")
-                        End If
-                End Select
+                NewItem.LabVersion.Text = ModLoaderDescriptionFull
             End If
             End If
             NewItem.LabSource.Text = If(FromCurseForge, "CurseForge", "Modrinth")
             NewItem.LabSource.Text = If(FromCurseForge, "CurseForge", "Modrinth")
             If LastUpdate IsNot Nothing Then
             If LastUpdate IsNot Nothing Then
@@ -1255,6 +1261,7 @@ Retry:
                 If RawVersions.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge)
                 If RawVersions.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge)
                 If RawVersions.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric)
                 If RawVersions.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric)
                 If RawVersions.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
                 If RawVersions.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt)
+                If RawVersions.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge)
 #End Region
 #End Region
             Else
             Else
 #Region "Modrinth"
 #Region "Modrinth"

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

@@ -625,7 +625,7 @@
                     Dim ReleaseDate As New Date(ReleaseTimeSplit(0), ReleaseTimeSplit(1), ReleaseTimeSplit(2), '年月日
                     Dim ReleaseDate As New Date(ReleaseTimeSplit(0), ReleaseTimeSplit(1), ReleaseTimeSplit(2), '年月日
                                                 ReleaseTimeSplit(3), ReleaseTimeSplit(4), ReleaseTimeSplit(5), '时分秒
                                                 ReleaseTimeSplit(3), ReleaseTimeSplit(4), ReleaseTimeSplit(5), '时分秒
                                                 0, DateTimeKind.Utc) '以 UTC 时间作为标准
                                                 0, DateTimeKind.Utc) '以 UTC 时间作为标准
-                    Dim ReleaseTime As String = ReleaseDate.ToLocalTime.ToString("yyyy/MM/dd HH:mm") '时区与格式转换
+                    Dim ReleaseTime As String = ReleaseDate.ToLocalTime.ToString("yyyy'/'MM'/'dd HH':'mm") '时区与格式转换
                     '分类与 MD5 获取
                     '分类与 MD5 获取
                     Dim MD5 As String, Category As String
                     Dim MD5 As String, Category As String
                     If VersionCode.Contains("classifier-installer""") Then
                     If VersionCode.Contains("classifier-installer""") Then
@@ -706,7 +706,7 @@
                 '基础信息获取
                 '基础信息获取
                 Dim Entry = New DlForgeVersionEntry With {.Hash = Hash, .Category = Category, .Version = Name, .Branch = Branch, .Inherit = Inherit, .IsRecommended = Recommended = Name}
                 Dim Entry = New DlForgeVersionEntry With {.Hash = Hash, .Category = Category, .Version = Name, .Branch = Branch, .Inherit = Inherit, .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
@@ -812,7 +812,7 @@
                              .IsPreview = RealEntry("stream").ToString.ToLower = "snapshot",
                              .IsPreview = RealEntry("stream").ToString.ToLower = "snapshot",
                              .FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar",
                              .FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar",
                              .MD5 = RealEntry("md5"),
                              .MD5 = RealEntry("md5"),
-                             .ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy/MM/dd HH:mm"),
+                             .ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy'/'MM'/'dd HH':'mm"),
                              .JsonToken = RealEntry
                              .JsonToken = RealEntry
                          })
                          })
             Next
             Next
@@ -841,7 +841,7 @@
                              .IsPreview = RealEntry("stream").ToString.ToLower = "snapshot",
                              .IsPreview = RealEntry("stream").ToString.ToLower = "snapshot",
                              .FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar",
                              .FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar",
                              .MD5 = RealEntry("md5"),
                              .MD5 = RealEntry("md5"),
-                             .ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy/MM/dd HH:mm"),
+                             .ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy'/'MM'/'dd HH':'mm"),
                              .JsonToken = RealEntry
                              .JsonToken = RealEntry
                          })
                          })
             Next
             Next

+ 17 - 56
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb

@@ -435,13 +435,7 @@ NextInner:
             Case McLoginType.Ms
             Case McLoginType.Ms
                 Loader = McLoginMsLoader
                 Loader = McLoginMsLoader
             Case McLoginType.Legacy
             Case McLoginType.Legacy
-                If PageLinkHiper.HiperState = LoadState.Finished Then
-                    '使用 HiPer 内网验证
-                    Loader = McLoginHiperLoader
-                Else
-                    '默认的离线验证
-                    Loader = McLoginLegacyLoader
-                End If
+                Loader = McLoginLegacyLoader
             Case McLoginType.Nide
             Case McLoginType.Nide
                 Loader = McLoginNideLoader
                 Loader = McLoginNideLoader
             Case McLoginType.Auth
             Case McLoginType.Auth
@@ -462,7 +456,6 @@ NextInner:
     Public McLoginLegacyLoader As New LoaderTask(Of McLoginLegacy, McLoginResult)("Loader Login Legacy", AddressOf McLoginLegacyStart)
     Public McLoginLegacyLoader As New LoaderTask(Of McLoginLegacy, McLoginResult)("Loader Login Legacy", AddressOf McLoginLegacyStart)
     Public McLoginNideLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Nide", AddressOf McLoginServerStart) With {.ReloadTimeout = 60000}
     Public McLoginNideLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Nide", AddressOf McLoginServerStart) With {.ReloadTimeout = 60000}
     Public McLoginAuthLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Auth", AddressOf McLoginServerStart) With {.ReloadTimeout = 60000}
     Public McLoginAuthLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Auth", AddressOf McLoginServerStart) With {.ReloadTimeout = 60000}
-    Public McLoginHiperLoader As New LoaderTask(Of McLoginLegacy, McLoginResult)("Loader Login HiPer", AddressOf McLoginHiperStart) With {.ReloadTimeout = 60000}
 
 
     '主加载函数,返回所有需要的登录信息
     '主加载函数,返回所有需要的登录信息
     Private Sub McLoginMsStart(Data As LoaderTask(Of McLoginMs, McLoginResult))
     Private Sub McLoginMsStart(Data As LoaderTask(Of McLoginMs, McLoginResult))
@@ -615,45 +608,6 @@ LoginFinish:
         Names.Insert(0, Input.UserName)
         Names.Insert(0, Input.UserName)
         Setup.Set("LoginLegacyName", Join(Names.ToArray, "¨"))
         Setup.Set("LoginLegacyName", Join(Names.ToArray, "¨"))
     End Sub
     End Sub
-    Private Sub McLoginHiperStart(Data As LoaderTask(Of McLoginLegacy, McLoginResult))
-        Dim Input As McLoginLegacy = Data.Input
-        McLaunchLog("登录方式:联机离线(" & Input.UserName & ")")
-        Data.Progress = 0.05
-        '尝试登录
-        Try
-            McLaunchLog("登录开始(Login, HiPer)")
-            Dim LoginJson As JObject = GetJson(NetRequestRetry(
-                   Url:="http://hiperauth.tech/api/yggdrasil-hiper/authserver/authenticate",
-                   Method:="POST",
-                   Data:="{""agent"": {""name"": ""Minecraft"",""version"": 1},""username"":""" & Data.Input.UserName & """,""password"":""" &
-                         McLoginLegacyUuidWithCustomSkin(Input.UserName, Input.SkinType, Input.SkinName) & """,""requestUser"":true}",
-                   ContentType:="application/json; charset=utf-8"))
-            '将登录结果输出
-            Data.Output.AccessToken = LoginJson("accessToken").ToString
-            Data.Output.ClientToken = LoginJson("clientToken").ToString
-            Data.Output.Name = LoginJson("selectedProfile")("name").ToString
-            Data.Output.Uuid = LoginJson("selectedProfile")("id").ToString
-            Data.Output.Type = "Auth"
-            McLaunchLog("登录成功(Login, HiPer)")
-            '保存启动记录
-            Dim Names As New List(Of String)
-            If Not Setup.Get("LoginLegacyName") = "" Then Names.AddRange(Setup.Get("LoginLegacyName").ToString.Split("¨"))
-            Names.Remove(Input.UserName)
-            Names.Insert(0, Input.UserName)
-            Setup.Set("LoginLegacyName", Join(Names.ToArray, "¨"))
-        Catch ex As Exception
-            Dim AllMessage As String = GetExceptionSummary(ex)
-            Log(ex, "登录失败原始错误信息", LogLevel.Normal)
-            Dim ThrowEx As Exception = ex
-            If AllMessage.Contains("403") Then
-                ThrowEx = New Exception("登录尝试过于频繁,导致被系统暂时屏蔽。请不要操作,等待 10 分钟后再试。", ex)
-            ElseIf AllMessage.Contains("超时") OrElse AllMessage.Contains("imeout") OrElse AllMessage.Contains("网络请求失败") Then
-                ThrowEx = New Exception("$登录失败:连接登录服务器超时。" & vbCrLf & "请检查 HiPer 联机模块的连接状况是否良好,或选择其他登录方式!")
-            End If
-            McLaunchLog("登录失败:" & GetExceptionSummary(ThrowEx))
-            Throw ThrowEx
-        End Try
-    End Sub
 
 
     'Server 登录:三种验证方式的请求
     'Server 登录:三种验证方式的请求
     Private Sub McLoginRequestValidate(ByRef Data As LoaderTask(Of McLoginServer, McLoginResult))
     Private Sub McLoginRequestValidate(ByRef Data As LoaderTask(Of McLoginServer, McLoginResult))
@@ -664,11 +618,13 @@ LoginFinish:
         Dim Uuid As String = Setup.Get("Cache" & Data.Input.Token & "Uuid")
         Dim Uuid As String = Setup.Get("Cache" & Data.Input.Token & "Uuid")
         Dim Name As String = Setup.Get("Cache" & Data.Input.Token & "Name")
         Dim Name As String = Setup.Get("Cache" & Data.Input.Token & "Name")
         '发送登录请求
         '发送登录请求
+        Dim RequestData As New JObject(
+            New JProperty("accessToken", AccessToken), New JProperty("clientToken", ClientToken), New JProperty("requestUser", True))
         NetRequestRetry(
         NetRequestRetry(
-               Url:=Data.Input.BaseUrl & "/validate",
-               Method:="POST",
-               Data:="{""accessToken"":""" & AccessToken & """,""clientToken"":""" & ClientToken & """,""requestUser"":true}",
-               ContentType:="application/json; charset=utf-8") '没有返回值的
+            Url:=Data.Input.BaseUrl & "/validate",
+            Method:="POST",
+            Data:=RequestData.ToString(0),
+            ContentType:="application/json; charset=utf-8") '没有返回值的
         '将登录结果输出
         '将登录结果输出
         Data.Output.AccessToken = AccessToken
         Data.Output.AccessToken = AccessToken
         Data.Output.ClientToken = ClientToken
         Data.Output.ClientToken = ClientToken
@@ -712,11 +668,16 @@ LoginFinish:
         Try
         Try
             Dim NeedRefresh As Boolean = False
             Dim NeedRefresh As Boolean = False
             McLaunchLog("登录开始(Login, " & Data.Input.Token & ")")
             McLaunchLog("登录开始(Login, " & Data.Input.Token & ")")
+            Dim RequestData As New JObject(
+                New JProperty("agent", New JObject(New JProperty("name", "Minecraft"), New JProperty("version", 1))),
+                New JProperty("username", Data.Input.UserName),
+                New JProperty("password", Data.Input.Password),
+                New JProperty("requestUser", True))
             Dim LoginJson As JObject = GetJson(NetRequestRetry(
             Dim LoginJson As JObject = GetJson(NetRequestRetry(
-                   Url:=Data.Input.BaseUrl & "/authenticate",
-                   Method:="POST",
-                   Data:="{""agent"": {""name"": ""Minecraft"",""version"": 1},""username"":""" & Data.Input.UserName & """,""password"":""" & Data.Input.Password & """,""requestUser"":true}",
-                   ContentType:="application/json; charset=utf-8"))
+                Url:=Data.Input.BaseUrl & "/authenticate",
+                Method:="POST",
+                Data:=RequestData.ToString(0),
+                ContentType:="application/json; charset=utf-8"))
             '检查登录结果
             '检查登录结果
             If LoginJson("availableProfiles").Count = 0 Then
             If LoginJson("availableProfiles").Count = 0 Then
                 If Data.Input.ForceReselectProfile Then Hint("你还没有创建角色,无法更换!", HintType.Critical)
                 If Data.Input.ForceReselectProfile Then Hint("你还没有创建角色,无法更换!", HintType.Critical)
@@ -964,7 +925,7 @@ SystemBrowser:
     Private Function MsLoginStep5(Tokens As String()) As String
     Private Function MsLoginStep5(Tokens As String()) As String
         McLaunchLog("开始微软登录步骤 5")
         McLaunchLog("开始微软登录步骤 5")
 
 
-        Dim Request As String = "{""identityToken"": ""XBL3.0 x=" & Tokens(1) & ";" & Tokens(0) & """}"
+        Dim Request As String = New JObject(New JProperty("identityToken", $"XBL3.0 x={Tokens(1)};{Tokens(0)}")).ToString(0)
         Dim Result As String
         Dim Result As String
         Try
         Try
             Result = NetRequestMulty("https://api.minecraftservices.com/authentication/login_with_xbox", "POST", Request, "application/json", 2)
             Result = NetRequestMulty("https://api.minecraftservices.com/authentication/login_with_xbox", "POST", Request, "application/json", 2)

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

@@ -128,7 +128,7 @@
             ""name"": ""PCL"",
             ""name"": ""PCL"",
             ""lastVersionId"": ""latest-release"",
             ""lastVersionId"": ""latest-release"",
             ""type"": ""latest-release"",
             ""type"": ""latest-release"",
-            ""lastUsed"": """ & Date.Now.ToString("yyyy-MM-dd") & "T" & Date.Now.ToString("HH:mm:ss") & ".0000Z""
+            ""lastUsed"": """ & Date.Now.ToString("yyyy'-'MM'-'dd") & "T" & Date.Now.ToString("HH':'mm':'ss") & ".0000Z""
         }
         }
     },
     },
     ""selectedProfile"": ""PCL"",
     ""selectedProfile"": ""PCL"",
@@ -779,7 +779,7 @@ ExitDataLoad:
                     WriteIni(Path & "PCL\Setup.ini", "Logo", Logo)
                     WriteIni(Path & "PCL\Setup.ini", "Logo", Logo)
                 End If
                 End If
                 If State <> McVersionState.Error Then
                 If State <> McVersionState.Error Then
-                    WriteIni(Path & "PCL\Setup.ini", "ReleaseTime", ReleaseTime.ToString("yyyy-MM-dd HH:mm:ss"))
+                    WriteIni(Path & "PCL\Setup.ini", "ReleaseTime", ReleaseTime.ToString("yyyy'-'MM'-'dd HH':'mm"))
                     WriteIni(Path & "PCL\Setup.ini", "VersionFabric", Version.FabricVersion)
                     WriteIni(Path & "PCL\Setup.ini", "VersionFabric", Version.FabricVersion)
                     WriteIni(Path & "PCL\Setup.ini", "VersionOptiFine", Version.OptiFineVersion)
                     WriteIni(Path & "PCL\Setup.ini", "VersionOptiFine", Version.OptiFineVersion)
                     WriteIni(Path & "PCL\Setup.ini", "VersionLiteLoader", Version.HasLiteLoader)
                     WriteIni(Path & "PCL\Setup.ini", "VersionLiteLoader", Version.HasLiteLoader)
@@ -1613,13 +1613,13 @@ NextVersion:
         End Property
         End Property
         Private _Url As String
         Private _Url As String
         ''' <summary>
         ''' <summary>
-        ''' 原 Json 中 Name 项除去最后一部分版本号的较前部分。可能为 Nothing。
+        ''' 原 Json 中 Name 项除去版本号部分的较前部分。可能为 Nothing。
         ''' </summary>
         ''' </summary>
         Public ReadOnly Property Name As String
         Public ReadOnly Property Name As String
             Get
             Get
                 If OriginalName Is Nothing Then Return Nothing
                 If OriginalName Is Nothing Then Return Nothing
                 Dim Splited As New List(Of String)(OriginalName.Split(":"))
                 Dim Splited As New List(Of String)(OriginalName.Split(":"))
-                Splited.RemoveAt(Splited.Count - 1)
+                Splited.RemoveAt(2) 'Java 的此格式下版本号固定为第三段,第四段可能包含架构、分包等其他信息
                 Return Join(Splited, ":")
                 Return Join(Splited, ":")
             End Get
             End Get
         End Property
         End Property
@@ -1678,7 +1678,7 @@ NextVersion:
             End If
             End If
             If Not IsNothing(Rule("features")) Then '标签
             If Not IsNothing(Rule("features")) Then '标签
                 IsRightRule = IsRightRule AndAlso IsNothing(Rule("features")("is_demo_user")) '反选是否为 Demo 用户
                 IsRightRule = IsRightRule AndAlso IsNothing(Rule("features")("is_demo_user")) '反选是否为 Demo 用户
-                If CType(Rule("features"), JObject).Children.Any(Function(j As JProperty) j.Name.StartsWith("is_quick_play")) Then
+                If CType(Rule("features"), JObject).Children.Any(Function(j As JProperty) j.Name.Contains("quick_play")) Then
                     IsRightRule = False '不开 Quick Play,让玩家自己加去
                     IsRightRule = False '不开 Quick Play,让玩家自己加去
                 End If
                 End If
             End If
             End If
@@ -1788,8 +1788,7 @@ NextVersion:
             End If
             End If
 
 
             '根据是否本地化处理(Natives)
             '根据是否本地化处理(Natives)
-            If Library("natives") Is Nothing Then
-                '没有 Natives
+            If Library("natives") Is Nothing Then '没有 Natives
                 Dim LocalPath As String
                 Dim LocalPath As String
                 If IsJumpLoader Then
                 If IsJumpLoader Then
                     LocalPath = McLibGet(Library("name"), CustomMcFolder:=If(JumpLoaderFolder, CustomMcFolder))
                     LocalPath = McLibGet(Library("name"), CustomMcFolder:=If(JumpLoaderFolder, CustomMcFolder))
@@ -1813,29 +1812,26 @@ NextVersion:
                     Log(ex, "处理实际支持库列表失败(无 Natives," & If(Library("name"), "Nothing").ToString & ")")
                     Log(ex, "处理实际支持库列表失败(无 Natives," & If(Library("name"), "Nothing").ToString & ")")
                     BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing})
                     BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing})
                 End Try
                 End Try
-            Else
-                '有 Natives
-                If Library("natives")("windows") IsNot Nothing Then
-                    Try
-                        If Library("downloads") IsNot Nothing AndAlso Library("downloads")("classifiers") IsNot Nothing AndAlso Library("downloads")("classifiers")("natives-windows") IsNot Nothing Then
-                            BasicArray.Add(New McLibToken With {
-                                                       .IsJumpLoader = IsJumpLoader,
-                                                       .OriginalName = Library("name"),
-                                                       .Url = If(RootUrl, Library("downloads")("classifiers")("natives-windows")("url")),
-                                                       .LocalPath = If(Library("downloads")("classifiers")("natives-windows")("path") Is Nothing,
-                                                           McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")),
-                                                           CustomMcFolder & "libraries\" & Library("downloads")("classifiers")("natives-windows")("path").ToString.Replace("/", "\")),
-                                                       .Size = Val(Library("downloads")("classifiers")("natives-windows")("size").ToString),
-                                                       .IsNatives = True,
-                                                       .SHA1 = Library("downloads")("classifiers")("natives-windows")("sha1").ToString})
-                        Else
-                            BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")), .Size = 0, .IsNatives = True, .SHA1 = Nothing})
-                        End If
-                    Catch ex As Exception
-                        Log(ex, "处理实际支持库列表失败(有 Natives," & If(Library("name"), "Nothing").ToString & ")")
+            ElseIf Library("natives")("windows") IsNot Nothing Then '有 Windows Natives
+                Try
+                    If Library("downloads") IsNot Nothing AndAlso Library("downloads")("classifiers") IsNot Nothing AndAlso Library("downloads")("classifiers")("natives-windows") IsNot Nothing Then
+                        BasicArray.Add(New McLibToken With {
+                             .IsJumpLoader = IsJumpLoader,
+                             .OriginalName = Library("name"),
+                             .Url = If(RootUrl, Library("downloads")("classifiers")("natives-windows")("url")),
+                             .LocalPath = If(Library("downloads")("classifiers")("natives-windows")("path") Is Nothing,
+                                 McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")),
+                                 CustomMcFolder & "libraries\" & Library("downloads")("classifiers")("natives-windows")("path").ToString.Replace("/", "\")),
+                             .Size = Val(Library("downloads")("classifiers")("natives-windows")("size").ToString),
+                             .IsNatives = True,
+                             .SHA1 = Library("downloads")("classifiers")("natives-windows")("sha1").ToString})
+                    Else
                         BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")), .Size = 0, .IsNatives = True, .SHA1 = Nothing})
                         BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")), .Size = 0, .IsNatives = True, .SHA1 = Nothing})
-                    End Try
-                End If
+                    End If
+                Catch ex As Exception
+                    Log(ex, "处理实际支持库列表失败(有 Natives," & If(Library("name"), "Nothing").ToString & ")")
+                    BasicArray.Add(New McLibToken With {.IsJumpLoader = IsJumpLoader, .OriginalName = Library("name"), .Url = RootUrl, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder).Replace(".jar", "-" & Library("natives")("windows").ToString & ".jar").Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")), .Size = 0, .IsNatives = True, .SHA1 = Nothing})
+                End Try
             End If
             End If
 
 
         Next
         Next
@@ -1845,17 +1841,19 @@ NextVersion:
         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 OrElse BasicArray(i).Version.Contains("natives-windows")) Then
-                    'Contains("natives-windows") 源于 1.19-Pre1 开始,lwjgl-3.3.1-natives-windows 与 lwjgl-3.3.1-natives-windows-x86 重复
+                If BasicArray(i).Version <> ResultArray(Key).Version AndAlso KeepSameNameDifferentVersionResult Then
+                    Log($"[Minecraft] 发现疑似重复的支持库:{BasicArray(i)} 与 {ResultArray(Key)}")
                     ResultArray.Add(Key & GetUuid(), BasicArray(i))
                     ResultArray.Add(Key & GetUuid(), BasicArray(i))
-                ElseIf VersionSortBoolean(BasicArray(i).Version, ResultArray(Key).Version) Then
-                    ResultArray(Key) = BasicArray(i)
+                Else
+                    Log($"[Minecraft] 发现重复的支持库:{BasicArray(i)} 与 {ResultArray(Key)},已忽略其中之一")
+                    If VersionSortBoolean(BasicArray(i).Version, ResultArray(Key).Version) Then
+                        ResultArray(Key) = BasicArray(i)
+                    End If
                 End If
                 End If
             Else
             Else
                 ResultArray.Add(Key, BasicArray(i))
                 ResultArray.Add(Key, BasicArray(i))
             End If
             End If
-        Next i
+        Next
         Return ResultArray.Values.ToList
         Return ResultArray.Values.ToList
     End Function
     End Function
 
 
@@ -2043,14 +2041,13 @@ NextVersion:
             '    Return GetJson("{""id"": """ & AssetsName & """}")
             '    Return GetJson("{""id"": """ & AssetsName & """}")
             'Else
             'Else
             Log("[Minecraft] 无法获取资源文件索引下载地址,使用默认的 legacy 下载地址")
             Log("[Minecraft] 无法获取资源文件索引下载地址,使用默认的 legacy 下载地址")
-            Return GetJson("
-                    {
-                        ""id"": ""legacy"",
-                        ""sha1"": ""c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729"",
-                        ""size"": 134284,
-                        ""url"": ""https://launchermeta.mojang.com/mc-staging/assets/legacy/c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729/legacy.json"",
-                        ""totalSize"": 111220701
-                    }")
+            Return GetJson("{
+                ""id"": ""legacy"",
+                ""sha1"": ""c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729"",
+                ""size"": 134284,
+                ""url"": ""https://launchermeta.mojang.com/mc-staging/assets/legacy/c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729/legacy.json"",
+                ""totalSize"": 111220701
+            }")
             'End If
             'End If
         Else
         Else
             Throw New Exception("该版本不存在资源文件索引信息")
             Throw New Exception("该版本不存在资源文件索引信息")

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

@@ -943,7 +943,7 @@ VersionFindFail:
                     Dim Project As New CompProject(ProjectJson)
                     Dim Project As New CompProject(ProjectJson)
                     For Each Entry In ModrinthMapping(Project.Id)
                     For Each Entry In ModrinthMapping(Project.Id)
                         If Entry.Comp IsNot Nothing AndAlso Not Entry.IsCompFromModrinth Then
                         If Entry.Comp IsNot Nothing AndAlso Not Entry.IsCompFromModrinth Then
-                            Project.LogoUrl = Entry.Comp.LogoUrl 'Modrinth 部分 Logo 加载不出来
+                            Project.LogoUrl = Entry.Comp.LogoUrl 'Modrinth 的部分 Logo 加载不出来
                         End If
                         End If
                         Entry.IsCompFromModrinth = True
                         Entry.IsCompFromModrinth = True
                         Entry.Comp = Project
                         Entry.Comp = Project
@@ -992,6 +992,7 @@ VersionFindFail:
                 Dim CurseForgeProject = CType(GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods", "POST",
                 Dim CurseForgeProject = CType(GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods", "POST",
                                     $"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")), JObject)("data")
                                     $"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")), JObject)("data")
                 For Each ProjectJson In CurseForgeProject
                 For Each ProjectJson In CurseForgeProject
+                    If Not ProjectJson("isAvailable").ToObject(Of Boolean) Then Continue For
                     Dim Project As New CompProject(ProjectJson)
                     Dim Project As New CompProject(ProjectJson)
                     For Each Entry In CurseForgeMapping(Project.Id) '倒查防止 CurseForge 返回的内容有漏
                     For Each Entry In CurseForgeMapping(Project.Id) '倒查防止 CurseForge 返回的内容有漏
                         If Entry.Comp IsNot Nothing AndAlso Entry.IsCompFromModrinth Then
                         If Entry.Comp IsNot Nothing AndAlso Entry.IsCompFromModrinth Then

+ 27 - 20
Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml.vb

@@ -46,34 +46,41 @@
         End Set
         End Set
     End Property
     End Property
     '后台加载 Logo
     '后台加载 Logo
-    Private Sub LogoLoader(Address As String)
-        Dim Retry As Boolean = False
+    Private Sub LogoLoader(LocalFileAddress As String)
+        Dim Retried As Boolean = False
         Dim DownloadEnd As String = GetUuid()
         Dim DownloadEnd As String = GetUuid()
 RetryStart:
 RetryStart:
         Try
         Try
-            NetDownload(_Logo, Address & DownloadEnd)
+            'CurseForge 图片使用缩略图
+            Dim Url As String = _Logo
+            If Url.Contains("/256/256/") AndAlso GetPixelSize(1) <= 1.25 AndAlso Not Retried Then
+                Url = Url.Replace("/256/256/", "/64/64/") '#3075:部分 Mod 不存在 64x64 图标,所以重试时不再缩小
+            End If
+            '下载图片
+            NetDownload(Url, LocalFileAddress & DownloadEnd)
             Dim LoadError As Exception = Nothing
             Dim LoadError As Exception = Nothing
-            RunInUiWait(Sub()
-                            Try
-                                '在地址更换时取消加载
-                                If Not Address = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png" Then Exit Sub
-                                '在完成正常加载后才保存缓存图片
-                                PathLogo.Source = New MyBitmap(Address & DownloadEnd)
-                            Catch ex As Exception
-                                Log(ex, "读取资源工程图标失败(" & Address & ")")
-                                File.Delete(Address & DownloadEnd)
-                                LoadError = ex
-                            End Try
-                        End Sub)
+            RunInUiWait(
+            Sub()
+                Try
+                    '在地址更换时取消加载
+                    If LocalFileAddress <> $"{PathTemp}CompLogo\{GetHash(_Logo)}.png" Then Exit Sub
+                    '在完成正常加载后才保存缓存图片
+                    PathLogo.Source = New MyBitmap(LocalFileAddress & DownloadEnd)
+                Catch ex As Exception
+                    Log(ex, $"读取资源工程图标失败({LocalFileAddress})")
+                    File.Delete(LocalFileAddress & DownloadEnd)
+                    LoadError = ex
+                End Try
+            End Sub)
             If LoadError IsNot Nothing Then Throw LoadError
             If LoadError IsNot Nothing Then Throw LoadError
-            If File.Exists(Address) Then
-                File.Delete(Address & DownloadEnd)
+            If File.Exists(LocalFileAddress) Then
+                File.Delete(LocalFileAddress & DownloadEnd)
             Else
             Else
-                FileIO.FileSystem.MoveFile(Address & DownloadEnd, Address)
+                FileIO.FileSystem.MoveFile(LocalFileAddress & DownloadEnd, LocalFileAddress)
             End If
             End If
         Catch ex As Exception
         Catch ex As Exception
-            If Not Retry Then
-                Retry = True
+            If Not Retried Then
+                Retried = True
                 GoTo RetryStart
                 GoTo RetryStart
             Else
             Else
                 Log(ex, $"下载资源工程图标失败({_Logo})")
                 Log(ex, $"下载资源工程图标失败({_Logo})")

+ 27 - 20
Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb

@@ -48,34 +48,41 @@ Public Class MyLocalModItem
         End Set
         End Set
     End Property
     End Property
     '后台加载 Logo
     '后台加载 Logo
-    Private Sub LogoLoader(Address As String)
-        Dim Retry As Boolean = False
+    Private Sub LogoLoader(LocalFileAddress As String)
+        Dim Retried As Boolean = False
         Dim DownloadEnd As String = GetUuid()
         Dim DownloadEnd As String = GetUuid()
 RetryStart:
 RetryStart:
         Try
         Try
-            NetDownload(_Logo, Address & DownloadEnd)
+            'CurseForge 图片使用缩略图
+            Dim Url As String = _Logo
+            If Url.Contains("/256/256/") AndAlso GetPixelSize(1) <= 1.25 AndAlso Not Retried Then
+                Url = Url.Replace("/256/256/", "/64/64/") '#3075:部分 Mod 不存在 64x64 图标,所以重试时不再缩小
+            End If
+            '下载图片
+            NetDownload(Url, LocalFileAddress & DownloadEnd)
             Dim LoadError As Exception = Nothing
             Dim LoadError As Exception = Nothing
-            RunInUiWait(Sub()
-                            Try
-                                '在地址更换时取消加载
-                                If Not Address = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png" Then Exit Sub
-                                '在完成正常加载后才保存缓存图片
-                                PathLogo.Source = New MyBitmap(Address & DownloadEnd)
-                            Catch ex As Exception
-                                Log(ex, "读取本地 Mod 图标失败(" & Address & ")")
-                                File.Delete(Address & DownloadEnd)
-                                LoadError = ex
-                            End Try
-                        End Sub)
+            RunInUiWait(
+            Sub()
+                Try
+                    '在地址更换时取消加载
+                    If LocalFileAddress <> $"{PathTemp}CompLogo\{GetHash(_Logo)}.png" Then Exit Sub
+                    '在完成正常加载后才保存缓存图片
+                    PathLogo.Source = New MyBitmap(LocalFileAddress & DownloadEnd)
+                Catch ex As Exception
+                    Log(ex, "读取本地 Mod 图标失败(" & LocalFileAddress & ")")
+                    File.Delete(LocalFileAddress & DownloadEnd)
+                    LoadError = ex
+                End Try
+            End Sub)
             If LoadError IsNot Nothing Then Throw LoadError
             If LoadError IsNot Nothing Then Throw LoadError
-            If File.Exists(Address) Then
-                File.Delete(Address & DownloadEnd)
+            If File.Exists(LocalFileAddress) Then
+                File.Delete(LocalFileAddress & DownloadEnd)
             Else
             Else
-                FileIO.FileSystem.MoveFile(Address & DownloadEnd, Address)
+                FileIO.FileSystem.MoveFile(LocalFileAddress & DownloadEnd, LocalFileAddress)
             End If
             End If
         Catch ex As Exception
         Catch ex As Exception
-            If Not Retry Then
-                Retry = True
+            If Not Retried Then
+                Retried = True
                 GoTo RetryStart
                 GoTo RetryStart
             Else
             Else
                 Log(ex, $"下载本地 Mod 图标失败({_Logo})")
                 Log(ex, $"下载本地 Mod 图标失败({_Logo})")

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

@@ -12,7 +12,7 @@ Imports System.Runtime.InteropServices
 <Assembly: AssemblyDescription("Minecraft 启动器 (制作:龙腾猫跃)")>
 <Assembly: AssemblyDescription("Minecraft 启动器 (制作:龙腾猫跃)")>
 <Assembly: AssemblyCompany("")>
 <Assembly: AssemblyCompany("")>
 <Assembly: AssemblyProduct("Plain Craft Launcher 2")>
 <Assembly: AssemblyProduct("Plain Craft Launcher 2")>
-<Assembly: AssemblyCopyright("Copyright © 龙腾猫跃 2016-2023. All Rights Reserved.")>
+<Assembly: AssemblyCopyright("Copyright © 龙腾猫跃 2016-2024. All Rights Reserved.")>
 <Assembly: AssemblyConfiguration("PCL2 Config Mark")>
 <Assembly: AssemblyConfiguration("PCL2 Config Mark")>
 <Assembly: ComVisible(False)>
 <Assembly: ComVisible(False)>
 
 
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
 ' 方法是按如下所示使用“*”
 ' 方法是按如下所示使用“*”
 
 
-<Assembly: AssemblyVersion("2.6.12.0")>
-<Assembly: AssemblyFileVersion("2.6.12.0")>
+<Assembly: AssemblyVersion("2.6.13.0")>
+<Assembly: AssemblyFileVersion("2.6.13.0")>
 <Assembly: NeutralResourcesLanguage("")>
 <Assembly: NeutralResourcesLanguage("")>

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

@@ -192,7 +192,7 @@ Public Module ModDownloadLib
         '建立控件
         '建立控件
         Dim NewItem As New MyListItem With {.Logo = Logo, .SnapsToDevicePixels = True, .Title = Entry("id").ToString, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry}
         Dim NewItem As New MyListItem With {.Logo = Logo, .SnapsToDevicePixels = True, .Title = Entry("id").ToString, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry}
         If Entry("lore") Is Nothing Then
         If Entry("lore") Is Nothing Then
-            NewItem.Info = Entry("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
+            NewItem.Info = Entry("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
         Else
         Else
             NewItem.Info = Entry("lore").ToString
             NewItem.Info = Entry("lore").ToString
         End If
         End If
@@ -632,8 +632,8 @@ Retry:
                     Dim Json As String = "{
                     Dim Json As String = "{
     ""id"": """ & Id & """,
     ""id"": """ & Id & """,
     ""inheritsFrom"": """ & DownloadInfo.Inherit & """,
     ""inheritsFrom"": """ & DownloadInfo.Inherit & """,
-    ""time"": """ & If(DownloadInfo.ReleaseTime = "", InheritVersion.ReleaseTime.ToString("yyyy-MM-dd"), DownloadInfo.ReleaseTime.Replace("/", "-")) & "T23:33:33+08:00"",
-    ""releaseTime"": """ & If(DownloadInfo.ReleaseTime = "", InheritVersion.ReleaseTime.ToString("yyyy-MM-dd"), DownloadInfo.ReleaseTime.Replace("/", "-")) & "T23:33:33+08:00"",
+    ""time"": """ & If(DownloadInfo.ReleaseTime = "", InheritVersion.ReleaseTime.ToString("yyyy'-'MM'-'dd"), DownloadInfo.ReleaseTime.Replace("/", "-")) & "T23:33:33+08:00"",
+    ""releaseTime"": """ & If(DownloadInfo.ReleaseTime = "", InheritVersion.ReleaseTime.ToString("yyyy'-'MM'-'dd"), DownloadInfo.ReleaseTime.Replace("/", "-")) & "T23:33:33+08:00"",
     ""type"": ""release"",
     ""type"": ""release"",
     ""libraries"": [
     ""libraries"": [
         {""name"": ""optifine:OptiFine:" & DownloadInfo.NameFile.Replace("OptiFine_", "").Replace(".jar", "").Replace("preview_", "") & """},
         {""name"": ""optifine:OptiFine:" & DownloadInfo.NameFile.Replace("OptiFine_", "").Replace(".jar", "").Replace("preview_", "") & """},
@@ -900,42 +900,41 @@ Retry:
 
 
         '启动依赖版本的下载
         '启动依赖版本的下载
         If ClientDownloadLoader Is Nothing Then
         If ClientDownloadLoader Is Nothing Then
-            Loaders.Add(New LoaderTask(Of String, String)(
-                    "启动 LiteLoader 依赖版本下载",
-                    Sub()
-                        If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
-                        ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, DownloadInfo.Inherit)
-                    End Sub) With {.ProgressWeight = 0.2, .Show = False, .Block = False})
+            Loaders.Add(New LoaderTask(Of String, String)("启动 LiteLoader 依赖版本下载",
+            Sub()
+                If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
+                ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, DownloadInfo.Inherit)
+            End Sub) With {.ProgressWeight = 0.2, .Show = False, .Block = False})
         End If
         End If
         '安装
         '安装
         Loaders.Add(New LoaderTask(Of String, String)("安装 LiteLoader",
         Loaders.Add(New LoaderTask(Of String, String)("安装 LiteLoader",
-                                                            Sub(Task As LoaderTask(Of String, String))
-                                                                Try
-                                                                    '新建版本文件夹
-                                                                    Directory.CreateDirectory(VersionFolder)
-                                                                    '构造版本 Json
-                                                                    Dim VersionJson As New JObject
-                                                                    VersionJson.Add("id", VersionName)
-                                                                    VersionJson.Add("time", Date.ParseExact(DownloadInfo.ReleaseTime, "yyyy/MM/dd HH:mm", Globalization.CultureInfo.CurrentCulture))
-                                                                    VersionJson.Add("releaseTime", Date.ParseExact(DownloadInfo.ReleaseTime, "yyyy/MM/dd HH:mm", Globalization.CultureInfo.CurrentCulture))
-                                                                    VersionJson.Add("type", "release")
-                                                                    VersionJson.Add("arguments", GetJson("{""game"":[""--tweakClass"",""" & DownloadInfo.JsonToken("tweakClass").ToString & """]}"))
-                                                                    VersionJson.Add("libraries", DownloadInfo.JsonToken("libraries"))
-                                                                    CType(VersionJson("libraries"), JContainer).Add(GetJson("{""name"": ""com.mumfrey:liteloader:" & DownloadInfo.JsonToken("version").ToString & """,""url"": ""https://dl.liteloader.com/versions/""}"))
-                                                                    VersionJson.Add("mainClass", "net.minecraft.launchwrapper.Launch")
-                                                                    VersionJson.Add("minimumLauncherVersion", 18)
-                                                                    VersionJson.Add("inheritsFrom", DownloadInfo.Inherit)
-                                                                    VersionJson.Add("jar", DownloadInfo.Inherit)
-                                                                    '输出 Json 文件
-                                                                    WriteFile(VersionFolder & VersionName & ".json", VersionJson.ToString)
-                                                                Catch ex As Exception
-                                                                    Throw New Exception("安装新 LiteLoader 版本失败", ex)
-                                                                End Try
-                                                            End Sub) With {.ProgressWeight = 1})
+        Sub(Task As LoaderTask(Of String, String))
+            Try
+                '新建版本文件夹
+                Directory.CreateDirectory(VersionFolder)
+                '构造版本 Json
+                Dim VersionJson As New JObject
+                VersionJson.Add("id", VersionName)
+                VersionJson.Add("time", Date.ParseExact(DownloadInfo.ReleaseTime, "yyyy/MM/dd HH:mm", Globalization.CultureInfo.CurrentCulture))
+                VersionJson.Add("releaseTime", Date.ParseExact(DownloadInfo.ReleaseTime, "yyyy/MM/dd HH:mm", Globalization.CultureInfo.CurrentCulture))
+                VersionJson.Add("type", "release")
+                VersionJson.Add("arguments", GetJson("{""game"":[""--tweakClass"",""" & DownloadInfo.JsonToken("tweakClass").ToString & """]}"))
+                VersionJson.Add("libraries", DownloadInfo.JsonToken("libraries"))
+                CType(VersionJson("libraries"), JContainer).Add(GetJson("{""name"": ""com.mumfrey:liteloader:" & DownloadInfo.JsonToken("version").ToString & """,""url"": ""https://dl.liteloader.com/versions/""}"))
+                VersionJson.Add("mainClass", "net.minecraft.launchwrapper.Launch")
+                VersionJson.Add("minimumLauncherVersion", 18)
+                VersionJson.Add("inheritsFrom", DownloadInfo.Inherit)
+                VersionJson.Add("jar", DownloadInfo.Inherit)
+                '输出 Json 文件
+                WriteFile(VersionFolder & VersionName & ".json", VersionJson.ToString)
+            Catch ex As Exception
+                Throw New Exception("安装新 LiteLoader 版本失败", ex)
+            End Try
+        End Sub) With {.ProgressWeight = 1})
         '下载支持库
         '下载支持库
         If FixLibrary Then
         If FixLibrary Then
             Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 LiteLoader 支持库文件",
             Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 LiteLoader 支持库文件",
-                                                                Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
+                Sub(Task) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
             Loaders.Add(New LoaderDownload("下载 LiteLoader 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 6})
             Loaders.Add(New LoaderDownload("下载 LiteLoader 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 6})
         End If
         End If
 
 
@@ -1797,7 +1796,7 @@ Retry:
         '建立控件
         '建立控件
         Dim NewItem As New MyListItem With {
         Dim NewItem As New MyListItem With {
             .Title = Entry.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").Split("+").First.Trim, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
             .Title = Entry.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").Split("+").First.Trim, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
-            .Info = Entry.StatusDescription & ",发布于 " & Entry.ReleaseDate.ToString("yyyy/MM/dd HH:mm"),
+            .Info = Entry.StatusDescription & ",发布于 " & Entry.ReleaseDate.ToString("yyyy'/'MM'/'dd HH':'mm"),
             .Logo = PathImage & "Blocks/Fabric.png"
             .Logo = PathImage & "Blocks/Fabric.png"
         }
         }
         AddHandler NewItem.Click, OnClick
         AddHandler NewItem.Click, OnClick
@@ -1808,7 +1807,7 @@ Retry:
         '建立控件
         '建立控件
         Dim NewItem As New MyListItem With {
         Dim NewItem As New MyListItem With {
             .Title = Entry.DisplayName.ToLower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v"), .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
             .Title = Entry.DisplayName.ToLower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v"), .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
-            .Info = Entry.StatusDescription & ",发布于 " & Entry.ReleaseDate.ToString("yyyy/MM/dd HH:mm"),
+            .Info = Entry.StatusDescription & ",发布于 " & Entry.ReleaseDate.ToString("yyyy'/'MM'/'dd HH':'mm"),
             .Logo = PathImage & "Blocks/OptiFabric.png"
             .Logo = PathImage & "Blocks/OptiFabric.png"
         }
         }
         AddHandler NewItem.Click, OnClick
         AddHandler NewItem.Click, OnClick

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadClient"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadClient"
+    PanScroll="{Binding ElementName=PanBack}">
     <Grid>
     <Grid>
         <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
             <StackPanel Orientation="Vertical" Margin="5">
             <StackPanel Orientation="Vertical" Margin="5">

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

@@ -55,9 +55,8 @@
             Next
             Next
             '排序
             '排序
             For i = 0 To Dict.Keys.Count - 1
             For i = 0 To Dict.Keys.Count - 1
-                Dict(Dict.Keys(i)) = Sort(Dict.Values(i), Function(Left As JObject, Right As JObject) As Boolean
-                                                              Return Left("releaseTime").Value(Of Date) > Right("releaseTime").Value(Of Date)
-                                                          End Function)
+                Dict(Dict.Keys(i)) = Sort(Dict.Values(i),
+                                          Function(a, b) a("releaseTime").Value(Of Date) > b("releaseTime").Value(Of Date))
             Next
             Next
             '清空当前
             '清空当前
             PanMain.Children.Clear()
             PanMain.Children.Clear()
@@ -65,11 +64,11 @@
             Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 2}
             Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 2}
             Dim TopestVersions As New List(Of JObject)
             Dim TopestVersions As New List(Of JObject)
             Dim Release As JObject = Dict("正式版")(0).DeepClone()
             Dim Release As JObject = Dict("正式版")(0).DeepClone()
-            Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
+            Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
             TopestVersions.Add(Release)
             TopestVersions.Add(Release)
             If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
             If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
                 Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
                 Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
-                Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
+                Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
                 TopestVersions.Add(Snapshot)
                 TopestVersions.Add(Snapshot)
             End If
             End If
             Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}
             Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadCompDetail"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadCompDetail"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <Grid Margin="25,25,25,10">
         <Grid Margin="25,25,25,10">
             <Grid.RowDefinitions>
             <Grid.RowDefinitions>

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadFabric"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadFabric"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel Orientation="Vertical" Margin="5">
         <StackPanel Orientation="Vertical" Margin="5">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="Fabric 简介" x:Name="CardTip">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="Fabric 简介" x:Name="CardTip">

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadForge"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadForge"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel Orientation="Vertical" Margin="5">
         <StackPanel Orientation="Vertical" Margin="5">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="Forge 简介" x:Name="CardTip">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="Forge 简介" x:Name="CardTip">

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadInstall"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadInstall"
+    PanScroll="{Binding ElementName=PanBack}">
     <Grid>
     <Grid>
         <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
             <Grid Margin="25,10,25,25">
             <Grid Margin="25,10,25,25">

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

@@ -549,11 +549,11 @@
             Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15), .SwapType = 2}
             Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15), .SwapType = 2}
             Dim TopestVersions As New List(Of JObject)
             Dim TopestVersions As New List(Of JObject)
             Dim Release As JObject = Dict("正式版")(0).DeepClone()
             Dim Release As JObject = Dict("正式版")(0).DeepClone()
-            Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
+            Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
             TopestVersions.Add(Release)
             TopestVersions.Add(Release)
             If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
             If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
                 Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
                 Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
-                Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
+                Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
                 TopestVersions.Add(Snapshot)
                 TopestVersions.Add(Snapshot)
             End If
             End If
             Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}
             Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadLiteLoader"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadLiteLoader"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel Orientation="Vertical" Margin="5">
         <StackPanel Orientation="Vertical" Margin="5">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="LiteLoader 简介" x:Name="CardTip">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="LiteLoader 简介" x:Name="CardTip">

+ 6 - 5
Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadMod"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadMod"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel Orientation="Vertical" Margin="25">
         <StackPanel Orientation="Vertical" Margin="25">
             <local:MyCard Title="搜索 Mod" Margin="0,0,0,15" x:Name="PanAlways">
             <local:MyCard Title="搜索 Mod" Margin="0,0,0,15" x:Name="PanAlways">
@@ -57,6 +57,7 @@
                             <local:MyComboBoxItem Content="Forge" Tag="1" />
                             <local:MyComboBoxItem Content="Forge" Tag="1" />
                             <local:MyComboBoxItem Content="Fabric" Tag="4" />
                             <local:MyComboBoxItem Content="Fabric" Tag="4" />
                             <local:MyComboBoxItem Content="Quilt" Tag="5" />
                             <local:MyComboBoxItem Content="Quilt" Tag="5" />
+                            <local:MyComboBoxItem Content="NeoForge" Tag="6" />
                         </local:MyComboBox>
                         </local:MyComboBox>
                         <TextBlock VerticalAlignment="Center" Grid.Column="4" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
                         <TextBlock VerticalAlignment="Center" Grid.Column="4" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
                         <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="5" Grid.Row="2" MaxDropDownHeight="320">
                         <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="5" Grid.Row="2" MaxDropDownHeight="320">

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

@@ -120,7 +120,11 @@
     End Sub
     End Sub
 
 
     '版本选择
     '版本选择
-    Private Sub TextSearchVersion_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TextSearchVersion.TextChanged
+    '#3067:当下拉菜单展开时,程序会被 WPF 挂起,因而无法更新 Grid 布局,所以必须延迟到下拉菜单收起后才能更新
+    Private Sub TextSearchVersion_TextChanged() Handles TextSearchVersion.TextChanged
+        If Not TextSearchVersion.IsDropDownOpen Then UpdateSearchLoaderVisibility()
+    End Sub
+    Private Sub UpdateSearchLoaderVisibility() Handles TextSearchVersion.DropDownClosed
         If TextSearchVersion.Text.Contains(".") OrElse TextSearchVersion.Text.Contains("w") Then
         If TextSearchVersion.Text.Contains(".") OrElse TextSearchVersion.Text.Contains("w") Then
             ComboSearchLoader.Visibility = Visibility.Visible
             ComboSearchLoader.Visibility = Visibility.Visible
             Grid.SetColumnSpan(TextSearchVersion, 1)
             Grid.SetColumnSpan(TextSearchVersion, 1)

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadOptiFine"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadOptiFine"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel Orientation="Vertical" Margin="5">
         <StackPanel Orientation="Vertical" Margin="5">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="OptiFine 简介" x:Name="CardTip">
             <local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="OptiFine 简介" x:Name="CardTip">

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageDownloadPack"
-             d:DesignWidth="778.571" d:DesignHeight="90.857">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageDownloadPack"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel Orientation="Vertical" Margin="25">
         <StackPanel Orientation="Vertical" Margin="25">
             <local:MyCard Title="搜索整合包" Margin="0,0,0,15" x:Name="PanAlways">
             <local:MyCard Title="搜索整合包" Margin="0,0,0,15" x:Name="PanAlways">

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

@@ -145,26 +145,27 @@
             '由于 Abort 不是实时的,暂时不会释放文件,会导致删除报错,故只能取消执行
             '由于 Abort 不是实时的,暂时不会释放文件,会导致删除报错,故只能取消执行
             Hint("有正在获取中的皮肤,请稍后再试!", HintType.Info)
             Hint("有正在获取中的皮肤,请稍后再试!", HintType.Info)
         Else
         Else
-            RunInThread(Sub()
-                            Try
-                                Hint("正在刷新头像……")
-                                '清空缓存
-                                Log("[Skin] 正在清空皮肤缓存")
-                                If Directory.Exists(PathTemp & "Cache\Skin") Then DeleteDirectory(PathTemp & "Cache\Skin")
-                                If Directory.Exists(PathTemp & "Cache\Uuid") Then DeleteDirectory(PathTemp & "Cache\Uuid")
-                                IniClearCache(PathTemp & "Cache\Skin\IndexMs.ini")
-                                IniClearCache(PathTemp & "Cache\Skin\IndexNide.ini")
-                                IniClearCache(PathTemp & "Cache\Skin\IndexAuth.ini")
-                                IniClearCache(PathTemp & "Cache\Uuid\Mojang.ini")
-                                '刷新控件
-                                For Each SkinLoader In If(sender IsNot Nothing, {sender}, {PageLaunchLeft.SkinLegacy, PageLaunchLeft.SkinMs})
-                                    SkinLoader.WaitForExit(IsForceRestart:=True)
-                                Next
-                                Hint("已刷新头像!", HintType.Finish)
-                            Catch ex As Exception
-                                Log(ex, "刷新皮肤缓存失败", LogLevel.Msgbox)
-                            End Try
-                        End Sub)
+            RunInThread(
+            Sub()
+                Try
+                    Hint("正在刷新头像……")
+                    '清空缓存
+                    Log("[Skin] 正在清空皮肤缓存")
+                    If Directory.Exists(PathTemp & "Cache\Skin") Then DeleteDirectory(PathTemp & "Cache\Skin")
+                    If Directory.Exists(PathTemp & "Cache\Uuid") Then DeleteDirectory(PathTemp & "Cache\Uuid")
+                    IniClearCache(PathTemp & "Cache\Skin\IndexMs.ini")
+                    IniClearCache(PathTemp & "Cache\Skin\IndexNide.ini")
+                    IniClearCache(PathTemp & "Cache\Skin\IndexAuth.ini")
+                    IniClearCache(PathTemp & "Cache\Uuid\Mojang.ini")
+                    '刷新控件
+                    For Each SkinLoader In If(sender IsNot Nothing, {sender}, {PageLaunchLeft.SkinLegacy, PageLaunchLeft.SkinMs})
+                        SkinLoader.WaitForExit(IsForceRestart:=True)
+                    Next
+                    Hint("已刷新头像!", HintType.Finish)
+                Catch ex As Exception
+                    Log(ex, "刷新皮肤缓存失败", LogLevel.Msgbox)
+                End Try
+            End Sub)
         End If
         End If
     End Sub
     End Sub
     ''' <summary>
     ''' <summary>
@@ -172,21 +173,22 @@
     ''' </summary>
     ''' </summary>
     ''' <param name="SkinAddress">新的正版皮肤完整地址。</param>
     ''' <param name="SkinAddress">新的正版皮肤完整地址。</param>
     Public Shared Sub ReloadCache(SkinAddress As String)
     Public Shared Sub ReloadCache(SkinAddress As String)
-        RunInThread(Sub()
-                        Try
-                            '更新缓存
-                            WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Setup.Get("CacheMsUuid"), SkinAddress)
-                            Log(String.Format("[Skin] 已写入皮肤地址缓存 {0} -> {1}", Setup.Get("CacheMsUuid"), SkinAddress))
-                            '刷新控件
-                            For Each SkinLoader In {PageLaunchLeft.SkinMs, PageLaunchLeft.SkinLegacy}
-                                SkinLoader.WaitForExit(IsForceRestart:=True)
-                            Next
-                            '完成提示
-                            Hint("更改皮肤成功!", HintType.Finish)
-                        Catch ex As Exception
-                            Log(ex, "更改正版皮肤后刷新皮肤失败", LogLevel.Feedback)
-                        End Try
-                    End Sub)
+        RunInThread(
+        Sub()
+            Try
+                '更新缓存
+                WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Setup.Get("CacheMsUuid"), SkinAddress)
+                Log(String.Format("[Skin] 已写入皮肤地址缓存 {0} -> {1}", Setup.Get("CacheMsUuid"), SkinAddress))
+                '刷新控件
+                For Each SkinLoader In {PageLaunchLeft.SkinMs, PageLaunchLeft.SkinLegacy}
+                    SkinLoader.WaitForExit(IsForceRestart:=True)
+                Next
+                '完成提示
+                Hint("更改皮肤成功!", HintType.Finish)
+            Catch ex As Exception
+                Log(ex, "更改正版皮肤后刷新皮肤失败", LogLevel.Feedback)
+            End Try
+        End Sub)
     End Sub
     End Sub
 
 
     '披风
     '披风
@@ -216,58 +218,60 @@
         Hint("正在获取披风列表,请稍候……")
         Hint("正在获取披风列表,请稍候……")
         IsChanging = True
         IsChanging = True
         '开始实际获取
         '开始实际获取
-        RunInNewThread(Sub()
-                           Try
+        RunInNewThread(
+        Sub()
+            Try
 Retry:
 Retry:
-                               '获取登录信息
-                               If McLoginMsLoader.State <> LoadState.Finished Then McLoginMsLoader.WaitForExit(PageLoginMsSkin.GetLoginData())
-                               If McLoginMsLoader.State <> LoadState.Finished Then
-                                   Hint("登录失败,无法更改披风!", HintType.Critical)
-                                   Exit Sub
-                               End If
-                               Dim AccessToken As String = McLoginMsLoader.Output.AccessToken
-                               Dim Uuid As String = McLoginMsLoader.Output.Uuid
-                               Dim SkinData As JObject = GetJson(McLoginMsLoader.Output.ProfileJson)
-                               '获取玩家的所有披风
-                               Dim SelId As Integer? = Nothing
-                               RunInUiWait(Sub()
-                                               Try
-                                                   Dim CapeNames As New Dictionary(Of String, String) From {
-                                                       {"Migrator", "迁移者披风"}, {"MapMaker", "Realms 地图制作者披风"}, {"Moderator", "Mojira 管理员披风"},
-                                                       {"Translator-Chinese", "Crowdin 中文翻译者披风"}, {"Translator", "Crowdin 翻译者披风"}, {"Cobalt", "Cobalt 披风"},
-                                                       {"Vanilla", "原版披风"}, {"Minecon2011", "Minecon 2011 参与者披风"}, {"Minecon2012", "Minecon 2012 参与者披风"},
-                                                       {"Minecon2013", "Minecon 2013 参与者披风"}, {"Minecon2015", "Minecon 2015 参与者披风"}, {"Minecon2016", "Minecon 2016 参与者披风"},
-                                                       {"Cherry Blossom", "樱花披风"}
-                                                   }
-                                                   Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}}
-                                                   For Each Cape In SkinData("capes")
-                                                       Dim CapeName As String = Cape("alias").ToString
-                                                       If CapeNames.ContainsKey(CapeName) Then CapeName = CapeNames(CapeName)
-                                                       SelectionControl.Add(New MyRadioBox With {.Text = CapeName})
-                                                   Next
-                                                   SelId = MyMsgBoxSelect(SelectionControl, "选择披风", "确定", "取消")
-                                               Catch ex As Exception
-                                                   Log(ex, "获取玩家皮肤列表失败", LogLevel.Feedback)
-                                               End Try
-                                           End Sub)
-                               If SelId Is Nothing Then Exit Sub
-                               '发送请求
-                               Dim Result As String = NetRequestRetry("https://api.minecraftservices.com/minecraft/profile/capes/active",
-                                                                       If(SelId = 0, "DELETE", "PUT"),
-                                                                       If(SelId = 0, "", "{""capeId"": """ & SkinData("capes")(SelId - 1)("id").ToString & """}"),
-                                                                       "application/json", Headers:=New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}})
-                               If Result.Contains("""errorMessage""") Then
-                                   Hint("更改披风失败:" & GetJson(Result)("errorMessage"), HintType.Critical)
-                                   Exit Sub
-                               Else
-                                   Hint("更改披风成功!", HintType.Finish)
-                               End If
-                           Catch ex As Exception
-                               Log(ex, "更改披风失败", LogLevel.Hint)
-                           Finally
-                               IsChanging = False
-                           End Try
-                       End Sub, "Cape Change")
+                '获取登录信息
+                If McLoginMsLoader.State <> LoadState.Finished Then McLoginMsLoader.WaitForExit(PageLoginMsSkin.GetLoginData())
+                If McLoginMsLoader.State <> LoadState.Finished Then
+                    Hint("登录失败,无法更改披风!", HintType.Critical)
+                    Exit Sub
+                End If
+                Dim AccessToken As String = McLoginMsLoader.Output.AccessToken
+                Dim Uuid As String = McLoginMsLoader.Output.Uuid
+                Dim SkinData As JObject = GetJson(McLoginMsLoader.Output.ProfileJson)
+                '获取玩家的所有披风
+                Dim SelId As Integer? = Nothing
+                RunInUiWait(
+                Sub()
+                    Try
+                        Dim CapeNames As New Dictionary(Of String, String) From {
+                            {"Migrator", "迁移者披风"}, {"MapMaker", "Realms 地图制作者披风"}, {"Moderator", "Mojira 管理员披风"},
+                            {"Translator-Chinese", "Crowdin 中文翻译者披风"}, {"Translator", "Crowdin 翻译者披风"}, {"Cobalt", "Cobalt 披风"},
+                            {"Vanilla", "原版披风"}, {"Minecon2011", "Minecon 2011 参与者披风"}, {"Minecon2012", "Minecon 2012 参与者披风"},
+                            {"Minecon2013", "Minecon 2013 参与者披风"}, {"Minecon2015", "Minecon 2015 参与者披风"}, {"Minecon2016", "Minecon 2016 参与者披风"},
+                            {"Cherry Blossom", "樱花披风"}
+                        }
+                        Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}}
+                        For Each Cape In SkinData("capes")
+                            Dim CapeName As String = Cape("alias").ToString
+                            If CapeNames.ContainsKey(CapeName) Then CapeName = CapeNames(CapeName)
+                            SelectionControl.Add(New MyRadioBox With {.Text = CapeName})
+                        Next
+                        SelId = MyMsgBoxSelect(SelectionControl, "选择披风", "确定", "取消")
+                    Catch ex As Exception
+                        Log(ex, "获取玩家皮肤列表失败", LogLevel.Feedback)
+                    End Try
+                End Sub)
+                If SelId Is Nothing Then Exit Sub
+                '发送请求
+                Dim Result As String = NetRequestRetry("https://api.minecraftservices.com/minecraft/profile/capes/active",
+                    If(SelId = 0, "DELETE", "PUT"),
+                    If(SelId = 0, "", New JObject(New JProperty("capeId", SkinData("capes")(SelId - 1)("id"))).ToString(0)),
+                    "application/json", Headers:=New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}})
+                If Result.Contains("""errorMessage""") Then
+                    Hint("更改披风失败:" & GetJson(Result)("errorMessage"), HintType.Critical)
+                    Exit Sub
+                Else
+                    Hint("更改披风成功!", HintType.Finish)
+                End If
+            Catch ex As Exception
+                Log(ex, "更改披风失败", LogLevel.Hint)
+            Finally
+                IsChanging = False
+            End Try
+        End Sub, "Cape Change")
     End Sub
     End Sub
 
 
 End Class
 End Class

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

@@ -1,10 +1,9 @@
 <local:MyPageRight x:Class="PageLaunchRight"
 <local:MyPageRight x:Class="PageLaunchRight"
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-             xmlns:local="clr-namespace:PCL"
-             mc:Ignorable="d">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+    xmlns:local="clr-namespace:PCL"> <!-- 不知道为啥只有这个文件不能在 XAML 设置 PanScroll -->
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
         <StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
             <StackPanel x:Name="PanCustom">
             <StackPanel x:Name="PanCustom">

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

@@ -2,6 +2,7 @@
 
 
     Private Sub Init() Handles Me.Loaded
     Private Sub Init() Handles Me.Loaded
         PanBack.ScrollToHome()
         PanBack.ScrollToHome()
+        PanScroll = PanBack '不知道为啥不能在 XAML 设置
         PanLog.Visibility = If(ModeDebug, Visibility.Visible, Visibility.Collapsed)
         PanLog.Visibility = If(ModeDebug, Visibility.Visible, Visibility.Collapsed)
         '快照版提示
         '快照版提示
 #If BETA Then
 #If BETA Then

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

@@ -29,7 +29,7 @@
             </Grid.ColumnDefinitions>
             </Grid.ColumnDefinitions>
             <local:MyTextButton Text="»  购买正版" EventType="打开网页" EventData="https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj"
             <local:MyTextButton Text="»  购买正版" EventType="打开网页" EventData="https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj"
                             Grid.Column="0" />
                             Grid.Column="0" />
-            <local:MyTextButton Text="»  老账号迁移" x:Name="BtnMigration"
+            <local:MyTextButton Text="»  前往官网" EventType="打开网页" EventData="https://www.minecraft.net/zh-hans"
                             Grid.Column="2" />
                             Grid.Column="2" />
         </Grid>
         </Grid>
     </Grid>
     </Grid>

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

@@ -101,10 +101,5 @@
                            End Try
                            End Try
                        End Sub, "Ms Login")
                        End Sub, "Ms Login")
     End Sub
     End Sub
-    '账号迁移入口
-    Private Sub BtnMigration_Click(sender As Object, e As EventArgs) Handles BtnMigration.Click
-        MyMsgBox($"请在接下来要打开的页面登录你的 Mojang 账号。{vbCrLf}在迁移时,你可能需要设置档案信息,请注意让年龄大于 18 岁,否则可能会导致无法登录!", "迁移提示", "继续", ForceWait:=True)
-        OpenWebsite("https://www.minecraft.net/zh-hans/login")
-    End Sub
 
 
 End Class
 End Class

+ 5 - 5
Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageLinkFeedback"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageLinkFeedback"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
         <StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
             <local:MyCard Title="关于" Margin="0,0,0,15">
             <local:MyCard Title="关于" Margin="0,0,0,15">

+ 6 - 6
Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml

@@ -1,10 +1,10 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:System="clr-namespace:System;assembly=mscorlib" 
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageLinkIoi"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:System="clr-namespace:System;assembly=mscorlib" 
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageLinkIoi"
+    PanScroll="{Binding ElementName=PanBack}">
     <Grid>
     <Grid>
         <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
             <StackPanel Orientation="Vertical" Margin="25,10">
             <StackPanel Orientation="Vertical" Margin="25,10">

+ 5 - 5
Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageOtherHelp"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageOtherHelp"
+    PanScroll="{Binding ElementName=PanBack}">
     <Grid>
     <Grid>
         <local:MyScrollViewer Visibility="Collapsed" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <local:MyScrollViewer Visibility="Collapsed" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
             <StackPanel x:Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
             <StackPanel x:Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">

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

@@ -1,10 +1,10 @@
 <local:MyPageRight x:Class="PageOtherHelpDetail"
 <local:MyPageRight x:Class="PageOtherHelpDetail"
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-             xmlns:local="clr-namespace:PCL"
-             mc:Ignorable="d">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+    xmlns:local="clr-namespace:PCL"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel x:Name="PanCustom" Margin="25,25,25,10">
         <StackPanel x:Name="PanCustom" Margin="25,25,25,10">
             <StackPanel.Resources>
             <StackPanel.Resources>

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

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageSelectRight"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageSelectRight"
+    PanScroll="{Binding ElementName=PanBack}">
     <Grid>
     <Grid>
         <Grid x:Name="PanAllBack">
         <Grid x:Name="PanAllBack">
             <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
             <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">

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

@@ -1,10 +1,10 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:System="clr-namespace:System;assembly=mscorlib" 
-             mc:Ignorable="d" x:Class="PageSetupLaunch"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    xmlns:System="clr-namespace:System;assembly=mscorlib" 
+    mc:Ignorable="d" x:Class="PageSetupLaunch"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel x:Name="PanMain" Margin="25,10">
         <StackPanel x:Name="PanMain" Margin="25,10">
             <local:MyCard x:Name="CardSkin" Margin="0,15" Title="离线皮肤">
             <local:MyCard x:Name="CardSkin" Margin="0,15" Title="离线皮肤">

+ 5 - 5
Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageSetupLink"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageSetupLink"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel x:Name="PanMain" Margin="25,10">
         <StackPanel x:Name="PanMain" Margin="25,10">
             <local:MyCard Margin="0,15" Title="HiPer">
             <local:MyCard Margin="0,15" Title="HiPer">

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

@@ -1,10 +1,10 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:sys="clr-namespace:System;assembly=mscorlib"
-             mc:Ignorable="d" x:Class="PageSetupSystem"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    xmlns:sys="clr-namespace:System;assembly=mscorlib"
+    mc:Ignorable="d" x:Class="PageSetupSystem"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel x:Name="PanMain" Margin="25,10">
         <StackPanel x:Name="PanMain" Margin="25,10">
 
 
@@ -52,9 +52,9 @@
                         <local:MyCheckBox Margin="0,5,0,4" Text="安装整合包时保留原始压缩包" Grid.Row="7" Height="22" Grid.ColumnSpan="2"
                         <local:MyCheckBox Margin="0,5,0,4" Text="安装整合包时保留原始压缩包" Grid.Row="7" Height="22" Grid.ColumnSpan="2"
                                           x:Name="CheckDownloadKeepModpack" Tag="ToolDownloadKeepModpack" 
                                           x:Name="CheckDownloadKeepModpack" Tag="ToolDownloadKeepModpack" 
                                           ToolTip="安装整合包时,在版本文件夹下保留用于安装的原始整合包压缩包文件" />
                                           ToolTip="安装整合包时,在版本文件夹下保留用于安装的原始整合包压缩包文件" />
-                        <local:MyCheckBox Margin="0,2,0,4" Text="简化 Mod 加载器需求(忽略 Quilt)" Grid.Row="8" Height="22" Grid.ColumnSpan="2"
+                        <local:MyCheckBox Margin="0,2,0,4" Text="简化 Mod 加载器显示" Grid.Row="8" Height="22" Grid.ColumnSpan="2"
                                           x:Name="CheckDownloadIgnoreQuilt" Tag="ToolDownloadIgnoreQuilt" 
                                           x:Name="CheckDownloadIgnoreQuilt" Tag="ToolDownloadIgnoreQuilt" 
-                                          ToolTip="当 Mod 支持 Forge、Fabric 但不支持 Quilt 时,不显示它的 Mod 加载器需求。&#xa;例如,关闭时 JEI 会显示需要 Forge / Fabric 1.8+,开启后 JEI 仅显示需要 1.8+。" />
+                                          ToolTip="下载 Mod 时,若该 Mod 支持 Forge 和 Fabric,则显示为支持任意 Mod 加载器。&#xa;例如,开启时 JEI 显示支持全版本,关闭后 JEI 就会显示仅支持 Forge / Fabric 全版本。" />
                     </Grid>
                     </Grid>
                 </StackPanel>
                 </StackPanel>
             </local:MyCard>
             </local:MyCard>

+ 5 - 5
Plain Craft Launcher 2/Pages/PageSpeedRight.xaml

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageSpeedRight"
-             d:DesignWidth="800" d:DesignHeight="800">
+     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+     xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+     mc:Ignorable="d" x:Class="PageSpeedRight"
+     PanScroll="{Binding ElementName=PanBack}">
      <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
      <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel x:Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
         <StackPanel x:Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
             <!--<local:MyCard Title="UI 的示例下载任务">
             <!--<local:MyCard Title="UI 的示例下载任务">

+ 8 - 11
Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml

@@ -1,9 +1,9 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             mc:Ignorable="d" x:Class="PageVersionMod"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    mc:Ignorable="d" x:Class="PageVersionMod"
+    PanScroll="{Binding ElementName=PanBack}">
     <Grid>
     <Grid>
         <Grid x:Name="PanAllBack">
         <Grid x:Name="PanAllBack">
             <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
             <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
@@ -23,12 +23,9 @@
                             <local:MyButton x:Name="BtnManageCheck" Grid.Column="3" MinWidth="140" Text="检查 Mod" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ToolTip="快速检查 Mod 的版本要求、重复、前置缺失等问题。&#xa;结果仅供参考,由于部分 Mod 标注的信息有误,可能并不准确。" Visibility="Collapsed" />
                             <local:MyButton x:Name="BtnManageCheck" Grid.Column="3" MinWidth="140" Text="检查 Mod" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ToolTip="快速检查 Mod 的版本要求、重复、前置缺失等问题。&#xa;结果仅供参考,由于部分 Mod 标注的信息有误,可能并不准确。" Visibility="Collapsed" />
                         </Grid>
                         </Grid>
                     </local:MyCard>
                     </local:MyCard>
-                    <Grid>
-                        <local:MyCard x:Name="PanSearch" Visibility="Collapsed" VerticalAlignment="Top" Opacity="0" Margin="0,0,0,15" Title=" " MinHeight="40">
-                            <StackPanel Margin="20,40,18,18" Name="PanSearchList" VerticalAlignment="Top" />
-                        </local:MyCard>
-                        <StackPanel Name="PanList" />
-                    </Grid>
+                    <local:MyCard x:Name="PanListBack" VerticalAlignment="Top" Opacity="0" Margin="0,0,0,15" Title=" " MinHeight="40">
+                        <StackPanel Margin="20,38,18,18" Name="PanList" VerticalAlignment="Top" />
+                    </local:MyCard>
                 </StackPanel>
                 </StackPanel>
             </local:MyScrollViewer>
             </local:MyScrollViewer>
             <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40" x:Name="PanEmpty">
             <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40" x:Name="PanEmpty">

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

@@ -34,7 +34,7 @@
     End Sub
     End Sub
 
 
     Private Sub LoaderInit() Handles Me.Initialized
     Private Sub LoaderInit() Handles Me.Initialized
-        PageLoaderInit(Load, PanLoad, PanAllBack, Nothing, McModLoader, AddressOf Load_Finish, AutoRun:=False)
+        PageLoaderInit(Load, PanLoad, PanAllBack, Nothing, McModLoader, AddressOf LoadUIFromLoaderOutput, AutoRun:=False)
     End Sub
     End Sub
     Private Sub Load_Click(sender As Object, e As MouseButtonEventArgs) Handles Load.Click
     Private Sub Load_Click(sender As Object, e As MouseButtonEventArgs) Handles Load.Click
         If McModLoader.State = LoadState.Failed Then
         If McModLoader.State = LoadState.Failed Then
@@ -46,55 +46,36 @@
 
 
 #Region "UI 化"
 #Region "UI 化"
 
 
-    Private PanItems As StackPanel
     ''' <summary>
     ''' <summary>
-    ''' 将 Mod 列表加载为 UI。
+    ''' 已加载的 Mod UI 缓存,不确保按显示顺序排列。Key 为 Mod 的 RawFileName。
     ''' </summary>
     ''' </summary>
-    Private Sub Load_Finish(Loader As LoaderTask(Of String, List(Of McMod)))
-        Dim List As List(Of McMod) = Loader.Output
+    Public ModItems As New Dictionary(Of String, MyLocalModItem)
+    ''' <summary>
+    ''' 将加载器结果的 Mod 列表加载为 UI。
+    ''' </summary>
+    Private Sub LoadUIFromLoaderOutput()
+        Dim Mods As List(Of McMod) = McModLoader.Output
         Try
         Try
-            PanList.Children.Clear()
-
             '判断应该显示哪一个页面
             '判断应该显示哪一个页面
-            If List.Count = 0 Then
+            If Mods.Any() Then
+                PanBack.Visibility = Visibility.Visible
+                PanEmpty.Visibility = Visibility.Collapsed
+            Else
                 PanEmpty.Visibility = Visibility.Visible
                 PanEmpty.Visibility = Visibility.Visible
                 PanBack.Visibility = Visibility.Collapsed
                 PanBack.Visibility = Visibility.Collapsed
                 Exit Sub
                 Exit Sub
-            Else
-                PanBack.Visibility = Visibility.Visible
-                PanEmpty.Visibility = Visibility.Collapsed
             End If
             End If
-
             SearchBox.Text = ""
             SearchBox.Text = ""
-            '建立 StackPanel
-            PanItems = New StackPanel With {.Margin = New Thickness(20, 38, 18, If(List.Count > 0, 20, 0)), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
-            For Each ModEntity As McMod In List
-                PanItems.Children.Add(McModListItem(ModEntity))
+            '输出结果
+            ModItems.Clear()
+            For Each ModEntity As McMod In Mods
+                ModItems(ModEntity.RawFileName) = McModListItem(ModEntity)
             Next
             Next
-            '建立 MyCard
-            Dim NewCard As New MyCard With {.Title = McModGetTitle(List), .Margin = New Thickness(0, 0, 0, 15)}
-            NewCard.Children.Add(PanItems)
-            PanList.Children.Add(NewCard)
-
+            RefreshResult(Mods)
         Catch ex As Exception
         Catch ex As Exception
             Log(ex, "加载 Mod 列表 UI 失败", LogLevel.Feedback)
             Log(ex, "加载 Mod 列表 UI 失败", LogLevel.Feedback)
         End Try
         End Try
     End Sub
     End Sub
-    ''' <summary>
-    ''' 获取 Card 的标题。
-    ''' </summary>
-    Private Function McModGetTitle(List As List(Of McMod)) As String
-        Dim Counter = {0, 0, 0}
-        For Each ModEntity As McMod In List
-            Counter(ModEntity.State) += 1
-        Next
-        If List.Count = 0 Then Return "未找到任何 Mod"
-        Dim TypeList As New List(Of String)
-        If Counter(McMod.McModState.Fine) > 0 Then TypeList.Add("启用 " & Counter(McMod.McModState.Fine))
-        If Counter(McMod.McModState.Disabled) > 0 Then TypeList.Add("禁用 " & Counter(McMod.McModState.Disabled))
-        If Counter(McMod.McModState.Unavaliable) > 0 Then TypeList.Add("错误 " & Counter(McMod.McModState.Unavaliable))
-        Return "Mod 列表(" & Join(TypeList, ",") & ")"
-    End Function
     Private Function McModListItem(Entry As McMod) As MyLocalModItem
     Private Function McModListItem(Entry As McMod) As MyLocalModItem
         AniControlEnabled += 1
         AniControlEnabled += 1
         Dim NewItem As New MyLocalModItem With {.SnapsToDevicePixels = True, .Entry = Entry,
         Dim NewItem As New MyLocalModItem With {.SnapsToDevicePixels = True, .Entry = Entry,
@@ -109,26 +90,26 @@
         AddHandler sender.Changed, AddressOf CheckChanged
         AddHandler sender.Changed, AddressOf CheckChanged
         AddHandler sender.Click, Sub(ss As MyLocalModItem, ee As EventArgs) ss.Checked = Not ss.Checked
         AddHandler sender.Click, Sub(ss As MyLocalModItem, ee As EventArgs) ss.Checked = Not ss.Checked
         '图标按钮
         '图标按钮
-        Dim BtnOpen As New MyIconButton With {.LogoScale = 1.15, .Logo = Logo.IconButtonOpen, .Tag = sender}
+        Dim BtnOpen As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonOpen, .Tag = sender}
         BtnOpen.ToolTip = "打开文件位置"
         BtnOpen.ToolTip = "打开文件位置"
         ToolTipService.SetPlacement(BtnOpen, Primitives.PlacementMode.Center)
         ToolTipService.SetPlacement(BtnOpen, Primitives.PlacementMode.Center)
         ToolTipService.SetVerticalOffset(BtnOpen, 30)
         ToolTipService.SetVerticalOffset(BtnOpen, 30)
         ToolTipService.SetHorizontalOffset(BtnOpen, 2)
         ToolTipService.SetHorizontalOffset(BtnOpen, 2)
         AddHandler BtnOpen.Click, AddressOf Open_Click
         AddHandler BtnOpen.Click, AddressOf Open_Click
-        Dim BtnCont As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .Tag = sender}
+        Dim BtnCont As New MyIconButton With {.LogoScale = 1, .Logo = Logo.IconButtonInfo, .Tag = sender}
         BtnCont.ToolTip = "详情"
         BtnCont.ToolTip = "详情"
         ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center)
         ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center)
         ToolTipService.SetVerticalOffset(BtnCont, 30)
         ToolTipService.SetVerticalOffset(BtnCont, 30)
         ToolTipService.SetHorizontalOffset(BtnCont, 2)
         ToolTipService.SetHorizontalOffset(BtnCont, 2)
         AddHandler BtnCont.Click, AddressOf Info_Click
         AddHandler BtnCont.Click, AddressOf Info_Click
         AddHandler sender.MouseRightButtonDown, AddressOf Info_Click
         AddHandler sender.MouseRightButtonDown, AddressOf Info_Click
-        Dim BtnDelete As New MyIconButton With {.LogoScale = 1.1, .Logo = Logo.IconButtonDelete, .Tag = sender}
+        Dim BtnDelete As New MyIconButton With {.LogoScale = 1, .Logo = Logo.IconButtonDelete, .Tag = sender}
         BtnDelete.ToolTip = "删除"
         BtnDelete.ToolTip = "删除"
         ToolTipService.SetPlacement(BtnDelete, Primitives.PlacementMode.Center)
         ToolTipService.SetPlacement(BtnDelete, Primitives.PlacementMode.Center)
         ToolTipService.SetVerticalOffset(BtnDelete, 30)
         ToolTipService.SetVerticalOffset(BtnDelete, 30)
         ToolTipService.SetHorizontalOffset(BtnDelete, 2)
         ToolTipService.SetHorizontalOffset(BtnDelete, 2)
         AddHandler BtnDelete.Click, AddressOf Delete_Click
         AddHandler BtnDelete.Click, AddressOf Delete_Click
-        Dim BtnED As New MyIconButton With {.LogoScale = 1.1, .Logo = If(sender.Entry.State = McMod.McModState.Fine,
+        Dim BtnED As New MyIconButton With {.LogoScale = 1, .Logo = If(sender.Entry.State = McMod.McModState.Fine,
             "M508 990.4c-261.6 0-474.4-212-474.4-474.4S246.4 41.6 508 41.6s474.4 212 474.4 474.4S769.6 990.4 508 990.4zM508 136.8c-209.6 0-379.2 169.6-379.2 379.2 0 209.6 169.6 379.2 379.2 379.2s379.2-169.6 379.2-379.2C887.2 306.4 717.6 136.8 508 136.8zM697.6 563.2 318.4 563.2c-26.4 0-47.2-21.6-47.2-47.2 0-26.4 21.6-47.2 47.2-47.2l379.2 0c26.4 0 47.2 21.6 47.2 47.2C744.8 542.4 724 563.2 697.6 563.2z",
             "M508 990.4c-261.6 0-474.4-212-474.4-474.4S246.4 41.6 508 41.6s474.4 212 474.4 474.4S769.6 990.4 508 990.4zM508 136.8c-209.6 0-379.2 169.6-379.2 379.2 0 209.6 169.6 379.2 379.2 379.2s379.2-169.6 379.2-379.2C887.2 306.4 717.6 136.8 508 136.8zM697.6 563.2 318.4 563.2c-26.4 0-47.2-21.6-47.2-47.2 0-26.4 21.6-47.2 47.2-47.2l379.2 0c26.4 0 47.2 21.6 47.2 47.2C744.8 542.4 724 563.2 697.6 563.2z",
             "M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m0 921.6a409.6 409.6 0 1 1 409.6-409.6 409.6 409.6 0 0 1-409.6 409.6z M716.8 339.968l-256 253.44L328.192 460.8A51.2 51.2 0 0 0 256 532.992l168.448 168.96a51.2 51.2 0 0 0 72.704 0l289.28-289.792A51.2 51.2 0 0 0 716.8 339.968z"),
             "M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m0 921.6a409.6 409.6 0 1 1 409.6-409.6 409.6 409.6 0 0 1-409.6 409.6z M716.8 339.968l-256 253.44L328.192 460.8A51.2 51.2 0 0 0 256 532.992l168.448 168.96a51.2 51.2 0 0 0 72.704 0l289.28-289.792A51.2 51.2 0 0 0 716.8 339.968z"),
             .Tag = sender}
             .Tag = sender}
@@ -144,6 +125,39 @@
         End If
         End If
     End Sub
     End Sub
 
 
+    ''' <summary>
+    ''' 刷新结果显示。
+    ''' </summary>
+    Private Sub RefreshResult(Mods As List(Of McMod))
+        PanList.Children.Clear()
+        For Each TargetMod In Mods
+            PanList.Children.Add(ModItems(TargetMod.RawFileName))
+        Next
+        RefreshTitle()
+    End Sub
+    ''' <summary>
+    ''' 刷新卡片标题。
+    ''' </summary>
+    Private Sub RefreshTitle()
+        Dim Mods = PanList.Children.Cast(Of MyLocalModItem).Select(Function(i) i.Entry).ToList
+        Dim Counter = {0, 0, 0}
+        For Each ModEntity As McMod In Mods
+            Counter(ModEntity.State) += 1
+        Next
+        Dim TypeList As New List(Of String)
+        If Counter(McMod.McModState.Disabled) > 0 Then TypeList.Add("禁用 " & Counter(McMod.McModState.Disabled))
+        If Counter(McMod.McModState.Unavaliable) > 0 Then TypeList.Add("错误 " & Counter(McMod.McModState.Unavaliable))
+        If Counter(McMod.McModState.Fine) > 0 Then TypeList.Insert(0, If(TypeList.Any, "启用 ", "") & Counter(McMod.McModState.Fine))
+        If Not IsSearching Then
+            PanListBack.Title = "Mod 列表 (" & Join(TypeList, ",") & ")"
+        ElseIf TypeList.Any() Then
+            PanListBack.Title = "搜索结果 (" & Join(TypeList, ",") & ")"
+        Else
+            PanListBack.Title = "无搜索结果"
+        End If
+        PanList.Visibility = If(Mods.Any(), Visibility.Visible, Visibility.Collapsed)
+    End Sub
+
 #End Region
 #End Region
 
 
 #Region "管理"
 #Region "管理"
@@ -182,7 +196,7 @@
     ''' 全选。
     ''' 全选。
     ''' </summary>
     ''' </summary>
     Private Sub BtnManageSelectAll_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageSelectAll.Click
     Private Sub BtnManageSelectAll_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageSelectAll.Click
-        If SelectedMods.Count < If(IsSearching, PanSearchList.Children.Count, McModLoader.Output.Count) Then
+        If SelectedMods.Count < PanList.Children.Count Then
             ChangeAllSelected(True)
             ChangeAllSelected(True)
         Else
         Else
             ChangeAllSelected(False)
             ChangeAllSelected(False)
@@ -289,28 +303,10 @@
     Private Sub ChangeAllSelected(Value As Boolean)
     Private Sub ChangeAllSelected(Value As Boolean)
         AniControlEnabled += 1
         AniControlEnabled += 1
         SelectedMods.Clear()
         SelectedMods.Clear()
-        If IsSearching Then
-            '搜索中
-            For Each Item As MyLocalModItem In PanSearchList.Children
-                Item.Checked = Value
-                If Value Then SelectedMods.Add(Item.Entry.RawFileName)
-            Next
-            If Not Value Then '只取消选择
-                If PanItems IsNot Nothing Then
-                    For Each Item As MyLocalModItem In PanItems.Children
-                        Item.Checked = Value
-                    Next
-                End If
-            End If
-        Else
-            '非搜索中
-            If PanItems IsNot Nothing Then
-                For Each Item As MyLocalModItem In PanItems.Children
-                    Item.Checked = Value
-                    If Value Then SelectedMods.Add(Item.Entry.RawFileName)
-                Next
-            End If
-        End If
+        For Each Item As MyLocalModItem In PanList.Children
+            Item.Checked = Value
+            If Value Then SelectedMods.Add(Item.Entry.RawFileName)
+        Next
         AniControlEnabled -= 1
         AniControlEnabled -= 1
         '更新下边栏 UI
         '更新下边栏 UI
         RefreshBottomBar()
         RefreshBottomBar()
@@ -331,13 +327,13 @@
 
 
     '启用 / 禁用
     '启用 / 禁用
     Private Sub BtnSelectED_Click(sender As MyIconTextButton, e As RouteEventArgs) Handles BtnSelectEnable.Click, BtnSelectDisable.Click
     Private Sub BtnSelectED_Click(sender As MyIconTextButton, e As RouteEventArgs) Handles BtnSelectEnable.Click, BtnSelectDisable.Click
-        EDMods(McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.RawFileName)).ToList(),
+        EDMods(McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.RawFileName)),
                Not sender.Equals(BtnSelectDisable))
                Not sender.Equals(BtnSelectDisable))
         ChangeAllSelected(False)
         ChangeAllSelected(False)
     End Sub
     End Sub
-    Private Sub EDMods(ModList As List(Of McMod), IsEnable As Boolean)
+    Private Sub EDMods(ModList As IEnumerable(Of McMod), IsEnable As Boolean)
         Dim IsSuccessful As Boolean = True
         Dim IsSuccessful As Boolean = True
-        For Each ModEntity In ModList
+        For Each ModEntity In ModList.ToList
             Dim NewPath As String = Nothing
             Dim NewPath As String = Nothing
             If ModEntity.State = McMod.McModState.Fine AndAlso Not IsEnable Then
             If ModEntity.State = McMod.McModState.Fine AndAlso Not IsEnable Then
                 '禁用
                 '禁用
@@ -361,24 +357,21 @@
                 Log(ex, $"重命名 Mod 失败({If(ModEntity.Path, "null")})")
                 Log(ex, $"重命名 Mod 失败({If(ModEntity.Path, "null")})")
                 IsSuccessful = False
                 IsSuccessful = False
             End Try
             End Try
-            '更改 Loader 和 UI 中的列表
+            '更改 Loader 中的列表
             Dim NewModEntity As New McMod(NewPath)
             Dim NewModEntity As New McMod(NewPath)
             NewModEntity.Comp = ModEntity.Comp
             NewModEntity.Comp = ModEntity.Comp
             Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity)
             Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity)
             McModLoader.Output.RemoveAt(IndexOfLoader)
             McModLoader.Output.RemoveAt(IndexOfLoader)
             McModLoader.Output.Insert(IndexOfLoader, NewModEntity)
             McModLoader.Output.Insert(IndexOfLoader, NewModEntity)
-            Dim List = If(IsSearching, PanSearchList, PanItems).Children
-            Dim IndexOfUi As Integer = List.IndexOf(List.OfType(Of MyLocalModItem).FirstOrDefault(Function(i) i.Entry Is ModEntity))
+            '更改 UI 中的列表
+            Dim NewItem As MyLocalModItem = McModListItem(NewModEntity)
+            ModItems(ModEntity.RawFileName) = NewItem
+            Dim IndexOfUi As Integer = PanList.Children.IndexOf(PanList.Children.OfType(Of MyLocalModItem).FirstOrDefault(Function(i) i.Entry Is ModEntity))
             If IndexOfUi = -1 Then Continue For '因为未知原因 Mod 的状态已经切换完了
             If IndexOfUi = -1 Then Continue For '因为未知原因 Mod 的状态已经切换完了
-            List.RemoveAt(IndexOfUi)
-            List.Insert(IndexOfUi, McModListItem(NewModEntity))
+            PanList.Children.RemoveAt(IndexOfUi)
+            PanList.Children.Insert(IndexOfUi, NewItem)
         Next
         Next
-        If Not IsSearching Then
-            '改变禁用数量的显示
-            CType(PanItems.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
-            '更新加载器状态
-            LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
-        End If
+        RefreshTitle() '改变数量显示
         If Not IsSuccessful Then
         If Not IsSuccessful Then
             Hint("由于文件被占用,Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
             Hint("由于文件被占用,Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
             RefreshList(True)
             RefreshList(True)
@@ -416,21 +409,16 @@
                 SelectedMods.Remove(ModEntity.RawFileName)
                 SelectedMods.Remove(ModEntity.RawFileName)
                 '更改 Loader 和 UI 中的列表
                 '更改 Loader 和 UI 中的列表
                 McModLoader.Output.Remove(ModEntity)
                 McModLoader.Output.Remove(ModEntity)
-                Dim Parent As StackPanel = If(IsSearching, PanSearchList, PanItems)
-                Dim IndexOfUi As Integer = Parent.Children.IndexOf(Parent.Children.OfType(Of MyLocalModItem).First(Function(i) i.Entry Is ModEntity))
-                Parent.Children.RemoveAt(IndexOfUi)
+                ModItems.Remove(ModEntity.RawFileName)
+                Dim IndexOfUi As Integer = PanList.Children.IndexOf(PanList.Children.OfType(Of MyLocalModItem).First(Function(i) i.Entry Is ModEntity))
+                PanList.Children.RemoveAt(IndexOfUi)
             Next
             Next
-            If Not IsSearching Then
-                '改变禁用数量的显示
-                CType(PanItems.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
-                '更新加载器状态
-                LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
-            End If
+            RefreshTitle()
             If Not IsSuccessful Then
             If Not IsSuccessful Then
                 Hint("由于文件被占用,Mod 删除失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
                 Hint("由于文件被占用,Mod 删除失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
                 RefreshList(True)
                 RefreshList(True)
-            ElseIf If(IsSearching, PanSearchList, PanItems).Children.Count = 0 Then
-                RefreshList(True)
+            ElseIf PanList.Children.Count = 0 Then
+                RefreshList(True) '删除了全部文件
             Else
             Else
                 RefreshBottomBar()
                 RefreshBottomBar()
             End If
             End If
@@ -553,7 +541,7 @@
     '启用 / 禁用
     '启用 / 禁用
     Public Sub ED_Click(sender As MyIconButton, e As EventArgs)
     Public Sub ED_Click(sender As MyIconButton, e As EventArgs)
         Dim ListItem As MyLocalModItem = sender.Tag
         Dim ListItem As MyLocalModItem = sender.Tag
-        EDMods(New List(Of McMod) From {ListItem.Entry}, ListItem.Entry.State = McMod.McModState.Disabled)
+        EDMods({ListItem.Entry}, ListItem.Entry.State = McMod.McModState.Disabled)
     End Sub
     End Sub
 
 
 #End Region
 #End Region
@@ -588,43 +576,12 @@
                 End If
                 End If
                 QueryList.Add(New SearchEntry(Of McMod) With {.Item = Entry, .SearchSource = SearchSource})
                 QueryList.Add(New SearchEntry(Of McMod) With {.Item = Entry, .SearchSource = SearchSource})
             Next
             Next
-            '进行搜索,构造列表
+            '进行搜索
             Dim SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=6, MinBlurSimilarity:=0.35)
             Dim SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=6, MinBlurSimilarity:=0.35)
-            PanSearchList.Children.Clear()
-            If SearchResult.Count = 0 Then
-                PanSearch.Title = "无搜索结果"
-                PanSearchList.Visibility = Visibility.Collapsed
-            Else
-                PanSearch.Title = "搜索结果"
-                For Each Result In SearchResult
-                    Dim Item = McModListItem(Result.Item)
-                    If ModeDebug Then Item.Description = If(Result.AbsoluteRight, "完全匹配,", "") & "相似度:" & Math.Round(Result.Similarity, 3) & "," & Item.Description
-                    PanSearchList.Children.Add(Item)
-                Next
-                PanSearchList.Visibility = Visibility.Visible
-            End If
-            '显示
-            AniStart({
-                     AaOpacity(PanList, -PanList.Opacity, 100),
-                     AaCode(Sub()
-                                PanList.Visibility = Visibility.Collapsed
-                                PanSearch.Visibility = Visibility.Visible
-                                PanSearch.TriggerForceResize()
-                            End Sub,, True),
-                     AaOpacity(PanSearch, 1 - PanSearch.Opacity, 200, 60)
-                }, "FrmVersionMod Search Switch", True)
+            RefreshResult(SearchResult.Select(Function(r) r.Item).ToList)
         Else
         Else
-            '隐藏
-            LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.RunOnUpdated)
-            AniStart({
-                     AaOpacity(PanSearch, -PanSearch.Opacity, 100),
-                     AaCode(Sub()
-                                PanSearch.Height = 0
-                                PanSearch.Visibility = Visibility.Collapsed
-                                PanList.Visibility = Visibility.Visible
-                            End Sub,, True),
-                     AaOpacity(PanList, 1 - PanList.Opacity, 150, 30)
-                }, "FrmVersionMod Search Switch", True)
+            '退出搜索状态
+            RefreshResult(McModLoader.Output)
         End If
         End If
     End Sub
     End Sub
 
 

+ 6 - 6
Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml

@@ -1,10 +1,10 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:System="clr-namespace:System;assembly=mscorlib" 
-             mc:Ignorable="d" x:Class="PageVersionOverall"
-             d:DesignWidth="800" d:DesignHeight="800" Grid.IsSharedSizeScope="True">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    xmlns:System="clr-namespace:System;assembly=mscorlib" 
+    mc:Ignorable="d" x:Class="PageVersionOverall"
+    PanScroll="{Binding ElementName=PanBack}" Grid.IsSharedSizeScope="True">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel x:Name="PanMain" Margin="25,10">
         <StackPanel x:Name="PanMain" Margin="25,10">
             <local:MyCard Margin="0,15" Title="">
             <local:MyCard Margin="0,15" Title="">

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

@@ -1,10 +1,10 @@
 <local:MyPageRight
 <local:MyPageRight
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:System="clr-namespace:System;assembly=mscorlib" 
-             mc:Ignorable="d" x:Class="PageVersionSetup"
-             d:DesignWidth="800" d:DesignHeight="800">
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+    xmlns:System="clr-namespace:System;assembly=mscorlib" 
+    mc:Ignorable="d" x:Class="PageVersionSetup"
+    PanScroll="{Binding ElementName=PanBack}">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
     <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
         <StackPanel x:Name="PanMain" Margin="25,10">
         <StackPanel x:Name="PanMain" Margin="25,10">
             <local:MyHint Text="本页面的设置均只对当前版本生效,这对整合包制作应该会有所帮助。&#xa;你也可以在设置页面中修改对全部版本生效的全局设置。" IsWarn="False" Margin="0,15" />
             <local:MyHint Text="本页面的设置均只对当前版本生效,这对整合包制作应该会有所帮助。&#xa;你也可以在设置页面中修改对全部版本生效的全局设置。" IsWarn="False" Margin="0,15" />