龙腾猫跃 4 ani în urmă
părinte
comite
0066d1b35e
40 a modificat fișierele cu 731 adăugiri și 431 ștergeri
  1. 1 11
      Plain Craft Launcher 2/Application.xaml.vb
  2. 2 2
      Plain Craft Launcher 2/Controls/MyCard.vb
  3. 8 0
      Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb
  4. 67 36
      Plain Craft Launcher 2/Controls/MyPageRight.vb
  5. 73 190
      Plain Craft Launcher 2/FormMain.xaml.vb
  6. 2 2
      Plain Craft Launcher 2/Modules/Base/ModAnimation.vb
  7. 77 27
      Plain Craft Launcher 2/Modules/Base/ModBase.vb
  8. 1 2
      Plain Craft Launcher 2/Modules/Base/ModLoader.vb
  9. 21 2
      Plain Craft Launcher 2/Modules/Base/ModNet.vb
  10. 2 2
      Plain Craft Launcher 2/Modules/Base/ModValidate.vb
  11. 19 7
      Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
  12. 16 5
      Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
  13. 22 17
      Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
  14. 12 13
      Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
  15. 2 2
      Plain Craft Launcher 2/My Project/AssemblyInfo.vb
  16. 0 10
      Plain Craft Launcher 2/My Project/Resources.Designer.vb
  17. 0 3
      Plain Craft Launcher 2/My Project/Resources.resx
  18. 10 14
      Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
  19. 2 2
      Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCfDetail.xaml.vb
  20. 3 3
      Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb
  21. 1 1
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMojangSkin.xaml.vb
  22. 2 1
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb
  23. 29 25
      Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml
  24. 0 1
      Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml.vb
  25. 108 0
      Plain Craft Launcher 2/Pages/PageLink/PageLinkHiper.xaml
  26. 4 2
      Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml
  27. 8 18
      Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml
  28. 192 0
      Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml.vb
  29. 1 1
      Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb
  30. 7 7
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb
  31. 8 4
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml
  32. 13 5
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb
  33. 0 1
      Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb
  34. 2 2
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb
  35. 4 0
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml.vb
  36. 1 1
      Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb
  37. 11 12
      Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj
  38. BIN
      Plain Craft Launcher 2/Resources/Help.zip
  39. BIN
      Plain Craft Launcher 2/Resources/STUN.dll
  40. BIN
      Plain Craft Launcher 2/Resources/java-wrapper.jar

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

@@ -30,7 +30,7 @@ Public Class Application
                     UpdateReplace(e.Args(1), e.Args(2).Trim(""""), e.Args(3).Trim(""""), e.Args(4))
                     UpdateReplace(e.Args(1), e.Args(2).Trim(""""), e.Args(3).Trim(""""), e.Args(4))
                     Environment.[Exit](Result.Cancel)
                     Environment.[Exit](Result.Cancel)
                     Exit Sub
                     Exit Sub
-                ElseIf e.Args(0) = "--link" Then
+                ElseIf e.Args(0).StartsWith("--link") Then
                     '稍作等待后切换到联机页面
                     '稍作等待后切换到联机页面
                     Thread.Sleep(1000)
                     Thread.Sleep(1000)
                     FormMain.IsLinkRestart = True
                     FormMain.IsLinkRestart = True
@@ -142,11 +142,9 @@ Public Class Application
     End Sub
     End Sub
 
 
     '动态 DLL 调用
     '动态 DLL 调用
-    Private Shared AssemblyStun As Assembly
     Private Shared AssemblyNAudio As Assembly
     Private Shared AssemblyNAudio As Assembly
     Private Shared AssemblyJson As Assembly
     Private Shared AssemblyJson As Assembly
     Private Shared AssemblyDialog As Assembly
     Private Shared AssemblyDialog As Assembly
-    Private Shared ReadOnly AssemblyStunLock As New Object
     Private Shared ReadOnly AssemblyNAudioLock As New Object
     Private Shared ReadOnly AssemblyNAudioLock As New Object
     Private Shared ReadOnly AssemblyJsonLock As New Object
     Private Shared ReadOnly AssemblyJsonLock As New Object
     Private Shared ReadOnly AssemblyDialogLock As New Object
     Private Shared ReadOnly AssemblyDialogLock As New Object
@@ -175,14 +173,6 @@ Public Class Application
                 End If
                 End If
                 Return AssemblyDialog
                 Return AssemblyDialog
             End SyncLock
             End SyncLock
-        ElseIf args.Name.StartsWith("STUN") Then
-            SyncLock AssemblyStunLock
-                If AssemblyStun Is Nothing Then
-                    Log("[Start] 加载 DLL:STUN")
-                    AssemblyStun = Assembly.Load(GetResources("STUN"))
-                End If
-                Return AssemblyStun
-            End SyncLock
         Else
         Else
             Return Nothing
             Return Nothing
         End If
         End If

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

@@ -25,9 +25,9 @@
     Public Sub New()
     Public Sub New()
         MainChrome = New SystemDropShadowChrome With {.Margin = New Thickness(-9.5, -9, 0.5, -0.5), .Opacity = 0.1, .CornerRadius = New CornerRadius(6)}
         MainChrome = New SystemDropShadowChrome With {.Margin = New Thickness(-9.5, -9, 0.5, -0.5), .Opacity = 0.1, .CornerRadius = New CornerRadius(6)}
         MainChrome.SetResourceReference(SystemDropShadowChrome.ColorProperty, "ColorObject1")
         MainChrome.SetResourceReference(SystemDropShadowChrome.ColorProperty, "ColorObject1")
-        Children.Add(MainChrome)
+        Children.Insert(0, MainChrome)
         MainBorder = New Border With {.Background = New SolidColorBrush(Color.FromArgb(205, 255, 255, 255)), .CornerRadius = New CornerRadius(6), .IsHitTestVisible = False}
         MainBorder = New Border With {.Background = New SolidColorBrush(Color.FromArgb(205, 255, 255, 255)), .CornerRadius = New CornerRadius(6), .IsHitTestVisible = False}
-        Children.Add(MainBorder)
+        Children.Insert(1, MainBorder)
         MainGrid = New Grid
         MainGrid = New Grid
         Children.Add(MainGrid)
         Children.Add(MainGrid)
     End Sub
     End Sub

+ 8 - 0
Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb

@@ -30,6 +30,7 @@
         Color
         Color
         White
         White
         Black
         Black
+        Red
         Custom
         Custom
     End Enum
     End Enum
     Public Property Theme As Themes = Themes.Color
     Public Property Theme As Themes = Themes.Color
@@ -101,6 +102,8 @@
                             AnimList.Add(AaColor(Path, Shape.FillProperty, "ColorBrush2", AnimationColorIn))
                             AnimList.Add(AaColor(Path, Shape.FillProperty, "ColorBrush2", AnimationColorIn))
                         Case Themes.White
                         Case Themes.White
                             AnimList.Add(AaColor(PanBack, BackgroundProperty, New MyColor(50, 255, 255, 255) - PanBack.Background, AnimationColorIn))
                             AnimList.Add(AaColor(PanBack, BackgroundProperty, New MyColor(50, 255, 255, 255) - PanBack.Background, AnimationColorIn))
+                        Case Themes.Red
+                            AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(255, 76, 76) - Path.Fill, AnimationColorIn))
                         Case Themes.Black
                         Case Themes.Black
                             AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(230, 0, 0, 0) - Path.Fill, AnimationColorIn))
                             AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(230, 0, 0, 0) - Path.Fill, AnimationColorIn))
                         Case Themes.Custom
                         Case Themes.Custom
@@ -117,6 +120,9 @@
                         Case Themes.White
                         Case Themes.White
                             AnimList.Add(AaColor(Path, Shape.FillProperty, "ColorBrush8", AnimationColorOut))
                             AnimList.Add(AaColor(Path, Shape.FillProperty, "ColorBrush8", AnimationColorOut))
                             AnimList.Add(AaColor(PanBack, BackgroundProperty, New MyColor(0, 255, 255, 255) - PanBack.Background, AnimationColorOut))
                             AnimList.Add(AaColor(PanBack, BackgroundProperty, New MyColor(0, 255, 255, 255) - PanBack.Background, AnimationColorOut))
+                        Case Themes.Red
+                            AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(160, 255, 76, 76) - Path.Fill, AnimationColorOut))
+                            PanBack.Background = New MyColor(0, 255, 255, 255)
                         Case Themes.Black
                         Case Themes.Black
                             AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(160, 0, 0, 0) - Path.Fill, AnimationColorOut))
                             AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(160, 0, 0, 0) - Path.Fill, AnimationColorOut))
                             PanBack.Background = New MyColor(0, 255, 255, 255)
                             PanBack.Background = New MyColor(0, 255, 255, 255)
@@ -135,6 +141,8 @@
                         Path.SetResourceReference(Shape.FillProperty, "ColorBrush5")
                         Path.SetResourceReference(Shape.FillProperty, "ColorBrush5")
                     Case Themes.White
                     Case Themes.White
                         Path.SetResourceReference(Shape.FillProperty, "ColorBrush8")
                         Path.SetResourceReference(Shape.FillProperty, "ColorBrush8")
+                    Case Themes.Red
+                        Path.Fill = New MyColor(160, 255, 76, 76)
                     Case Themes.Black
                     Case Themes.Black
                         Path.Fill = New MyColor(160, 0, 0, 0)
                         Path.Fill = New MyColor(160, 0, 0, 0)
                     Case Themes.Custom
                     Case Themes.Custom

+ 67 - 36
Plain Craft Launcher 2/Controls/MyPageRight.vb

@@ -12,7 +12,7 @@
         LoaderExit '加载环退出动画
         LoaderExit '加载环退出动画
         ContentEnter '内容进入动画
         ContentEnter '内容进入动画
         ContentStay '内容正常显示
         ContentStay '内容正常显示
-        ReloadExit '刷新导致的全部退出动画
+        ContentExit '刷新导致的全部退出动画,或页面内容退出(子页面更改)导致的全部退出动画
         PageExit '切换页面导致的全部退出动画
         PageExit '切换页面导致的全部退出动画
     End Enum
     End Enum
     Private _PageState As PageStates = PageStates.Empty
     Private _PageState As PageStates = PageStates.Empty
@@ -48,7 +48,8 @@
     ''' <param name="RealLoader">在工作线程执行的加载器。</param>
     ''' <param name="RealLoader">在工作线程执行的加载器。</param>
     ''' <param name="FinishedInvoke">当加载器执行完成,在 UI 线程触发的 UI 初始化事件。</param>
     ''' <param name="FinishedInvoke">当加载器执行完成,在 UI 线程触发的 UI 初始化事件。</param>
     Public Sub PageLoaderInit(LoaderUi As MyLoading, PanLoader As FrameworkElement, PanContent As FrameworkElement, PanAlways As FrameworkElement,
     Public Sub PageLoaderInit(LoaderUi As MyLoading, PanLoader As FrameworkElement, PanContent As FrameworkElement, PanAlways As FrameworkElement,
-                              RealLoader As LoaderBase, FinishedInvoke As Action(Of LoaderBase), Optional InputInvoke As Func(Of Object) = Nothing,
+                              RealLoader As LoaderBase,
+                              Optional FinishedInvoke As Action(Of LoaderBase) = Nothing, Optional InputInvoke As Func(Of Object) = Nothing,
                               Optional AutoRun As Boolean = True)
                               Optional AutoRun As Boolean = True)
         '初始化参数
         '初始化参数
         Me.PanLoader = PanLoader
         Me.PanLoader = PanLoader
@@ -59,14 +60,16 @@
         Me.PageLoaderInputInvoke = InputInvoke
         Me.PageLoaderInputInvoke = InputInvoke
         Me.PageLoaderAutoRun = AutoRun
         Me.PageLoaderAutoRun = AutoRun
         '添加结束 Invoke
         '添加结束 Invoke
-        AddHandler RealLoader.PreviewFinish,
-            Sub()
-                Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ReloadExit
-                    Thread.Sleep(10) '不在退出动画时执行 UI 线程操作,避免退出动画被重置
+        If FinishedInvoke IsNot Nothing Then
+            AddHandler RealLoader.PreviewFinish,
+                Sub()
+                    Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ContentExit
+                        Thread.Sleep(10) '不在退出动画时执行 UI 线程操作,避免退出动画被重置
                 Loop
                 Loop
-                RunInUiWait(Sub() FinishedInvoke(RealLoader))
-                Thread.Sleep(20) '由于大量初始化控件会导致掉帧,延迟触发 State 改变事件
+                    RunInUiWait(Sub() FinishedInvoke(RealLoader))
+                    Thread.Sleep(20) '由于大量初始化控件会导致掉帧,延迟触发 State 改变事件
             End Sub
             End Sub
+        End If
         AddHandler RealLoader.OnStateChangedUi, Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) RunInUi(Sub() PageLoaderState(Loader, NewState, OldState))
         AddHandler RealLoader.OnStateChangedUi, Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) RunInUi(Sub() PageLoaderState(Loader, NewState, OldState))
         '隐藏 UI
         '隐藏 UI
         PanLoader.Visibility = Visibility.Collapsed
         PanLoader.Visibility = Visibility.Collapsed
@@ -82,14 +85,13 @@
                 PageLoader.Start(Input)
                 PageLoader.Start(Input)
             End If
             End If
         End If
         End If
-        If PageLoader.State = LoadState.Finished Then
+        If PageLoader.State = LoadState.Finished AndAlso FinishedInvoke IsNot Nothing Then
             RunInUiWait(Sub() FinishedInvoke(RealLoader)) '加载器已提前完成,直接触发事件
             RunInUiWait(Sub() FinishedInvoke(RealLoader)) '加载器已提前完成,直接触发事件
         End If
         End If
         '设置加载环
         '设置加载环
         PageLoaderUi.State = RealLoader
         PageLoaderUi.State = RealLoader
         AddHandler PageLoaderUi.Click, Sub() If RealLoader.State = LoadState.Failed Then PageLoaderRestart() '点击重试事件
         AddHandler PageLoaderUi.Click, Sub() If RealLoader.State = LoadState.Failed Then PageLoaderRestart() '点击重试事件
     End Sub
     End Sub
-
     '重试
     '重试
     Public Sub PageLoaderRestart(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = True) '由外部调用的重试
     Public Sub PageLoaderRestart(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = True) '由外部调用的重试
         If Not PageLoaderAutoRun Then Exit Sub
         If Not PageLoaderAutoRun Then Exit Sub
@@ -112,32 +114,38 @@
     ''' </summary>
     ''' </summary>
     Public Sub PageOnEnter()
     Public Sub PageOnEnter()
         If ModeDebug Then Log("[UI] 已触发 PageOnEnter")
         If ModeDebug Then Log("[UI] 已触发 PageOnEnter")
-        RaiseEvent OnPageEnter()
-
+        RaiseEvent PageEnter()
         Select Case PageState
         Select Case PageState
             Case PageStates.Empty
             Case PageStates.Empty
-                If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Aborted Then
+                If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Aborted Then
+                    '如果加载器在进入页面时不启动(例如 HiPer 联机),那么在此时就会有 State = Waiting
                     PageState = PageStates.ContentEnter
                     PageState = PageStates.ContentEnter
                     TriggerEnterAnimation(PanAlways, If(PanContent, Child))
                     TriggerEnterAnimation(PanAlways, If(PanContent, Child))
                 ElseIf PageLoader.State = LoadState.Loading Then
                 ElseIf PageLoader.State = LoadState.Loading Then
                     PageState = PageStates.LoaderWait
                     PageState = PageStates.LoaderWait
                     AniStart(AaCode(AddressOf PageOnLoaderWaitFinished, 200), "PageRight PageChange " & PageUuid)
                     AniStart(AaCode(AddressOf PageOnLoaderWaitFinished, 200), "PageRight PageChange " & PageUuid)
-                ElseIf PageLoader.State = LoadState.Failed Then
+                Else 'PageLoader.State = LoadState.Failed
                     PageState = PageStates.LoaderEnter
                     PageState = PageStates.LoaderEnter
                     TriggerEnterAnimation(PanAlways, PanLoader)
                     TriggerEnterAnimation(PanAlways, PanLoader)
-                ElseIf PageLoader.State = LoadState.Waiting Then
-                    '由于 “页面加载器 Minecraft Version List 不应在 PageOnEnter 事件出现 Waiting 状态” 的神秘反馈添加的临时修复
+                End If
+            Case PageStates.ContentExit
+                '和上面的一样,但是不管 PanAlways
+                If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Aborted Then
+                    PageState = PageStates.ContentEnter
+                    TriggerEnterAnimation(If(PanContent, Child))
+                ElseIf PageLoader.State = LoadState.Loading Then
                     PageState = PageStates.LoaderWait
                     PageState = PageStates.LoaderWait
                     AniStart(AaCode(AddressOf PageOnLoaderWaitFinished, 200), "PageRight PageChange " & PageUuid)
                     AniStart(AaCode(AddressOf PageOnLoaderWaitFinished, 200), "PageRight PageChange " & PageUuid)
-                    Log("[Anim] 警告:页面加载器 " & PageLoader.Name & " 不应在 PageOnEnter 事件出现 " & GetStringFromEnum(PageLoader.State) & " 状态", LogLevel.Debug)
-                Else
-                    Throw New Exception("页面加载器 " & PageLoader.Name & " 不应在 PageOnEnter 事件出现 " & GetStringFromEnum(PageLoader.State) & " 状态。")
+                Else 'PageLoader.State = LoadState.Failed
+                    PageState = PageStates.LoaderEnter
+                    TriggerEnterAnimation(PanLoader)
                 End If
                 End If
+            Case PageStates.ContentEnter '重复调用 PageOnEnter,直接忽略
             Case Else
             Case Else
                 Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnEnter 事件。")
                 Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnEnter 事件。")
         End Select
         End Select
     End Sub
     End Sub
-    Public Event OnPageEnter()
+    Public Event PageEnter()
     ''' <summary>
     ''' <summary>
     ''' 需要切换到其他页面。
     ''' 需要切换到其他页面。
     ''' 需要立即切换至 PageExit 或 Empty。
     ''' 需要立即切换至 PageExit 或 Empty。
@@ -154,7 +162,7 @@
             Case PageStates.LoaderWait
             Case PageStates.LoaderWait
                 PageState = PageStates.PageExit
                 PageState = PageStates.PageExit
                 TriggerExitAnimation(PanAlways)
                 TriggerExitAnimation(PanAlways)
-            Case PageStates.LoaderExit, PageStates.ReloadExit
+            Case PageStates.LoaderExit, PageStates.ContentExit
                 PageState = PageStates.PageExit
                 PageState = PageStates.PageExit
                 If PanAlways IsNot Nothing Then TriggerExitAnimation(PanAlways, If(PanContent, Child))
                 If PanAlways IsNot Nothing Then TriggerExitAnimation(PanAlways, If(PanContent, Child))
             Case PageStates.PageExit, PageStates.Empty
             Case PageStates.PageExit, PageStates.Empty
@@ -178,6 +186,29 @@
             If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed
             If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed
         End If
         End If
     End Sub
     End Sub
+    ''' <summary>
+    ''' PanContent 中的子页面改变,需要让当前内容退出,再显示新的内容。
+    ''' 需要在 PageEnter 事件确认要显示的子页面有哪些。
+    ''' </summary>
+    Public Sub PageOnContentExit()
+        If ModeDebug Then Log("[UI] 已触发 PageOnContentExit")
+        If PageLoader IsNot Nothing AndAlso PageLoader.State = LoadState.Loading Then
+            Throw New Exception("在调用 PageOnContentExit 时,加载器不能为 Loading 状态")
+            'Loading 的加载器可能触发进一步变化,难以预测会触发子页面的动画还是加载器完成的动画
+        End If
+        Select Case PageState
+            Case PageStates.ContentEnter, PageStates.ContentStay
+                PageState = PageStates.ContentExit
+                TriggerExitAnimation(PanContent)
+            Case PageStates.LoaderExit
+                PageState = PageStates.ContentExit
+            Case PageStates.LoaderEnter, PageStates.LoaderStayForce, PageStates.LoaderStay
+                PageState = PageStates.ContentExit
+                TriggerExitAnimation(PanLoader)
+            Case PageStates.LoaderWait, PageStates.Empty
+                PageOnEnter()
+        End Select
+    End Sub
 
 
     '内部触发的事件
     '内部触发的事件
     ''' <summary>
     ''' <summary>
