龙腾猫跃 5 месяцев назад
Родитель
Сommit
c86fdc3af1
36 измененных файлов с 275 добавлено и 255 удалено
  1. 1 1
      MeloongCore
  2. 0 1
      Plain Craft Launcher 2/Application.xaml
  3. 26 56
      Plain Craft Launcher 2/Application.xaml.vb
  4. 1 1
      Plain Craft Launcher 2/Controls/MyButton.xaml
  5. 1 1
      Plain Craft Launcher 2/Controls/MyCheckBox.xaml
  6. 1 1
      Plain Craft Launcher 2/Controls/MyExtraButton.xaml
  7. 1 1
      Plain Craft Launcher 2/Controls/MyIconTextButton.xaml
  8. 1 1
      Plain Craft Launcher 2/Controls/MyImage.vb
  9. 1 1
      Plain Craft Launcher 2/Controls/MyListItem.xaml
  10. 1 1
      Plain Craft Launcher 2/Controls/MyRadioBox.xaml
  11. 0 4
      Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb
  12. 1 1
      Plain Craft Launcher 2/Controls/MyRadioButton.xaml
  13. 0 1
      Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb
  14. 8 3
      Plain Craft Launcher 2/FormMain.xaml.vb
  15. 14 33
      Plain Craft Launcher 2/Modules/Base/ModBase.vb
  16. 3 4
      Plain Craft Launcher 2/Modules/Base/ModLoader.vb
  17. 5 5
      Plain Craft Launcher 2/Modules/Base/ModNet.vb
  18. 25 30
      Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
  19. 2 2
      Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
  20. 8 8
      Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb
  21. 3 2
      Plain Craft Launcher 2/Modules/ModMain.vb
  22. 0 47
      Plain Craft Launcher 2/Modules/ModSecret.vb
  23. 3 3
      Plain Craft Launcher 2/Modules/Resource/LocalResourceFile.vb
  24. 1 0
      Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb
  25. 2 2
      Plain Craft Launcher 2/My Project/AssemblyInfo.vb
  26. 1 1
      Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml
  27. 9 0
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml
  28. 3 3
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.vb
  29. 5 13
      Plain Craft Launcher 2/Pages/PageInstance/PageInstanceMod.xaml.vb
  30. 28 6
      Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
  31. 4 4
      Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
  32. 2 2
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml
  33. 40 12
      Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb
  34. 1 1
      Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb
  35. 69 0
      Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
  36. 4 3
      Plain Craft Launcher 2/Pages/PageSetup/Settings.vb

+ 1 - 1
MeloongCore

@@ -1 +1 @@
-Subproject commit 5ee6f88cde9def4bb93c9086567f28410319871c
+Subproject commit f30c861f6ea5ae9a52a93ffa71357d20ce0090ab

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

@@ -368,7 +368,6 @@
                 <Setter Property="FocusVisualStyle" Value="{x:Null}" />
                 <Setter Property="FontSize" Value="13" />
                 <Setter Property="MaxDropDownHeight" Value="320" />
-                <Setter Property="Cursor" Value="Hand" />
                 <Setter Property="Template">
                     <Setter.Value>
                         <ControlTemplate TargetType="ComboBox">

+ 26 - 56
Plain Craft Launcher 2/Application.xaml.vb

