From c86fdc3af17b6b5f3ea63bd8e68aef3576eea3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E8=85=BE=E7=8C=AB=E8=B7=83?= <1043137532@qq.com> Date: Thu, 21 May 2026 01:15:20 +0800 Subject: [PATCH] 2.12.8.1 --- MeloongCore | 2 +- Plain Craft Launcher 2/Application.xaml | 1 - Plain Craft Launcher 2/Application.xaml.vb | 82 ++++++------------- Plain Craft Launcher 2/Controls/MyButton.xaml | 2 +- .../Controls/MyCheckBox.xaml | 2 +- .../Controls/MyExtraButton.xaml | 2 +- .../Controls/MyIconTextButton.xaml | 2 +- Plain Craft Launcher 2/Controls/MyImage.vb | 2 +- .../Controls/MyListItem.xaml | 2 +- .../Controls/MyRadioBox.xaml | 2 +- .../Controls/MyRadioBox.xaml.vb | 4 - .../Controls/MyRadioButton.xaml | 2 +- .../Controls/MyRadioButton.xaml.vb | 1 - Plain Craft Launcher 2/FormMain.xaml.vb | 11 ++- .../Modules/Base/ModBase.vb | 47 ++++------- .../Modules/Base/ModLoader.vb | 7 +- Plain Craft Launcher 2/Modules/Base/ModNet.vb | 10 +-- .../Modules/Minecraft/ModLaunch.vb | 55 ++++++------- .../Modules/Minecraft/ModMinecraft.vb | 4 +- .../Modules/Minecraft/ModWatcher.vb | 16 ++-- Plain Craft Launcher 2/Modules/ModMain.vb | 5 +- Plain Craft Launcher 2/Modules/ModSecret.vb | 47 ----------- .../Modules/Resource/LocalResourceFile.vb | 6 +- .../Modules/Resource/ResourceSearcher.vb | 1 + .../My Project/AssemblyInfo.vb | 4 +- .../Pages/PageInstance/MyLocalModItem.xaml | 2 +- .../PageInstance/PageInstanceExport.xaml | 9 ++ .../PageInstance/PageInstanceExport.xaml.vb | 6 +- .../PageInstance/PageInstanceMod.xaml.vb | 18 ++-- .../Pages/PageLaunch/MySkin.xaml.vb | 34 ++++++-- .../Pages/PageLaunch/PageLaunchRight.xaml.vb | 8 +- .../Pages/PageLaunch/PageLoginMsSkin.xaml | 4 +- .../Pages/PageLaunch/PageLoginMsSkin.xaml.vb | 52 +++++++++--- .../Pages/PageLink/PageLinkMain.xaml.vb | 2 +- .../Pages/PageOther/PageOtherAbout.xaml | 69 ++++++++++++++++ .../Pages/PageSetup/Settings.vb | 7 +- 36 files changed, 275 insertions(+), 255 deletions(-) diff --git a/MeloongCore b/MeloongCore index 5ee6f88..f30c861 160000 --- a/MeloongCore +++ b/MeloongCore @@ -1 +1 @@ -Subproject commit 5ee6f88cde9def4bb93c9086567f28410319871c +Subproject commit f30c861f6ea5ae9a52a93ffa71357d20ce0090ab diff --git a/Plain Craft Launcher 2/Application.xaml b/Plain Craft Launcher 2/Application.xaml index fde857c..e523a44 100644 --- a/Plain Craft Launcher 2/Application.xaml +++ b/Plain Craft Launcher 2/Application.xaml @@ -368,7 +368,6 @@ - diff --git a/Plain Craft Launcher 2/Application.xaml.vb b/Plain Craft Launcher 2/Application.xaml.vb index 872bc91..851baf0 100644 --- a/Plain Craft Launcher 2/Application.xaml.vb +++ b/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 - ''' - ''' 尝试获取单例锁 + ''' 要求程序以单例运行。 + ''' 如果已在运行,则将其窗口拖出来并播放提示音,然后结束当前进程。 ''' - ''' 文件锁位置 - ''' 一个值用于指示是否获得文件锁 - 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 - - ''' - ''' 从文件锁中尝试拖出进程 - ''' - 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 diff --git a/Plain Craft Launcher 2/Controls/MyButton.xaml b/Plain Craft Launcher 2/Controls/MyButton.xaml index a952e94..ad6142d 100644 --- a/Plain Craft Launcher 2/Controls/MyButton.xaml +++ b/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}"> diff --git a/Plain Craft Launcher 2/Controls/MyCheckBox.xaml b/Plain Craft Launcher 2/Controls/MyCheckBox.xaml index 34b2a45..c0cac06 100644 --- a/Plain Craft Launcher 2/Controls/MyCheckBox.xaml +++ b/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"> diff --git a/Plain Craft Launcher 2/Controls/MyExtraButton.xaml b/Plain Craft Launcher 2/Controls/MyExtraButton.xaml index 27686cd..f8a0d88 100644 --- a/Plain Craft Launcher 2/Controls/MyExtraButton.xaml +++ b/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"> diff --git a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml index 5e1c188..abd786d 100644 --- a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml +++ b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml @@ -1,7 +1,7 @@  + HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27"> diff --git a/Plain Craft Launcher 2/Controls/MyImage.vb b/Plain Craft Launcher 2/Controls/MyImage.vb index 06a18fe..f4f007e 100644 --- a/Plain Craft Launcher 2/Controls/MyImage.vb +++ b/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 '显示缓存的图片 diff --git a/Plain Craft Launcher 2/Controls/MyListItem.xaml b/Plain Craft Launcher 2/Controls/MyListItem.xaml index 9c722d6..1624ab8 100644 --- a/Plain Craft Launcher 2/Controls/MyListItem.xaml +++ b/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"> diff --git a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml index e13890e..2a8849e 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml +++ b/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"> diff --git a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb index a5f1510..71bfccc 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb +++ b/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 '防止默认属性变更触发动画 '有动画 diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml index 4fb214b..aa42f53 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml +++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml @@ -1,7 +1,7 @@  + HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27"> diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb index 23d77f8..a7d3a7e 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb +++ b/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 diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb index 5ab4ed7..1d7d171 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.vb +++ b/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 diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb index 4ab2286..b51d89c 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb +++ b/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 - ''' - ''' 获取字符串哈希值。 - ''' - 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 - ''' - ''' 获取字符串 MD5。 - ''' - 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 - ''' ''' 不会报错的 Val。 ''' 如果输入有误,返回 0。 @@ -1399,12 +1375,17 @@ Public Module ModBase ''' 将程序中的资源释放到文件。 ''' 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 diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb index 2adc2e2..0b785f9 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb +++ b/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"} '基础属性 ''' @@ -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() '未中断,本次输出有效 diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb index fad8b5d..72ab616 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb +++ b/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 超时 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index ee40936..7eb0032 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/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 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb index 5833d96..47d93ac 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb +++ b/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: ''' 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") diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb index 1935c28..830f1ea 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb +++ b/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( diff --git a/Plain Craft Launcher 2/Modules/ModMain.vb b/Plain Craft Launcher 2/Modules/ModMain.vb index 70afc56..0972d21 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.vb +++ b/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: ''' 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 & diff --git a/Plain Craft Launcher 2/Modules/ModSecret.vb b/Plain Craft Launcher 2/Modules/ModSecret.vb index 97e5e19..09ed647 100644 --- a/Plain Craft Launcher 2/Modules/ModSecret.vb +++ b/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 "字符串加解密" - - ''' - ''' 获取八位密钥。 - ''' - Private Function SecretKeyGet(Key As String) As String - Return "00000000" - End Function - ''' - ''' 加密字符串。 - ''' - 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 - ''' - ''' 解密字符串。 - ''' - 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) diff --git a/Plain Craft Launcher 2/Modules/Resource/LocalResourceFile.vb b/Plain Craft Launcher 2/Modules/Resource/LocalResourceFile.vb index a38028e..62337e9 100644 --- a/Plain Craft Launcher 2/Modules/Resource/LocalResourceFile.vb +++ b/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 diff --git a/Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb b/Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb index a286cfc..a7686cf 100644 --- a/Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb +++ b/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}") diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb index 08bc312..c39a58e 100644 --- a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb +++ b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb @@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 ' 方法是按如下所示使用“*” - - + + diff --git a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml index ac889ca..445f44b 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml +++ b/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"> diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml index e29a1f2..db2ee7c 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml @@ -222,6 +222,15 @@ + + + + + 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 被主动取消") diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb index e35d3a4..627a499 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb +++ b/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 diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb index c30354a..f545141 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb +++ b/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 ''' 清空主页缓存信息。 ''' 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 diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml index edd0547..9d334ca 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml @@ -23,11 +23,11 @@ + - - + diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb index 441c74a..bc12c52 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb @@ -18,8 +18,8 @@ ''' ''' 获取当前页面的登录信息。 ''' - 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 diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb b/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb index 5b795ae..37fd025 100644 --- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb +++ b/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 diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml index 3f37fce..2f1aeb3 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml @@ -123,6 +123,7 @@ + @@ -150,6 +151,8 @@ + + @@ -164,7 +167,9 @@ + + @@ -179,6 +184,7 @@ + @@ -198,6 +204,7 @@ + @@ -236,25 +243,40 @@ + + + + + + + + + + + + + + + @@ -266,6 +288,7 @@ + @@ -273,11 +296,15 @@ + + + + @@ -323,6 +350,17 @@ + + + + + + + + + + + @@ -343,11 +381,13 @@ + + @@ -367,6 +407,7 @@ + @@ -374,12 +415,15 @@ + + + @@ -390,6 +434,7 @@ + @@ -427,8 +472,14 @@ + + + + + + @@ -443,6 +494,7 @@ + @@ -457,6 +509,7 @@ + @@ -469,6 +522,7 @@ + @@ -496,14 +550,19 @@ + + + + + @@ -511,6 +570,7 @@ + @@ -518,6 +578,7 @@ + @@ -528,16 +589,19 @@ + + + @@ -549,11 +613,13 @@ + + @@ -564,7 +630,9 @@ + + @@ -574,6 +642,7 @@ + diff --git a/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb b/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb index a6c2148..ea4f0c0 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb +++ b/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