@@ -205,8 +236,7 @@
         Select Case PageState
         Select Case PageState
             Case PageStates.PageExit
             Case PageStates.PageExit
                 PageState = PageStates.Empty
                 PageState = PageStates.Empty
-            Case PageStates.ReloadExit
-                PageState = PageStates.Empty
+            Case PageStates.ContentExit
                 PageOnEnter()
                 PageOnEnter()
             Case PageStates.LoaderExit
             Case PageStates.LoaderExit
                 PageState = PageStates.ContentEnter
                 PageState = PageStates.ContentEnter
@@ -258,20 +288,20 @@
     Private Sub PageLoaderState(sender As Object, NewState As LoadState, OldState As LoadState)
     Private Sub PageLoaderState(sender As Object, NewState As LoadState, OldState As LoadState)
         Select Case NewState
         Select Case NewState
             Case LoadState.Failed, LoadState.Loading
             Case LoadState.Failed, LoadState.Loading
-                If Not OldState = LoadState.Finished Then Exit Sub
-                If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Refresh)")
-                '重新开始运行
+                If OldState = LoadState.Failed OrElse OldState = LoadState.Loading Then Exit Sub
+                If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Start/Refresh)")
+                '(重新)开始运行
                 '需要从部分状态切换到 ReloadExit
                 '需要从部分状态切换到 ReloadExit
                 Select Case PageState
                 Select Case PageState
                     Case PageStates.ContentEnter, PageStates.ContentStay
                     Case PageStates.ContentEnter, PageStates.ContentStay
-                        PageState = PageStates.ReloadExit
+                        PageState = PageStates.ContentExit
                         TriggerExitAnimation(PanContent)
                         TriggerExitAnimation(PanContent)
-                    Case PageStates.LoaderExit, PageStates.ReloadExit
-                        PageState = PageStates.ReloadExit
+                    Case PageStates.LoaderExit
+                        PageState = PageStates.ContentExit
                 End Select
                 End Select
-            Case LoadState.Finished
-                If Not OldState = LoadState.Loading Then Exit Sub
-                If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Stop)")
+            Case LoadState.Finished, LoadState.Aborted, LoadState.Waiting
+                If Not (OldState = LoadState.Failed OrElse OldState = LoadState.Loading) Then Exit Sub
+                If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Stop/Abort)")
                 '运行结束
                 '运行结束
                 '需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit
                 '需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit
                 Select Case PageState
                 Select Case PageState
@@ -360,13 +390,14 @@
     End Function
     End Function
     Private Sub GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement), IgnoreInvisibility As Boolean)
     Private Sub GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement), IgnoreInvisibility As Boolean)
         If Not IgnoreInvisibility AndAlso Element.Visibility = Visibility.Collapsed Then Exit Sub
         If Not IgnoreInvisibility AndAlso Element.Visibility = Visibility.Collapsed Then Exit Sub
-        If TypeOf Element Is MyCard OrElse TypeOf Element Is MyHint Then
+        If TypeOf Element Is MyCard OrElse TypeOf Element Is MyHint OrElse TypeOf Element Is TextBlock OrElse TypeOf Element Is MyTextButton Then
             AllControls.Add(Element)
             AllControls.Add(Element)
         ElseIf TypeOf Element Is ContentControl Then
         ElseIf TypeOf Element Is ContentControl Then
-            GetAllAnimControls(CType(Element, ContentControl).Content, AllControls, IgnoreInvisibility)
+            Dim Content = CType(Element, ContentControl).Content
+            If Content IsNot Nothing AndAlso TypeOf Content Is FrameworkElement Then GetAllAnimControls(Content, AllControls, IgnoreInvisibility)
         ElseIf TypeOf Element Is Panel Then
         ElseIf TypeOf Element Is Panel Then
-            For Each Element2 As FrameworkElement In CType(Element, Panel).Children
-                GetAllAnimControls(Element2, AllControls, IgnoreInvisibility)
+            For Each Element2 In CType(Element, Panel).Children
+                If TypeOf Element2 Is FrameworkElement Then GetAllAnimControls(Element2, AllControls, IgnoreInvisibility)
             Next
             Next
         End If
         End If
     End Sub
     End Sub

+ 73 - 190
Plain Craft Launcher 2/FormMain.xaml.vb

@@ -17,7 +17,7 @@ Public Class FormMain
             BugCount += 9
             BugCount += 9
         End If
         End If
         If LastVersion < 260 Then 'Release 2.3.2
         If LastVersion < 260 Then 'Release 2.3.2
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "解决了联机人数 ≥3 人时出现的频繁掉线或突发高延迟的问题"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "解决了联机人数 ≥3 人时出现的频繁掉线或突发高延迟的问题"))
             FeatureCount += 22
             FeatureCount += 22
             BugCount += 4
             BugCount += 4
         End If
         End If
@@ -32,22 +32,21 @@ Public Class FormMain
             BugCount += 3
             BugCount += 3
         End If
         End If
         If LastVersion < 253 Then 'Release 2.2.13
         If LastVersion < 253 Then 'Release 2.2.13
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(7, "支持在安装菜单中直接安装 OptiFabric"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持调整 Mod 文件名中中文译名的位置"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "崩溃分析优化,支持分析更多 Forge 相关的崩溃"))
+            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
             FeatureCount += 13
             BugCount += 27
             BugCount += 27
         End If
         End If
         If LastVersion < 250 Then 'Release 2.2.11
         If LastVersion < 250 Then 'Release 2.2.11
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "支持将 Mod 文件拖入窗口进行安装"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持将 Mod 文件拖入窗口进行安装"))
             If LastVersion = 246 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法使用中文搜索 Mod 的 Bug"))
             If LastVersion = 246 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法使用中文搜索 Mod 的 Bug"))
             FeatureCount += 8
             FeatureCount += 8
             BugCount += 33
             BugCount += 33
         End If
         End If
         If LastVersion < 246 Then 'Release 2.2.9
         If LastVersion < 246 Then 'Release 2.2.9
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "Mod 下载支持筛选 Forge Mod 与 Fabric Mod"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "大幅修改联机页面布局(作为联机优化的第二个阶段)"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod、整合包下载的综合优化"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 下载支持筛选 Forge Mod 与 Fabric Mod"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "Mod、整合包下载的综合优化"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复使用离线登录进入 Forge 的存档可能导致游戏崩溃"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复使用离线登录进入 Forge 的存档可能导致游戏崩溃"))
             FeatureCount += 13
             FeatureCount += 13
             BugCount += 11
             BugCount += 11
@@ -62,92 +61,41 @@ Public Class FormMain
             BugCount += 2
             BugCount += 2
         End If
         End If
         If LastVersion < 236 Then 'Release 2.2.5
         If LastVersion < 236 Then 'Release 2.2.5
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "网络状态检测支持检测 Windows 防火墙与网络延迟"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "重制右侧页面的切换动画,卡片与提示条将逐个进入退出,并具有独特的位移动画"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "添加 MC 1.18 中要求 Java 17 的检测与提醒"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "优化页面切换、下载的性能"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "允许拖拽按钮的设置第三方登录"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复网络状态检测的结果总为 A 级的 Bug"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法下载新版本的 Forge 的 Bug"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "网络状态检测支持检测 Windows 防火墙与网络延迟"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "重制右侧页面的切换动画,卡片与提示条将逐个进入退出,并具有独特的位移动画"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "添加 MC 1.18 中要求 Java 17 的检测与提醒"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化页面切换、下载的性能"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "允许拖拽按钮设置第三方登录"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "修复无法下载新版本的 Forge 的 Bug"))
             FeatureCount += 25
             FeatureCount += 25
             BugCount += 22
             BugCount += 22
         End If
         End If
         If LastVersion < 233 Then 'Release 2.2.3
         If LastVersion < 233 Then 'Release 2.2.3
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(7, "微软账号支持更换皮肤与披风"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "支持拖拽整合包文件到 PCL2 进行快捷安装"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "Mod 下载支持显示对应的 MC 版本与 Mod 加载器,且可以跳转到 MCBBS 介绍页"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持安装 1.17 OptiFine + Forge"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "使用 Mojang 账号登录将会显示迁移提醒"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "微软账号支持更换皮肤与披风"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持拖拽整合包文件到 PCL2 进行快捷安装"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod 下载支持显示对应的 MC 版本与 Mod 加载器,且可以跳转到 MCBBS 介绍页"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持安装 1.17 OptiFine + Forge"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "使用 Mojang 账号登录将会显示迁移提醒"))
             FeatureCount += 12
             FeatureCount += 12
             BugCount += 26
             BugCount += 26
         End If
         End If
         If LastVersion < 231 Then 'Release 2.2.1, Also 229
         If LastVersion < 231 Then 'Release 2.2.1, Also 229
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(9, "联机功能的早期测试(尚未完成,延迟很高,之后会优化的)"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "添加 1.18 实验性快照 5 的特供下载,且支持列表的联网更新"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "添加 1.18 实验性快照 5 的特供下载,且支持列表的联网更新"))
             FeatureCount += 11
             FeatureCount += 11
             BugCount += 3
             BugCount += 3
         End If
         End If
-        If LastVersion < 226 Then 'Release 2.1.4
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "支持 1.17.1 Forge、Fabric 的安装与启动"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "优化 Forge 下载与安装速度,提高安装稳定性"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "更新内置帮助库,添加数个指南页面与整合包、存档的安装教程"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持将游戏文件夹压缩包作为游戏整合包导入"))
-            FeatureCount += 12
-            BugCount += 13
-        End If
-        If LastVersion < 224 Then 'Release 2.1.3
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "界面与动画综合优化,重新制作主题配色"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "添加 1.18 实验性快照的特供下载"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "更新内置帮助库,添加光影、数据包、Mod 等资源的安装教程"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "游戏崩溃分析优化"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "若设置为自动更新,PCL2 会在关闭时才替换文件"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "追加大量千万████的可能性"))
-            'FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持 1.17 Forge 的安装与启动"))
-            FeatureCount += 33
-            BugCount += 20
-        End If
-        If LastVersion < 217 Then 'Release 2.0.5
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(7, "可以根据游戏版本自动选择所需的 Java"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "允许在 Java 版本检测不通过时强制指定使用 Java"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "允许为不同版本独立设置 Java"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "Java 选择与搜索的综合优化"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法使用 Mod、整合包搜索功能的 Bug"))
-            FeatureCount += 8
-            BugCount += 20
-        End If
-        If LastVersion < 214 Then 'Release 2.0.2
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "添加一键关闭所有运行中的 Minecraft 的按钮"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "增加对 MC 1.17 需要 Java 16 的检测与说明"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Minecraft 崩溃分析优化"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法修改部分个性化设置的严重 Bug"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复 Windows 7 可能无法登录微软账号的严重 Bug"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复网络不稳定时安装整合包极易失败的严重 Bug"))
-            FeatureCount += 10
-            BugCount += 13
-        End If
-        If LastVersion < 212 Then 'Release 2.0.0
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(9, "添加帮助页面,且可以自行添加、删除其中的内容"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "支持安装 MCBBS 格式的整合包"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "自定义主页/帮助页面的 XAML 功能扩展"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "同时安装 OptiFine 与 Forge 时,OptiFine 将作为 Mod 安装"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "优化 CurseForge 搜索"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化多个报错提示,更加人性化"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "适配适用于快照版 MC 的 OptiFine"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复进入 OptiFine 下载页面导致卡死的严重 Bug"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法启动部分 OptiFine+Forge 版本的 Bug"))
-            FeatureCount += 20
-            BugCount += 42
-        End If
 #Else
 #Else
-        '9:大+
-        '8:中大+
-        '7:中+,大*
-        '6:中小型+,中大*
-        '5:小型+,中*
-        '4:中小*
-        '3:小*
-        '2:极度严重的 Bug
-        '1:严重的 Bug
+        '5:          FEAT+
+        '4:     IMP+ FEAT*
+        '3:BUG+ IMP* FEAT-
+        '2:BUG* IMP-
+        '1:BUG-
+        If LastVersion < 266 Then 'Snapshot 2.4.0
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "追加新的联机方式(HiPer 联机模块)"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "游戏崩溃的弹窗添加了直接查看日志的选项"))
+            FeatureCount += 3
+            BugCount += 8
+        End If
         If LastVersion < 264 Then 'Snapshot 2.3.5
         If LastVersion < 264 Then 'Snapshot 2.3.5
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法启动部分 Forge 版本的 Bug"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法启动部分 Forge 版本的 Bug"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复多个可能导致 OptiFine、Forge 安装失败的 Bug"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复多个可能导致 OptiFine、Forge 安装失败的 Bug"))
@@ -160,7 +108,7 @@ Public Class FormMain
             BugCount += 5
             BugCount += 5
         End If
         End If
         If LastVersion < 262 Then 'Snapshot 2.3.3
         If LastVersion < 262 Then 'Snapshot 2.3.3
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法使用 Mod、整合包搜索功能的 Bug"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "修复无法使用 Mod、整合包搜索功能的 Bug"))
             BugCount += 1
             BugCount += 1
         End If
         End If
         If LastVersion < 261 Then 'Snapshot 2.3.2
         If LastVersion < 261 Then 'Snapshot 2.3.2
@@ -168,11 +116,10 @@ Public Class FormMain
             BugCount += 4
             BugCount += 4
         End If
         End If
         If LastVersion < 259 Then 'Snapshot 2.3.1
         If LastVersion < 259 Then 'Snapshot 2.3.1
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "解决了联机人数 ≥3 人时出现的频繁掉线或突发高延迟的问题"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "解决了联机人数 ≥3 人时出现的频繁掉线或突发高延迟的问题"))
             FeatureCount += 14
             FeatureCount += 14
         End If
         End If
         If LastVersion < 258 Then 'Snapshot 2.3.0
         If LastVersion < 258 Then 'Snapshot 2.3.0
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复下载部分 Mod、整合包的 Bug"))
             FeatureCount += 4
             FeatureCount += 4
             BugCount += 4
             BugCount += 4
         End If
         End If
@@ -182,19 +129,19 @@ Public Class FormMain
             BugCount += 3
             BugCount += 3
         End If
         End If
         If LastVersion < 254 Then 'Snapshot 2.2.13
         If LastVersion < 254 Then 'Snapshot 2.2.13
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持调整 Mod 文件名中中文译名的位置"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持调整 Mod 文件名中中文译名的位置"))
             FeatureCount += 3
             FeatureCount += 3
             BugCount += 17
             BugCount += 17
         End If
         End If
         If LastVersion < 252 Then 'Snapshot 2.2.12
         If LastVersion < 252 Then 'Snapshot 2.2.12
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(7, "支持在安装菜单中直接安装 OptiFabric"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "崩溃分析优化,支持分析更多 Forge 相关的崩溃"))
-            If LastVersion = 251 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复同时安装 Forge 和 OptiFine 时 OptiFine 无效的 Bug"))
+            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
             FeatureCount += 10
             BugCount += 10
             BugCount += 10
         End If
         End If
         If LastVersion < 251 Then 'Snapshot 2.2.11
         If LastVersion < 251 Then 'Snapshot 2.2.11
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "支持将 Mod 文件拖入窗口进行安装"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持将 Mod 文件拖入窗口进行安装"))
             FeatureCount += 2
             FeatureCount += 2
             BugCount += 16
             BugCount += 16
         End If
         End If
@@ -204,14 +151,13 @@ Public Class FormMain
             BugCount += 17
             BugCount += 17
         End If
         End If
         If LastVersion < 247 Then 'Snapshot 2.2.9
         If LastVersion < 247 Then 'Snapshot 2.2.9
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "Mod 下载支持筛选 Forge Mod 与 Fabric Mod"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 下载支持筛选 Forge Mod 与 Fabric Mod"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod、整合包下载的综合优化"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod、整合包下载的综合优化"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复使用离线登录进入 Forge 的存档可能导致游戏崩溃"))
             FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复使用离线登录进入 Forge 的存档可能导致游戏崩溃"))
             FeatureCount += 8
             FeatureCount += 8
             BugCount += 4
             BugCount += 4
         End If
         End If
         If LastVersion < 245 Then 'Snapshot 2.2.8
         If LastVersion < 245 Then 'Snapshot 2.2.8
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "大幅修改联机页面布局(作为联机优化的第二个阶段)"))
             FeatureCount += 5
             FeatureCount += 5
             BugCount += 7
             BugCount += 7
         End If
         End If
@@ -221,116 +167,48 @@ Public Class FormMain
         End If
         End If
         If LastVersion < 239 Then 'Snapshot 2.2.6
         If LastVersion < 239 Then 'Snapshot 2.2.6
             If LastVersion >= 235 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复自动更新由于路径错误失败的 Bug"))
             If LastVersion >= 235 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复自动更新由于路径错误失败的 Bug"))
-            If LastVersion = 237 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法使用联机模块的 Bug"))
+            If LastVersion = 237 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "修复无法使用联机模块的 Bug"))
             FeatureCount += 1
             FeatureCount += 1
             BugCount += 1
             BugCount += 1
         End If
         End If
         If LastVersion < 237 Then 'Snapshot 2.2.5
         If LastVersion < 237 Then 'Snapshot 2.2.5
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "允许拖拽按钮的设置第三方登录"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "允许拖拽按钮设置第三方登录"))
             If LastVersion = 235 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复在启动游戏时有可能卡死的 Bug"))
             If LastVersion = 235 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复在启动游戏时有可能卡死的 Bug"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法下载新版本的 Forge 的 Bug"))
             FeatureCount += 2
             FeatureCount += 2
             BugCount += 3
             BugCount += 3
         End If
         End If
         If LastVersion < 235 Then 'Snapshot 2.2.4
         If LastVersion < 235 Then 'Snapshot 2.2.4
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "网络状态检测支持检测 Windows 防火墙与网络延迟"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "重制右侧页面的切换动画,卡片与提示条将逐个进入退出,并具有独特的位移动画"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "添加 MC 1.18 中要求 Java 17 的检测与提醒"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "优化页面切换、下载的性能"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复网络状态检测的结果总为 A 级的 Bug"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "网络状态检测支持检测 Windows 防火墙与网络延迟"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "重制右侧页面的切换动画,卡片与提示条将逐个进入退出,并具有独特的位移动画"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "添加 MC 1.18 中要求 Java 17 的检测与提醒"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化页面切换、下载的性能"))
             FeatureCount += 23
             FeatureCount += 23
             BugCount += 19
             BugCount += 19
         End If
         End If
         If LastVersion < 234 Then 'Snapshot 2.2.3
         If LastVersion < 234 Then 'Snapshot 2.2.3
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "支持拖拽整合包文件到 PCL2 进行快捷安装"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持安装 1.17 OptiFine + Forge"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "Mod 详情页面支持跳转 MCBBS 介绍页"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持拖拽整合包文件到 PCL2 进行快捷安装"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持安装 1.17 OptiFine + Forge"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "Mod 详情页面支持跳转 MCBBS 介绍页"))
             FeatureCount += 10
             FeatureCount += 10
             BugCount += 17
             BugCount += 17
         End If
         End If
         If LastVersion < 232 Then 'Snapshot 2.2.2
         If LastVersion < 232 Then 'Snapshot 2.2.2
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(7, "微软账号支持更换皮肤与披风"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "支持显示 Mod 与整合包对应的 MC 版本与 Mod 加载器名称"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "使用 Mojang 账号登录将会显示迁移提醒"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "微软账号支持更换皮肤与披风"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持显示 Mod 与整合包对应的 MC 版本与 Mod 加载器名称"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "使用 Mojang 账号登录将会显示迁移提醒"))
             FeatureCount += 2
             FeatureCount += 2
             BugCount += 9
             BugCount += 9
         End If
         End If
         If LastVersion < 230 Then 'Snapshot 2.2.1, Also 228
         If LastVersion < 230 Then 'Snapshot 2.2.1, Also 228
-            If LastVersion = 227 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "联机功能的小优化"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "添加 1.18 实验性快照 5 的特供下载,且支持列表的联网更新"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复 Win7 上使用联机功能导致日志文件极大,占用硬盘空间的 Bug"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "添加 1.18 实验性快照 5 的特供下载,且支持列表的联网更新"))
+            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复 Win7 上 IOI 联机导致日志文件极大,占用硬盘空间的 Bug"))
             FeatureCount += 12
             FeatureCount += 12
             BugCount += 4
             BugCount += 4
         End If
         End If
         If LastVersion < 227 Then 'Snapshot 2.2.0
         If LastVersion < 227 Then 'Snapshot 2.2.0
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(9, "新增联机功能的早期测试版本"))
             FeatureCount += 2
             FeatureCount += 2
             BugCount += 2
             BugCount += 2
         End If
         End If