@@ -91,37 +91,8 @@ RetryCacheCheck:
             End Try
             DirectoryUtils.Create(PathTemp & "Cache\")
             DirectoryUtils.Create(PathAppdata)
-
-#If DEBUG Then
-            Dim FileLockPath = Path.Combine(PathAppdata.TrimEnd("\"), "PCL.dev.Lock")
-#Else
-            Dim FileLockPath = Path.Combine(PathAppdata.TrimEnd("\"), "PCL.Lock")
-#End If
-
             '要求单例
-            If BuildType <> BuildTypes.Debug Then
-                If Not GetProgramLock(FileLockPath) Then
-                    Dim IsLocked = False
-                    Dim ShouldWaitForExit As Boolean = e.Args.Length > 0 AndAlso e.Args(0) = "--wait" '要求等待已有的 PCL 退出
-                    If Not ShouldWaitForExit Then
-                        DropToTopByLock(FileLockPath)
-                        Beep()
-                        Environment.Exit(ProcessReturnValues.Cancel)
-                    End If
-                    For i = 0 To 10
-                        If GetProgramLock(FileLockPath) Then
-                            IsLocked = True
-                            Exit For
-                        End If
-                        Thread.Sleep(500)
-                    Next
-                    If Not IsLocked Then 
-                        DropToTopByLock(FileLockPath)
-                        Beep()
-                        Environment.Exit(ProcessReturnValues.Cancel)
-                    End If
-                End If
-            End If
+            WaitingMutex(e)
             '设置 ToolTipService 默认值
             ToolTipService.InitialShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(300))
             ToolTipService.BetweenShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(400))
@@ -173,38 +144,37 @@ RetryCacheCheck:
             FormMain.EndProgramForce(ProcessReturnValues.Exception)
         End Try
     End Sub
-    
-    Private Shared KernelLock As Mutex
-
     ''' <summary>
-    ''' 尝试获取单例锁
+    ''' 要求程序以单例运行。
+    ''' 如果已在运行,则将其窗口拖出来并播放提示音,然后结束当前进程。
     ''' </summary>
-    ''' <param name="LockPath">文件锁位置</param>
-    ''' <returns>一个值用于指示是否获得文件锁</returns>
-    Private Function GetProgramLock(LockPath As String) As Boolean
+    Private Shared Sub WaitingMutex(e As StartupEventArgs)
+        If BuildType = BuildTypes.Debug Then Return
         Try
-            Dim IsLocked = False
-            KernelLock = New Mutex(True, "Local\Plain Craft Launcher", IsLocked)
-            If Not IsLocked Then Return False
-            Logger.Info("获取单例锁成功")
-            File.WriteAllText(LockPath, Process.GetCurrentProcess().Id.ToString())
-            Return IsLocked
+            Dim MutexCreatedNew As Boolean
+            PclMutex = New Mutex(True, "PCL_SingletonMutex", MutexCreatedNew)
+            If MutexCreatedNew Then Return
+            Logger.Warn("已有一个 PCL 实例正在运行")
+            '等待已有的 PCL 退出
+            If e.Args.Length > 0 AndAlso e.Args(0) = "--wait" Then
+                Try
+                    If PclMutex.WaitOne(10000) Then Return '等待至多 10 秒
+                Catch Ignored As AbandonedMutexException
+                    Return '已有实例异常退出,继续启动
+                End Try
+            End If
+            '将已有的 PCL 窗口拖出来
+            Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher ")
+            If WindowHwnd = IntPtr.Zero Then WindowHwnd = FindWindow(Nothing, "Plain Craft Launcher 2 ")
+            If WindowHwnd <> IntPtr.Zero Then ShowWindowToTop(WindowHwnd)
+            '播放提示音并退出
+            Beep()
+            Environment.[Exit](ProcessReturnValues.Cancel)
         Catch ex As Exception
-
+            Logger.Warn(ex, "单例检查失败")
         End Try
-
-        Return False
-    End Function
-
-    ''' <summary>
-    ''' 从文件锁中尝试拖出进程
-    ''' </summary>
-    Public Sub DropToTopByLock(LockPath As String)
-        Dim Pid As Integer
-        If Not Integer.TryParse(File.ReadAllText(LockPath), Pid) Then Return
-        Dim Handle = Process.GetProcessById(Pid)?.MainWindowHandle
-        If Handle <> Intptr.Zero Then ShowWindowToTop(Handle)
     End Sub
+    Private Shared PclMutex As Mutex
 
     '结束
     Private Sub Application_SessionEnding(sender As Object, e As SessionEndingCancelEventArgs) Handles Me.SessionEnding

+ 1 - 1
Plain Craft Launcher 2/Controls/MyButton.xaml

@@ -2,7 +2,7 @@
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              FocusVisualStyle="{x:Null}" x:Name="PanBack"
-             Focusable="True" UseLayoutRounding="False" SnapsToDevicePixels="False" Background="{StaticResource ColorBrushSemiTransparent}" Cursor="Hand">
+             Focusable="True" UseLayoutRounding="False" SnapsToDevicePixels="False" Background="{StaticResource ColorBrushSemiTransparent}">
     <Border CornerRadius="3" x:Name="PanFore" BorderThickness="1" BorderBrush="{DynamicResource ColorBrush1}" RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushHalfWhite}">
         <Border.RenderTransform>
             <ScaleTransform />

+ 1 - 1
Plain Craft Launcher 2/Controls/MyCheckBox.xaml

@@ -3,7 +3,7 @@
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MyCheckBox"
              FocusVisualStyle="{x:Null}"
-            MinWidth="20" x:Name="PanBack" UseLayoutRounding="False" SnapsToDevicePixels="False" MinHeight="20" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True" d:DesignWidth="126.4" d:DesignHeight="44.8" Cursor="Hand">
+            MinWidth="20" x:Name="PanBack" UseLayoutRounding="False" SnapsToDevicePixels="False" MinHeight="20" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True" d:DesignWidth="126.4" d:DesignHeight="44.8">
     <TextBlock IsHitTestVisible="False" FontSize="13" x:FieldModifier="Public" x:Name="LabText" Padding="0" Margin="26,0,0,0" Foreground="{DynamicResource ColorBrush1}" HorizontalAlignment="Left" VerticalAlignment="Center" />
     <Border IsHitTestVisible="False" x:Name="ShapeBorder" BorderThickness="1.1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="18" Height="18" BorderBrush="{DynamicResource ColorBrush1}" CornerRadius="3" Margin="1,0,0,0" Background="{StaticResource ColorBrushHalfWhite}" />
     <Path IsHitTestVisible="False" x:Name="ShapeCheck" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="{Binding BorderBrush, ElementName=ShapeBorder}" Width="12" Height="12" Margin="4,0,0,0" Data="M0,6L1.5,4.5 4.5,7.5 10.5,1.5 12,3 4.5,10.5 0,6z">

+ 1 - 1
Plain Craft Launcher 2/Controls/MyExtraButton.xaml

@@ -2,7 +2,7 @@
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="PanBack" mc:Ignorable="d" x:Class="MyExtraButton"
-            Width="40" RenderTransformOrigin="0.5,0.5" ToolTipService.Placement="Left" ToolTipService.VerticalOffset="16" ToolTipService.HorizontalOffset="-8" Height="0" Cursor="Hand">
+            Width="40" RenderTransformOrigin="0.5,0.5" ToolTipService.Placement="Left" ToolTipService.VerticalOffset="16" ToolTipService.HorizontalOffset="-8" Height="0">
     <Grid.RenderTransform>
         <ScaleTransform ScaleX="0" ScaleY="0" />
     </Grid.RenderTransform>

+ 1 - 1
Plain Craft Launcher 2/Controls/MyIconTextButton.xaml

@@ -1,7 +1,7 @@
 <Border x:Name="PanBack" x:Class="MyIconTextButton"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27" Cursor="Hand">
+             HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27">
     <StackPanel Orientation="Horizontal">
         <Path x:Name="ShapeLogo" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="White" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center" />
         <TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="7,0,12,1" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />

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

@@ -112,7 +112,7 @@
         End If
         '从缓存加载网络图片
         Dim EnableCache As Boolean = Me.EnableCache
-        Dim TempPath As String = $"{PathTemp}MyImage\{GetHash(Source)}.png{If(EnableCache, "", GetUuid())}" '不启用缓存时在末尾加上随机字符串,避免冲突
+        Dim TempPath As String = $"{PathTemp}MyImage\{Source.GetStableHashCode()}.png{If(EnableCache, "", GetUuid())}" '不启用缓存时在末尾加上随机字符串,避免冲突
         Dim TempFile = FileUtils.GetInfo(TempPath)
         If EnableCache AndAlso TempFile.Exists Then
             ActualSource = TempPath '显示缓存的图片

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

@@ -2,7 +2,7 @@
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              x:Name="PanBack"
-            RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" Height="42" Cursor="Hand">
+            RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" Height="42">
     <Grid.RenderTransform>
         <ScaleTransform ScaleX="1" ScaleY="1" />
     </Grid.RenderTransform>

+ 1 - 1
Plain Craft Launcher 2/Controls/MyRadioBox.xaml

@@ -2,7 +2,7 @@
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              FocusVisualStyle="{x:Null}"
-             MinWidth="20" x:Name="PanBack" UseLayoutRounding="False" SnapsToDevicePixels="False" MinHeight="20" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True" Cursor="Hand">
+             MinWidth="20" x:Name="PanBack" UseLayoutRounding="False" SnapsToDevicePixels="False" MinHeight="20" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True">
     <TextBlock IsHitTestVisible="False" x:Name="LabText" FontSize="13" Padding="0" Margin="26,0,0,0" Foreground="{DynamicResource ColorBrush1}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
     <Ellipse IsHitTestVisible="False" x:Name="ShapeBorder" StrokeThickness="1.1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="18" Height="18" Stroke="{DynamicResource ColorBrush1}" Margin="1,0,0,0" Fill="{StaticResource ColorBrushHalfWhite}" />
     <Ellipse IsHitTestVisible="False" x:Name="ShapeDot" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="{Binding Stroke, ElementName=ShapeBorder}" Width="0" Height="0" Margin="10,0,0,0" StrokeThickness="0" />

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

@@ -99,7 +99,6 @@ Public Class MyRadioBox
         End Try
     End Sub
     Private Sub SyncUI()
-        Cursor = If(Checked, Nothing, Cursors.Hand)
         If AniControlEnabled = 0 AndAlso IsLoaded Then '防止默认属性变更触发动画
             If Checked Then
                 '由无变有
@@ -198,9 +197,6 @@ Public Class MyRadioBox
     Private Const AnimationTimeOfMouseIn As Integer = 100 '鼠标指向动画长度
     Private Const AnimationTimeOfMouseOut As Integer = 200 '鼠标指向动画长度
     Private Const AnimationTimeOfCheck As Integer = 150 '勾选状态变更动画长度
-    Private Sub MyRadioBox_Loaded() Handles Me.Loaded
-        Cursor = If(Checked, Nothing, Cursors.Hand)
-    End Sub
     Private Sub Radiobox_IsEnabledChanged() Handles Me.IsEnabledChanged
         If Me.IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
             '有动画

+ 1 - 1
Plain Craft Launcher 2/Controls/MyRadioButton.xaml

@@ -1,7 +1,7 @@
 <Border x:Name="PanBack" x:Class="MyRadioButton"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27" Cursor="Hand">
+             HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27">
     <StackPanel Orientation="Horizontal">
         <Path x:Name="ShapeLogo" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="White" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center" />
         <TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="8,0,12,0" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />

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

@@ -167,7 +167,6 @@ Public Class MyRadioButton
     Private Const AnimationTimeOfMouseOut As Integer = 150 '鼠标移出动画长度
     Private Const AnimationTimeOfCheck As Integer = 120 '勾选状态变更动画长度
     Private Sub RefreshColor(Optional obj = Nothing, Optional e = Nothing) Handles Me.MouseEnter, Me.MouseLeave, Me.Loaded
-        Cursor = If(Checked, Nothing, Cursors.Hand)
         Try
             If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not False.Equals(e) Then '防止默认属性变更触发动画,若强制不执行动画,则 e 为 False
 

+ 8 - 3
Plain Craft Launcher 2/FormMain.xaml.vb

@@ -11,10 +11,10 @@ Public Class FormMain
         Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
         '统计更新日志条目
         If BuildType = BuildTypes.Release Then
-            If LastVersion < 400 Then 'Release 2.12.8.0
+            If LastVersion < 402 Then 'Release 2.12.8.1
                 FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:升级框架到 .NET Framework 4.8"))
-                FeatureCount += 28
-                BugCount += 19
+                FeatureCount += 35
+                BugCount += 21
             End If
             If LastVersion < 398 Then 'Release 2.12.7.3
                 FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:下载游戏、整合包的稳定性"))
@@ -74,6 +74,11 @@ Public Class FormMain
             '3:BUG+ IMP* FEAT-
             '2:BUG* IMP-
             '1:BUG-
+            If LastVersion < 401 Then 'Snapshot 2.12.8.1
+                FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:可能无法更换披风"))
+                FeatureCount += 8
+                BugCount += 6
+            End If
             If LastVersion < 399 Then 'Snapshot 2.12.8.0
                 FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:升级框架到 .NET Framework 4.8"))
                 FeatureCount += 28

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

@@ -10,12 +10,12 @@ Public Module ModBase
 #Region "声明"
 
     '下列版本信息由更新器自动修改
-    Public Const VersionBaseName As String = "2.12.8.0" '显示用版本名
+    Public Const VersionBaseName As String = "2.12.8.1" '显示用版本名
     Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
 #If RELEASE Then
-    Public Const VersionCode As Integer = 400 '正式版
+    Public Const VersionCode As Integer = 402 '正式版
 #Else
-    Public Const VersionCode As Integer = 399 '快照版
+    Public Const VersionCode As Integer = 401 '快照版
 #End If
 
     '版本信息
@@ -710,13 +710,13 @@ Public Module ModBase
                 End If
                 If Not String.IsNullOrEmpty(Hash) Then
                     If Hash.Length < 35 Then 'MD5
-                        Dim md5 As String = HashUtils.ComputeFromFile(LocalPath, HashUtils.HashMethod.Md5)
+                        Dim md5 As String = CryptographyUtils.ComputeFileHash(LocalPath, CryptographyUtils.HashMethod.Md5)
                         If Hash.Lower <> md5 Then Return "文件 MD5 应为 " & Hash & ",实际为 " & md5
                     ElseIf Hash.Length = 64 Then 'SHA256
-                        Dim sha256 As String = HashUtils.ComputeFromFile(LocalPath, HashUtils.HashMethod.Sha256)
+                        Dim sha256 As String = CryptographyUtils.ComputeFileHash(LocalPath, CryptographyUtils.HashMethod.Sha256)
                         If Hash.Lower <> sha256 Then Return "文件 SHA256 应为 " & Hash & ",实际为 " & sha256
                     Else 'SHA1 (40)
-                        Dim sha1 As String = HashUtils.ComputeFromFile(LocalPath, HashUtils.HashMethod.Sha1)
+                        Dim sha1 As String = CryptographyUtils.ComputeFileHash(LocalPath, CryptographyUtils.HashMethod.Sha1)
                         If Hash.Lower <> sha1 Then Return "文件 SHA1 应为 " & Hash & ",实际为 " & sha1
                     End If
                 End If
@@ -793,30 +793,6 @@ Public Module ModBase
         End Try
     End Function
 
-    ''' <summary>
-    ''' 获取字符串哈希值。
-    ''' </summary>
-    Public Function GetHash(Str As String) As ULong
-        Dim Result As ULong = 5381
-        For Each v In Str
-            Result = (Result << 5) Xor Result Xor CType(AscW(v), ULong)
-        Next
-        Return Result Xor &HA98F501BC684032FUL
-    End Function
-    ''' <summary>
-    ''' 获取字符串 MD5。
-    ''' </summary>
-    Public Function GetStringMD5(Str As String) As String
-        Using h = MD5Cng.Create()
-            Dim hashedDataBytes = h.ComputeHash(Encoding.UTF8.GetBytes(Str))
-            Dim tmp As New StringBuilder(hashedDataBytes.Length * 2)
-            For Each i As Byte In hashedDataBytes
-                tmp.Append(i.ToString("x2"))
-            Next
-            Return tmp.ToString()
-        End Using
-    End Function
-
     ''' <summary>
     ''' 不会报错的 Val。
     ''' 如果输入有误,返回 0。
@@ -1399,12 +1375,17 @@ Public Module ModBase
     ''' 将程序中的资源释放到文件。
     ''' </summary>
     Public Sub ExtractResources(FilePath As String, ResourceName As String)
-        Logger.Info($"将资源写入到文件:{ResourceName} → {FilePath}")
         Dim Resource = My.Resources.ResourceManager.GetObject(ResourceName)
         If TypeOf Resource Is Byte() Then
-            FileUtils.Write(FilePath, DirectCast(Resource, Byte()))
+            Dim Bytes = DirectCast(Resource, Byte())
+            If FileUtils.Exists(FilePath) AndAlso CryptographyUtils.ComputeFileHash(FilePath) = CryptographyUtils.ComputeHash(Bytes) Then Return
+            Logger.Info($"将资源写入到文件:{ResourceName} → {FilePath}")
+            FileUtils.Write(FilePath, Bytes)
         ElseIf TypeOf Resource Is String Then
-            FileUtils.Write(FilePath, DirectCast(Resource, String))
+            Dim Content = DirectCast(Resource, String)
+            If FileUtils.Exists(FilePath) AndAlso FileUtils.ReadAsString(FilePath) = Content Then Return
+            Logger.Info($"将资源写入到文件:{ResourceName} → {FilePath}")
+            FileUtils.Write(FilePath, Content)
         Else
             Throw New Exception($"资源 {ResourceName} 的类型不支持:{Resource.GetType.Name}")
         End If

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

@@ -8,7 +8,6 @@
         Implements ILoadingTrigger
 
         Public ReadOnly Property IsLoader As Boolean = True Implements ILoadingTrigger.IsLoader
-        Protected Shared LogBlackList As String() = {"EasyTier CLI"}
 
         '基础属性
         ''' <summary>
@@ -90,7 +89,7 @@
                 Dim OldState = _State
                 If value = LoadState.Finished AndAlso Settings.Get(Of Boolean)("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000))
                 _State = value
-                If Not LogBlackList.Contains(Name) Then Logger.Info($"加载器 {Name} 状态改变:{value}")
+                Logger.Log($"加载器 {Name} 状态改变:{value}", If(value = LoadState.Failed, LogLevel.Error, LogLevel.Info))
                 '实现 ILoadingTrigger 接口与 OnStateChanged 回调
                 RunInUi(
                 Sub()
@@ -319,13 +318,13 @@
             Sub()
                 Try
                     IsForceRestarting = IsForceRestart
-                    If Not LogBlackList.Contains(Name) Then Logger.Trace(Function() $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动")
+                    Logger.Trace(Function() $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动")
                     LoadDelegate(Me)
                     If IsInterrupted Then
                         Logger.Warn($"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId)})")
                         Return
                     End If
-                    If Not LogBlackList.Contains(Name) Then Logger.Trace(Function() $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已完成")
+                    Logger.Trace(Function() $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已完成")
                     RaisePreviewFinish()
                     State = LoadState.Finished
                     LastFinishedTime = GetTimeMs() '未中断,本次输出有效

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

@@ -261,8 +261,11 @@ Retry:
                     })
                 End If
             End SyncLock
-            CancelToken.Dispose() : CancelToken = New CancellationTokenSource(Timeout)
-            Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
+            ResilientUtils.RetryOn(Of FileNotFoundException, IOException)( 'CacheCow 读取缓存时若文件被占用,会调用不存在的 System.Net.Http.Formatting.resources,抛出此异常(#8150)
+            Sub()
+                CancelToken.Dispose() : CancelToken = New CancellationTokenSource(Timeout)
+                Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
+            End Sub)
             Dim ResponseBytes As Byte()
             CancelToken.Dispose() : CancelToken = New CancellationTokenSource(Timeout)
             Using ResponseStream = Response.Content.ReadAsStreamAsync().GetResultWithTimeout(CancelToken, Timeout)
@@ -286,9 +289,6 @@ Retry:
             Throw
         Catch ex As HttpRequestException
             Throw
-        Catch ex As FileNotFoundException
-            '由于 CacheCow 读取缓存失败,然后系统调用不存在的 System.Net.Http.Formatting.resources 抛出(#8150)
-            Throw New Exception($"网络请求时读取缓存失败", ex)
         Catch ex As Exception
             RecordIPReliability(HostIp, -1)
             If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then 'CancellationToken 超时

+ 25 - 30
Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb

@@ -333,7 +333,7 @@ NextInner:
             Me.Type = Type
         End Sub
         Public Overrides Function GetHashCode() As Integer
-            Return GetHash(UserName & Password & BaseUrl & Token & Type) Mod Integer.MaxValue
+            Return (UserName & Password & BaseUrl & Token & Type).GetStableHashCode() Mod Integer.MaxValue
         End Function
 
     End Class
@@ -353,7 +353,7 @@ NextInner:
             Type = McLoginType.Ms
         End Sub
         Public Overrides Function GetHashCode() As Integer
-            Return GetHash(OAuthRefreshToken & AccessToken & Uuid & UserName & ProfileJson) Mod Integer.MaxValue
+            Return (OAuthRefreshToken & AccessToken & Uuid & UserName & ProfileJson).GetStableHashCode() Mod Integer.MaxValue
         End Function
     End Class
     Public Class McLoginLegacy
@@ -375,7 +375,7 @@ NextInner:
             Type = McLoginType.Legacy
         End Sub
         Public Overrides Function GetHashCode() As Integer
-            Return GetHash(UserName & SkinType & SkinName & Type) Mod Integer.MaxValue
+            Return (UserName & SkinType & SkinName & Type).GetStableHashCode() Mod Integer.MaxValue
         End Function
     End Class
 
@@ -535,21 +535,15 @@ NextInner:
         Data.Progress = 0.05
         '检查是否已经登录完成
         Dim ExpiresAt = Settings.Get(Of Long)("CacheMsV2Expires")
-
         If Not Data.IsForceRestarting AndAlso '不要求强行重启
-           ExpiresAt > 0 AndAlso ExpiresAt > GetUnixTimestampUtc() Then 'AccessToken 尚未过期
-            'https://github.com/Meloong-Git/PCL/issues/8638
-            '如果是程序刚启动时调用的登录,此时加载器的状态为 Waiting,GetLoginData 函数会返回不带 ProfileJson 的数据作为输入
-            If String.IsNullOrEmpty(Input.ProfileJson) Then
-                Input = PageLoginMsSkin.GetLoginData(True)
-            End If
+           ExpiresAt > 0 AndAlso ExpiresAt > GetUnixTimestampUtc() AndAlso 'AccessToken 尚未过期
+           Input.UserName = Settings.Get(Of String)("CacheMsV2Name") Then
             Data.Output = New McLoginResult With {
-                .AccessToken = Input.AccessToken,
-                .Name = Input.UserName,
-                .Uuid = Input.Uuid,
-                .Type = "Microsoft",
-                .ClientToken = Input.Uuid,
-                .ProfileJson = Input.ProfileJson
+                .Name = Input.UserName, .Type = "Microsoft",
+                .AccessToken = Settings.Get(Of String)("CacheMsV2Access"),
+                .Uuid = Settings.Get(Of String)("CacheMsV2Uuid"),
+                .ClientToken = Settings.Get(Of String)("CacheMsV2Uuid"),
+                .ProfileJson = Settings.Get(Of String)("CacheMsV2ProfileJson")
             }
             McLaunchLog("无需登录,AccessToken 尚未过期")
             GoTo SkipLogin
@@ -1018,16 +1012,18 @@ Retry:
             Result = NetRequestByClientRetry("https://api.minecraftservices.com/authentication/login_with_xbox", HttpMethod.Post,
                 Content:=Request, ContentType:="application/json", RequireJson:=True)
         Catch ex As HttpRequestCodeException
-            Select Case ex.StatusCode
-                Case 429
-                    Logger.Warn(ex, "微软登录第 4 步汇报 429")
-                    Throw New Exception("$登录尝试太过频繁,请等待几分钟后再试!")
-                Case HttpStatusCode.Forbidden
-                    Logger.Warn(ex, "微软登录第 4 步汇报 403")
-                    Throw New Exception("$当前 IP 的登录尝试异常。" & vbCrLf & "如果你使用了 VPN 或加速器,请把它们关掉或更换节点后再试!")
-                Case Else
-                    Throw
-            End Select
+            If ex.StatusCode = 429 Then
+                Logger.Warn(ex, "微软登录第 4 步汇报 429")
+                Throw New Exception("$登录尝试太过频繁,请等待几分钟后再试!")
+            ElseIf ex.StatusCode = HttpStatusCode.Forbidden Then
+                Logger.Warn(ex, "微软登录第 4 步汇报 403")
+                Throw New Exception("$当前 IP 的登录尝试异常。" & vbCrLf & "如果你使用了 VPN 或加速器,请把它们关掉或更换节点后再试!")
+            ElseIf ex.Response?.Contains("ACCOUNT_SUSPENDED") Then '#8655
+                MyMsgBox("该账号似乎已被微软封禁,无法登录。", "登录失败", "我知道了", IsWarn:=True)
+                Throw New Exception("$$")
+            Else
+                Throw
+            End If
         End Try
 
         Dim ResultJson As JObject = GetJson(Result)
@@ -1152,7 +1148,7 @@ Retry:
         Return Uuid
     End Function
     Public Function McLoginLegacyUuid(Name As String)
-        Dim FullUuid As String = Name.Length.ToString("X").EnsureLength("0", 16) & GetHash(Name).ToString("X").EnsureLength("0", 16)
+        Dim FullUuid As String = Name.Length.ToString("X").EnsureLength("0", 16) & Name.GetStableHashCode().ToString("X").EnsureLength("0", 16)
         Return FullUuid.Substring(0, 12) & "3" & FullUuid.Substring(13, 3) & "9" & FullUuid.Substring(17, 15)
     End Function
 
@@ -1445,14 +1441,13 @@ NextInstance:
         End If
 
         'JLW
-        '修复 Java 18- 在 Windows UTF-8 Beta 模式(非 GBK 编码)下命令行参数乱码的问题(JDK-8272352)
+        '非 GBK 编码下命令行参数乱码的问题(JDK-8272352)
         Dim UseJLW As Boolean =
             Not Settings.Get(Of Boolean)("LaunchAdvanceDisableJLW") AndAlso Not Settings.Get(Of Boolean)("VersionAdvanceDisableJLW", McInstanceSelected) AndAlso
-            McLaunchJavaSelected.MajorVersion <= 18 AndAlso 'Java 19+ 已经修复了该 Bug
             Not IsGBKEncoding AndAlso Not McFolderSelected.IsAsciiOnly() '仅在该环境下才会触发该 Bug
         If UseJLW AndAlso CustomArg.Contains("-javaagent") Then
             UseJLW = False
-            McLaunchLog("由于使用自定义 javaagent,已禁用 JLW,这可能导致游戏崩溃!", LogLevel.Warn)
+            McLaunchLog("由于使用了自定义 javaagent,已禁用 JLW,这可能导致游戏崩溃!", LogLevel.Warn)
         End If
         If UseJLW Then
             If McLaunchJavaSelected.MajorVersion >= 9 Then

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

@@ -1286,7 +1286,7 @@ ExitDataLoad:
                 GoTo OnLoaded
             End If
             '有可用版本
-            Dim FolderListCheck As Integer = GetHash(Versions.MCINSTANCE_CACHE_VERSION & "#" & FolderList.Join("#"c)) Mod (Integer.MaxValue - 1) '根据文件夹名列表生成辨识码
+            Dim FolderListCheck As Integer = (Versions.MCINSTANCE_CACHE_VERSION & "#" & FolderList.Join("#"c)).GetStableHashCode() Mod (Integer.MaxValue - 1) '根据文件夹名列表生成辨识码
             If Not McInstanceListForceRefresh AndAlso Val(ReadIni(PathMc & "PCL.ini", "InstanceCache")) = FolderListCheck Then
                 '可以使用缓存
                 Dim Result = InitMcInstanceListWithCache(PathMc)
@@ -1747,7 +1747,7 @@ OnLoaded:
     ''' </summary>
     Public Function McSkinDownload(Address As String) As String
         Dim SkinName As String = PathUtils.GetLastPart(Address)
-        Dim FileAddress As String = PathTemp & "Cache\Skin\" & GetHash(Address) & ".png"
+        Dim FileAddress As String = PathTemp & "Cache\Skin\" & Address.GetStableHashCode() & ".png"
         SyncLock McSkinDownloadLock
             If Not FileUtils.Exists(FileAddress) Then
                 NetDownloadByClient(Address, FileAddress & ".PCLDownloading")

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

@@ -162,11 +162,11 @@
                     'Else
                     If State = MinecraftState.Loading Then
                         '窗口未出现
-                        WatcherLog("Minecraft 尚未加载完成,可能已崩溃")
+                        WatcherLog("Minecraft 尚未加载完成,可能已崩溃", LogLevel.Error)
                         Crashed()
                     ElseIf GameProcess.ExitCode <> 0 AndAlso State = MinecraftState.Running AndAlso Instance.ReleaseTime.Year >= 2012 Then
                         '返回值不为 0 且未结束
-                        WatcherLog("Minecraft 返回值异常,可能已崩溃")
+                        WatcherLog("Minecraft 返回值异常,可能已崩溃", LogLevel.Error)
                         Crashed()
                     ElseIf State <> MinecraftState.Crashed Then
                         '正常关闭
@@ -215,15 +215,15 @@
                 ElseIf Text.Contains("Crash report saved to") OrElse Text.Contains("This crash report has been saved to:") Then
                     ' Text.Contains("Minecraft ran into a problem! Report saved to:") Then
                     'Minecraft 崩溃,忽略 VanillaFix
-                    WatcherLog("识别为崩溃的 Log:" & Text)
+                    WatcherLog("识别为崩溃的 Log:" & Text, LogLevel.Error)
                     Crashed()
                 ElseIf Text.Contains("Could not save crash report to") Then
                     'Minecraft 崩溃,无法保存崩溃日志
-                    WatcherLog("识别为崩溃的 Log:" & Text)
+                    WatcherLog("识别为崩溃的 Log:" & Text, LogLevel.Error)
                     Crashed()
                 ElseIf Text.Contains("/ERROR]: Unable to launch") OrElse Text.Contains("An exception was thrown, the game will display an error screen and halt.") Then
                     'Forge 崩溃
-                    WatcherLog("识别为崩溃的 Log:" & Text)
+                    WatcherLog("识别为崩溃的 Log:" & Text, LogLevel.Error)
                     Crashed()
                     'ElseIf Text.Contains("Shutdown failure!") Then
                     '    'Minecraft 强行崩溃,由于点 X 强行关闭也会触发这句话,所以不可用
@@ -231,8 +231,8 @@
                 End If
             End If
         End Sub
-        Private Sub WatcherLog(Text As String)
-            McLaunchLog("[" & PID & "] " & Text)
+        Private Sub WatcherLog(Text As String, Optional Level As LogLevel = LogLevel.Info)
+            McLaunchLog("[" & PID & "] " & Text, Level)
         End Sub
 
         '进度更新
@@ -349,7 +349,7 @@
             If State = MinecraftState.Crashed OrElse State = MinecraftState.Ended Then Return
             State = MinecraftState.Crashed
             '崩溃分析
-            WatcherLog("Minecraft 已崩溃,将在 2 秒后开始崩溃分析")
+            WatcherLog("Minecraft 已崩溃,将在 2 秒后开始崩溃分析", LogLevel.Error)
             Hint("检测到 Minecraft 出现错误,错误分析已开始……", HintType.Red)
             FeedbackInfo()
             RunInNewThread(

+ 3 - 2
Plain Craft Launcher 2/Modules/ModMain.vb

@@ -850,7 +850,8 @@ NextFile:
         Text = Text.Replace("{path}", Replacer(PathUtils.CurrentFolder))
         Text = Text.Replace("{path_with_name}", Replacer(PathExe))
         Text = Text.Replace("{path_temp}", Replacer(PathTemp))
-        Text = Text.Replace("{pcl_md5}", Function() Replacer(HashUtils.ComputeFromFile(PathExe, HashUtils.HashMethod.Md5)))
+        Text = Text.Replace("{pcl_md5}", Function() Replacer(CryptographyUtils.ComputeFileHash(PathExe, CryptographyUtils.HashMethod.Md5)))
+        Text = Text.Replace("{pcl_sha1}", Function() Replacer(CryptographyUtils.ComputeFileHash(PathExe, CryptographyUtils.HashMethod.Sha1)))
         '时间
         If ReplaceTime Then '在窗口标题中,时间会被后续动态替换,所以此时不应该替换
             Text = Text.Replace("{date}", Replacer(Date.Now.ToString("yyyy'/'M'/'d")))
@@ -976,7 +977,7 @@ NextFile:
     ''' </summary>
     Public Sub FeedbackInfo()
         On Error Resume Next
-        Logger.Info($"诊断信息:{vbCrLf}" &
+        Logger.Warn($"诊断信息:{vbCrLf}" &
             "操作系统:" & My.Computer.Info.OSFullName & "(32 位:" & Is32BitSystem & ")" & vbCrLf &
             "剩余内存:" & Int(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024) & " M / " & Int(My.Computer.Info.TotalPhysicalMemory / 1024 / 1024) & " M" & vbCrLf &
             "DPI:" & DPI & "(" & Math.Round(DPI / 96, 2) * 100 & "%)" & vbCrLf &

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

@@ -1,7 +1,5 @@
 '由于包含加解密等安全信息,本文件中的部分代码已被删除
 
-Imports System.Security.Cryptography
-
 Friend Module ModSecret
 
     '标注 PCL 的不同分支,仅用于替换标记
@@ -40,51 +38,6 @@ Friend Module ModSecret
 
 #End Region
 
-#Region "字符串加解密"
-
-    ''' <summary>
-    ''' 获取八位密钥。
-    ''' </summary>
-    Private Function SecretKeyGet(Key As String) As String
-        Return "00000000"
-    End Function
-    ''' <summary>
-    ''' 加密字符串。
-    ''' </summary>
-    Friend Function SecretEncrypt(SourceString As String, Optional Key As String = "") As String
-        Key = SecretKeyGet(Key)
-        Dim btKey As Byte() = Encoding.UTF8.GetBytes(Key)
-        Dim btIV As Byte() = Encoding.UTF8.GetBytes("87160295")
-        Dim des As New DESCryptoServiceProvider
-        Using MS As New MemoryStream
-            Dim inData As Byte() = Encoding.UTF8.GetBytes(SourceString)
-            Using cs As New CryptoStream(MS, des.CreateEncryptor(btKey, btIV), CryptoStreamMode.Write)
-                cs.Write(inData, 0, inData.Length)
-                cs.FlushFinalBlock()
-                Return Convert.ToBase64String(MS.ToArray())
-            End Using
-        End Using
-    End Function
-    ''' <summary>
-    ''' 解密字符串。
-    ''' </summary>
-    Friend Function SecretDecrypt(SourceString As String, Optional Key As String = "") As String
-        Key = SecretKeyGet(Key)
-        Dim btKey As Byte() = Encoding.UTF8.GetBytes(Key)
-        Dim btIV As Byte() = Encoding.UTF8.GetBytes("87160295")
-        Dim des As New DESCryptoServiceProvider
-        Using MS As New MemoryStream
-            Dim inData As Byte() = Convert.FromBase64String(SourceString)
-            Using cs As New CryptoStream(MS, des.CreateDecryptor(btKey, btIV), CryptoStreamMode.Write)
-                cs.Write(inData, 0, inData.Length)
-                cs.FlushFinalBlock()
-                Return Encoding.UTF8.GetString(MS.ToArray())
-            End Using
-        End Using
-    End Function
-
-#End Region
-
 #Region "主题"
 
     Public Color1 As New MyColor(52, 61, 74)

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

@@ -418,7 +418,7 @@ Finished:
         Get
             If _CurseForgeHash Is Nothing Then
                 '读取缓存
-                Dim CacheKey As String = GetHash($"{EnabledFullName}-{File.LastWriteTime.ToLongTimeString}-{File.Length}-C")
+                Dim CacheKey As String = $"{EnabledFullName}-{File.LastWriteTime.ToLongTimeString}-{File.Length}-C".GetStableHashCode()
                 Dim Cached As String = ReadIni(PathTemp & "Cache\ModHash.ini", CacheKey)
                 If Cached <> "" AndAlso Cached.RegexCheck("^\d+$") Then '#5062
                     _CurseForgeHash = Cached
@@ -473,14 +473,14 @@ Finished:
         Get
             If _ModrinthHash Is Nothing Then
                 '读取缓存
-                Dim CacheKey As String = GetHash($"{EnabledFullName}-{File.LastWriteTime.ToLongTimeString}-{File.Length}-M")
+                Dim CacheKey As String = $"{EnabledFullName}-{File.LastWriteTime.ToLongTimeString}-{File.Length}-M".GetStableHashCode()
                 Dim Cached As String = ReadIni(PathTemp & "Cache\ModHash.ini", CacheKey)
                 If Cached <> "" Then
                     _ModrinthHash = Cached
                     Return _ModrinthHash
                 End If
                 '计算 SHA1
-                _ModrinthHash = HashUtils.ComputeFromFile(File.FullName, HashUtils.HashMethod.Sha1)
+                _ModrinthHash = CryptographyUtils.ComputeFileHash(File.FullName, CryptographyUtils.HashMethod.Sha1)
                 '写入缓存
                 WriteIni(PathTemp & "Cache\ModHash.ini", CacheKey, _ModrinthHash)
             End If

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

@@ -189,6 +189,7 @@
 #Region "中文搜索"
 
         Dim RawSearchText As String = If(Request.SearchText, "").Trim
+        RawSearchText = StrConv(RawSearchText, VbStrConv.SimplifiedChinese) '繁体转简体
         RawSearchText = RawSearchText.Lower
         Logger.Info($"工程列表搜索原始文本:{RawSearchText}")
 

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

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

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

@@ -3,7 +3,7 @@
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:local="clr-namespace:PCL;assembly="
       x:Name="PanBack" Height="44"
-      RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True" Cursor="Hand">
+      RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True">
     <Grid.ColumnDefinitions>
         <ColumnDefinition Width="6" />
         <ColumnDefinition Width="34" />

+ 9 - 0
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml

@@ -222,6 +222,15 @@
                         <StackPanel Margin="30,0,0,0" x:Name="PanOptionsSaves"
                                 Visibility="{Binding Checked, ElementName=CheckOptionsSaves, Converter={StaticResource BooleanToVisibilityConverter}}">
                         </StackPanel>
+                        <local:MyCheckBox>
+                            <local:MyCheckBox.Tag>
+                                <local:ExportOption 
+                                Title="协议"
+                                Description="Licence 文件"
+                                Rules="LICEN*"
+                                DefaultChecked="True" />
+                            </local:MyCheckBox.Tag>
+                        </local:MyCheckBox>
                         <local:MyCheckBox>
                             <local:MyCheckBox.Tag>
                                 <local:ExportOption 

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

@@ -119,7 +119,7 @@ Public Class PageInstanceExport
                 If Rule.StartsWithF("!") Then Return False '只看正向规则
                 '检查前两级
                 Try
-                    If AllEntries.Any(Function(Entry) Entry Like Rule) Then Return True
+                    If AllEntries.Any(Function(Entry) Entry.Lower Like Rule.Lower) Then Return True
                 Catch ex As Exception
                     Logger.Error(ex, $"错误的规则:{Rule}", LogBehavior.Toast)
                     Return False
@@ -482,7 +482,7 @@ Public Class PageInstanceExport
                     Dim ShouldKeep As Boolean = False
                     For Each Rule In AllRules
                         Dim Revert = Rule.StartsWithF("!")
-                        If RelativePath Like Rule.TrimStart("!") Then ShouldKeep = Not Revert
+                        If RelativePath.Lower Like Rule.TrimStart("!").Lower Then ShouldKeep = Not Revert
                     Next
                     If Not ShouldKeep Then Continue For
                     Dim TargetPath As String = OverridesFolder & RelativePath
@@ -641,7 +641,7 @@ Public Class PageInstanceExport
                 Dim ModFile As LocalResourceFile = Pair.Key
                 Files.Add(New JObject From {
                     {"path", PathUtils.RemoveExtendedPrefix(ModFile.File.FullName).AfterFirst(OverridesFolder).Replace("\", "/")},
-                    {"hashes", New JObject From {{"sha1", ModFile.ModrinthHash}, {"sha512", HashUtils.ComputeFromFile(ModFile.File.FullName, HashUtils.HashMethod.Sha512)}}},
+                    {"hashes", New JObject From {{"sha1", ModFile.ModrinthHash}, {"sha512", CryptographyUtils.ComputeFileHash(ModFile.File.FullName, CryptographyUtils.HashMethod.Sha512)}}},
                     {"downloads", New JArray(Pair.Value.OrderBy(Function(u) u.Contains("modrinth.com")))}, '不优先选择 Modrinth
                     {"fileSize", ModFile.File.Length}
                 })

+ 5 - 13
Plain Craft Launcher 2/Pages/PageInstance/PageInstanceMod.xaml.vb

@@ -483,7 +483,7 @@ Install:
                 If FileUtils.Exists(NewPath) Then
                     If FileUtils.Exists(ModEntity.File.FullName) Then
                         '同时存在两个名称的 Mod
-                        If HashUtils.ComputeFromFile(ModEntity.File.FullName, HashUtils.HashMethod.Md5) <> HashUtils.ComputeFromFile(NewPath, HashUtils.HashMethod.Md5) Then
+                        If CryptographyUtils.ComputeFileHash(ModEntity.File.FullName) <> CryptographyUtils.ComputeFileHash(NewPath) Then
                             MyMsgBox($"目前同时存在启用和禁用的两个 Mod 文件:{vbCrLf} - {PathUtils.GetLastPart(NewPath)}{vbCrLf} - {ModEntity.File.Name}{vbCrLf}{vbCrLf}注意,这两个文件的内容并不相同。{vbCrLf}在手动删除或重命名其中一个文件后,才能继续操作。", "存在文件冲突")
                             Continue For
                         End If
@@ -608,8 +608,8 @@ Install:
                     Next
                     For Each Entry As KeyValuePair(Of String, String) In FileCopyList
                         If FileUtils.Exists(Entry.Value) Then
-                            FileUtils.Delete(Entry.Value, True)
                             Logger.Warn($"更新后的 Mod 文件已存在,将会把它放入回收站:{Entry.Value}")
+                            FileUtils.Delete(Entry.Value, True)
                         End If
                         If DirectoryUtils.Exists(PathUtils.RemoveLastPart(Entry.Value)) Then
                             FileUtils.Move(Entry.Key, Entry.Value)
@@ -723,18 +723,10 @@ Install:
             End If
             '显示结果提示
             If Not IsSuccessful Then Return
-            If IsShiftPressed Then
-                If ModList.IsSingle Then
-                    Hint($"已彻底删除 {ModList.Single.File.Name}!", HintType.Green)
-                Else
-                    Hint($"已彻底删除 {ModList.Count} 个文件!", HintType.Green)
-                End If
+            If ModList.IsSingle Then
+                Hint($"已删除 {ModList.Single.File.Name}!", HintType.Green)
             Else
-                If ModList.IsSingle Then
-                    Hint($"已将 {ModList.Single.File.Name} 删除到回收站!", HintType.Green)
-                Else
-                    Hint($"已将 {ModList.Count} 个文件删除到回收站!", HintType.Green)
-                End If
+                Hint($"已删除 {ModList.Count} 个文件!", HintType.Green)
             End If
         Catch ex As OperationCanceledException
             Logger.Warn(ex, "删除 Mod 被主动取消")

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

@@ -149,7 +149,7 @@
             RunInThread(
             Sub()
                 Try
-                    Hint("正在刷新头像……")
+                    Hint("正在刷新皮肤……")
                     '清空缓存
                     Logger.Info("正在清空皮肤缓存")
                     If DirectoryUtils.Exists(PathTemp & "Cache\Skin") Then DirectoryUtils.Delete(PathTemp & "Cache\Skin")
@@ -162,7 +162,7 @@
                     For Each SkinLoader In If(sender IsNot Nothing, {sender}, {PageLaunchLeft.SkinLegacy, PageLaunchLeft.SkinMs})
                         SkinLoader.WaitForExit(IsForceRestart:=True)
                     Next
-                    Hint("已刷新头像!", HintType.Green)
+                    Hint("已刷新皮肤!", HintType.Green)
                 Catch ex As Exception
                     Logger.Error(ex, "刷新皮肤缓存失败", LogBehavior.Alert)
                 End Try
@@ -216,13 +216,13 @@
             Hint("登录失败,无法更改披风!", HintType.Red)
             Return
         End If
-        Hint("正在获取披风列表,请稍候……")
+        If McLoginMsLoader.State <> LoadState.Finished Then Hint("正在获取披风列表,请稍候……")
         IsChanging = True
         '开始实际获取
         RunInNewThread(
         Sub()
-            Try
 Retry:
+            Try
                 '获取登录信息
                 If McLoginMsLoader.State <> LoadState.Finished Then McLoginMsLoader.WaitForExit(PageLoginMsSkin.GetLoginData())
                 If McLoginMsLoader.State <> LoadState.Finished Then
@@ -256,7 +256,7 @@ Retry:
                         Next
                         SelectedIndex = MyMsgBoxSelect(SelectionControl, "选择披风", "确定", "取消")
                     Catch ex As Exception
-                        Logger.Error(ex, "获取玩家披风列表失败")
+                        Logger.Error(ex, "获取玩家皮肤列表失败")
                     End Try
                 End Sub)
                 If SelectedIndex Is Nothing Then Return
@@ -279,7 +279,29 @@ Retry:
                     McLoginMsLoader.Output.ProfileJson = SkinData.ToString()
                 End If
             Catch ex As Exception
-                Logger.Error(ex, "更改披风失败", LogBehavior.Toast)
+                If TypeOf ex Is HttpRequestCodeException Then
+                    Dim requestException As HttpRequestCodeException = CType(ex, HttpRequestCodeException)
+                    Select Case requestException.StatusCode
+                        Case HttpStatusCode.BadRequest
+                            Logger.Warn(ex, "更改披风时遭遇 400 错误")
+                            If requestException.Response?.Contains("""error""") Then
+                                Hint("更改披风失败:" & GetJson(requestException.Response)("error").ToString, HintType.Red)
+                                Return
+                            ElseIf requestException.Response?.Contains("""errorMessage""") Then
+                                Hint("更改披风失败:" & GetJson(requestException.Response)("errorMessage").ToString, HintType.Red)
+                                Return
+                            End If
+                        Case HttpStatusCode.Unauthorized
+                            Logger.Warn(ex, "更改披风时遭遇 401 错误")
+                            Hint("正在重新登录,将在登录后自动更改披风……")
+                            McLoginMsLoader.Start(PageLoginMsSkin.GetLoginData(), IsForceRestart:=True)
+                            GoTo Retry
+                    End Select
+                ElseIf ex.IsBadNetwork Then
+                    Hint("更改披风失败:连接 Mojang 服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red)
+                Else
+                    Logger.Error(ex, "更改披风失败", LogBehavior.Toast)
+                End If
             Finally
                 IsChanging = False
             End Try

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

@@ -170,7 +170,7 @@ Public Class PageLaunchRight
             Settings.Set("CacheSavedPageVersion", Version)
             FileUtils.Write(PathTemp & "Cache\Custom.xaml", FileContent)
             '若内容变更则要求刷新
-            If LoadedContentHash <> FileContent.GetHashCode() AndAlso ShouldRefresh Then Refresh()
+            If LoadedContentHash <> FileContent.GetStableHashCode() AndAlso ShouldRefresh Then Refresh()
         Catch ex As Exception
             Logger.Error(ex, $"下载主页失败({Address})", If(ModeDebug, LogBehavior.Alert, LogBehavior.Toast))
         End Try
@@ -196,7 +196,7 @@ Public Class PageLaunchRight
     ''' 清空主页缓存信息。
     ''' </summary>
     Private Sub ClearCache()
-        LoadedContentHash = -1
+        LoadedContentHash = Nothing
         OnlineLoader.Input = ("", True)
         Settings.Set("CacheSavedPageUrl", "")
         Settings.Set("CacheSavedPageVersion", "")
@@ -211,7 +211,7 @@ Public Class PageLaunchRight
         Try
             SyncLock LoadContentLock
                 '如果加载目标内容一致则不加载
-                Dim Hash = If(Content, "").GetHashCode()
+                Dim Hash = If(Content, "").GetStableHashCode()
                 If Hash = LoadedContentHash Then Return
                 LoadedContentHash = Hash
                 '实际加载内容
@@ -261,7 +261,7 @@ Public Class PageLaunchRight
         OnLoadContentFailed(e.Exception)
     End Sub
 
-    Private LoadedContentHash As Integer = -1
+    Private LoadedContentHash As ULong? = Nothing
     Private LoadContentLock As New Object
 
 #End Region

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

@@ -23,11 +23,11 @@
                     <local:MyIconButton.ContextMenu>
                         <ContextMenu Closed="HidePanel" HorizontalOffset="10" VerticalOffset="18">
                             <local:MyMenuItem Click="BtnSkinEdit_Click" Header="修改皮肤"/>
+                            <local:MyMenuItem Click="BtnSkinRefresh_Click" Header="刷新皮肤"/>
                             <local:MyMenuItem Click="BtnSkinSave_Click" Header="保存皮肤文件"/>
                             <Separator />
                             <local:MyMenuItem Click="BtnSkinCape_Click" Header="修改披风"/>
-                            <Separator />
-                            <local:MyMenuItem Click="BtnSkinRefresh_Click" Header="刷新"/>
+                            <local:MyMenuItem Click="BtnSkinCapeRefresh_Click" Header="刷新披风列表"/>
                         </ContextMenu>
                     </local:MyIconButton.ContextMenu>
                 </local:MyIconButton>

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

@@ -18,8 +18,8 @@
     ''' <summary>
     ''' 获取当前页面的登录信息。
     ''' </summary>
-    Public Shared Function GetLoginData(Optional IgnoreState As Boolean = False) As McLoginMs
-        If IgnoreState OrElse McLoginMsLoader.State = LoadState.Finished Then
+    Public Shared Function GetLoginData() As McLoginMs
+        If McLoginMsLoader.State = LoadState.Finished Then
             Return New McLoginMs With {.OAuthRefreshToken = Settings.Get(Of String)("CacheMsV2OAuthRefresh"), .UserName = Settings.Get(Of String)("CacheMsV2Name"), .AccessToken = Settings.Get(Of String)("CacheMsV2Access"), .Uuid = Settings.Get(Of String)("CacheMsV2Uuid"), .ProfileJson = Settings.Get(Of String)("CacheMsV2ProfileJson")}
         Else
             Return New McLoginMs With {.OAuthRefreshToken = Settings.Get(Of String)("CacheMsV2OAuthRefresh"), .UserName = Settings.Get(Of String)("CacheMsV2Name")}
@@ -105,9 +105,6 @@ Retry:
                 Hint("正在重新登录,将在登录后自动更改皮肤……")
                 McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
                 GoTo Retry
-            ElseIf Result.Contains("""error""") Then
-                Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Red)
-                Return
             End If
             '获取新皮肤地址
             Logger.Info($"皮肤修改返回值:{vbCrLf}{Result}")
@@ -121,13 +118,26 @@ Retry:
             Next
             Throw New Exception("未知错误(" & Result & ")")
         Catch ex As Exception
-            If ex.IsBadNetwork Then
-                Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red)
-            ElseIf TypeOf ex Is HttpRequestCodeException AndAlso CType(ex, HttpRequestCodeException).StatusCode = HttpStatusCode.Unauthorized Then
-                Logger.Warn(ex, "更改皮肤时遭遇 401 错误")
-                Hint("正在重新登录,将在登录后自动更改皮肤……")
-                McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
-                GoTo Retry
+            If TypeOf ex Is HttpRequestCodeException Then
+                Dim requestException As HttpRequestCodeException = CType(ex, HttpRequestCodeException)
+                Select Case requestException.StatusCode
+                    Case HttpStatusCode.BadRequest
+                        Logger.Warn(ex, "更改皮肤时遭遇 400 错误")
+                        If requestException.Response?.Contains("""error""") Then
+                            Hint("更改皮肤失败:" & GetJson(requestException.Response)("error").ToString, HintType.Red)
+                            Return
+                        ElseIf requestException.Response?.Contains("""errorMessage""") Then
+                            Hint("更改皮肤失败:" & GetJson(requestException.Response)("errorMessage").ToString, HintType.Red)
+                            Return
+                        End If
+                    Case HttpStatusCode.Unauthorized
+                        Logger.Warn(ex, "更改皮肤时遭遇 401 错误")
+                        Hint("正在重新登录,将在登录后自动更改皮肤……")
+                        McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
+                        GoTo Retry
+                End Select
+            ElseIf ex.IsBadNetwork Then
+                Hint("更改皮肤失败:连接 Mojang 服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red)
             Else
                 Logger.Error(ex, "更改皮肤失败", LogBehavior.Toast)
             End If
@@ -151,6 +161,24 @@ Retry:
         Skin.BtnSkinCape_Click()
     End Sub
 
+    '刷新披风
+    Public Sub BtnSkinCapeRefresh_Click(sender As Object, e As RoutedEventArgs)
+        RunInThread(
+        Sub()
+            Try
+                Hint("正在刷新披风列表……")
+                If McLaunchLoader.State = LoadState.Loading Then
+                    McLoginMsLoader.WaitForExit()
+                Else
+                    McLoginMsLoader.WaitForExit(GetLoginData(), IsForceRestart:=True)
+                End If
+                Hint("已刷新披风列表!", HintType.Green)
+            Catch ex As Exception
+                Logger.Error(ex, "刷新披风列表失败", LogBehavior.Toast)
+            End Try
+        End Sub)
+    End Sub
+
 #End Region
 
 End Class

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

@@ -522,7 +522,7 @@ Public Class PageLinkMain
         '获取启动参数
         Dim Arguments As String = ServerConfig("Link")("Argument")
         Arguments += $" --network-name={NetworkName} --network-secret={NetworkSecret} --listeners {ListenersPort} --rpc-portal {RPCPort} --private-mode true"
-        Dim HostName = If(IsServerSide, "Server-", "Client-") & Math.Abs(Identify.GetHashCode).ConvertRadix(36)
+        Dim HostName = If(IsServerSide, "Server-", "Client-") & Identify.GetStableHashCode().ConvertRadix(36).TrimStart("-"c).EnsureLength("0", 6)
         If IsServerSide Then
             Arguments += $" -i 10.114.114.114 --hostname={HostName} --tcp-whitelist={ServerPort} --udp-whitelist={ServerPort}"
         Else

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

@@ -123,6 +123,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="IT" />
                         <TextBlock Margin="0,1.5,6,0" Text="卓" />
                         <TextBlock Margin="0,1.5,6,0" Text="玖" />
+                        <TextBlock Margin="0,1.5,6,0" Text="自" />
                         <TextBlock Margin="0,1.5,6,0" Text="辰" />
                         <TextBlock Margin="0,1.5,6,0" Text="顺" />
                         <TextBlock Margin="0,1.5,6,0" Text="茧" />
@@ -150,6 +151,8 @@
                         <TextBlock Margin="0,1.5,6,0" Text="柒ᝰ" />
                         <TextBlock Margin="0,1.5,6,0" Text="廖" />
                         <TextBlock Margin="0,1.5,6,0" Text="烨" />
+                        <TextBlock Margin="0,1.5,6,0" Text="煌" />
+                        <TextBlock Margin="0,1.5,6,0" Text="雲" />
                         <TextBlock Margin="0,1.5,6,0" Text="yu" />
                         <TextBlock Margin="0,1.5,6,0" Text="💬" />
                         <TextBlock Margin="0,1.5,6,0" Text="7%" />
@@ -164,7 +167,9 @@
                         <TextBlock Margin="0,1.5,6,0" Text="PFF" />
                         <TextBlock Margin="0,1.5,6,0" Text="ZYL" />
                         <TextBlock Margin="0,1.5,6,0" Text="LSP" />
+                        <TextBlock Margin="0,1.5,6,0" Text="110" />
                         <TextBlock Margin="0,1.5,6,0" Text="Van" />
+                        <TextBlock Margin="0,1.5,6,0" Text="TKK" />
                         <TextBlock Margin="0,1.5,6,0" Text="hhh" />
                         <TextBlock Margin="0,1.5,6,0" Text="bbb" />
                         <TextBlock Margin="0,1.5,6,0" Text="阿宅" />
@@ -179,6 +184,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="沐清" />
                         <TextBlock Margin="0,1.5,6,0" Text="阳仔" />
                         <TextBlock Margin="0,1.5,6,0" Text="吸管" />
+                        <TextBlock Margin="0,1.5,6,0" Text="灭宇" />
                         <TextBlock Margin="0,1.5,6,0" Text="冰块" />
                         <TextBlock Margin="0,1.5,6,0" Text="莫林" />
                         <TextBlock Margin="0,1.5,6,0" Text="Gun" />
@@ -198,6 +204,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="白芷" />
                         <TextBlock Margin="0,1.5,6,0" Text="汤圆" />
                         <TextBlock Margin="0,1.5,6,0" Text="黑猫" />
+                        <TextBlock Margin="0,1.5,6,0" Text="言慎" />
                         <TextBlock Margin="0,1.5,6,0" Text="柠檬" />
                         <TextBlock Margin="0,1.5,6,0" Text="愚者" />
                         <TextBlock Margin="0,1.5,6,0" Text="久蛊" />
@@ -236,25 +243,40 @@
                         <TextBlock Margin="0,1.5,6,0" Text="玄狐" />
                         <TextBlock Margin="0,1.5,6,0" Text="tusk" />
                         <TextBlock Margin="0,1.5,6,0" Text="星甲" />
+                        <TextBlock Margin="0,1.5,6,0" Text="亚心" />
+                        <TextBlock Margin="0,1.5,6,0" Text="千羽" />
+                        <TextBlock Margin="0,1.5,6,0" Text="阿勺" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小鱼" />
+                        <TextBlock Margin="0,1.5,6,0" Text="白杨" />
+                        <TextBlock Margin="0,1.5,6,0" Text="蜼鸣" />
+                        <TextBlock Margin="0,1.5,6,0" Text="皮皮" />
                         <TextBlock Margin="0,1.5,6,0" Text="YmY" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Enss" />
                         <TextBlock Margin="0,1.5,6,0" Text="ZHH" />
+                        <TextBlock Margin="0,1.5,6,0" Text="z666" />
                         <TextBlock Margin="0,1.5,6,0" Text="GUO" />
                         <TextBlock Margin="0,1.5,6,0" Text="gino" />
                         <TextBlock Margin="0,1.5,6,0" Text="luoo" />
                         <TextBlock Margin="0,1.5,6,0" Text="9787" />
                         <TextBlock Margin="0,1.5,6,0" Text="Ilyen" />
                         <TextBlock Margin="0,1.5,6,0" Text="1950" />
+                        <TextBlock Margin="0,1.5,6,0" Text="QAQ" />
                         <TextBlock Margin="0,1.5,6,0" Text="AL76" />
                         <TextBlock Margin="0,1.5,6,0" Text="WAR" />
+                        <TextBlock Margin="0,1.5,6,0" Text="yfble" />
                         <TextBlock Margin="0,1.5,6,0" Text="。_。" />
                         <TextBlock Margin="0,1.5,6,0" Text="vbird" />
                         <TextBlock Margin="0,1.5,6,0" Text="空调c" />
                         <TextBlock Margin="0,1.5,6,0" Text="Brant" />
                         <TextBlock Margin="0,1.5,6,0" Text="⁣    ​" />
                         <TextBlock Margin="0,1.5,6,0" Text="RKRK" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Neko" />
                         <TextBlock Margin="0,1.5,6,0" Text="verge" />
+                        <TextBlock Margin="0,1.5,6,0" Text="ciel希" />
                         <TextBlock Margin="0,1.5,6,0" Text="Tarka" />
                         <TextBlock Margin="0,1.5,6,0" Text="Elysia" />
+                        <TextBlock Margin="0,1.5,6,0" Text="onlye" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Spark" />
                         <TextBlock Margin="0,1.5,6,0" Text="Eiligo" />
                         <TextBlock Margin="0,1.5,6,0" Text="友人A" />
                         <TextBlock Margin="0,1.5,6,0" Text="jiagar" />
@@ -266,6 +288,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="ToTxT" />
                         <TextBlock Margin="0,1.5,6,0" Text="HzzzT" />
                         <TextBlock Margin="0,1.5,6,0" Text="EAger" />
+                        <TextBlock Margin="0,1.5,6,0" Text="fufulb" />
                         <TextBlock Margin="0,1.5,6,0" Text="ziqian" />
                         <TextBlock Margin="0,1.5,6,0" Text="kunsir" />
                         <TextBlock Margin="0,1.5,6,0" Text="LiarCT" />
@@ -273,11 +296,15 @@
                         <TextBlock Margin="0,1.5,6,0" Text="Lloora" />
                         <TextBlock Margin="0,1.5,6,0" Text="咕咕柒" />
                         <TextBlock Margin="0,1.5,6,0" Text="xuque" />
+                        <TextBlock Margin="0,1.5,6,0" Text="绮晓络" />
                         <TextBlock Margin="0,1.5,6,0" Text="希希希" />
                         <TextBlock Margin="0,1.5,6,0" Text="飞猪侠" />
+                        <TextBlock Margin="0,1.5,6,0" Text="门东山" />
+                        <TextBlock Margin="0,1.5,6,0" Text="流星陨" />
                         <TextBlock Margin="0,1.5,6,0" Text="狐猫喵" />
                         <TextBlock Margin="0,1.5,6,0" Text="祤之锌" />
                         <TextBlock Margin="0,1.5,6,0" Text="柳贯一" />
+                        <TextBlock Margin="0,1.5,6,0" Text="汐月语" />
                         <TextBlock Margin="0,1.5,6,0" Text="徐炳文" />
                         <TextBlock Margin="0,1.5,6,0" Text="大鱻鱼" />
                         <TextBlock Margin="0,1.5,6,0" Text="颠修钩" />
@@ -323,6 +350,17 @@
                         <TextBlock Margin="0,1.5,6,0" Text="陈两仪" />
                         <TextBlock Margin="0,1.5,6,0" Text="叶辛梓" />
                         <TextBlock Margin="0,1.5,6,0" Text="窗锁昼" />
+                        <TextBlock Margin="0,1.5,6,0" Text="泠晖晖" />
+                        <TextBlock Margin="0,1.5,6,0" Text="悠悠子" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Kiheki" />
+                        <TextBlock Margin="0,1.5,6,0" Text="顾冉竹" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小化哥" />
+                        <TextBlock Margin="0,1.5,6,0" Text="27A03" />
+                        <TextBlock Margin="0,1.5,6,0" Text="白逍遥" />
+                        <TextBlock Margin="0,1.5,6,0" Text="陈钫浩" />
+                        <TextBlock Margin="0,1.5,6,0" Text="滑稽君" />
+                        <TextBlock Margin="0,1.5,6,0" Text="悔轮台" />
+                        <TextBlock Margin="0,1.5,6,0" Text="懒洋洋" />
                         <TextBlock Margin="0,1.5,6,0" Text="ITMTX" />
                         <TextBlock Margin="0,1.5,6,0" Text="SEKGY" />
                         <TextBlock Margin="0,1.5,6,0" Text="111sui" />
@@ -343,11 +381,13 @@
                         <TextBlock Margin="0,1.5,6,0" Text="cmly03" />
                         <TextBlock Margin="0,1.5,6,0" Text="jiduhui" />
                         <TextBlock Margin="0,1.5,6,0" Text="424241" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Rig_kill" />
                         <TextBlock Margin="0,1.5,6,0" Text="XIruotE" />
                         <TextBlock Margin="0,1.5,6,0" Text="Dr.Ayin" />
                         <TextBlock Margin="0,1.5,6,0" Text="onlong" />
                         <TextBlock Margin="0,1.5,6,0" Text="zuozhe" />
                         <TextBlock Margin="0,1.5,6,0" Text="Secular" />
+                        <TextBlock Margin="0,1.5,6,0" Text="之苏ing" />
                         <TextBlock Margin="0,1.5,6,0" Text="zxxxfan" />
                         <TextBlock Margin="0,1.5,6,0" Text="MY17IT" />
                         <TextBlock Margin="0,1.5,6,0" Text="張 懙 李" />
@@ -367,6 +407,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="Flawless" />
                         <TextBlock Margin="0,1.5,6,0" Text="Buyihan" />
                         <TextBlock Margin="0,1.5,6,0" Text="我不在线" />
+                        <TextBlock Margin="0,1.5,6,0" Text="憨憨剑踏" />
                         <TextBlock Margin="0,1.5,6,0" Text="跳水的鱼" />
                         <TextBlock Margin="0,1.5,6,0" Text="咸鱼雷音" />
                         <TextBlock Margin="0,1.5,6,0" Text="云映鹤影" />
@@ -374,12 +415,15 @@
                         <TextBlock Margin="0,1.5,6,0" Text="气息荒古" />
                         <TextBlock Margin="0,1.5,6,0" Text="milenter" />
                         <TextBlock Margin="0,1.5,6,0" Text="霜木翔凤" />
+                        <TextBlock Margin="0,1.5,6,0" Text="丨丨丨丨" />
                         <TextBlock Margin="0,1.5,6,0" Text="唐吉課德" />
                         <TextBlock Margin="0,1.5,6,0" Text="童年的梦" />
                         <TextBlock Margin="0,1.5,6,0" Text="时灵风逝" />
                         <TextBlock Margin="0,1.5,6,0" Text="望月悠月" />
+                        <TextBlock Margin="0,1.5,6,0" Text="三金知日" />
                         <TextBlock Margin="0,1.5,6,0" Text="有事掘坟" />
                         <TextBlock Margin="0,1.5,6,0" Text="爱源神!" />
+                        <TextBlock Margin="0,1.5,6,0" Text="亮黑晚钟" />
                         <TextBlock Margin="0,1.5,6,0" Text="鸡鸡鸡鸡" />
                         <TextBlock Margin="0,1.5,6,0" Text="阿元颜月" />
                         <TextBlock Margin="0,1.5,6,0" Text="不想社交" />
@@ -390,6 +434,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="凌瑶雪莹" />
                         <TextBlock Margin="0,1.5,6,0" Text="wswsing" />
                         <TextBlock Margin="0,1.5,6,0" Text="漆黑噤默" />
+                        <TextBlock Margin="0,1.5,6,0" Text="爆炎龙王" />
                         <TextBlock Margin="0,1.5,6,0" Text="云水莫伊" />
                         <TextBlock Margin="0,1.5,6,0" Text="孤星隐耀" />
                         <TextBlock Margin="0,1.5,6,0" Text="蓝莓蛋糕" />
@@ -427,8 +472,14 @@
                         <TextBlock Margin="0,1.5,6,0" Text="阿克华孜" />
                         <TextBlock Margin="0,1.5,6,0" Text="yunwuyi" />
                         <TextBlock Margin="0,1.5,6,0" Text="落幕星空" />
+                        <TextBlock Margin="0,1.5,6,0" Text="黑耀黄昏" />
+                        <TextBlock Margin="0,1.5,6,0" Text="金木萧雨" />
+                        <TextBlock Margin="0,1.5,6,0" Text="隔壁的熊" />
+                        <TextBlock Margin="0,1.5,6,0" Text="星辰彼方" />
+                        <TextBlock Margin="0,1.5,6,0" Text="霜笙雪落" />
                         <TextBlock Margin="0,1.5,6,0" Text="muming" />
                         <TextBlock Margin="0,1.5,6,0" Text="纸币ORZ" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Thorium" />
                         <TextBlock Margin="0,1.5,6,0" Text="西蛮qwq" />
                         <TextBlock Margin="0,1.5,6,0" Text="nyanmjc" />
                         <TextBlock Margin="0,1.5,6,0" Text="J_danzai" />
@@ -443,6 +494,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="xiaoyuya" />
                         <TextBlock Margin="0,1.5,6,0" Text="N3W04H" />
                         <TextBlock Margin="0,1.5,6,0" Text="久遠 蓮華" />
+                        <TextBlock Margin="0,1.5,6,0" Text="小山7132" />
                         <TextBlock Margin="0,1.5,6,0" Text="HHHbbb" />
                         <TextBlock Margin="0,1.5,6,0" Text="Whelone" />
                         <TextBlock Margin="0,1.5,6,0" Text="Beholder" />
@@ -457,6 +509,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="CHLSama" />
                         <TextBlock Margin="0,1.5,6,0" Text="wanglizhi" />
                         <TextBlock Margin="0,1.5,6,0" Text="chen0701" />
+                        <TextBlock Margin="0,1.5,6,0" Text="FXXKGUN" />
                         <TextBlock Margin="0,1.5,6,0" Text="江寒_John" />
                         <TextBlock Margin="0,1.5,6,0" Text="bentianjia" />
                         <TextBlock Margin="0,1.5,6,0" Text="yukihomu" />
@@ -469,6 +522,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="飞天大锅饭" />
                         <TextBlock Margin="0,1.5,6,0" Text="烟熏秋刀鱼" />
                         <TextBlock Margin="0,1.5,6,0" Text="人海不可爱" />
+                        <TextBlock Margin="0,1.5,6,0" Text="安静不会错" />
                         <TextBlock Margin="0,1.5,6,0" Text="摆地摊的王" />
                         <TextBlock Margin="0,1.5,6,0" Text="团结起来!" />
                         <TextBlock Margin="0,1.5,6,0" Text="BeiWu_CN" />
@@ -496,14 +550,19 @@
                         <TextBlock Margin="0,1.5,6,0" Text="落雨乄北辰" />
                         <TextBlock Margin="0,1.5,6,0" Text="一条闲鲨鱼" />
                         <TextBlock Margin="0,1.5,6,0" Text="一只木元鸽" />
+                        <TextBlock Margin="0,1.5,6,0" Text="这是江江叭" />
+                        <TextBlock Margin="0,1.5,6,0" Text="柒月贰拾捌" />
+                        <TextBlock Margin="0,1.5,6,0" Text="kiboAlong" />
                         <TextBlock Margin="0,1.5,6,0" Text="W.D.gaster" />
                         <TextBlock Margin="0,1.5,6,0" Text="星野源.小毅" />
                         <TextBlock Margin="0,1.5,6,0" Text="Kimonomc" />
                         <TextBlock Margin="0,1.5,6,0" Text="翎安Lingan" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Michael_蒋" />
                         <TextBlock Margin="0,1.5,6,0" Text="Stevens520" />
                         <TextBlock Margin="0,1.5,6,0" Text="123456。?" />
                         <TextBlock Margin="0,1.5,6,0" Text="蛋白质_变质" />
                         <TextBlock Margin="0,1.5,6,0" Text="LMY666888" />
+                        <TextBlock Margin="0,1.5,6,0" Text="青灯诗酒Lily" />
                         <TextBlock Margin="0,1.5,6,0" Text="sheng_1062" />
                         <TextBlock Margin="0,1.5,6,0" Text="Zerovaluelh" />
                         <TextBlock Margin="0,1.5,6,0" Text="JUST LIKE IT" />
@@ -511,6 +570,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="一叶,知秋~" />
                         <TextBlock Margin="0,1.5,6,0" Text="joinwick789" />
                         <TextBlock Margin="0,1.5,6,0" Text="250的敌敌畏" />
+                        <TextBlock Margin="0,1.5,6,0" Text="-ET0RN1TY-" />
                         <TextBlock Margin="0,1.5,6,0" Text="forever_晨风" />
                         <TextBlock Margin="0,1.5,6,0" Text="Fakecaptain" />
                         <TextBlock Margin="0,1.5,6,0" Text="C.肥宅快乐水" />
@@ -518,6 +578,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="while(true){}" />
                         <TextBlock Margin="0,1.5,6,0" Text="Haobot2026" />
                         <TextBlock Margin="0,1.5,6,0" Text="粉色妖精小姐" />
+                        <TextBlock Margin="0,1.5,6,0" Text="打包还是带走" />
                         <TextBlock Margin="0,1.5,6,0" Text="Romarunner" />
                         <TextBlock Margin="0,1.5,6,0" Text="双狼天下第一" />
                         <TextBlock Margin="0,1.5,6,0" Text="丿地狱天使丿" />
@@ -528,16 +589,19 @@
                         <TextBlock Margin="0,1.5,6,0" Text="这位是非人类" />
                         <TextBlock Margin="0,1.5,6,0" Text="红白巫女です" />
                         <TextBlock Margin="0,1.5,6,0" Text="吃满保底之人" />
+                        <TextBlock Margin="0,1.5,6,0" Text="转电表的霍格" />
                         <TextBlock Margin="0,1.5,6,0" Text="Sylph_茜尔芙" />
                         <TextBlock Margin="0,1.5,6,0" Text="dadadadada" />
                         <TextBlock Margin="0,1.5,6,0" Text="longmao666" />
                         <TextBlock Margin="0,1.5,6,0" Text="Awolfofcolor" />
                         <TextBlock Margin="0,1.5,6,0" Text="请不要打luosi" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Fly with You!!" />
                         <TextBlock Margin="0,1.5,6,0" Text="ン黑色幽默🏮" />
                         <TextBlock Margin="0,1.5,6,0" Text="Rinshonagon" />
                         <TextBlock Margin="0,1.5,6,0" Text="esj554611445" />
                         <TextBlock Margin="0,1.5,6,0" Text="Chara&Chara" />
                         <TextBlock Margin="0,1.5,6,0" Text="lightning_bolt" />
+                        <TextBlock Margin="0,1.5,6,0" Text="卡壬纳_Karena" />
                         <TextBlock Margin="0,1.5,6,0" Text="123456789000" />
                         <TextBlock Margin="0,1.5,6,0" Text="捞猴子的月亮呐" />
                         <TextBlock Margin="0,1.5,6,0" Text="躁郁钢管大魅魔" />
@@ -549,11 +613,13 @@
                         <TextBlock Margin="0,1.5,6,0" Text="再来一笼小笼包" />
                         <TextBlock Margin="0,1.5,6,0" Text="玩魔术的暗杀者" />
                         <TextBlock Margin="0,1.5,6,0" Text="只留清白在人间" />
+                        <TextBlock Margin="0,1.5,6,0" Text="最美不过你深爱" />
                         <TextBlock Margin="0,1.5,6,0" Text="maboyuaneasy" />
                         <TextBlock Margin="0,1.5,6,0" Text="Kiana   Kasiana" />
                         <TextBlock Margin="0,1.5,6,0" Text="南ིྀ熙ིྀ寒ིྀ笙ིྀ" />
                         <TextBlock Margin="0,1.5,6,0" Text="18949212459aa" />
                         <TextBlock Margin="0,1.5,6,0" Text="M3GALOVANIA" />
+                        <TextBlock Margin="0,1.5,6,0" Text="Samuel Bridges" />
                         <TextBlock Margin="0,1.5,6,0" Text="WeimingFanzhe" />
                         <TextBlock Margin="0,1.5,6,0" Text="筱筱雨吖_Official" />
                         <TextBlock Margin="0,1.5,6,0" Text="大笨蛋你在里面吗" />
@@ -564,7 +630,9 @@
                         <TextBlock Margin="0,1.5,6,0" Text="好好吃饭好好睡觉" />
                         <TextBlock Margin="0,1.5,6,0" Text="六月に舞う雪の鳶" />
                         <TextBlock Margin="0,1.5,6,0" Text="AAALLLAAANNN" />
+                        <TextBlock Margin="0,1.5,6,0" Text="a cat wear a hear" />
                         <TextBlock Margin="0,1.5,6,0" Text="Minecraft_DeBug" />
+                        <TextBlock Margin="0,1.5,6,0" Text="爱吃蛋白的丶圆周率" />
                         <TextBlock Margin="0,1.5,6,0" Text="祖国未来的狗尾巴草" />
                         <TextBlock Margin="0,1.5,6,0" Text="化权埵萨柯摩,隆奎" />
                         <TextBlock Margin="0,1.5,6,0" Text="AAA今州耙耙柑批发" />
@@ -574,6 +642,7 @@
                         <TextBlock Margin="0,1.5,6,0" Text="牛至涂芥末越冲越上头" />
                         <TextBlock Margin="0,1.5,6,0" Text="正电荷PositiveCharge" />
                         <TextBlock Margin="0,1.5,6,0" Text="(ꐦ°᷄д°᷅)咱也不敢问啊" />
+                        <TextBlock Margin="0,1.5,6,0" Text="༺东༃方༒闲༒人༃家༻" />
                         <TextBlock Margin="0,1.5,6,0" Text="去撞南墙再撞北墙然后西墙最后东墙" />
                     </WrapPanel>
                     <Grid Height="35">

+ 4 - 3
Plain Craft Launcher 2/Pages/PageSetup/Settings.vb

@@ -1,4 +1,5 @@
 Public Class Settings
+    'TODO: 目前仅有此处在使用 DES 加密,后续考虑更换加密算法
     Public Shared ReadOnly Entries As Dictionary(Of String, Setting) = (New List(Of Setting) From {
         New Setting("Identify", "", Source:=Sources.Registry),
         New Setting("WindowHeight", 550),
@@ -248,7 +249,7 @@
             If Encrypted Then
                 Try
                     If Value Is Nothing Then Value = ""
-                    Value = SecretEncrypt(Value, "PCL" & Identify)
+                    Value = CryptographyUtils.DesEncrypt(Value, "PCL" & Identify)
                 Catch ex As Exception
                     Logger.Warn(ex, $"加密设置失败:{Key}")
                 End Try
@@ -318,7 +319,7 @@
         '正常读取
         Try
             Dim GotValue As String = Nothing '先用 String 储存,避免类型转换
-            Dim DefaultValue As String = If(Entry.Encrypted, SecretEncrypt(Entry.DefaultValue, "PCL" & Identify), Entry.DefaultValue)
+            Dim DefaultValue As String = If(Entry.Encrypted, CryptographyUtils.DesEncrypt(Entry.DefaultValue, "PCL" & Identify), Entry.DefaultValue)
             Select Case Entry.Source
                 Case Sources.Normal
                     GotValue = ReadIni("Setup", Key, DefaultValue)
@@ -336,7 +337,7 @@
                     GotValue = Entry.DefaultValue
                 Else
                     Try
-                        GotValue = SecretDecrypt(GotValue, "PCL" & Identify)
+                        GotValue = CryptographyUtils.DesDecrypt(GotValue, "PCL" & Identify)
                     Catch ex As Exception
                         Logger.Warn(ex, $"解密设置失败:{Key}")
                         GotValue = Entry.DefaultValue