-        If LastVersion < 225 Then 'Snapshot 2.1.4
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "支持 1.17.1 Forge、Fabric 的安装与启动"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "优化 Forge 下载与安装速度,提高安装稳定性"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "更新内置帮助库,添加数个指南页面与整合包、存档的安装教程"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持将游戏文件夹压缩包作为游戏整合包导入"))
-            FeatureCount += 12
-            BugCount += 13
-        End If
-        If LastVersion < 223 Then 'Snapshot 2.1.3
-            BugCount += 4
-        End If
-        If LastVersion < 222 Then 'Snapshot 2.1.2
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "更新内置帮助库,添加光影、数据包、Mod 的安装教程"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "游戏崩溃分析优化"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复登录微软账号启动游戏时报错的 Bug"))
-            FeatureCount += 8
-            BugCount += 11
-        End If
-        If LastVersion < 221 Then 'Snapshot 2.1.1
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "界面与动画综合优化,重新制作主题配色"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "若识别码不变,更新密钥在输入一次后会一直有效"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "若设置为自动更新,PCL2 会在关闭时才替换文件"))
-            FeatureCount += 10
-            BugCount += 5
-        End If
-        If LastVersion < 220 Then 'Snapshot 2.1.0
-            'FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "界面与动画综合优化"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "追加大量千万████的可能性"))
-            FeatureCount += 15
-        End If
-        If LastVersion < 219 Then 'Snapshot 2.0.5
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法使用 Mod、整合包搜索功能的 Bug"))
-            BugCount += 2
-        End If
-        If LastVersion < 218 Then 'Snapshot 2.0.4
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "允许为不同版本独立设置 Java"))
-            BugCount += 12
-        End If
-        If LastVersion < 216 Then 'Snapshot 2.0.3
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(7, "可以根据游戏版本自动选择所需的 Java"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "允许在 Java 版本检测不通过时强制指定使用 Java"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "Java 选择与搜索的综合优化"))
-            FeatureCount += 8
-            BugCount += 7
-        End If
-        If LastVersion < 215 Then 'Snapshot 2.0.2
-            If LastVersion = 213 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复账号切换、版本选择下拉框无法展开的严重 Bug"))
-            If LastVersion = 213 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复误判部分客户端需要 Java 16,导致无法启动游戏的严重 Bug"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复 Windows 7 可能无法登录微软账号的严重 Bug"))
-            BugCount += 1
-        End If
-        If LastVersion < 213 Then 'Snapshot 2.0.1
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(6, "添加一键关闭所有运行中的 Minecraft 的按钮"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "增加对 MC 1.17 需要 Java 16 的检测与说明"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Minecraft 崩溃分析优化"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复网络不稳定时安装整合包极易失败的严重 Bug"))
-            FeatureCount += 10
-            BugCount += 12
-        End If
-        If LastVersion < 211 Then 'Snapshot 2.0.0
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "适配适用于快照版 MC 的 OptiFine"))
-            FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复进入 OptiFine 下载页面导致卡死的严重 Bug"))
-            BugCount += 3
-        End If
 #End If
 #End If
         '整理更新日志文本
         '整理更新日志文本
         Dim ContentList As New List(Of String)
         Dim ContentList As New List(Of String)
@@ -361,7 +239,10 @@ Public Class FormMain
 
 
     '窗口加载
     '窗口加载
     Private IsWindowLoadFinished As Boolean = False
     Private IsWindowLoadFinished As Boolean = False
-    Public Shared IsLinkRestart As Boolean = False '是否为联机提权后自动重启
+    ''' <summary>
+    ''' 是否为联机提权后自动重启。
+    ''' </summary>
+    Public Shared IsLinkRestart As Boolean = False
     Public Sub New()
     Public Sub New()
         ApplicationStartTick = GetTimeTick()
         ApplicationStartTick = GetTimeTick()
         '窗体参数初始化
         '窗体参数初始化
@@ -392,7 +273,7 @@ Public Class FormMain
         PanMainLeft.Child = FrmLaunchLeft
         PanMainLeft.Child = FrmLaunchLeft
         PanMainRight.Child = FrmLaunchRight
         PanMainRight.Child = FrmLaunchRight
         FrmLaunchRight.PageState = MyPageRight.PageStates.ContentStay
         FrmLaunchRight.PageState = MyPageRight.PageStates.ContentStay
-        If IsLinkRestart Then PageChange(PageType.Link)
+        If IsLinkRestart Then PageChange(PageType.Link, PageSubType.LinkIoi)
         '模式提醒
         '模式提醒
 #If DEBUG Then
 #If DEBUG Then
         Hint("[开发者模式] PCL 正以开发者模式运行,这可能会造成严重的性能下降,请务必立即向开发者反馈此问题!", HintType.Critical)
         Hint("[开发者模式] PCL 正以开发者模式运行,这可能会造成严重的性能下降,请务必立即向开发者反馈此问题!", HintType.Critical)
@@ -469,7 +350,7 @@ Public Class FormMain
         RunInNewThread(Sub()
         RunInNewThread(Sub()
                            If Not Setup.Get("SystemEula") Then
                            If Not Setup.Get("SystemEula") Then
 Reopen:
 Reopen:
-                               Select Case MyMsgBox("在使用 PCL2 前,请同意 PCL2 的用户协议与免责声明。", "协议授权", "同意", "拒绝", "打开用户协议与免责声明页面")
+                               Select Case MyMsgBox("在使用 PCL2 前,请同意 PCL2 的用户协议与免责声明。", "协议授权", "同意", "拒绝", "查看用户协议与免责声明")
                                    Case 1
                                    Case 1
                                        Setup.Set("SystemEula", True)
                                        Setup.Set("SystemEula", True)
                                    Case 2
                                    Case 2
@@ -481,7 +362,6 @@ Reopen:
                            End If
                            End If
                            Try
                            Try
                                Thread.Sleep(200)
                                Thread.Sleep(200)
-                               If Setup.Get("LinkAuto") Then PageLinkIoi.InitLoader.Start()
                                DlClientListMojangLoader.Start(1)
                                DlClientListMojangLoader.Start(1)
                                RunCountSub()
                                RunCountSub()
                                ServerLoader.Start(1)
                                ServerLoader.Start(1)
@@ -558,9 +438,13 @@ Reopen:
                      "多谢各位的理解啦!", "重新解锁提醒")
                      "多谢各位的理解啦!", "重新解锁提醒")
         End If
         End If
         '移动自定义皮肤
         '移动自定义皮肤
-        If LastVersionCode <= 161 AndAlso File.Exists(Path & "PCL\CustomSkin.png") AndAlso Not File.Exists(PathTemp & "CustomSkin.png") Then
-            CopyFile(Path & "PCL\CustomSkin.png", PathTemp & "CustomSkin.png")
-            Log("[Start] 已移动离线自定义皮肤")
+        If LastVersionCode <= 161 AndAlso File.Exists(Path & "PCL\CustomSkin.png") AndAlso Not File.Exists(PathAppdata & "CustomSkin.png") Then
+            CopyFile(Path & "PCL\CustomSkin.png", PathAppdata & "CustomSkin.png")
+            Log("[Start] 已移动离线自定义皮肤 (162)")
+        End If
+        If LastVersionCode <= 263 AndAlso File.Exists(PathTemp & "CustomSkin.png") AndAlso Not File.Exists(PathAppdata & "CustomSkin.png") Then
+            CopyFile(PathTemp & "CustomSkin.png", PathAppdata & "CustomSkin.png")
+            Log("[Start] 已移动离线自定义皮肤 (264)")
         End If
         End If
         '解除帮助页面的隐藏
         '解除帮助页面的隐藏
         If LastVersionCode <= 205 Then
         If LastVersionCode <= 205 Then
@@ -632,13 +516,14 @@ Reopen:
         IsProgramEnded = True
         IsProgramEnded = True
         AniControlEnabled += 1
         AniControlEnabled += 1
         PageLinkIoi.IoiStop(False)
         PageLinkIoi.IoiStop(False)
+        PageLinkHiper.HiperStop(False)
         If IsUpdateWaitingRestart Then UpdateRestart(False)
         If IsUpdateWaitingRestart Then UpdateRestart(False)
         If ReturnCode = Result.Exception Then
         If ReturnCode = Result.Exception Then
             If Not IsLogShown Then
             If Not IsLogShown Then
                 FeedbackInfo()
                 FeedbackInfo()
                 Log("请在 https://jinshuju.net/f/rP4b6E?x_field_1=crash 提交错误报告,以便于作者解决此问题!")
                 Log("请在 https://jinshuju.net/f/rP4b6E?x_field_1=crash 提交错误报告,以便于作者解决此问题!")
                 IsLogShown = True
                 IsLogShown = True
-                ShellAndGetExitCode(Path & "PCL\Log1.txt")
+                ShellOnly(Path & "PCL\Log1.txt")
             End If
             End If
             Thread.Sleep(500) '防止 PCL 在记事本打开前就被掐掉
             Thread.Sleep(500) '防止 PCL 在记事本打开前就被掐掉
         End If
         End If
@@ -841,7 +726,7 @@ Reopen:
                                        '获取并检查目标版本
                                        '获取并检查目标版本
                                        Dim TargetVersion As McVersion = McVersionCurrent
                                        Dim TargetVersion As McVersion = McVersionCurrent
                                        If PageCurrent = PageType.VersionSetup Then TargetVersion = PageVersionLeft.Version
                                        If PageCurrent = PageType.VersionSetup Then TargetVersion = PageVersionLeft.Version
-                                       If PageCurrent = PageType.VersionSelect OrElse TargetVersion Is Nothing OrElse Not TargetVersion.Version.Modable Then
+                                       If PageCurrent = PageType.VersionSelect OrElse TargetVersion Is Nothing OrElse Not TargetVersion.Modable Then
                                            '正在选择版本,或当前版本不能安装 Mod
                                            '正在选择版本,或当前版本不能安装 Mod
                                            Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!")
                                            Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!")
                                        ElseIf Not (PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionMod) Then
                                        ElseIf Not (PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionMod) Then
@@ -1039,11 +924,11 @@ Install:
         SetupUI = 1
         SetupUI = 1
         SetupSystem = 2
         SetupSystem = 2
         SetupLink = 3
         SetupLink = 3
-        LinkCato = 2
-        LinkIoi = 3
-        LinkSetup = 5
-        LinkHelp = 6
-        LinkFeedback = 7
+        LinkHiper = 1
+        LinkIoi = 2
+        LinkSetup = 4
+        LinkHelp = 5
+        LinkFeedback = 6
         OtherHelp = 0
         OtherHelp = 0
         OtherAbout = 1
         OtherAbout = 1
         OtherTest = 2
         OtherTest = 2
@@ -1281,7 +1166,6 @@ Install:
                     PageChangeAnim(FrmDownloadLeft, FrmDownloadLeft.PageGet(SubType))
                     PageChangeAnim(FrmDownloadLeft, FrmDownloadLeft.PageGet(SubType))
                 Case PageType.Link '联机
                 Case PageType.Link '联机
                     If FrmLinkLeft Is Nothing Then FrmLinkLeft = New PageLinkLeft
                     If FrmLinkLeft Is Nothing Then FrmLinkLeft = New PageLinkLeft
-                    If FrmLinkIoi Is Nothing Then FrmLinkIoi = New PageLinkIoi
                     PageChangeAnim(FrmLinkLeft, FrmLinkLeft.PageGet(SubType))
                     PageChangeAnim(FrmLinkLeft, FrmLinkLeft.PageGet(SubType))
                 Case PageType.Setup '设置
                 Case PageType.Setup '设置
                     If FrmSetupLeft Is Nothing Then FrmSetupLeft = New PageSetupLeft
                     If FrmSetupLeft Is Nothing Then FrmSetupLeft = New PageSetupLeft
@@ -1337,7 +1221,6 @@ Install:
         AniStart({
         AniStart({
             AaCode(Sub()
             AaCode(Sub()
                        AniControlEnabled += 1
                        AniControlEnabled += 1
-                       CType(PanMainRight.Child, MyPageRight).PageOnForceExit()
                        '把新页面添加进容器
                        '把新页面添加进容器
                        PanMainLeft.Child = PageLeft
                        PanMainLeft.Child = PageLeft
                        PageLeft.Opacity = 0
                        PageLeft.Opacity = 0

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

@@ -777,12 +777,12 @@ Public Module ModAnimation
                                Log("[Animation] 动画线程开始")
                                Log("[Animation] 动画线程开始")
                                Do While True
                                Do While True
                                    '两帧之间的间隔时间
                                    '两帧之间的间隔时间
-                                   Dim DeltaTime As Long = MathRange(GetTimeTick() - AniLastTick, 0, 10000)
+                                   Dim DeltaTime As Long = MathRange(GetTimeTick() - AniLastTick, 0, 100000)
                                    If DeltaTime < 3 Then GoTo Sleeper
                                    If DeltaTime < 3 Then GoTo Sleeper
                                    AniLastTick = GetTimeTick()
                                    AniLastTick = GetTimeTick()
                                    '记录 FPS
                                    '记录 FPS
                                    If ModeDebug Then
                                    If ModeDebug Then
-                                       If MathRange(AniLastTick - AniFPSTimer, 0, 10000) >= 500 Then
+                                       If MathRange(AniLastTick - AniFPSTimer, 0, 100000) >= 500 Then
                                            AniFPS = AniFPSCounter
                                            AniFPS = AniFPSCounter
                                            AniFPSCounter = 0
                                            AniFPSCounter = 0
                                            AniFPSTimer = AniLastTick
                                            AniFPSTimer = AniLastTick

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

@@ -10,12 +10,12 @@ Public Module ModBase
 #Region "声明"
 #Region "声明"
 
 
     '下列版本信息由更新器自动修改
     '下列版本信息由更新器自动修改
-    Public Const VersionBaseName As String = "2.3.5" '不含分支前缀的显示用版本名
-    Public Const VersionStandardCode As String = "2.3.5." & VersionBranchCode '标准格式的四段式版本号
+    Public Const VersionBaseName As String = "2.4.0" '不含分支前缀的显示用版本名
+    Public Const VersionStandardCode As String = "2.4.0." & VersionBranchCode '标准格式的四段式版本号
 #If BETA Then
 #If BETA Then
     Public Const VersionCode As Integer = 265 'Release
     Public Const VersionCode As Integer = 265 'Release
 #Else
 #Else
-    Public Const VersionCode As Integer = 264 'Snapshot
+    Public Const VersionCode As Integer = 266 'Snapshot
 #End If
 #End If
     '自动生成的版本信息
     '自动生成的版本信息
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
     Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -82,6 +82,10 @@ Public Module ModBase
     ''' 程序的缓存文件夹路径,以“\”结尾。
     ''' 程序的缓存文件夹路径,以“\”结尾。
     ''' </summary>
     ''' </summary>
     Public PathTemp As String = If(Setup.Get("SystemSystemCache") = "", IO.Path.GetTempPath() & "PCL\", Setup.Get("SystemSystemCache")).ToString.Replace("/", "\").TrimEnd("\") & "\"
     Public PathTemp As String = If(Setup.Get("SystemSystemCache") = "", IO.Path.GetTempPath() & "PCL\", Setup.Get("SystemSystemCache")).ToString.Replace("/", "\").TrimEnd("\") & "\"
+    ''' <summary>
+    ''' AppData 中的 PCL 文件夹路径,以“\”结尾。
+    ''' </summary>
+    Public PathAppdata As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\PCL\"
 
 
 #End Region
 #End Region
 
 
@@ -447,6 +451,32 @@ Public Module ModBase
 
 
 #Region "数学"
 #Region "数学"
 
 
+    ''' <summary>
+    ''' 2~65 进制的转换。
+    ''' </summary>
+    Public Function RadixConvert(Input As String, FromRadix As Integer, ToRadix As Integer) As String
+        Const Digits As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+="
+        '零与负数的处理
+        If String.IsNullOrEmpty(Input) Then Return "0"
+        Dim IsNegative As Boolean = Input.StartsWith("-")
+        If IsNegative Then Input = Input.TrimStart("-")
+        '转换为十进制
+        Dim RealNum As Long = 0, Scale As Long = 1
+        For Each Digit In Input.Reverse.Select(Function(l) Digits.IndexOf(l))
+            RealNum += Digit * Scale
+            Scale *= FromRadix
+        Next
+        '转换为指定进制
+        Dim Result = ""
+        While RealNum > 0
+            Dim NewNum As Integer = RealNum Mod ToRadix
+            RealNum = (RealNum - NewNum) / ToRadix
+            Result = Digits(NewNum) & Result
+        End While
+        '负数的结束处理与返回
+        Return If(IsNegative, "-", "") & Result
+    End Function
+
     ''' <summary>
     ''' <summary>
     ''' 计算二阶贝塞尔曲线。
     ''' 计算二阶贝塞尔曲线。
     ''' </summary>
     ''' </summary>
@@ -1039,14 +1069,14 @@ Re:
             Next
             Next
             Return Result.ToString
             Return Result.ToString
         Catch ex As Exception
         Catch ex As Exception
-            If Not Retry Then
+            If Retry OrElse TypeOf ex Is FileNotFoundException Then
+                Log(ex, "获取文件 MD5 失败:" & FilePath)
+                Return ""
+            Else
                 Retry = True
                 Retry = True
                 Log(ex, "获取文件 MD5 可重试失败:" & FilePath, LogLevel.Normal)
                 Log(ex, "获取文件 MD5 可重试失败:" & FilePath, LogLevel.Normal)
                 Thread.Sleep(RandomInteger(200, 500))
                 Thread.Sleep(RandomInteger(200, 500))
                 GoTo Re
                 GoTo Re
-            Else
-                Log(ex, "获取文件 MD5 失败:" & FilePath)
-                Return ""
             End If
             End If
         End Try
         End Try
     End Function
     End Function
@@ -1070,14 +1100,14 @@ Re:
             Next
             Next
             Return Result.ToString
             Return Result.ToString
         Catch ex As Exception
         Catch ex As Exception
-            If Not Retry Then
+            If Retry OrElse TypeOf ex Is FileNotFoundException Then
+                Log(ex, "获取文件 SHA256 失败:" & FilePath)
+                Return ""
+            Else
                 Retry = True
                 Retry = True
                 Log(ex, "获取文件 SHA256 可重试失败:" & FilePath, LogLevel.Normal)
                 Log(ex, "获取文件 SHA256 可重试失败:" & FilePath, LogLevel.Normal)
                 Thread.Sleep(RandomInteger(200, 500))
                 Thread.Sleep(RandomInteger(200, 500))
                 GoTo Re
                 GoTo Re
-            Else
-                Log(ex, "获取文件 SHA256 失败:" & FilePath)
-                Return ""
             End If
             End If
         End Try
         End Try
     End Function
     End Function
@@ -1101,14 +1131,14 @@ Re:
             Next
             Next
             Return Result.ToString
             Return Result.ToString
         Catch ex As Exception
         Catch ex As Exception
-            If Not Retry Then
+            If Retry OrElse TypeOf ex Is FileNotFoundException Then
+                Log(ex, "获取文件 SHA1 失败:" & FilePath)
+                Return ""
+            Else
                 Retry = True
                 Retry = True
                 Log(ex, "获取文件 SHA1 可重试失败:" & FilePath, LogLevel.Normal)
                 Log(ex, "获取文件 SHA1 可重试失败:" & FilePath, LogLevel.Normal)
                 Thread.Sleep(RandomInteger(200, 500))
                 Thread.Sleep(RandomInteger(200, 500))
                 GoTo Re
                 GoTo Re
-            Else
-                Log(ex, "获取文件 SHA1 失败:" & FilePath)
-                Return ""
             End If
             End If
         End Try
         End Try
     End Function
     End Function
@@ -1175,7 +1205,7 @@ Re:
                         If Hash <> GetAuthMD5(LocalPath) Then Return "文件 MD5 应为 " & Hash & ",实际为 " & GetAuthMD5(LocalPath)
                         If Hash <> GetAuthMD5(LocalPath) Then Return "文件 MD5 应为 " & Hash & ",实际为 " & GetAuthMD5(LocalPath)
                     ElseIf Hash.Length = 64 Then 'SHA256
                     ElseIf Hash.Length = 64 Then 'SHA256
                         If Hash <> GetAuthSHA256(LocalPath) Then Return "文件 SHA256 应为 " & Hash & ",实际为 " & GetAuthSHA256(LocalPath)
                         If Hash <> GetAuthSHA256(LocalPath) Then Return "文件 SHA256 应为 " & Hash & ",实际为 " & GetAuthSHA256(LocalPath)
-                    Else 'SHA1
+                    Else 'SHA1 (40)
                         If Hash <> GetAuthSHA1(LocalPath) Then Return "文件 SHA1 应为 " & Hash & ",实际为 " & GetAuthSHA1(LocalPath)
                         If Hash <> GetAuthSHA1(LocalPath) Then Return "文件 SHA1 应为 " & Hash & ",实际为 " & GetAuthSHA1(LocalPath)
                     End If
                     End If
                 End If
                 End If
@@ -1803,28 +1833,36 @@ NextElement:
         End Sub
         End Sub
     End Class
     End Class
 
 
+    ''' <summary>
+    ''' 前台运行文件。
+    ''' </summary>
+    ''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
+    ''' <param name="Arguments">运行参数。</param>
+    Public Sub ShellOnly(FileName As String, Optional Arguments As String = "")
+        Using Program As New Process
+            Program.StartInfo.Arguments = Arguments
+            Program.StartInfo.FileName = FileName
+            Log("[System] 执行外部命令:" & FileName & " " & Arguments)
+            Program.Start()
+        End Using
+    End Sub
     ''' <summary>
     ''' <summary>
     ''' 前台运行文件并返回返回值。
     ''' 前台运行文件并返回返回值。
     ''' </summary>
     ''' </summary>
     ''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
     ''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
     ''' <param name="Arguments">运行参数。</param>
     ''' <param name="Arguments">运行参数。</param>
-    ''' <param name="WaitForExit">是否等待该程序结束。默认为 False。</param>
     ''' <param name="Timeout">等待该程序结束的最长时间(毫秒)。超时会返回 Result.Timeout。</param>
     ''' <param name="Timeout">等待该程序结束的最长时间(毫秒)。超时会返回 Result.Timeout。</param>
-    Public Function ShellAndGetExitCode(FileName As String, Optional Arguments As String = "", Optional WaitForExit As Boolean = False, Optional Timeout As Integer = 1000000) As Result
+    Public Function ShellAndGetExitCode(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000) As Result
         Try
         Try
             Using Program As New Process
             Using Program As New Process
                 Program.StartInfo.Arguments = Arguments
                 Program.StartInfo.Arguments = Arguments
                 Program.StartInfo.FileName = FileName
                 Program.StartInfo.FileName = FileName
                 Log("[System] 执行外部命令并等待返回码:" & FileName & " " & Arguments)
                 Log("[System] 执行外部命令并等待返回码:" & FileName & " " & Arguments)
                 Program.Start()
                 Program.Start()
-                If WaitForExit Then
-                    If Program.WaitForExit(Timeout) Then
-                        Return Program.ExitCode
-                    Else
-                        Return Result.Timeout
-                    End If
+                If Program.WaitForExit(Timeout) Then
+                    Return Program.ExitCode
                 Else
                 Else
-                    Return Result.Success
+                    Return Result.Timeout
                 End If
                 End If
             End Using
             End Using
         Catch ex As Exception
         Catch ex As Exception
@@ -1909,6 +1947,18 @@ NextElement:
     ''' 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。
     ''' 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。
     ''' 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用!
     ''' 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用!
     ''' </summary>
     ''' </summary>
+    Public Function RunInUiWait(Of Output)(Action As Func(Of Output)) As Output
+        If RunInUi() Then
+            Return Action()
+        Else
+            Return Application.Current.Dispatcher.Invoke(Action)
+        End If
+    End Function
+    ''' <summary>
+    ''' 确保在 UI 线程中执行代码。
+    ''' 如果当前并非 UI 线程,则会阻断当前线程,直至 UI 线程执行完毕。
+    ''' 为防止线程互锁,请仅在开始加载动画、从 UI 获取输入时使用!
+    ''' </summary>
     Public Sub RunInUiWait(Action As Action)
     Public Sub RunInUiWait(Action As Action)
         If RunInUi() Then
         If RunInUi() Then
             Action()
             Action()
@@ -2003,11 +2053,11 @@ NextElement:
         End Try
         End Try
     End Sub
     End Sub
     ''' <summary>
     ''' <summary>
-    ''' 打开 explorer。
+    ''' 打开 explorer。注意参数中的路径要尽量加上双引号!
     ''' </summary>
     ''' </summary>
     Public Sub OpenExplorer(Argument As String)
     Public Sub OpenExplorer(Argument As String)
         Try
         Try
-            Process.Start("explorer.exe", Argument)
+            ShellOnly("explorer.exe", Argument)
         Catch ex As Exception
         Catch ex As Exception
             Log(ex, "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", LogLevel.Msgbox)
             Log(ex, "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", LogLevel.Msgbox)
         End Try
         End Try

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

@@ -418,7 +418,7 @@
                     Loader.State = LoadState.Waiting
                     Loader.State = LoadState.Waiting
                 Next
                 Next
             End If
             End If
-            Update()
+            RunInThread(AddressOf Update)
         End Sub
         End Sub
         Public Overrides Sub Abort()
         Public Overrides Sub Abort()
             '改变状态
             '改变状态
@@ -484,7 +484,6 @@
                     Case LoadState.Finished
                     Case LoadState.Finished
                         '检查是否需要重启
                         '检查是否需要重启
                         If Loader.GetType.Name.StartsWith("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith
                         If Loader.GetType.Name.StartsWith("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith
-                            'UNDONE: 这里的 IgnoreReloadTimeout 导致加载器不会重启,也就是微软登录不会自动重新登录
                             If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then
                             If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then
                                 If ModeDebug Then Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name)
                                 If ModeDebug Then Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name)
                                 GoTo Restart
                                 GoTo Restart

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

@@ -1,9 +1,28 @@
 Imports System.Net
 Imports System.Net
 
 
 Public Module ModNet
 Public Module ModNet
-
     Public Const NetDownloadEnd As String = ".PCLDownloading"
     Public Const NetDownloadEnd As String = ".PCLDownloading"
 
 
+    ''' <summary>
+    ''' 测试 Ping。失败则返回 -1。
+    ''' </summary>
+    Public Function Ping(Ip As String, Optional Timeout As Integer = 10000, Optional MakeLog As Boolean = True) As Integer
+        Dim PingResult As NetworkInformation.PingReply
+        Try
+            PingResult = (New NetworkInformation.Ping).Send(Ip)
+        Catch ex As Exception
+            If MakeLog Then Log("[Net] Ping " & Ip & " 失败:" & ex.Message)
+            Return -1
+        End Try
+        If PingResult.Status = NetworkInformation.IPStatus.Success Then
+            If MakeLog Then Log("[Net] Ping " & Ip & " 结束:" & PingResult.RoundtripTime & "ms")
+            Return PingResult.RoundtripTime
+        Else
+            If MakeLog Then Log("[Net] Ping " & Ip & " 失败")
+            Return -1
+        End If
+    End Function
+
     ''' <summary>
     ''' <summary>
     ''' 以 WebClient 获取网页源代码。会进行至多 45 秒 3 次的尝试,允许最长 30s 的超时。
     ''' 以 WebClient 获取网页源代码。会进行至多 45 秒 3 次的尝试,允许最长 30s 的超时。
     ''' </summary>
     ''' </summary>
@@ -940,7 +959,7 @@ Capture:
                     Next
                     Next
                     '是否禁用多线程,以及规定碎片大小
                     '是否禁用多线程,以及规定碎片大小
                     Dim TargetUrl As String = GetSource().Url
                     Dim TargetUrl As String = GetSource().Url
-                    If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("gitcode.net") Then Return False
+                    If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("gitcode.net") OrElse TargetUrl.Contains("mcer.cn") Then Return False
                     Dim RealFilePieceLimit = If(TargetUrl.Contains("download.mcbbs.net"), FilePieceLimit * 5, FilePieceLimit)
                     Dim RealFilePieceLimit = If(TargetUrl.Contains("download.mcbbs.net"), FilePieceLimit * 5, FilePieceLimit)
                     '寻找最大碎片
                     '寻找最大碎片
                     Dim FilePieceMax As NetThread = Threads
                     Dim FilePieceMax As NetThread = Threads

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

@@ -49,10 +49,10 @@ End Class
 Public Class ValidateRegex
 Public Class ValidateRegex
     Inherits Validate
     Inherits Validate
     Public Property Regex As String
     Public Property Regex As String
-    Public Property ErrorDescription As String = ""
+    Public Property ErrorDescription As String = "正则检查失败!"
     Public Sub New()
     Public Sub New()
     End Sub '用于 XAML 初始化
     End Sub '用于 XAML 初始化
-    Public Sub New(Regex As String, Optional ErrorDescription As String = "")
+    Public Sub New(Regex As String, Optional ErrorDescription As String = "正则检查失败!")
         Me.Regex = Regex
         Me.Regex = Regex
         Me.ErrorDescription = ErrorDescription
         Me.ErrorDescription = ErrorDescription
     End Sub
     End Sub

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

@@ -9,7 +9,7 @@
         SyncLock IsAnalyzeCacheClearedLock
         SyncLock IsAnalyzeCacheClearedLock
             If Not IsAnalyzeCacheCleared Then
             If Not IsAnalyzeCacheCleared Then
                 Try
                 Try
-                    DeleteDirectory(PathTemp & "CrashAnalyzer")
+                    DeleteDirectory(PathTemp & "CrashAnalyzer\")
                 Catch ex As Exception
                 Catch ex As Exception
                     Log(ex, "清理崩溃分析缓存失败")
                     Log(ex, "清理崩溃分析缓存失败")
                 End Try
                 End Try
@@ -153,6 +153,7 @@
         ExtraLog
         ExtraLog
         CrashReport
         CrashReport
     End Enum
     End Enum
+    Private DirectFile As KeyValuePair(Of String, String())? = Nothing '在弹窗中选择直接打开的文件
     ''' <summary>
     ''' <summary>
     ''' 从 AnalyzeRawFiles 中提取实际有用的文本片段存储到 AnalyzeFiles,并整理可用于生成报告的文件。
     ''' 从 AnalyzeRawFiles 中提取实际有用的文本片段存储到 AnalyzeFiles,并整理可用于生成报告的文件。
     ''' 返回找到的用于分析的项目数。
     ''' 返回找到的用于分析的项目数。
@@ -161,18 +162,22 @@
         Log("[Crash] 步骤 2:准备日志文本")
         Log("[Crash] 步骤 2:准备日志文本")
 
 
         '对日志文件进行分类
         '对日志文件进行分类
+        DirectFile = Nothing
         Dim TotalFiles As New List(Of KeyValuePair(Of AnalyzeFileType, KeyValuePair(Of String, String())))
         Dim TotalFiles As New List(Of KeyValuePair(Of AnalyzeFileType, KeyValuePair(Of String, String())))
         For Each LogFile In AnalyzeRawFiles
         For Each LogFile In AnalyzeRawFiles
             Dim FileName As String = GetFileNameFromPath(LogFile.Key)
             Dim FileName As String = GetFileNameFromPath(LogFile.Key)
             Dim TargetType As AnalyzeFileType
             Dim TargetType As AnalyzeFileType
             If FileName.StartsWith("hs_err") Then
             If FileName.StartsWith("hs_err") Then
                 TargetType = AnalyzeFileType.HsErr
                 TargetType = AnalyzeFileType.HsErr
+                DirectFile = LogFile
             ElseIf FileName.StartsWith("crash-") Then
             ElseIf FileName.StartsWith("crash-") Then
                 TargetType = AnalyzeFileType.CrashReport
                 TargetType = AnalyzeFileType.CrashReport
+                DirectFile = LogFile
             ElseIf FileName = "latest.log" OrElse FileName = "latest log.txt" OrElse
             ElseIf FileName = "latest.log" OrElse FileName = "latest log.txt" OrElse
                    FileName = "debug.log" OrElse FileName = "debug log.txt" OrElse FileName = "游戏崩溃前的输出.txt" OrElse
                    FileName = "debug.log" OrElse FileName = "debug log.txt" OrElse FileName = "游戏崩溃前的输出.txt" OrElse
                    FileName = "rawoutput.log" OrElse FileName = "启动器日志.txt" OrElse FileName = "PCL2 启动器日志.txt" OrElse FileName = "log1.txt" Then
                    FileName = "rawoutput.log" OrElse FileName = "启动器日志.txt" OrElse FileName = "PCL2 启动器日志.txt" OrElse FileName = "log1.txt" Then
                 TargetType = AnalyzeFileType.MinecraftLog
                 TargetType = AnalyzeFileType.MinecraftLog
+                If DirectFile Is Nothing Then DirectFile = LogFile
             ElseIf FileName.EndsWith(".log") OrElse FileName.EndsWith(".txt") Then
             ElseIf FileName.EndsWith(".log") OrElse FileName.EndsWith(".txt") Then
                 TargetType = AnalyzeFileType.ExtraLog
                 TargetType = AnalyzeFileType.ExtraLog
             Else
             Else
@@ -689,8 +694,19 @@ NextStack:
     Public Sub Output(IsHandAnalyze As Boolean, Optional ExtraFiles As List(Of String) = Nothing)
     Public Sub Output(IsHandAnalyze As Boolean, Optional ExtraFiles As List(Of String) = Nothing)
         '弹窗提示
         '弹窗提示
         FrmMain.ShowWindowToTop()
         FrmMain.ShowWindowToTop()
-        Select Case MyMsgBox(GetAnalyzeResult(IsHandAnalyze), If(IsHandAnalyze, "错误报告分析结果", "Minecraft 出现错误"), "确定", If(IsHandAnalyze, "", "导出错误报告"))
+Redo:
+        Select Case MyMsgBox(GetAnalyzeResult(IsHandAnalyze), If(IsHandAnalyze, "错误报告分析结果", "Minecraft 出现错误"),
+                             "确定", If(IsHandAnalyze OrElse DirectFile Is Nothing, "", "查看日志"), If(IsHandAnalyze, "", "导出错误报告"))
             Case 2
             Case 2
+                If File.Exists(DirectFile.Value.Key) Then
+                    ShellOnly(DirectFile.Value.Key)
+                Else
+                    Dim FilePath As String = PathTemp & "Crash.txt"
+                    WriteFile(FilePath, Join(DirectFile.Value.Value, vbCrLf))
+                    ShellOnly(FilePath)
+                End If
+                GoTo Redo
+            Case 3
                 Dim FileAddress As String = Nothing
                 Dim FileAddress As String = Nothing
                 Try
                 Try
                     '获取文件路径
                     '获取文件路径
@@ -723,11 +739,7 @@ NextStack:
                     Log(ex, "导出错误报告失败", LogLevel.Feedback)
                     Log(ex, "导出错误报告失败", LogLevel.Feedback)
                     Exit Sub
                     Exit Sub
                 End Try
                 End Try
-                Try
-                    Process.Start("explorer", "/select," & FileAddress)
-                Catch ex As Exception
-                    Log(ex, "打开错误报告的存放文件夹失败")
-                End Try
+                OpenExplorer("/select,""" & FileAddress & """")
         End Select
         End Select
     End Sub
     End Sub
     ''' <summary>
     ''' <summary>

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

@@ -1217,7 +1217,7 @@
     ''' CurseForge 工程列表获取事件。
     ''' CurseForge 工程列表获取事件。
     ''' </summary>
     ''' </summary>
     Public Sub DlCfProjectSub(Task As LoaderTask(Of DlCfProjectRequest, DlCfProjectResult))
     Public Sub DlCfProjectSub(Task As LoaderTask(Of DlCfProjectRequest, DlCfProjectResult))
-        Dim RawFilter As String = If(Task.Input.SearchFilter, "")
+        Dim RawFilter As String = If(Task.Input.SearchFilter, "").Trim.ToLower
         Task.Input.SearchFilter = RawFilter
         Task.Input.SearchFilter = RawFilter
         Log("[Download] CurseForge 工程列表搜索原始文本:" & RawFilter)
         Log("[Download] CurseForge 工程列表搜索原始文本:" & RawFilter)
         '中文请求关键字处理
         '中文请求关键字处理
@@ -1263,12 +1263,20 @@
         Dim RightKeywords As New List(Of String)
         Dim RightKeywords As New List(Of String)
         For Each Keyword In AllPossibleKeywords.Split(" ")
         For Each Keyword In AllPossibleKeywords.Split(" ")
             If Keyword.Trim = "" Then Continue For
             If Keyword.Trim = "" Then Continue For
+            If Keyword = "forge" OrElse Keyword = "fabric" OrElse Keyword = "for" Then 'https://github.com/Hex-Dragon/PCL2/issues/208
+                Log("[Download] 已跳过搜索关键词 " & Keyword, LogLevel.Developer)
+                Continue For
+            End If
             RightKeywords.Add(Keyword)
             RightKeywords.Add(Keyword)
         Next
         Next
-        Task.Input.SearchFilter = Join(ArrayNoDouble(RightKeywords), " ").ToLower
+        If RawFilter.Length > 0 AndAlso RightKeywords.Count = 0 Then
+            Task.Input.SearchFilter = RawFilter '全都被过滤掉了
+        Else
+            Task.Input.SearchFilter = Join(ArrayNoDouble(RightKeywords), " ").ToLower
+        End If
         '例外项:OptiForge、OptiFabric(拆词后因为包含 Forge/Fabric 导致无法搜到实际的 Mod)
         '例外项:OptiForge、OptiFabric(拆词后因为包含 Forge/Fabric 导致无法搜到实际的 Mod)
-        If RawFilter.ToLower.Contains("optiforge") Then Task.Input.SearchFilter = "optiforge"
-        If RawFilter.ToLower.Contains("optifabric") Then Task.Input.SearchFilter = "optifabric"
+        If RawFilter.Replace(" ", "").ToLower.Contains("optiforge") Then Task.Input.SearchFilter = "optiforge"
+        If RawFilter.Replace(" ", "").ToLower.Contains("optifabric") Then Task.Input.SearchFilter = "optifabric"
         Log("[Download] CurseForge 工程列表搜索最终文本:" & Task.Input.SearchFilter, LogLevel.Developer)
         Log("[Download] CurseForge 工程列表搜索最终文本:" & Task.Input.SearchFilter, LogLevel.Developer)
         '正式获取
         '正式获取
         Dim Url = Task.Input.GetAddress()
         Dim Url = Task.Input.GetAddress()
@@ -1505,7 +1513,6 @@
                 Json = NetGetCodeByRequestRetry("https://api.curseforge.com/v1/mods/" & ProjectId & "/files?pageSize=999", Accept:="application/json", IsJson:=True)("data")
                 Json = NetGetCodeByRequestRetry("https://api.curseforge.com/v1/mods/" & ProjectId & "/files?pageSize=999", Accept:="application/json", IsJson:=True)("data")
             Else
             Else
                 'Mod 使用每个版本最新的文件
                 'Mod 使用每个版本最新的文件
-                'TODO: 完整 Mod 文件列表支持
                 Json = GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(TargetProject.FileIndexes, ",") & "]}", "application/json"))("data")
                 Json = GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(TargetProject.FileIndexes, ",") & "]}", "application/json"))("data")
             End If
             End If
             Dim Files As New Dictionary(Of Integer, DlCfFile)
             Dim Files As New Dictionary(Of Integer, DlCfFile)
@@ -1633,6 +1640,10 @@ ExitSub:
             If WaitCycle = 0 Then
             If WaitCycle = 0 Then
                 '启动第一个源
                 '启动第一个源
                 LoaderList(0).Key.Start(MainLoader.Input, IsForceRestart)
                 LoaderList(0).Key.Start(MainLoader.Input, IsForceRestart)
+                '将其他源标记为未启动,以确保可以切换下载源(#184)
+                For i = 1 To LoaderList.Count - 1
+                    LoaderList(i).Key.State = LoadState.Waiting
+                Next
             End If
             End If
             For i = 0 To LoaderList.Count - 1
             For i = 0 To LoaderList.Count - 1
                 If WaitCycle = LoaderList(i).Value * 100 Then
                 If WaitCycle = LoaderList(i).Value * 100 Then

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

@@ -15,7 +15,7 @@ Public Module ModLaunch
     End Sub
     End Sub
 
 
     '启动状态切换
     '启动状态切换
-    Public McLaunchLoader As New LoaderTask(Of String, Object)("Loader Launch", AddressOf McLaunchStart) With {.OnStateChanged = AddressOf McLaunchState, .ReloadTimeout = 1}
+    Public McLaunchLoader As New LoaderTask(Of String, Object)("Loader Launch", AddressOf McLaunchStart) With {.OnStateChanged = AddressOf McLaunchState}
     Public McLaunchLoaderReal As LoaderCombo(Of Object)
     Public McLaunchLoaderReal As LoaderCombo(Of Object)
     Public McLaunchProcess As Process
     Public McLaunchProcess As Process
     Public McLaunchWatcher As Watcher
     Public McLaunchWatcher As Watcher
@@ -206,12 +206,13 @@ NextInner:
         Public AccessToken As String = ""
         Public AccessToken As String = ""
         Public Uuid As String = ""
         Public Uuid As String = ""
         Public UserName As String = ""
         Public UserName As String = ""
+        Public ProfileJson As String = ""
 
 
         Public Sub New()
         Public Sub New()
             Type = McLoginType.Ms
             Type = McLoginType.Ms
         End Sub
         End Sub
         Public Overrides Function GetHashCode() As Integer
         Public Overrides Function GetHashCode() As Integer
-            Return GetHash(OAuthRefreshToken & AccessToken & Uuid & UserName) Mod Integer.MaxValue
+            Return GetHash(OAuthRefreshToken & AccessToken & Uuid & UserName & ProfileJson) Mod Integer.MaxValue
         End Function
         End Function
     End Class
     End Class
     Public Class McLoginLegacy
     Public Class McLoginLegacy
@@ -419,7 +420,8 @@ NextInner:
         Data.Progress = 0.05
         Data.Progress = 0.05
         '检查是否已经登录完成
         '检查是否已经登录完成
         If Input.AccessToken <> "" AndAlso Not Data.IsForceRestarting Then
         If Input.AccessToken <> "" AndAlso Not Data.IsForceRestarting Then
-            Data.Output = New McLoginResult With {.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid}
+            Data.Output = New McLoginResult With
+                {.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid, .ProfileJson = Input.ProfileJson}
             GoTo SkipLogin
             GoTo SkipLogin
         End If
         End If
         '尝试登录
         '尝试登录
@@ -456,6 +458,7 @@ Relogin:
         Setup.Set("CacheMsAccess", AccessToken)
         Setup.Set("CacheMsAccess", AccessToken)
         Setup.Set("CacheMsUuid", Result(0))
         Setup.Set("CacheMsUuid", Result(0))
         Setup.Set("CacheMsName", Result(1))
         Setup.Set("CacheMsName", Result(1))
+        Setup.Set("CacheMsProfileJson", Result(2))
         Data.Output = New McLoginResult With {.AccessToken = AccessToken, .Name = Result(1), .Uuid = Result(0), .Type = "Microsoft", .ClientToken = Result(0), .ProfileJson = Result(2)}
         Data.Output = New McLoginResult With {.AccessToken = AccessToken, .Name = Result(1), .Uuid = Result(0), .Type = "Microsoft", .ClientToken = Result(0), .ProfileJson = Result(2)}
         '解锁主题
         '解锁主题
 SkipLogin:
 SkipLogin:
@@ -1076,6 +1079,18 @@ SystemBrowser:
 
 
     Private McLaunchArgument As String
     Private McLaunchArgument As String
 
 
+    ''' <summary>
+    ''' 释放 Java Wrapper 并返回文件路径。
+    ''' </summary>
+    Public Function ExtractJavaWrapper() As String
+        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
+        If Not File.Exists(WrapperPath) OrElse New FileInfo(WrapperPath).Length > 20 * 1024 Then
+            WriteFile(WrapperPath, GetResources("JavaWrapper"))
+            McLaunchLog("已自动释放 Java Wrapper")
+        End If
+        Return WrapperPath
+    End Function
+
     '主方法,合并 Jvm、Game、Replace 三部分的参数数据
     '主方法,合并 Jvm、Game、Replace 三部分的参数数据
     Private Sub McLaunchArgumentMain(Loader As LoaderTask(Of String, List(Of McLibToken)))
     Private Sub McLaunchArgumentMain(Loader As LoaderTask(Of String, List(Of McLibToken)))
         McLaunchLog("开始获取 Minecraft 启动参数")
         McLaunchLog("开始获取 Minecraft 启动参数")
@@ -1175,12 +1190,7 @@ SystemBrowser:
 
 
         '添加 Java Wrapper 作为主 Jar
         '添加 Java Wrapper 作为主 Jar
         If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
         If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
-        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
-        If Not File.Exists(WrapperPath) Then
-            WriteFile(WrapperPath, GetResources("JavaWrapper"))
-            McLaunchLog("已自动释放 Java Wrapper")
-        End If
-        DataList.Add("-jar """ & WrapperPath & """")
+        DataList.Add("-jar """ & ExtractJavaWrapper() & """")
 
 
         '添加 MainClass
         '添加 MainClass
         If Version.JsonObject("mainClass") Is Nothing Then
         If Version.JsonObject("mainClass") Is Nothing Then
@@ -1244,12 +1254,7 @@ NextVersion:
 
 
         '添加 Java Wrapper 作为主 Jar
         '添加 Java Wrapper 作为主 Jar
         If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
         If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
-        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
-        If Not File.Exists(WrapperPath) Then
-            WriteFile(WrapperPath, GetResources("JavaWrapper"))
-            McLaunchLog("已自动释放 Java Wrapper")
-        End If
-        DataList.Add("-jar """ & WrapperPath & """")
+        DataList.Add("-jar """ & ExtractJavaWrapper() & """")
 
 
         '将 "-XXX" 与后面 "XXX" 合并到一起
         '将 "-XXX" 与后面 "XXX" 合并到一起
         '如果不合并,会导致 Forge 1.17 启动无效,它有两个 --add-exports,进一步导致其中一个在后面被去重
         '如果不合并,会导致 Forge 1.17 启动无效,它有两个 --add-exports,进一步导致其中一个在后面被去重
@@ -1619,7 +1624,7 @@ NextVersion:
             Directory.CreateDirectory(McVersionCurrent.PathIndie & "resourcepacks\")
             Directory.CreateDirectory(McVersionCurrent.PathIndie & "resourcepacks\")
             Dim ZipFileAddress As String = McVersionCurrent.PathIndie & "resourcepacks\PCL2 Skin.zip"
             Dim ZipFileAddress As String = McVersionCurrent.PathIndie & "resourcepacks\PCL2 Skin.zip"
             Dim NewTypeSetup As Boolean = McVersionCurrent.Version.McCodeMain >= 13 OrElse McVersionCurrent.Version.McCodeMain < 6
             Dim NewTypeSetup As Boolean = McVersionCurrent.Version.McCodeMain >= 13 OrElse McVersionCurrent.Version.McCodeMain < 6
-            If McLoginLoader.Input.Type = McLoginType.Legacy AndAlso Setup.Get("LaunchSkinType") = 4 AndAlso File.Exists(PathTemp & "CustomSkin.png") Then
+            If McLoginLoader.Input.Type = McLoginType.Legacy AndAlso Setup.Get("LaunchSkinType") = 4 AndAlso File.Exists(PathAppdata & "CustomSkin.png") Then
                 Directory.CreateDirectory(PathTemp)
                 Directory.CreateDirectory(PathTemp)
                 Dim MetaFileAddress As String = PathTemp & "pack.mcmeta"
                 Dim MetaFileAddress As String = PathTemp & "pack.mcmeta"
                 Dim PackPicAddress As String = PathTemp & "pack.png"
                 Dim PackPicAddress As String = PathTemp & "pack.png"
@@ -1659,7 +1664,7 @@ NextVersion:
                 Dim Bit As New MyBitmap(PathImage & "Heads/Logo.png")
                 Dim Bit As New MyBitmap(PathImage & "Heads/Logo.png")
                 Bit.Save(PackPicAddress)
                 Bit.Save(PackPicAddress)
                 WriteFile(MetaFileAddress, "{""pack"":{""pack_format"":" & PackFormat & ",""description"":""PCL2 自定义离线皮肤资源包""}}")
                 WriteFile(MetaFileAddress, "{""pack"":{""pack_format"":" & PackFormat & ",""description"":""PCL2 自定义离线皮肤资源包""}}")
-                Dim Skin As New MyBitmap(PathTemp & "CustomSkin.png")
+                Dim Skin As New MyBitmap(PathAppdata & "CustomSkin.png")
                 If (McVersionCurrent.Version.McCodeMain = 6 OrElse McVersionCurrent.Version.McCodeMain = 7) AndAlso Skin.Pic.Height = 64 Then
                 If (McVersionCurrent.Version.McCodeMain = 6 OrElse McVersionCurrent.Version.McCodeMain = 7) AndAlso Skin.Pic.Height = 64 Then
                     McLaunchLog("该 Minecraft 版本不支持双层皮肤,已进行裁剪")
                     McLaunchLog("该 Minecraft 版本不支持双层皮肤,已进行裁剪")
                     Skin = Skin.Clip(New System.Drawing.Rectangle(0, 0, 64, 32))
                     Skin = Skin.Clip(New System.Drawing.Rectangle(0, 0, 64, 32))

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

@@ -404,7 +404,6 @@ Wait:
             Log(ex, "遍历查找 Java 时出错(" & OriginalPath.FullName & ")")
             Log(ex, "遍历查找 Java 时出错(" & OriginalPath.FullName & ")")
         End Try
         End Try
     End Sub
     End Sub
-    Public PathAppdata As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\PCL\"
 
 
     '获取
     '获取
 
 
@@ -837,7 +836,7 @@ UserPass:
         ''' </summary>
         ''' </summary>
         Public ReadOnly Property PathIndie As String
         Public ReadOnly Property PathIndie As String
             Get
             Get
-                Return GetPathIndie(Version.Modable)
+                Return GetPathIndie(Modable)
             End Get
             End Get
         End Property
         End Property
         ''' <summary>
         ''' <summary>
@@ -917,6 +916,15 @@ UserPass:
         ''' </summary>
         ''' </summary>
         Public DisplayType As McVersionCardType = McVersionCardType.Auto
         Public DisplayType As McVersionCardType = McVersionCardType.Auto
         ''' <summary>
         ''' <summary>
+        ''' 该版本是否可以安装 Mod。
+        ''' </summary>
+        Public ReadOnly Property Modable As Boolean
+            Get
+                Return Version.HasFabric OrElse Version.HasForge OrElse Version.HasLiteLoader OrElse
+                    DisplayType = McVersionCardType.API '#223
+            End Get
+        End Property
+        ''' <summary>
         ''' 版本信息。
         ''' 版本信息。
         ''' </summary>
         ''' </summary>
         Public Property Version As McVersionInfo
         Public Property Version As McVersionInfo
@@ -1009,7 +1017,7 @@ UserPass:
                             _Version.McName = Regex
                             _Version.McName = Regex
                             GoTo VersionSearchFinish
                             GoTo VersionSearchFinish
                         End If
                         End If
-                        'TODO: [Quilt 支持] 从 Quilt 版本中获取版本号
+                        'FUTURE: [Quilt 支持] 从 Quilt 版本中获取版本号
                         '从 jar 项中获取版本号
                         '从 jar 项中获取版本号
                         If JsonObject("jar") IsNot Nothing Then
                         If JsonObject("jar") IsNot Nothing Then
                             _Version.McName = JsonObject("jar").ToString
                             _Version.McName = JsonObject("jar").ToString
@@ -1324,7 +1332,7 @@ Recheck:
                             Version.HasLiteLoader = True
                             Version.HasLiteLoader = True
                         End If
                         End If
                         'Fabric、Forge
                         'Fabric、Forge
-                        'TODO: [Quilt 支持] 确认这里的玩意儿对不对
+                        'FUTURE: [Quilt 支持] 确认这里的玩意儿对不对
                         If RealJson.Contains("net.fabricmc:fabric-loader") OrElse RealJson.Contains("org.quiltmc:quilt-loader") Then
                         If RealJson.Contains("net.fabricmc:fabric-loader") OrElse RealJson.Contains("org.quiltmc:quilt-loader") Then
                             State = McVersionState.Fabric
                             State = McVersionState.Fabric
                             Version.FabricVersion = If(RegexSeek(RealJson, "(?<=(net.fabricmc:fabric-loader:)|(org.quiltmc:quilt-loader:))[0-9\.]+(\+build.[0-9]+)?"), "未知版本").Replace("+build", "")
                             Version.FabricVersion = If(RegexSeek(RealJson, "(?<=(net.fabricmc:fabric-loader:)|(org.quiltmc:quilt-loader:))[0-9\.]+(\+build.[0-9]+)?"), "未知版本").Replace("+build", "")
@@ -1511,15 +1519,6 @@ ExitDataLoad:
 
 
         'API
         'API
 
 
-        ''' <summary>
-        ''' 该版本是否可以安装 Mod。
-        ''' </summary>
-        Public ReadOnly Property Modable As Boolean
-            Get
-                Return HasFabric OrElse HasForge OrElse HasLiteLoader
-            End Get
-        End Property
-
         ''' <summary>
         ''' <summary>
         ''' 生成对此版本信息的用户友好的描述性字符串。
         ''' 生成对此版本信息的用户友好的描述性字符串。
         ''' </summary>
         ''' </summary>

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

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

+ 0 - 10
Plain Craft Launcher 2/My Project/Resources.Designer.vb

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

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

@@ -142,9 +142,6 @@
   <data name="NAudio" type="System.Resources.ResXFileRef, System.Windows.Forms">
   <data name="NAudio" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
     <value>..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
   </data>
-  <data name="STUN" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\STUN.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </data>
   <data name="Transformer" type="System.Resources.ResXFileRef, System.Windows.Forms">
   <data name="Transformer" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\transformer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
     <value>..\Resources\transformer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </data>
   </data>

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

@@ -378,12 +378,7 @@ Public Module ModDownloadLib
             Throw New Exception("未找到用于安装 OptiFine 的 Java")
             Throw New Exception("未找到用于安装 OptiFine 的 Java")
         End If
         End If
         '添加 Java Wrapper 作为主 Jar
         '添加 Java Wrapper 作为主 Jar
-        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
-        If Not File.Exists(WrapperPath) Then
-            WriteFile(WrapperPath, GetResources("JavaWrapper"))
-            McLaunchLog("已自动释放 Java Wrapper")
-        End If
-        Dim Arguments = "-Duser.home=""" & BaseMcFolderHome & """ -cp """ & Target & """ -jar """ & WrapperPath & """ optifine.Installer"
+        Dim Arguments = "-Duser.home=""" & BaseMcFolderHome & """ -cp """ & Target & """ -jar """ & ExtractJavaWrapper() & """ optifine.Installer"
         If Java.VersionCode >= 9 Then Arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " & Arguments
         If Java.VersionCode >= 9 Then Arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " & Arguments
         '开始启动
         '开始启动
         SyncLock InstallSyncLock
         SyncLock InstallSyncLock
@@ -528,7 +523,10 @@ Public Module ModDownloadLib
                                                                              '等待原版文件下载完成
                                                                              '等待原版文件下载完成
                                                                              For Each Loader In ClientDownloadLoader.GetLoaderList
                                                                              For Each Loader In ClientDownloadLoader.GetLoaderList
                                                                                  If Loader.Name <> McDownloadClientLibName Then Continue For
                                                                                  If Loader.Name <> McDownloadClientLibName Then Continue For
-                                                                                 Loader.WaitForExit()
+                                                                                 If Loader.State = LoadState.Loading Then
+                                                                                     Log("[Download] OptiFine 安装正在等待原版文件下载完成")
+                                                                                     Loader.WaitForExit()
+                                                                                 End If
                                                                                  Exit For
                                                                                  Exit For
                                                                              Next
                                                                              Next
                                                                              '拷贝原版文件
                                                                              '拷贝原版文件
@@ -1094,12 +1092,7 @@ Public Module ModDownloadLib
             Throw New Exception("未找到用于安装 Forge 的 Java")
             Throw New Exception("未找到用于安装 Forge 的 Java")
         End If
         End If
         '添加 Java Wrapper 作为主 Jar
         '添加 Java Wrapper 作为主 Jar
-        Dim WrapperPath As String = PathAppdata & "JavaWrapper.jar"
-        If Not File.Exists(WrapperPath) Then
-            WriteFile(WrapperPath, GetResources("JavaWrapper"))
-            McLaunchLog("已自动释放 Java Wrapper")
-        End If
-        Dim Arguments = "-cp """ & PathTemp & "Cache\forge_installer.jar;" & Target & """ -jar """ & WrapperPath & """  com.bangbang93.ForgeInstaller """ & McFolder
+        Dim Arguments = "-cp """ & PathTemp & "Cache\forge_installer.jar;" & Target & """ -jar """ & ExtractJavaWrapper() & """  com.bangbang93.ForgeInstaller """ & McFolder
         If Java.VersionCode >= 9 Then Arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " & Arguments
         If Java.VersionCode >= 9 Then Arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " & Arguments
         '开始启动
         '开始启动
         SyncLock InstallSyncLock
         SyncLock InstallSyncLock
@@ -1339,7 +1332,10 @@ Public Module ModDownloadLib
                                                                              '等待原版文件下载完成
                                                                              '等待原版文件下载完成
                                                                              For Each Loader In ClientDownloadLoader.GetLoaderList
                                                                              For Each Loader In ClientDownloadLoader.GetLoaderList
                                                                                  If Loader.Name <> McDownloadClientLibName Then Continue For
                                                                                  If Loader.Name <> McDownloadClientLibName Then Continue For
-                                                                                 Loader.WaitForExit()
+                                                                                 If Loader.State = LoadState.Loading Then
+                                                                                     Log("[Download] Forge 安装正在等待原版文件下载完成")
+                                                                                     Loader.WaitForExit()
+                                                                                 End If
                                                                                  Exit For
                                                                                  Exit For
                                                                              Next
                                                                              Next
                                                                              '拷贝原版文件
                                                                              '拷贝原版文件

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

@@ -119,7 +119,7 @@
 #End Region
 #End Region
 
 
     Private IsFirstInit As Boolean = True
     Private IsFirstInit As Boolean = True
-    Public Sub Init() Handles Me.OnPageEnter
+    Public Sub Init() Handles Me.PageEnter
         AniControlEnabled += 1
         AniControlEnabled += 1
         Project = FrmMain.PageCurrent.Additional
         Project = FrmMain.PageCurrent.Additional
         PanBack.ScrollToHome()
         PanBack.ScrollToHome()
@@ -200,7 +200,7 @@
                 DefaultFolder = DownloadFolder
                 DefaultFolder = DownloadFolder
                 If McVersionCurrent IsNot Nothing Then
                 If McVersionCurrent IsNot Nothing Then
                     If Not McVersionCurrent.IsLoaded Then McVersionCurrent.Load()
                     If Not McVersionCurrent.IsLoaded Then McVersionCurrent.Load()
-                    If McVersionCurrent.Version.Modable Then
+                    If McVersionCurrent.Modable Then
                         DefaultFolder = McVersionCurrent.PathIndie & "mods\"
                         DefaultFolder = McVersionCurrent.PathIndie & "mods\"
                         Directory.CreateDirectory(DefaultFolder)
                         Directory.CreateDirectory(DefaultFolder)
                     End If
                     End If

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

@@ -479,12 +479,12 @@ UseDefault:
                     End If
                     End If
                 End Try
                 End Try
             Case 4 '自定义
             Case 4 '自定义
-                If Not File.Exists(PathTemp & "CustomSkin.png") Then
+                If Not File.Exists(PathAppdata & "CustomSkin.png") Then
                     Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL2 将使用默认的 Steve 皮肤!")
                     Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL2 将使用默认的 Steve 皮肤!")
                     Setup.Set("LaunchSkinType", 1)
                     Setup.Set("LaunchSkinType", 1)
                     GoTo UseDefault
                     GoTo UseDefault
                 End If
                 End If
-                Data.Output = PathTemp & "CustomSkin.png"
+                Data.Output = PathAppdata & "CustomSkin.png"
         End Select
         End Select
         '刷新显示
         '刷新显示
         If FrmLoginLegacy IsNot Nothing Then
         If FrmLoginLegacy IsNot Nothing Then
@@ -607,7 +607,7 @@ Finish:
     Public Sub LaunchButtonClick(Optional ServerIp As String = "")
     Public Sub LaunchButtonClick(Optional ServerIp As String = "")
         If BtnLaunch.IsEnabled AndAlso BtnLaunch.Visibility = Visibility.Visible AndAlso BtnLaunch.IsHitTestVisible Then
         If BtnLaunch.IsEnabled AndAlso BtnLaunch.Visibility = Visibility.Visible AndAlso BtnLaunch.IsHitTestVisible Then
             If BtnLaunch.Text = "启动游戏" Then
             If BtnLaunch.Text = "启动游戏" Then
-                McLaunchLoader.Start(ServerIp)
+                McLaunchLoader.Start(ServerIp, IsForceRestart:=True)
             ElseIf BtnLaunch.Text = "下载游戏" Then
             ElseIf BtnLaunch.Text = "下载游戏" Then
                 FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
                 FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
             End If
             End If

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

@@ -88,7 +88,7 @@
                                    MySkin.ReloadCache("http://textures.minecraft.net/texture/" & Result, False)
                                    MySkin.ReloadCache("http://textures.minecraft.net/texture/" & Result, False)
                                ElseIf Result.ToLower.Contains("ip not secured") Then
                                ElseIf Result.ToLower.Contains("ip not secured") Then
                                    If MyMsgBox("首次操作需要在官网验证密保问题。" & vbCrLf & "验证完成后,你即可使用 PCL 更改皮肤,且无需再次验证。", "验证密保问题", "开始验证", "取消") = 1 Then
                                    If MyMsgBox("首次操作需要在官网验证密保问题。" & vbCrLf & "验证完成后,你即可使用 PCL 更改皮肤,且无需再次验证。", "验证密保问题", "开始验证", "取消") = 1 Then
-                                       OpenWebsite("https://www.minecraft.net/zh-hans/msaprofile/mygames/editskin")
+                                       OpenWebsite("https://www.minecraft.net/zh-hans/profile/skin")
                                    End If
                                    End If
                                ElseIf Result.Contains("request requires user authentication") Then
                                ElseIf Result.Contains("request requires user authentication") Then
                                    Hint("正在重新登录,请稍后再次尝试更改皮肤!")
                                    Hint("正在重新登录,请稍后再次尝试更改皮肤!")

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

@@ -20,7 +20,7 @@
     ''' </summary>
     ''' </summary>
     Public Shared Function GetLoginData() As McLoginMs
     Public Shared Function GetLoginData() As McLoginMs
         If McLoginMsLoader.State = LoadState.Finished Then
         If McLoginMsLoader.State = LoadState.Finished Then
-            Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName"), .AccessToken = Setup.Get("CacheMsAccess"), .Uuid = Setup.Get("CacheMsUuid")}
+            Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName"), .AccessToken = Setup.Get("CacheMsAccess"), .Uuid = Setup.Get("CacheMsUuid"), .ProfileJson = Setup.Get("CacheMsProfileJson")}
         Else
         Else
             Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName")}
             Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName")}
         End If
         End If
@@ -51,6 +51,7 @@
     Private Sub BtnExit_Click() Handles BtnExit.Click
     Private Sub BtnExit_Click() Handles BtnExit.Click
         Setup.Set("CacheMsOAuthRefresh", "")
         Setup.Set("CacheMsOAuthRefresh", "")
         Setup.Set("CacheMsAccess", "")
         Setup.Set("CacheMsAccess", "")
+        Setup.Set("CacheMsProfileJson", "")
         Setup.Set("CacheMsUuid", "")
         Setup.Set("CacheMsUuid", "")
         Setup.Set("CacheMsName", "")
         Setup.Set("CacheMsName", "")
         McLoginMsLoader.Abort()
         McLoginMsLoader.Abort()

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

@@ -4,31 +4,35 @@
              xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              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"
              mc:Ignorable="d" x:Class="PageLinkFeedback"
              d:DesignWidth="800" d:DesignHeight="800">
              d:DesignWidth="800" d:DesignHeight="800">
-    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
-        <local:MyCard Title="反馈途径选择">
-            <StackPanel Margin="20,40,18,18">
-                <local:MyListItem Title="联机模块反馈" Info="向联机模块开发者反馈联机失败等异常"
-                              Type="Clickable" EventType="打开网页" EventData="https://mcer.cn/"
-                              PaddingRight="20" Logo="pack://application:,,,/images/Blocks/RedstoneBlock.png" />
-                <local:MyListItem Title="违法违规举报" Info="投诉、举报联机使用者的各类违法违规行为"
+    <local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
+        <StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
+            <local:MyCard Title="关于" Margin="0,0,0,15">
+                <StackPanel Margin="20,40,18,18">
+                    <TextBlock TextWrapping="Wrap" Text="多人联机服务由速聚授权提供,PCL2 仅为速聚提供多人联机服务入口,使用中遇到的任何问题由速聚负责处理。你在使用多人联机服务过程中所遇到的任何问题与纠纷(包括其付费业务)均与 PCL2 无关,应与速聚协商解决。" 
+                           Margin="0,0,0,3" />
+                    <TextBlock TextWrapping="Wrap" Text="PCL2 作者并不会从速聚的付费业务中获得任何分成、奖金等报酬,请不要瞎说。" 
+                           Margin="0,0,0,6" />
+                    <local:MyListItem Title="速聚官网" Info="打开速聚的官方网站"
+                              Type="Clickable" EventType="打开网页" EventData="https://www.the.bb/zh-cn"
+                              PaddingRight="20" Logo="pack://application:,,,/images/Blocks/Grass.png" />
+                    <local:MyListItem Title="授权协议书" Info="查看速聚与 PCL2 间的授权协议书"
+                              Type="Clickable" EventType="打开网页" EventData="https://shimo.im/docs/0l3NVXYzeXhb903R"
+                              PaddingRight="20" Logo="pack://application:,,,/images/Blocks/Grass.png" />
+                    <local:MyListItem Title="用户协议与隐私政策" Info="查看速聚的用户协议与隐私政策文档"
+                              Type="Clickable" EventType="打开网页" EventData="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxMTMyODk3Mg==&amp;action=getalbum&amp;album_id=2585385685407514625&amp;scene=173&amp;from_msgid=2247483720&amp;from_itemidx=1&amp;count=3&amp;nolastread=1#wechat_redirect"
+                              PaddingRight="20" Logo="pack://application:,,,/images/Blocks/Grass.png" />
+                </StackPanel>
+            </local:MyCard>
+            <local:MyCard Title="发送反馈" Margin="0,0,0,15">
+                <StackPanel Margin="20,40,18,18">
+                    <local:MyListItem Title="联机反馈与交流" Info="加入联机模块官方 QQ 群反馈联机异常,或询问联机功能的使用方式"
+                              Type="Clickable" PaddingRight="20" Logo="pack://application:,,,/images/Blocks/RedstoneBlock.png"
+                              EventType="打开网页" EventData="https://shimowendang.com/docs/KrkEVXz1K0frowAJ#anchor-7qQG" />
+                    <local:MyListItem Title="违法违规举报" Info="投诉、举报联机使用者的各类违法违规行为"
                               Type="Clickable" EventType="打开网页" EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW#anchor-7x6P"
                               Type="Clickable" EventType="打开网页" EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW#anchor-7x6P"
                               PaddingRight="20" Logo="pack://application:,,,/images/Blocks/RedstoneBlock.png" />
                               PaddingRight="20" Logo="pack://application:,,,/images/Blocks/RedstoneBlock.png" />
-            </StackPanel>
-        </local:MyCard>
-        <local:MyCard Margin="0,20,0,15">
-            <Grid Margin="15,12">
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="1*"/>
-                    <ColumnDefinition Width="Auto" />
-                    <ColumnDefinition Width="Auto" />
-                    <ColumnDefinition Width="Auto" />
-                    <ColumnDefinition Width="1*"/>
-                </Grid.ColumnDefinitions>
-                <TextBlock Grid.Column="1" Text="联机服务由 " Opacity="0.5"/>
-                <local:MyTextButton Grid.Column="2" Text="阿猫" x:Name="BtnNoin" Opacity="0.5"
-                                    EventType="打开网页" EventData="https://mcer.cn" />
-                <TextBlock Grid.Column="3" Text=" 授权提供" Opacity="0.5"/>
-            </Grid>
-        </local:MyCard>
-    </StackPanel>
+                </StackPanel>
+            </local:MyCard>
+        </StackPanel>
+    </local:MyScrollViewer>
 </local:MyPageRight>
 </local:MyPageRight>

+ 0 - 1
Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml.vb

@@ -1,3 +1,2 @@
 Public Class PageLinkFeedback
 Public Class PageLinkFeedback
-
 End Class
 End Class

Fișier diff suprimat deoarece este prea mare
+ 108 - 0
Plain Craft Launcher 2/Pages/PageLink/PageLinkHiper.xaml


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

@@ -8,7 +8,6 @@
     <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">
-                <local:MyHint Margin="0,15,0,0" Text="联机功能仍处于测试阶段,尚未制作完成,因此延迟很高,且存在较多 Bug。延迟与内存占用高的问题将在后续优化,请多多包涵……" />
                 <local:MyCard Margin="0,15,0,0" x:Name="CardUser" Title="已连接的玩家 (0)">
                 <local:MyCard Margin="0,15,0,0" x:Name="CardUser" Title="已连接的玩家 (0)">
                     <StackPanel Margin="20,37,20,15">
                     <StackPanel Margin="20,37,20,15">
                         <local:MyHint Margin="5,2,5,8" x:Name="LabHint" IsWarn="False" />
                         <local:MyHint Margin="5,2,5,8" x:Name="LabHint" IsWarn="False" />
@@ -19,7 +18,7 @@
                                 <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
                                 <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
                             </Grid.ColumnDefinitions>
                             </Grid.ColumnDefinitions>
                             <local:MyButton x:Name="BtnLeftCreate" Grid.Column="0" MinWidth="140" Text="建立连接" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
                             <local:MyButton x:Name="BtnLeftCreate" Grid.Column="0" MinWidth="140" Text="建立连接" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
-                            <local:MyButton x:Name="BtnLeftCopy" Grid.Column="1" MinWidth="140" Text="复制连接码" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
+                            <local:MyButton x:Name="BtnLeftCopy" Grid.Column="1" MinWidth="140" Text="复制联机码" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
                         </Grid>
                         </Grid>
                     </StackPanel>
                     </StackPanel>
                 </local:MyCard>
                 </local:MyCard>
@@ -44,5 +43,8 @@
         <local:MyCard Opacity="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40,0" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
         <local:MyCard Opacity="0" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40,0" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
             <local:MyLoading Text="正在加载联机模块" Margin="20,20,20,17" x:Name="Load" ShowProgress="True" HorizontalAlignment="Center" VerticalAlignment="Center" />
             <local:MyLoading Text="正在加载联机模块" Margin="20,20,20,17" x:Name="Load" ShowProgress="True" HorizontalAlignment="Center" VerticalAlignment="Center" />
         </local:MyCard>
         </local:MyCard>
+        <Grid x:Name="PanAlways" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="15" Opacity="0.5">
+            <local:MyTextButton Text="联机服务由 速聚 授权提供" EventType="打开网页" EventData="https://www.the.bb/zh-cn" />
+        </Grid>
     </Grid>
     </Grid>
 </local:MyPageRight>
 </local:MyPageRight>

+ 8 - 18
Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml

@@ -6,28 +6,18 @@
       xmlns:local="clr-namespace:PCL"
       xmlns:local="clr-namespace:PCL"
       mc:Ignorable="d" AnimatedControl="{Binding ElementName=PanItem}" MinWidth="150">
       mc:Ignorable="d" AnimatedControl="{Binding ElementName=PanItem}" MinWidth="150">
     <StackPanel Orientation="Vertical" x:Name="PanItem" Margin="0,12,0,0">
     <StackPanel Orientation="Vertical" x:Name="PanItem" Margin="0,12,0,0">
-        <local:MyListItem x:Name="ItemNet" IsScaleAnimationEnabled="False" Type="None" PaddingLeft="2" Height="36" Title="网络检测中" PaddingRight="35" 
-            LogoScale="0.75" Logo="M512 817c-48.601 0-88-39.399-88-88s39.399-88 88-88 88 39.399 88 88-39.399 88-88 88zM237.671 565.74C308.335 474.58 397.369 429 504.774 429c118.433 0 214.225 55.421 287.377 166.264l-53.407 30.369c-13.84 7.87-31.362 4.367-41.114-8.219-50.291-64.911-114.577-97.367-192.856-97.367-86.851 0-156.835 40.318-209.95 120.953l-47.995-28.02c-15.263-8.91-20.412-28.507-11.502-43.77a32 32 0 0 1 2.344-3.47zM107.691 419.47C205.24 278.491 337.805 208 505.379 208c178.77 0 317.694 80.224 416.772 240.672l-56.54 31.73c-13.686 7.68-30.922 4.303-40.697-7.975C735.581 360.213 629.07 303.009 505.38 300.815 373.997 298.485 261.637 362.88 168.3 494l-50.116-28.505c-15.362-8.738-20.732-28.275-11.994-43.637a32 32 0 0 1 1.5-2.387z"
-            ToolTipService.Placement="Bottom" ToolTipService.HorizontalOffset="10" ToolTipService.VerticalOffset="0" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="20">
-            <local:MyListItem.Buttons>
-                <x:Array Type="{x:Type local:MyIconButton}">
-                    <local:MyIconButton Click="BtnNetRescan_Click" ToolTip="重新检测" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" ToolTipService.VerticalOffset="-2" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" Visibility="Collapsed"
-                                    LogoScale="0.85" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
-                </x:Array>
-            </local:MyListItem.Buttons>
-        </local:MyListItem>
-        <TextBlock Text="联机方式" Margin="13,18,5,5" Opacity="0.6" FontSize="12" />
-        <local:MyListItem x:Name="ItemCato" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="2" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="Cato" Visibility="Collapsed" 
+        <TextBlock Text="联机方式" Margin="13,6,5,4" Opacity="0.6" FontSize="12" />
+        <local:MyListItem x:Name="ItemHiper" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="1" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="HiPer"
                           LogoScale="0.85" Logo="M554.496 170.496c141.312 0 256 114.688 256 256s-114.688 256-256 256H402.432c-22.016-1.536-39.424-19.968-39.424-42.496a42.391 42.391 0 0 1 42.496-42.496h149.504c94.208 0 170.496-76.288 170.496-170.496S648.704 256 554.496 256h-256C204.288 256 128 332.288 128 426.496c0 38.4 12.8 73.728 33.792 102.4 5.632 7.168 8.704 15.872 8.704 25.6A42.391 42.391 0 0 1 128 596.992c-11.264 0-20.992-4.096-28.672-11.264l-0.512 0.512c-35.328-44.032-56.32-99.328-56.32-159.744 0-141.312 114.688-256 256-256h256z m64 192h3.072c22.016 1.536 39.424 19.968 39.424 42.496a42.391 42.391 0 0 1-42.496 42.496H469.504c-94.208 0-170.496 76.288-170.496 170.496S375.296 788.48 469.504 788.48h256C819.712 788.48 896 712.192 896 617.984c0-38.4-12.8-73.728-33.792-102.4-5.632-7.168-8.704-15.872-8.704-25.6A42.391 42.391 0 0 1 896 447.488c11.264 0 20.992 4.096 28.672 11.264l0.512-0.512c35.328 44.032 56.32 99.328 56.32 159.744 0 141.312-114.688 256-256 256h-256c-141.312 0-256-114.688-256-256s114.688-256 256-256h148.992z">
                           LogoScale="0.85" Logo="M554.496 170.496c141.312 0 256 114.688 256 256s-114.688 256-256 256H402.432c-22.016-1.536-39.424-19.968-39.424-42.496a42.391 42.391 0 0 1 42.496-42.496h149.504c94.208 0 170.496-76.288 170.496-170.496S648.704 256 554.496 256h-256C204.288 256 128 332.288 128 426.496c0 38.4 12.8 73.728 33.792 102.4 5.632 7.168 8.704 15.872 8.704 25.6A42.391 42.391 0 0 1 128 596.992c-11.264 0-20.992-4.096-28.672-11.264l-0.512 0.512c-35.328-44.032-56.32-99.328-56.32-159.744 0-141.312 114.688-256 256-256h256z m64 192h3.072c22.016 1.536 39.424 19.968 39.424 42.496a42.391 42.391 0 0 1-42.496 42.496H469.504c-94.208 0-170.496 76.288-170.496 170.496S375.296 788.48 469.504 788.48h256C819.712 788.48 896 712.192 896 617.984c0-38.4-12.8-73.728-33.792-102.4-5.632-7.168-8.704-15.872-8.704-25.6A42.391 42.391 0 0 1 896 447.488c11.264 0 20.992 4.096 28.672 11.264l0.512-0.512c35.328 44.032 56.32 99.328 56.32 159.744 0 141.312-114.688 256-256 256h-256c-141.312 0-256-114.688-256-256s114.688-256 256-256h148.992z">
             <local:MyListItem.Buttons>
             <local:MyListItem.Buttons>
                 <x:Array Type="{x:Type local:MyIconButton}">
                 <x:Array Type="{x:Type local:MyIconButton}">
-                    <local:MyIconButton ToolTip="关闭联机模块" Loaded="BtnCatoStop_Loaded" Click="BtnCatoStop_Click"
+                    <local:MyIconButton ToolTip="关闭联机模块" Loaded="BtnHiperStop_Loaded" Click="BtnHiperStop_Click"
                                         ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" ToolTipService.VerticalOffset="-2" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.7" 
                                         ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" ToolTipService.VerticalOffset="-2" ToolTipService.ShowDuration="2333333" ToolTipService.InitialShowDelay="200" LogoScale="0.7" 
                                         Logo="M576 512l277.333333 277.333333-64 64-277.333333-277.333333L234.666667 853.333333 170.666667 789.333333l277.333333-277.333333L170.666667 234.666667 234.666667 170.666667l277.333333 277.333333L789.333333 170.666667 853.333333 234.666667 576 512z" />
                                         Logo="M576 512l277.333333 277.333333-64 64-277.333333-277.333333L234.666667 853.333333 170.666667 789.333333l277.333333-277.333333L170.666667 234.666667 234.666667 170.666667l277.333333 277.333333L789.333333 170.666667 853.333333 234.666667 576 512z" />
                 </x:Array>
                 </x:Array>
             </local:MyListItem.Buttons>
             </local:MyListItem.Buttons>
         </local:MyListItem>
         </local:MyListItem>
-        <local:MyListItem x:Name="ItemIoi" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="3" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="IOI"
+        <local:MyListItem x:Name="ItemIoi" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="2" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="IOI"
                           LogoScale="0.85" Logo="M554.496 170.496c141.312 0 256 114.688 256 256s-114.688 256-256 256H402.432c-22.016-1.536-39.424-19.968-39.424-42.496a42.391 42.391 0 0 1 42.496-42.496h149.504c94.208 0 170.496-76.288 170.496-170.496S648.704 256 554.496 256h-256C204.288 256 128 332.288 128 426.496c0 38.4 12.8 73.728 33.792 102.4 5.632 7.168 8.704 15.872 8.704 25.6A42.391 42.391 0 0 1 128 596.992c-11.264 0-20.992-4.096-28.672-11.264l-0.512 0.512c-35.328-44.032-56.32-99.328-56.32-159.744 0-141.312 114.688-256 256-256h256z m64 192h3.072c22.016 1.536 39.424 19.968 39.424 42.496a42.391 42.391 0 0 1-42.496 42.496H469.504c-94.208 0-170.496 76.288-170.496 170.496S375.296 788.48 469.504 788.48h256C819.712 788.48 896 712.192 896 617.984c0-38.4-12.8-73.728-33.792-102.4-5.632-7.168-8.704-15.872-8.704-25.6A42.391 42.391 0 0 1 896 447.488c11.264 0 20.992 4.096 28.672 11.264l0.512-0.512c35.328 44.032 56.32 99.328 56.32 159.744 0 141.312-114.688 256-256 256h-256c-141.312 0-256-114.688-256-256s114.688-256 256-256h148.992z">
                           LogoScale="0.85" Logo="M554.496 170.496c141.312 0 256 114.688 256 256s-114.688 256-256 256H402.432c-22.016-1.536-39.424-19.968-39.424-42.496a42.391 42.391 0 0 1 42.496-42.496h149.504c94.208 0 170.496-76.288 170.496-170.496S648.704 256 554.496 256h-256C204.288 256 128 332.288 128 426.496c0 38.4 12.8 73.728 33.792 102.4 5.632 7.168 8.704 15.872 8.704 25.6A42.391 42.391 0 0 1 128 596.992c-11.264 0-20.992-4.096-28.672-11.264l-0.512 0.512c-35.328-44.032-56.32-99.328-56.32-159.744 0-141.312 114.688-256 256-256h256z m64 192h3.072c22.016 1.536 39.424 19.968 39.424 42.496a42.391 42.391 0 0 1-42.496 42.496H469.504c-94.208 0-170.496 76.288-170.496 170.496S375.296 788.48 469.504 788.48h256C819.712 788.48 896 712.192 896 617.984c0-38.4-12.8-73.728-33.792-102.4-5.632-7.168-8.704-15.872-8.704-25.6A42.391 42.391 0 0 1 896 447.488c11.264 0 20.992 4.096 28.672 11.264l0.512-0.512c35.328 44.032 56.32 99.328 56.32 159.744 0 141.312-114.688 256-256 256h-256c-141.312 0-256-114.688-256-256s114.688-256 256-256h148.992z">
             <local:MyListItem.Buttons>
             <local:MyListItem.Buttons>
                 <x:Array Type="{x:Type local:MyIconButton}">
                 <x:Array Type="{x:Type local:MyIconButton}">
@@ -37,8 +27,8 @@
                 </x:Array>
                 </x:Array>
             </local:MyListItem.Buttons>
             </local:MyListItem.Buttons>
         </local:MyListItem>
         </local:MyListItem>
-        <TextBlock Text="更多选项" Margin="13,18,5,5" Opacity="0.6" FontSize="12" />
-        <local:MyListItem x:Name="ItemSetup" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="5" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="设置"
+        <TextBlock Text="更多选项" Margin="13,18,5,4" Opacity="0.6" FontSize="12" />
+        <local:MyListItem x:Name="ItemSetup" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="设置"
                           LogoScale="0.85" Logo="M940.4 463.7L773.3 174.2c-17.3-30-49.2-48.4-83.8-48.4H340.2c-34.6 0-66.5 18.5-83.8 48.4L89.2 463.7c-17.3 30-17.3 66.9 0 96.8L256.4 850c17.3 30 49.2 48.4 83.8 48.4h349.2c34.6 0 66.5-18.5 83.8-48.4l167.2-289.5c17.3-29.9 17.3-66.8 0-96.8z m-94.6 96.8L725.9 768.1c-17.3 30-49.2 48.4-83.8 48.4H387.5c-34.6 0-66.5-18.5-83.8-48.4L183.9 560.5c-17.3-30-17.3-66.9 0-96.8l119.8-207.5c17.3-30 49.2-48.4 83.8-48.4h254.6c34.6 0 66.5 18.5 83.8 48.4l119.8 207.5c17.3 30 17.3 66.9 0.1 96.8z M522.3 321.2c-2.5-0.1-5-0.2-7.5-0.2-119.9 0-214 110.3-186.3 235 15.8 70.9 71.5 126.6 142.4 142.4 17.5 3.9 34.7 5.4 51.4 4.7 102.1-3.9 183.6-87.9 183.6-191 0.1-103-81.5-187-183.6-190.9z m68.6 269.1c-18.5 18-43 28.9-68.6 30.7l-6 0.3c-30.2 0.4-58.6-11.4-79.7-33-19.5-20.1-30.7-47-30.9-75-0.3-29.6 11.1-57.4 32-78.3 20.6-20.6 48-32 77.2-32 2.5 0 5 0.1 7.5 0.3 26.7 1.8 51.5 13.2 70.5 32.5 19.6 20 30.8 46.9 31.2 74.9 0.2 30.2-11.5 58.6-33.2 79.6z">
                           LogoScale="0.85" Logo="M940.4 463.7L773.3 174.2c-17.3-30-49.2-48.4-83.8-48.4H340.2c-34.6 0-66.5 18.5-83.8 48.4L89.2 463.7c-17.3 30-17.3 66.9 0 96.8L256.4 850c17.3 30 49.2 48.4 83.8 48.4h349.2c34.6 0 66.5-18.5 83.8-48.4l167.2-289.5c17.3-29.9 17.3-66.8 0-96.8z m-94.6 96.8L725.9 768.1c-17.3 30-49.2 48.4-83.8 48.4H387.5c-34.6 0-66.5-18.5-83.8-48.4L183.9 560.5c-17.3-30-17.3-66.9 0-96.8l119.8-207.5c17.3-30 49.2-48.4 83.8-48.4h254.6c34.6 0 66.5 18.5 83.8 48.4l119.8 207.5c17.3 30 17.3 66.9 0.1 96.8z M522.3 321.2c-2.5-0.1-5-0.2-7.5-0.2-119.9 0-214 110.3-186.3 235 15.8 70.9 71.5 126.6 142.4 142.4 17.5 3.9 34.7 5.4 51.4 4.7 102.1-3.9 183.6-87.9 183.6-191 0.1-103-81.5-187-183.6-190.9z m68.6 269.1c-18.5 18-43 28.9-68.6 30.7l-6 0.3c-30.2 0.4-58.6-11.4-79.7-33-19.5-20.1-30.7-47-30.9-75-0.3-29.6 11.1-57.4 32-78.3 20.6-20.6 48-32 77.2-32 2.5 0 5 0.1 7.5 0.3 26.7 1.8 51.5 13.2 70.5 32.5 19.6 20 30.8 46.9 31.2 74.9 0.2 30.2-11.5 58.6-33.2 79.6z">
             <local:MyListItem.Buttons>
             <local:MyListItem.Buttons>
                 <x:Array Type="{x:Type local:MyIconButton}">
                 <x:Array Type="{x:Type local:MyIconButton}">
@@ -46,9 +36,9 @@
                 </x:Array>
                 </x:Array>
             </local:MyListItem.Buttons>
             </local:MyListItem.Buttons>
         </local:MyListItem>
         </local:MyListItem>
-        <local:MyListItem x:Name="ItemHelp" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="6" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="常见问题"
+        <local:MyListItem x:Name="ItemHelp" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="5" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="常见问题"
                           LogoScale="0.97" Logo="M520.6 620.3c-11.3-0.6-20.1-4-26.9-10.5-6.6-6.3-8.1-11-10.1-20.8-1.9-9.5-1.5-16.7-1-24.9l0.3-5.3c0.5-9.9 3.5-19.6 8.8-28.1 5.7-9 12.5-17.2 20.8-25.1 8.6-8 17.7-15.7 27-22.9 9.4-7.2 18.7-14.8 27.7-22.7 9-7.9 16.2-15.8 22.1-24.3 6.2-9 9.3-18.8 9.3-29.4 1.2-20.3-6.5-37.7-22.8-51.3-16-13.3-37.4-20-63.5-20-13.7 0-26.3 3.3-37.4 10-10.9 6.5-20.2 14.5-27.7 23.8-7.5 9.2-13.5 19-17.9 29.2-4.5 10.6-6.7 19.4-6.7 26.8 0 9.2-3.3 16-10.1 20.8-6.9 4.8-14.6 7.3-22.8 7.3h-1.3c-9-0.3-17-3.3-24.6-9.2-7.3-5.6-11.1-14.6-11.6-27.5-0.6-11.5 1.9-26.1 7.2-43.5 5.4-17.4 14.8-34.4 28.1-50.5 13.4-16.3 31.2-30.4 52.8-41.8 21.6-11.4 49.2-17.2 81.9-17.2 26.4 0 49.6 3.9 69.1 11.7 19.4 7.7 35.4 18.2 47.5 31.1l1.6 1.7c11.8 12.6 20.3 21.7 29.4 44.4 11.6 28.9 7.1 52.1 5.5 58.5-5.8 22.6-12.6 37.7-22.7 50.4-11.7 14.6-24.9 28.2-39.2 40.4-14 11.7-39.2 33.3-39.2 33.3-13.3 11.4-19.4 22.1-18.6 32.9V587c0.5 8.7-2.4 16.1-8.8 22.8-6.2 6.4-14.8 10-26.2 10.5zM519 766.1c-13 0-23.6-4.2-32.2-12.9-8.7-8.7-13-19-13-31.4 0-12.9 4.2-23.5 12.9-32.2 8.7-8.7 19.2-12.9 32.2-12.9 13 0 23.5 4.2 32.2 12.9s12.9 19.2 12.9 32.2c0 12.4-4.2 22.7-12.9 31.4-8.6 8.6-19.2 12.9-32.1 12.9z M515 928.3c-228.1 0-413.7-185.6-413.7-413.7S286.9 100.9 515 100.9s413.7 185.6 413.7 413.7c0.1 228.1-185.5 413.7-413.7 413.7z m0-747.4c-184 0-333.7 149.7-333.7 333.7S331 848.3 515 848.3s333.7-149.7 333.7-333.7S699 180.9 515 180.9z" />
                           LogoScale="0.97" Logo="M520.6 620.3c-11.3-0.6-20.1-4-26.9-10.5-6.6-6.3-8.1-11-10.1-20.8-1.9-9.5-1.5-16.7-1-24.9l0.3-5.3c0.5-9.9 3.5-19.6 8.8-28.1 5.7-9 12.5-17.2 20.8-25.1 8.6-8 17.7-15.7 27-22.9 9.4-7.2 18.7-14.8 27.7-22.7 9-7.9 16.2-15.8 22.1-24.3 6.2-9 9.3-18.8 9.3-29.4 1.2-20.3-6.5-37.7-22.8-51.3-16-13.3-37.4-20-63.5-20-13.7 0-26.3 3.3-37.4 10-10.9 6.5-20.2 14.5-27.7 23.8-7.5 9.2-13.5 19-17.9 29.2-4.5 10.6-6.7 19.4-6.7 26.8 0 9.2-3.3 16-10.1 20.8-6.9 4.8-14.6 7.3-22.8 7.3h-1.3c-9-0.3-17-3.3-24.6-9.2-7.3-5.6-11.1-14.6-11.6-27.5-0.6-11.5 1.9-26.1 7.2-43.5 5.4-17.4 14.8-34.4 28.1-50.5 13.4-16.3 31.2-30.4 52.8-41.8 21.6-11.4 49.2-17.2 81.9-17.2 26.4 0 49.6 3.9 69.1 11.7 19.4 7.7 35.4 18.2 47.5 31.1l1.6 1.7c11.8 12.6 20.3 21.7 29.4 44.4 11.6 28.9 7.1 52.1 5.5 58.5-5.8 22.6-12.6 37.7-22.7 50.4-11.7 14.6-24.9 28.2-39.2 40.4-14 11.7-39.2 33.3-39.2 33.3-13.3 11.4-19.4 22.1-18.6 32.9V587c0.5 8.7-2.4 16.1-8.8 22.8-6.2 6.4-14.8 10-26.2 10.5zM519 766.1c-13 0-23.6-4.2-32.2-12.9-8.7-8.7-13-19-13-31.4 0-12.9 4.2-23.5 12.9-32.2 8.7-8.7 19.2-12.9 32.2-12.9 13 0 23.5 4.2 32.2 12.9s12.9 19.2 12.9 32.2c0 12.4-4.2 22.7-12.9 31.4-8.6 8.6-19.2 12.9-32.1 12.9z M515 928.3c-228.1 0-413.7-185.6-413.7-413.7S286.9 100.9 515 100.9s413.7 185.6 413.7 413.7c0.1 228.1-185.5 413.7-413.7 413.7z m0-747.4c-184 0-333.7 149.7-333.7 333.7S331 848.3 515 848.3s333.7-149.7 333.7-333.7S699 180.9 515 180.9z" />
-        <local:MyListItem x:Name="ItemFeedback" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="7" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="反馈"
+        <local:MyListItem x:Name="ItemFeedback" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="6" PaddingRight="35" Height="36" VerticalAlignment="Top" Title="关于与反馈"
                           LogoScale="0.9" Logo="M613.717333 64.426667l3.413334 3.242666 331.861333 331.861334a85.333333 85.333333 0 0 1 3.2 117.269333l-3.2 3.413333L573.162667 896H960a21.333333 21.333333 0 0 1 21.333333 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333333 21.333333H64a21.333333 21.333333 0 0 1-21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h295.338667L74.069333 610.709333a85.333333 85.333333 0 0 1-3.221333-117.269333l3.2-3.413333 422.4-422.357334a85.333333 85.333333 0 0 1 117.269333-3.221333z m-20.629333 99.882666l-21.418667 321.493334a85.333333 85.333333 0 0 1-74.944 79.04l-4.522666 0.426666-321.493334 21.44 295.552 295.530667 422.4-422.378667L593.066667 164.309333z m-86.442667 13.824L184.533333 500.266667l301.994667-20.117334 20.117333-301.994666z" />
                           LogoScale="0.9" Logo="M613.717333 64.426667l3.413334 3.242666 331.861333 331.861334a85.333333 85.333333 0 0 1 3.2 117.269333l-3.2 3.413333L573.162667 896H960a21.333333 21.333333 0 0 1 21.333333 21.333333v42.666667a21.333333 21.333333 0 0 1-21.333333 21.333333H64a21.333333 21.333333 0 0 1-21.333333-21.333333v-42.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h295.338667L74.069333 610.709333a85.333333 85.333333 0 0 1-3.221333-117.269333l3.2-3.413333 422.4-422.357334a85.333333 85.333333 0 0 1 117.269333-3.221333z m-20.629333 99.882666l-21.418667 321.493334a85.333333 85.333333 0 0 1-74.944 79.04l-4.522666 0.426666-321.493334 21.44 295.552 295.530667 422.4-422.378667L593.066667 164.309333z m-86.442667 13.824L184.533333 500.266667l301.994667-20.117334 20.117333-301.994666z" />
     </StackPanel>
     </StackPanel>
 </local:MyPageLeft>
 </local:MyPageLeft>

+ 192 - 0
Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml.vb

@@ -0,0 +1,192 @@
+Imports NetFwTypeLib
+
+Public Class PageLinkLeft
+
+    Private IsLoad As Boolean = False
+    Private IsPageSwitched As Boolean = False '如果在 Loaded 前切换到其他页面,会导致触发 Loaded 时再次切换一次
+    Private Sub PageLinkLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
+        If IsLoad Then Exit Sub
+        IsLoad = True
+        '切换默认页面
+        If IsPageSwitched Then Exit Sub
+        ItemHiper.SetChecked(True, False, False)
+    End Sub
+    Private Sub PageOtherLeft_Unloaded(sender As Object, e As RoutedEventArgs) Handles Me.Unloaded
+        IsPageSwitched = False
+    End Sub
+
+#Region "Windows 防火墙"
+
+    '为联机模块添加防火墙通行权限的函数库
+    '不加防火墙权限你要我怎么办,这联机根本连都连不上,球球你们别看到防火墙就说是后门了,真的很恼火……
+
+    ''' <summary>
+    ''' 获取某个文件是否被 Windows 防火墙阻止。
+    ''' </summary>
+    Public Shared Function FirewallIsBlock(FilePath As String) As Boolean
+        '获取配置
+        If FirewallPolicy Is Nothing Then
+            Try
+                FirewallPolicy = FirewallPolicyGet()
+            Catch ex As Exception
+                Log(ex, "Windows 防火墙:可能关闭得太死了,根本检测不到,笑死", LogLevel.Normal)
+                Return False
+            End Try
+        End If
+        '检查是否开启
+        If Not FirewallPolicy.CurrentProfile.FirewallEnabled Then
+            Log("[Link] Windows 防火墙:防火墙关闭")
+            Return False
+        End If
+        '检查是否允许例外
+        If FirewallPolicy.CurrentProfile.ExceptionsNotAllowed Then
+            Log("[Link] Windows 防火墙:防火墙开启,不允许例外")
+            Return True
+        End If
+        '检查白名单
+        Dim Target As String = FilePath.Replace(PathTemp.Split("\").First, "").ToLower
+        For Each App As INetFwAuthorizedApplication In FirewallPolicy.CurrentProfile.AuthorizedApplications
+            If ModeDebug Then Log("[Link] 防火墙白名单(" & App.Enabled & "):" & App.ProcessImageFileName)
+            If Not App.Enabled Then Continue For
+            '信标的奇妙盘符 E:0/xxxxx/xxx 导致误判……
+            Dim FileNameTrimmed As String = App.ProcessImageFileName.Replace(App.ProcessImageFileName.Split("\").First, "")
+            If App.ProcessImageFileName.ToLower.Contains(FilePath) Then
+                Log("[Link] Windows 防火墙:开启,已在白名单中(" & FilePath & ")")
+                Return False
+            End If
+        Next
+        Log("[Link] Windows 防火墙:开启,未在白名单中(" & FilePath & ")")
+        Return True
+    End Function
+    ''' <summary>
+    ''' 添加防火墙通行权限。需要管理员权限。
+    ''' </summary>
+    Public Shared Sub FirewallAddAuthorized(DisplayName As String, FilePath As String)
+        Log("[Link] Windows 防火墙:添加通行权限(" & FilePath & ")")
+        '获取配置
+        If FirewallPolicy Is Nothing Then FirewallPolicy = FirewallPolicyGet()
+        '添加项目
+        FirewallPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_DOMAIN).AuthorizedApplications.Add(New FirewallApp(DisplayName, FilePath))
+        FirewallPolicy.GetProfileByType(NET_FW_PROFILE_TYPE_.NET_FW_PROFILE_STANDARD).AuthorizedApplications.Add(New FirewallApp(DisplayName, FilePath))
+        FirewallPolicy.CurrentProfile.AuthorizedApplications.Add(New FirewallApp(DisplayName, FilePath))
+    End Sub
+    Private Class FirewallApp
+        Implements INetFwAuthorizedApplication
+        Public Property Name As String Implements INetFwAuthorizedApplication.Name
+        Public Property ProcessImageFileName As String Implements INetFwAuthorizedApplication.ProcessImageFileName
+        Public Property IpVersion As NET_FW_IP_VERSION_ = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY Implements INetFwAuthorizedApplication.IpVersion
+        Public Property Scope As NET_FW_SCOPE_ = NET_FW_SCOPE_.NET_FW_SCOPE_ALL Implements INetFwAuthorizedApplication.Scope
+        Public Property RemoteAddresses As String = "*" Implements INetFwAuthorizedApplication.RemoteAddresses
+        Public Property Enabled As Boolean = True Implements INetFwAuthorizedApplication.Enabled
+        Public Sub New(DisplayName As String, FilePath As String)
+            Name = DisplayName
+            ProcessImageFileName = FilePath
+        End Sub
+    End Class
+    '获取防火墙配置
+    Public Shared FirewallPolicy As INetFwPolicy = Nothing
+    Public Shared Function FirewallPolicyGet() As INetFwPolicy
+        Const CLSID_FIREWALL_MANAGER As String = "{304CE942-6E39-40D8-943A-B913C40C9CD4}"
+        Dim objType As Type = Type.GetTypeFromCLSID(New Guid(CLSID_FIREWALL_MANAGER))
+        Return TryCast(Activator.CreateInstance(objType), INetFwMgr).LocalPolicy
+    End Function
+
+#End Region
+
+#Region "页面切换"
+
+    ''' <summary>
+    ''' 当前页面的编号。
+    ''' </summary>
+    Public PageID As FormMain.PageSubType = FormMain.PageSubType.LinkHiper
+
+    ''' <summary>
+    ''' 勾选事件改变页面。
+    ''' </summary>
+    Private Sub PageCheck(sender As MyListItem, e As RouteEventArgs) Handles ItemHiper.Check, ItemIoi.Check, ItemSetup.Check, ItemHelp.Check, ItemFeedback.Check
+        '尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0
+        '若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False)
+        If sender.Tag IsNot Nothing Then PageChange(Val(sender.Tag))
+    End Sub
+
+    Public Function PageGet(Optional ID As FormMain.PageSubType = -1)
+        If ID = -1 Then ID = PageID
+        Select Case ID
+            Case 0, FormMain.PageSubType.LinkHiper
+                If FrmLinkHiper Is Nothing Then FrmLinkHiper = New PageLinkHiper
+                Return FrmLinkHiper
+            Case FormMain.PageSubType.LinkIoi
+                If FrmLinkIoi Is Nothing Then FrmLinkIoi = New PageLinkIoi
+                Return FrmLinkIoi
+            Case FormMain.PageSubType.LinkSetup
+                If FrmSetupLink Is Nothing Then FrmSetupLink = New PageSetupLink
+                Return FrmSetupLink
+            Case FormMain.PageSubType.LinkHelp
+                If FrmLinkHelp Is Nothing Then FrmLinkHelp = PageOtherHelp.GetHelpPage(PathTemp & "Help\启动器\联机.json")
+                Return FrmLinkHelp
+            Case FormMain.PageSubType.LinkFeedback
+                If FrmLinkFeedback Is Nothing Then FrmLinkFeedback = New PageLinkFeedback
+                Return FrmLinkFeedback
+            Case Else
+                Throw New Exception("未知的更多子页面种类:" & ID)
+        End Select
+    End Function
+
+    ''' <summary>
+    ''' 切换现有页面。
+    ''' </summary>
+    Public Sub PageChange(ID As FormMain.PageSubType)
+        If PageID = ID Then Exit Sub
+        AniControlEnabled += 1
+        IsPageSwitched = True
+        Try
+            PageChangeRun(PageGet(ID))
+            PageID = ID
+        Catch ex As Exception
+            Log(ex, "切换设置分页面失败(ID " & ID & ")", LogLevel.Feedback)
+        Finally
+            AniControlEnabled -= 1
+        End Try
+    End Sub
+    Private Shared Sub PageChangeRun(Target As MyPageRight)
+        AniStop("FrmMain PageChangeRight") '停止主页面的右页面切换动画,防止它与本动画一起触发多次 PageOnEnter
+        If Target.Parent IsNot Nothing Then Target.SetValue(ContentPresenter.ContentProperty, Nothing)
+        FrmMain.PageRight = Target
+        CType(FrmMain.PanMainRight.Child, MyPageRight).PageOnExit()
+        AniStart({
+                         AaCode(Sub()
+                                    CType(FrmMain.PanMainRight.Child, MyPageRight).PageOnForceExit()
+                                    FrmMain.PanMainRight.Child = FrmMain.PageRight
+                                    FrmMain.PageRight.Opacity = 0
+                                End Sub, 130),
+                         AaCode(Sub()
+                                    '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
+                                    FrmMain.PageRight.Opacity = 1
+                                    FrmMain.PageRight.PageOnEnter()
+                                End Sub, 30, True)
+                     }, "PageLeft PageChange")
+    End Sub
+
+#End Region
+
+    Public Sub Reset(sender As Object, e As EventArgs)
+        If MyMsgBox("是否要初始化联机页的所有设置?该操作不可撤销。", "初始化确认",, "取消", IsWarn:=True) = 1 Then
+            If IsNothing(FrmSetupLink) Then FrmSetupLink = New PageSetupLink
+            FrmSetupLink.Reset()
+        End If
+    End Sub
+
+    Private Sub BtnHiperStop_Loaded(sender As Object, e As RoutedEventArgs)
+        sender.Visibility = If(PageLinkHiper.HiperState = LoadState.Finished OrElse PageLinkHiper.HiperState = LoadState.Loading, Visibility.Visible, Visibility.Collapsed)
+    End Sub
+    Private Sub BtnHiperStop_Click(sender As Object, e As EventArgs)
+        PageLinkHiper.ModuleStopManually()
+    End Sub
+    Private Sub BtnIoiStop_Loaded(sender As Object, e As RoutedEventArgs)
+        sender.Visibility = If(PageLinkIoi.InitLoader.State = LoadState.Finished, Visibility.Visible, Visibility.Collapsed)
+    End Sub
+    Private Sub BtnIoiStop_Click(sender As Object, e As EventArgs)
+        PageLinkIoi.ModuleStopManually()
+    End Sub
+
+End Class

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

@@ -238,7 +238,7 @@
                 For Each VersionPath In VersionFolder.EnumerateDirectories
                 For Each VersionPath In VersionFolder.EnumerateDirectories
                     Dim Version As New McVersion(VersionPath.FullName)
                     Dim Version As New McVersion(VersionPath.FullName)
                     Version.Load()
                     Version.Load()
-                    If Not Version.Version.Modable Then Continue For
+                    If Not Version.Modable Then Continue For
                     '4. 该版本的隔离文件夹下不存在 mods
                     '4. 该版本的隔离文件夹下不存在 mods
                     Dim ModIndieFolder As New DirectoryInfo(Version.Path & "mods\")
                     Dim ModIndieFolder As New DirectoryInfo(Version.Path & "mods\")
                     If ModIndieFolder.Exists AndAlso ModIndieFolder.EnumerateFiles.Count > 0 Then Exit Sub
                     If ModIndieFolder.Exists AndAlso ModIndieFolder.EnumerateFiles.Count > 0 Then Exit Sub

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

@@ -114,8 +114,8 @@
         '设置文件
         '设置文件
         Try
         Try
             '拷贝文件
             '拷贝文件
-            File.Delete(PathTemp & "CustomSkin.png")
-            CopyFile(SkinInfo.LocalFile, PathTemp & "CustomSkin.png")
+            File.Delete(PathAppdata & "CustomSkin.png")
+            CopyFile(SkinInfo.LocalFile, PathAppdata & "CustomSkin.png")
             '更新设置
             '更新设置
             Setup.Set("LaunchSkinSlim", SkinInfo.IsSlim)
             Setup.Set("LaunchSkinSlim", SkinInfo.IsSlim)
         Catch ex As Exception
         Catch ex As Exception
@@ -129,7 +129,7 @@
         If Not (AniControlEnabled = 0 AndAlso e.RaiseByMouse) Then Exit Sub
         If Not (AniControlEnabled = 0 AndAlso e.RaiseByMouse) Then Exit Sub
         Try
         Try
             '已有图片则不再选择
             '已有图片则不再选择
-            If File.Exists(PathTemp & "CustomSkin.png") Then Exit Sub
+            If File.Exists(PathAppdata & "CustomSkin.png") Then Exit Sub
             '没有图片则要求选择
             '没有图片则要求选择
             Dim SkinInfo As McSkinInfo = McSkinSelect(True)
             Dim SkinInfo As McSkinInfo = McSkinSelect(True)
             If Not SkinInfo.IsVaild Then
             If Not SkinInfo.IsVaild Then
@@ -137,8 +137,8 @@
                 Exit Sub
                 Exit Sub
             End If
             End If
             '拷贝文件
             '拷贝文件
-            File.Delete(PathTemp & "CustomSkin.png")
-            CopyFile(SkinInfo.LocalFile, PathTemp & "CustomSkin.png")
+            File.Delete(PathAppdata & "CustomSkin.png")
+            CopyFile(SkinInfo.LocalFile, PathAppdata & "CustomSkin.png")
             '更新设置
             '更新设置
             Setup.Set("LaunchSkinSlim", SkinInfo.IsSlim)
             Setup.Set("LaunchSkinSlim", SkinInfo.IsSlim)
         Catch ex As Exception
         Catch ex As Exception
@@ -151,7 +151,7 @@
     End Sub
     End Sub
     Private Sub BtnSkinDelete_Click(sender As Object, e As EventArgs) Handles BtnSkinDelete.Click
     Private Sub BtnSkinDelete_Click(sender As Object, e As EventArgs) Handles BtnSkinDelete.Click
         Try
         Try
-            File.Delete(PathTemp & "CustomSkin.png")
+            File.Delete(PathAppdata & "CustomSkin.png")
             RadioSkinType0.SetChecked(True, True, True)
             RadioSkinType0.SetChecked(True, True, True)
             Hint("离线皮肤已清空!", HintType.Finish)
             Hint("离线皮肤已清空!", HintType.Finish)
         Catch ex As Exception
         Catch ex As Exception
@@ -335,7 +335,7 @@
             Dim RamTarget2 As Double '估计没啥问题了的内存
             Dim RamTarget2 As Double '估计没啥问题了的内存
             Dim RamTarget3 As Double '放一百万个材质和 Mod 和光影需要的内存
             Dim RamTarget3 As Double '放一百万个材质和 Mod 和光影需要的内存
             If Version IsNot Nothing AndAlso Not Version.IsLoaded Then Version.Load()
             If Version IsNot Nothing AndAlso Not Version.IsLoaded Then Version.Load()
-            If Version IsNot Nothing AndAlso Version.Version.Modable Then
+            If Version IsNot Nothing AndAlso Version.Modable Then
                 '可安装 Mod 的版本
                 '可安装 Mod 的版本
                 Dim ModDir As New DirectoryInfo(Version.PathIndie & "mods\")
                 Dim ModDir As New DirectoryInfo(Version.PathIndie & "mods\")
                 Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Length, 0)
                 Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Length, 0)

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

@@ -6,8 +6,14 @@
              d:DesignWidth="800" d:DesignHeight="800">
              d:DesignWidth="800" d:DesignHeight="800">
     <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,20,0,-5" Title="通用设置">
-                <StackPanel Margin="25,40,25,15">
+            <local:MyCard Margin="0,15" Title="HiPer">
+                <StackPanel Margin="25,40,25,20" Orientation="Vertical">
+                    <local:MyCheckBox Text="在索引码还有 5 分钟到期时提醒我" x:Name="CheckHiperCertWarn" Tag="LinkHiperCertWarn" Height="22" />
+                    <local:MyButton x:Name="BtnHiperLog" Height="35" MinWidth="140" Text="查看日志" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" />
+                </StackPanel>
+            </local:MyCard>
+            <local:MyCard Margin="0,0,0,15" Title="IOI">
+                <StackPanel Margin="25,40,25,20">
                     <Grid>
                     <Grid>
                         <Grid.ColumnDefinitions>
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
                             <ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
@@ -26,8 +32,6 @@
                             </local:MyTextBox.ValidateRules>
                             </local:MyTextBox.ValidateRules>
                         </local:MyTextBox>
                         </local:MyTextBox>
                     </Grid>
                     </Grid>
-                    <local:MyCheckBox Text="打开启动器时启动联机模块" Height="22" x:Name="CheckLinkAuto" Tag="LinkAuto" ToolTipService.ShowDuration="2333333" Margin="0,10,0,4"
-                                          ToolTip="开启联机模块的人越多,所有使用 PCL2 的玩家的初次连接速度就会越快。因此,启用此项可以为大家作出贡献。&#13;联机模块仅使用少许网络带宽,几乎不使用硬盘与 CPU。" />
                 </StackPanel>
                 </StackPanel>
             </local:MyCard>
             </local:MyCard>
         </StackPanel>
         </StackPanel>

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

@@ -17,15 +17,15 @@
 
 
     End Sub
     End Sub
     Public Sub Reload()
     Public Sub Reload()
-        CheckLinkAuto.Checked = Setup.Get("LinkAuto")
         TextLinkName.Text = Setup.Get("LinkName")
         TextLinkName.Text = Setup.Get("LinkName")
+        CheckHiperCertWarn.Checked = Setup.Get("LinkHiperCertWarn")
     End Sub
     End Sub
 
 
     '初始化
     '初始化
     Public Sub Reset()
     Public Sub Reset()
         Try
         Try
-            Setup.Reset("LinkAuto")
             Setup.Reset("LinkName")
             Setup.Reset("LinkName")
+            Setup.Reset("LinkHiperCertWarn")
 
 
             Log("[Setup] 已初始化联机页设置")
             Log("[Setup] 已初始化联机页设置")
             Hint("已初始化联机页设置!", HintType.Finish, False)
             Hint("已初始化联机页设置!", HintType.Finish, False)
@@ -37,11 +37,19 @@
     End Sub
     End Sub
 
 
     '将控件改变路由到设置改变
     '将控件改变路由到设置改变
-    Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckLinkAuto.Change
-        If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
-    End Sub
     Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextLinkName.ValidatedTextChanged
     Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextLinkName.ValidatedTextChanged
         If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Text)
         If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Text)
     End Sub
     End Sub
+    Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckHiperCertWarn.Change
+        If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
+    End Sub
+
+    Private Sub BtnHiperLog_Click(sender As Object, e As EventArgs) Handles BtnHiperLog.Click
+        If File.Exists(PageLinkHiper.PathHiper & "logs\hiper.log") Then
+            OpenExplorer("/select,""" & PageLinkHiper.PathHiper & "logs\hiper.log""")
+        Else
+            Hint("没有找到 HiPer 联机模块的日志!")
+        End If
+    End Sub
 
 
 End Class
 End Class

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

@@ -183,7 +183,6 @@
         Dim Temp As String()
         Dim Temp As String()
         Temp = Directory.GetFiles(Path)
         Temp = Directory.GetFiles(Path)
         For Each str As String In Temp
         For Each str As String In Temp
-            If str = PathTemp & "CustomSkin.png" OrElse str = PathTemp & "联机模块.exe" Then Continue For '不删除的文件
             Try
             Try
                 Dim Info As New FileInfo(str)
                 Dim Info As New FileInfo(str)
                 Dim FileActualSize = Math.Ceiling(Info.Length / 4096) * 4096
                 Dim FileActualSize = Math.Ceiling(Info.Length / 4096) * 4096

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

@@ -5,8 +5,8 @@
     ''' </summary>
     ''' </summary>
     Public Shared Version As McVersion
     Public Shared Version As McVersion
 
 
-    Private Sub PageVersionLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
-        If Version IsNot Nothing AndAlso Version.Version.Modable Then
+    Public Sub RefreshModDisabled() Handles Me.Loaded
+        If Version IsNot Nothing AndAlso Version.Modable Then
             ItemMod.Visibility = Visibility.Visible
             ItemMod.Visibility = Visibility.Visible
             ItemModDisabled.Visibility = Visibility.Collapsed
             ItemModDisabled.Visibility = Visibility.Collapsed
         Else
         Else

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

@@ -57,7 +57,11 @@
         If ComboDisplayType.SelectedIndex <> 1 Then
         If ComboDisplayType.SelectedIndex <> 1 Then
             '改为不隐藏
             '改为不隐藏
             Try
             Try
+                '若设置分类为可安装 Mod,则显示正常的 Mod 管理页面
                 WriteIni(PageVersionLeft.Version.Path & "PCL\Setup.ini", "DisplayType", ComboDisplayType.SelectedIndex)
                 WriteIni(PageVersionLeft.Version.Path & "PCL\Setup.ini", "DisplayType", ComboDisplayType.SelectedIndex)
+                PageVersionLeft.Version.DisplayType = ReadIni(PageVersionLeft.Version.Path & "PCL\Setup.ini", "DisplayType", McVersionCardType.Auto)
+                FrmVersionLeft.RefreshModDisabled()
+
                 WriteIni(PathMcFolder & "PCL.ini", "VersionCache", "") '要求刷新缓存
                 WriteIni(PathMcFolder & "PCL.ini", "VersionCache", "") '要求刷新缓存
                 LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
                 LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
             Catch ex As Exception
             Catch ex As Exception

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

@@ -275,7 +275,7 @@
             Dim RamTarget2 As Double '估计没啥问题了的内存
             Dim RamTarget2 As Double '估计没啥问题了的内存
             Dim RamTarget3 As Double '安装过多附加组件需要的内存
             Dim RamTarget3 As Double '安装过多附加组件需要的内存
             If Version IsNot Nothing AndAlso Not Version.IsLoaded Then Version.Load()
             If Version IsNot Nothing AndAlso Not Version.IsLoaded Then Version.Load()
-            If Version IsNot Nothing AndAlso Version.Version.Modable Then
+            If Version IsNot Nothing AndAlso Version.Modable Then
                 '可安装 Mod 的版本
                 '可安装 Mod 的版本
                 Dim ModDir As New DirectoryInfo(Version.PathIndie & "mods\")
                 Dim ModDir As New DirectoryInfo(Version.PathIndie & "mods\")
                 Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Length, 0)
                 Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Length, 0)

+ 11 - 12
Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj

@@ -152,11 +152,6 @@
       <HintPath>Resources\Ookii.Dialogs.Wpf.dll</HintPath>
       <HintPath>Resources\Ookii.Dialogs.Wpf.dll</HintPath>
       <Private>False</Private>
       <Private>False</Private>
     </Reference>
     </Reference>
-    <Reference Include="STUN, Version=0.5.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>Resources\STUN.dll</HintPath>
-      <Private>False</Private>
-    </Reference>
     <Reference Include="System.Core" />
     <Reference Include="System.Core" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.IO.Compression" />
     <Reference Include="System.IO.Compression" />
@@ -260,6 +255,9 @@
     <Compile Include="Pages\PageLink\PageLinkFeedback.xaml.vb">
     <Compile Include="Pages\PageLink\PageLinkFeedback.xaml.vb">
       <DependentUpon>PageLinkFeedback.xaml</DependentUpon>
       <DependentUpon>PageLinkFeedback.xaml</DependentUpon>
     </Compile>
     </Compile>
+    <Compile Include="Pages\PageLink\PageLinkHiper.xaml.vb">
+      <DependentUpon>PageLinkHiper.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Pages\PageOther\PageOtherHelpDetail.xaml.vb">
     <Compile Include="Pages\PageOther\PageOtherHelpDetail.xaml.vb">
       <DependentUpon>PageOtherHelpDetail.xaml</DependentUpon>
       <DependentUpon>PageOtherHelpDetail.xaml</DependentUpon>
     </Compile>
     </Compile>
@@ -517,6 +515,10 @@
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
     </Page>
     </Page>
+    <Page Include="Pages\PageLink\PageLinkHiper.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="Pages\PageOther\PageOtherHelpDetail.xaml">
     <Page Include="Pages\PageOther\PageOtherHelpDetail.xaml">
       <SubType>Designer</SubType>
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
       <Generator>MSBuild:Compile</Generator>
@@ -786,22 +788,22 @@
   <ItemGroup>
   <ItemGroup>
     <PublishFile Include="NAudio">
     <PublishFile Include="NAudio">
       <Visible>False</Visible>
       <Visible>False</Visible>
-      <PublishState>Exclude</PublishState>
-      <IncludeHash>True</IncludeHash>
       <Group>
       <Group>
       </Group>
       </Group>
       <TargetPath>
       <TargetPath>
       </TargetPath>
       </TargetPath>
+      <PublishState>Exclude</PublishState>
+      <IncludeHash>True</IncludeHash>
       <FileType>Assembly</FileType>
       <FileType>Assembly</FileType>
     </PublishFile>
     </PublishFile>
     <PublishFile Include="Newtonsoft.Json">
     <PublishFile Include="Newtonsoft.Json">
       <Visible>False</Visible>
       <Visible>False</Visible>
-      <PublishState>Exclude</PublishState>
-      <IncludeHash>True</IncludeHash>
       <Group>
       <Group>
       </Group>
       </Group>
       <TargetPath>
       <TargetPath>
       </TargetPath>
       </TargetPath>
+      <PublishState>Exclude</PublishState>
+      <IncludeHash>True</IncludeHash>
       <FileType>Assembly</FileType>
       <FileType>Assembly</FileType>
     </PublishFile>
     </PublishFile>
   </ItemGroup>
   </ItemGroup>
@@ -869,9 +871,6 @@
   <ItemGroup>
   <ItemGroup>
     <Resource Include="Images\Heads\noin.png" />
     <Resource Include="Images\Heads\noin.png" />
   </ItemGroup>
   </ItemGroup>
-  <ItemGroup>
-    <None Include="Resources\STUN.dll" />
-  </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <WCFMetadata Include="Connected Services\" />
     <WCFMetadata Include="Connected Services\" />
   </ItemGroup>
   </ItemGroup>

BIN
Plain Craft Launcher 2/Resources/Help.zip


BIN
Plain Craft Launcher 2/Resources/STUN.dll


BIN
Plain Craft Launcher 2/Resources/java-wrapper.jar


Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff