diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4dbb7d1..6c0b6bfd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,13 +37,6 @@ jobs: (gc "Plain Craft Launcher 2\Modules\ModSecret.vb") -replace 'Public Const CurseForgeAPIKey As String = ""', 'Public Const CurseForgeAPIKey As String = "${{ secrets.CURSEFORGE_API_KEY }}"' | Out-File "Plain Craft Launcher 2\Modules\ModSecret.vb" (gc "Plain Craft Launcher 2\Modules\ModSecret.vb") -replace 'Public Const LittleSkinClientId As String = ""', 'Public Const LittleSkinClientId As String = "${{ secrets.LITTLESKIN_CLIENTID }}"' | Out-File "Plain Craft Launcher 2\Modules\ModSecret.vb" (gc "Plain Craft Launcher 2\Modules\Base\ModBase.vb") -replace 'Public Const CommitHash As String = ""', 'Public Const CommitHash As String = "${{ github.sha }}"' | Out-File "Plain Craft Launcher 2\Modules\Base\ModBase.vb" - rm "Plain Craft Launcher 2\Resources\Help.zip" - aria2c "--out=Plain Craft Launcher 2\Resources\Help.zip" "https://codeload.github.com/LTCatt/PCL2Help/zip/refs/heads/master" - 7z x "Plain Craft Launcher 2\Resources\Help.zip" -o"Plain Craft Launcher 2\Resources" - rm "Plain Craft Launcher 2\Resources\Help.zip" - rm "Plain Craft Launcher 2\Resources\PCL2Help-master\*.*" - 7z a "Plain Craft Launcher 2\Resources\Help.zip" ".\Plain Craft Launcher 2\Resources\PCL2Help-master\*" - rm "Plain Craft Launcher 2\Resources\PCL2Help-master\" -Recurse - name: Build run: msbuild "Plain Craft Launcher 2\Plain Craft Launcher 2.vbproj" -p:Configuration=${{ matrix.configuration }} - name: Upload a Build Artifact diff --git a/LICENCE b/LICENCE index 2336a988..47848b2f 100644 --- a/LICENCE +++ b/LICENCE @@ -2,25 +2,24 @@ 一、承诺与声明。 -  开发者承诺,在您遵守本指南且善意使用的情况下,不会追究您的责任,但最终裁量权仍由开发者保留。 +  开发者承诺,在您遵守本指南的情况下,不会追究您的责任,但最终裁量权仍由开发者保留。   法律上,开发者仍保留所有权利(All Rights Reserved),且可能随时修改本指南,本指南并不是永久性保证。 二、少量使用情形。   如果您仅合理使用本存储库中的少量内容,或是参考实现思路,您必须: -  1、给出适当的署名,且提供指向本存储库的链接。GitHub 上的 Fork 可视为满足此条。 +  1、给出适当的署名,且提供指向本存储库的链接。   2、不得以任何方式暗示开发者为您或您的使用作担保。 三、大量使用情形。   如果您基于该存储库创作衍生作品,或合理使用了本存储库中的较大量内容,您必须:   1、给出适当的署名,且提供指向本存储库的链接。GitHub 上的 Fork 可视为满足此条。 -  2、不得以任何方式暗示开发者为您或您的使用作担保。 -  3、给出适当的说明,以明确表示该衍生作品是非官方内容。 -  4、使用本指南文件作为协议,不得附加额外条款。 -  5、该衍生作品的名称必须以 “PCL” 或 “Plain Craft Launcher” 开头,并在其后添加后缀。例如 “PCL 整合包优化版”、“PCL PR Collection”。 -  6、该衍生作品不得包含 PCL 的赞助解锁功能,或与其用途相近的功能。包括但不限于:主题切换(自定义软件颜色/皮肤)、回声洞投稿等。 -  7、以善意目的进行合理使用,不要用 PCL 来干坏事、恰烂钱、整烂活。开发者可能会将撤销所有授权作为最终手段。 +  2、不得以任何方式暗示开发者为您或您的使用作担保,且需要给出适当的说明,表示这是非官方内容。 +  3、使用本指南文件作为协议,不得附加额外条款。 +  4、该衍生作品不能被允许用于再次分发。包括但不限于用于制作整合包。 +  5、该衍生作品的名称必须以 “PCL” 或 “Plain Craft Launcher” 开头,并在其后添加后缀,例如 “PCL 启动修复版”、“PCL PR Collection”。 +  6、该衍生作品不得包含 PCL 的赞助功能,或是其他作用相似的功能。包括但不限于主题功能、回声洞投稿功能等。 ———————————— diff --git a/Plain Craft Launcher 2/Application.xaml.vb b/Plain Craft Launcher 2/Application.xaml.vb index 4233f8f2..4791caf3 100644 --- a/Plain Craft Launcher 2/Application.xaml.vb +++ b/Plain Craft Launcher 2/Application.xaml.vb @@ -31,7 +31,7 @@ Public Class Application '内存优化 Dim Ram = My.Computer.Info.AvailablePhysicalMemory Try - PageOtherTest.MemoryOptimizeInternal(False) + PageOtherTest.MemoryOptimizeInternal() Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.Critical, "内存优化失败") Environment.Exit(-1) @@ -72,17 +72,9 @@ Public Class Application Directory.CreateDirectory(PathAppdata) '检测单例 #If Not DEBUG Then - Dim ShouldWaitForExit As Boolean = e.Args.Length > 0 AndAlso e.Args(0) = "--wait" '要求等待已有的 PCL 退出 - Dim WaitRetryCount As Integer = 0 -WaitRetry: Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher ") If WindowHwnd = IntPtr.Zero Then FindWindow(Nothing, "Plain Craft Launcher 2 ") If WindowHwnd <> IntPtr.Zero Then - If ShouldWaitForExit AndAlso WaitRetryCount < 20 Then '至多等待 10 秒 - WaitRetryCount += 1 - Thread.Sleep(500) - GoTo WaitRetry - End If '将已有的 PCL 窗口拖出来 ShowWindowToTop(WindowHwnd) '播放提示音并退出 @@ -110,11 +102,11 @@ WaitRetry: Log($"[Start] 程序版本:{VersionDisplayName} ({VersionCode}{If(CommitHash = "", "", $",#{CommitHash}")})") Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}") Log($"[Start] 程序路径:{PathWithName}") - Log($"[Start] 系统编码:{Encoding.Default.HeaderName} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})") + Log($"[Start] 系统编码:{Encoding.Default} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})") Log($"[Start] 管理员权限:{IsAdmin()}") '检测异常环境 If Path.Contains(IO.Path.GetTempPath()) OrElse Path.Contains("AppData\Local\Temp\") Then - MyMsgBox("请将 PCL 从压缩包中解压之后再使用!" & vbCrLf & "在当前环境下运行可能会导致丢失游戏存档或设置,部分功能也可能无法使用!", "环境警告", "我知道了", IsWarn:=True) + MyMsgBox("请将 PCL 从压缩文件中解压,或是更换文件夹后再继续使用!" & vbCrLf & "程序目前在临时文件夹中运行,设置、游戏存档等可能无法保存,且部分功能将无法使用。", "环境警告", "我知道了", IsWarn:=True) End If If Is32BitSystem Then MyMsgBox("PCL 和新版 Minecraft 均不再支持 32 位系统,部分功能将无法使用。" & vbCrLf & "非常建议重装为 64 位系统后再进行游戏!", "环境警告", "我知道了", IsWarn:=True) @@ -170,7 +162,7 @@ WaitRetry: ExceptionString.Contains(".NET Framework") OrElse ' “自动错误判断” 的结果分析 ExceptionString.Contains("未能加载文件或程序集") Then OpenWebsite("https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-offline-installer") - MsgBox("你的 .NET Framework 版本过低或损坏,请下载并重新安装 .NET Framework 4.6.2!", MsgBoxStyle.Information, "运行环境错误") + MsgBox("你的 .NET Framework 版本过低或损坏,请在打开的网页中重新下载并安装 .NET Framework 4.6.2 后重试!", MsgBoxStyle.Information, "运行环境错误") FormMain.EndProgramForce(Result.Cancel) Else FeedbackInfo() @@ -218,8 +210,8 @@ WaitRetry: If AssemblyImazenWebp Is Nothing Then Log("[Start] 加载 DLL:Imazen.WebP") AssemblyImazenWebp = Assembly.Load(GetResources("Imazen_WebP")) - SetDllDirectory(PathPure.TrimEnd("\")) - WriteFile(PathPure & "libwebp.dll", GetResources("libwebp64")) + SetDllDirectory(GetPureAsciiDir()) + File.WriteAllBytes(GetPureAsciiDir() & "\libwebp.dll", GetResources("libwebp64")) End If Return AssemblyImazenWebp End SyncLock diff --git a/Plain Craft Launcher 2/Controls/MyCard.vb b/Plain Craft Launcher 2/Controls/MyCard.vb index 821c5b05..0635cad4 100644 --- a/Plain Craft Launcher 2/Controls/MyCard.vb +++ b/Plain Craft Launcher 2/Controls/MyCard.vb @@ -295,28 +295,26 @@ Public Const SwapedHeight As Integer = 40 Private Sub MyCard_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown Dim Pos As Double = Mouse.GetPosition(Me).Y - If Not IsSwaped AndAlso - (SwapControl Is Nothing OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判 + If Not IsSwaped AndAlso (IsNothing(SwapControl) OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判 IsMouseDown = True End Sub Private Sub MyCard_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp - If Not IsMouseDown Then Return - IsMouseDown = False + If IsMouseDown Then + IsMouseDown = False + Dim Pos As Double = Mouse.GetPosition(Me).Y + If Not IsSwaped AndAlso (IsNothing(SwapControl) OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判 - Dim Pos As Double = Mouse.GetPosition(Me).Y - If Not IsSwaped AndAlso - (SwapControl Is Nothing OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判 + Dim ee = New RouteEventArgs(True) + RaiseEvent PreviewSwap(Me, ee) + If ee.Handled Then + IsMouseDown = False + Exit Sub + End If - Dim ee = New RouteEventArgs(True) - RaiseEvent PreviewSwap(Me, ee) - If ee.Handled Then - IsMouseDown = False - Return + IsSwaped = Not IsSwaped + Log("[Control] " & If(IsSwaped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title)) + RaiseEvent Swap(Me, ee) End If - - IsSwaped = Not IsSwaped - Log("[Control] " & If(IsSwaped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title)) - RaiseEvent Swap(Me, ee) End Sub Private Sub MyCard_MouseLeave_Swap(sender As Object, e As MouseEventArgs) Handles Me.MouseLeave IsMouseDown = False diff --git a/Plain Craft Launcher 2/Controls/MyImage.vb b/Plain Craft Launcher 2/Controls/MyImage.vb deleted file mode 100644 index 92ba1c07..00000000 --- a/Plain Craft Launcher 2/Controls/MyImage.vb +++ /dev/null @@ -1,189 +0,0 @@ -Public Class MyImage - Inherits Image - -#Region "公开属性" - - ''' - ''' 网络图片的缓存有效期。 - ''' 在这个时间后,才会重新尝试下载图片。 - ''' - Public FileCacheExpiredTime As New TimeSpan(7, 0, 0, 0) '7 天 - - ''' - ''' 是否允许将网络图片存储到本地用作缓存。 - ''' - Public Property EnableCache As Boolean - Get - Return GetValue(EnableCacheProperty) - End Get - Set(value As Boolean) - SetValue(EnableCacheProperty, value) - End Set - End Property - Public Shared Shadows ReadOnly EnableCacheProperty As DependencyProperty = DependencyProperty.Register( - "EnableCache", GetType(Boolean), GetType(MyImage), New PropertyMetadata(True)) - - ''' - ''' 与 Image 的 Source 类似。 - ''' 若输入以 http 开头的字符串,则会尝试下载图片然后显示,图片会保存为本地缓存。 - ''' 支持 WebP 格式的图片。 - ''' - Public Shadows Property Source As String '覆写 Image 的 Source 属性 - Get - Return _Source - End Get - Set(value As String) - If value = "" Then value = Nothing - If _Source = value Then Exit Property - _Source = value - If Not IsInitialized Then Exit Property '属性读取顺序修正:在完成 XAML 属性读取后再触发图片加载(#4868) - Load() - End Set - End Property - Private _Source As String = "" - Public Shared Shadows ReadOnly SourceProperty As DependencyProperty = DependencyProperty.Register( - "Source", GetType(String), GetType(MyImage), New PropertyMetadata(New PropertyChangedCallback( - Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyImage).Source = e.NewValue.ToString()))) - - ''' - ''' 当 Source 首次下载失败时,会从该备用地址加载图片。 - ''' - Public Property FallbackSource As String - Get - Return _FallbackSource - End Get - Set(value As String) - _FallbackSource = value - End Set - End Property - Private _FallbackSource As String = Nothing - - ''' - ''' 正在下载网络图片时显示的本地图片。 - ''' - Public Property LoadingSource As String - Get - Return _LoadingSource - End Get - Set(value As String) - _LoadingSource = value - End Set - End Property - Private _LoadingSource As String = "pack://application:,,,/images/Icons/NoIcon.png" - -#End Region - - ''' - ''' 实际被呈现的图片地址。 - ''' - Public Property ActualSource As String - Get - Return _ActualSource - End Get - Set(value As String) - If value = "" Then value = Nothing - If _ActualSource = value Then Exit Property - _ActualSource = value - Try - Dim Bitmap As MyBitmap = If(value Is Nothing, Nothing, New MyBitmap(value)) '在这里先触发可能的文件读取,尽量避免在 UI 线程中读取文件 - RunInUiWait(Sub() MyBase.Source = Bitmap) - Catch ex As Exception - Log(ex, $"加载图片失败({value})") - Try - If value.StartsWithF(PathTemp) AndAlso File.Exists(value) Then File.Delete(value) - Catch - End Try - End Try - End Set - End Property - Private _ActualSource As String = Nothing - - Private Sub Load() _ - Handles Me.Initialized '属性读取顺序修正:在完成 XAML 属性读取后再触发图片加载(#4868) - '空 - If Source Is Nothing Then - ActualSource = Nothing - Exit Sub - End If - '本地图片 - If Not Source.StartsWithF("http") Then - ActualSource = Source - Exit Sub - End If - '从缓存加载网络图片 - Dim Url As String = Source - Dim Retried As Boolean = False - Dim TempPath As String = GetTempPath(Url) - Dim TempFile As New FileInfo(TempPath) - Dim EnableCache As Boolean = Me.EnableCache - If EnableCache AndAlso TempFile.Exists Then - ActualSource = TempPath - If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Exit Sub '无需刷新缓存 - End If - RunInNewThread( - Sub() - Dim TempDownloadingPath As String = Nothing - Try -RetryStart: - '下载 - ActualSource = LoadingSource '显示加载中图片 - TempDownloadingPath = TempPath & RandomInteger(0, 10000000) - Directory.CreateDirectory(GetPathFromFullPath(TempPath)) '重新实现下载,以避免携带 Header(#5072) - Using Client As New Net.WebClient - Client.DownloadFile(Url, TempDownloadingPath) - End Using - If Url <> Source AndAlso Url <> FallbackSource Then - '已经更换了地址 - File.Delete(TempDownloadingPath) - ElseIf EnableCache Then - '保存缓存并显示 - If File.Exists(TempPath) Then File.Delete(TempPath) - Rename(TempDownloadingPath, TempPath) - RunInUi(Sub() ActualSource = TempPath) - Else - '直接显示 - RunInUiWait(Sub() ActualSource = TempDownloadingPath) - File.Delete(TempDownloadingPath) - End If - Catch ex As Exception - Try - If TempPath IsNot Nothing Then File.Delete(TempPath) - If TempDownloadingPath IsNot Nothing Then File.Delete(TempDownloadingPath) - Catch - End Try - If Not Retried Then - '更换备用地址 - Log(ex, $"下载图片可重试地失败({Url})", LogLevel.Developer) - Retried = True - Url = If(FallbackSource, Source) - '空 - If Url Is Nothing Then - ActualSource = Nothing - Exit Sub - End If - '本地图片 - If Not Url.StartsWithF("http") Then - ActualSource = Url - Exit Sub - End If - '从缓存加载网络图片 - TempPath = GetTempPath(Url) - TempFile = New FileInfo(TempPath) - If EnableCache AndAlso TempFile.Exists() Then - ActualSource = TempPath - If (Date.Now - TempFile.CreationTime) < FileCacheExpiredTime Then Exit Sub '无需刷新缓存 - End If - '下载 - If Source = Url Then Thread.Sleep(1000) '延迟 1s 重试 - GoTo RetryStart - Else - Log(ex, $"下载图片失败({Url})", LogLevel.Hint) - End If - End Try - End Sub, "MyImage PicLoader " & GetUuid() & "#", ThreadPriority.BelowNormal) - End Sub - Public Shared Function GetTempPath(Url As String) As String - Return $"{PathTemp}MyImage\{GetHash(Url)}.png" - End Function - -End Class \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb b/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb index 2efeecae..e0517e17 100644 --- a/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb @@ -268,26 +268,33 @@ If Not _Logo = "" Then If _Logo.StartsWithF("http", True) Then '网络图片 - PathLogo = New MyImage With { + PathLogo = New Image With { .Tag = Me, .IsHitTestVisible = LogoClickable, - .Source = _Logo, + .Source = New ImageSourceConverter().ConvertFromString(_Logo), .RenderTransformOrigin = New Point(0.5, 0.5), .RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale}, .SnapsToDevicePixels = True, .UseLayoutRounding = False} RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.Linear) - ElseIf _Logo.EndsWithF(".png", True) OrElse _Logo.EndsWithF(".jpg", True) OrElse _Logo.EndsWithF(".webp", True) Then + ElseIf _Logo.EndsWithF(".png", True) OrElse _Logo.EndsWithF(".jpg", True) Then '位图 + Dim Bitmap = New MyBitmap(_Logo) PathLogo = New Canvas With { .Tag = Me, .IsHitTestVisible = LogoClickable, - .Background = New MyBitmap(_Logo), + .Background = Bitmap, .RenderTransformOrigin = New Point(0.5, 0.5), .RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale}, - .SnapsToDevicePixels = True, .UseLayoutRounding = False, - .HorizontalAlignment = HorizontalAlignment.Stretch, .VerticalAlignment = VerticalAlignment.Stretch - } - RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.Linear) + .SnapsToDevicePixels = True, .UseLayoutRounding = False} + 'If Bitmap.Pic.Width = 16 AndAlso Bitmap.Pic.Height = 16 Then + ' '使用最适合 16x16 物品图片显示的大小 + ' RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.NearestNeighbor) + ' PathLogo.HorizontalAlignment = HorizontalAlignment.Center : PathLogo.VerticalAlignment = VerticalAlignment.Center + ' PathLogo.Width = GetWPFSize(Math.Floor(GetPixelSize(32) / 16) * 16) : PathLogo.Height = PathLogo.Width + 'Else + PathLogo.HorizontalAlignment = HorizontalAlignment.Stretch : PathLogo.VerticalAlignment = VerticalAlignment.Stretch + RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.HighQuality) + 'End If Else '矢量图 PathLogo = New Shapes.Path With { @@ -376,8 +383,8 @@ Private Sub OnSizeChanged() Handles Me.SizeChanged ColumnCheck.Width = New GridLength(If(_Type = CheckType.None OrElse _Type = CheckType.Clickable, If(Height < 40, 4, 2), 6)) ColumnLogo.Width = New GridLength(If(_Logo = "", 0, 34) + If(Height < 40, 0, 4)) - If PathLogo IsNot Nothing Then - If _Logo.EndsWithF(".png", True) OrElse _Logo.EndsWithF(".jpg", True) OrElse _Logo.EndsWithF(".webp", True) Then + If Not IsNothing(PathLogo) Then + If _Logo.EndsWithF(".png", True) Then PathLogo.Margin = New Thickness(4, 5, 3, 5) Else PathLogo.Margin = New Thickness(If(Height < 40, 6, 8), 8, If(Height < 40, 4, 6), 8) @@ -710,8 +717,6 @@ Dim Unused = New HelpEntry(GetEventAbsoluteUrls(EventData, EventType)(0)).SetToListItem(Me) Catch ex As Exception Log(ex, "设置帮助 MyListItem 失败", LogLevel.Msgbox) - EventType = Nothing - EventData = Nothing End Try End If End Sub diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml index 282ecb27..bf232812 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml @@ -25,7 +25,7 @@ + VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMuity="0.7"> diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml index b4f75ba3..5c21822d 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml @@ -24,7 +24,7 @@ + VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMuity="0.7"> diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml index 0bbf1578..10f2a924 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml @@ -24,7 +24,7 @@ + VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMuity="0.7"> diff --git a/Plain Craft Launcher 2/Controls/MyPageLeft.vb b/Plain Craft Launcher 2/Controls/MyPageLeft.vb index 9c368a60..b09897b7 100644 --- a/Plain Craft Launcher 2/Controls/MyPageLeft.vb +++ b/Plain Craft Launcher 2/Controls/MyPageLeft.vb @@ -104,7 +104,3 @@ End Sub End Class - -Public Interface IRefreshable - Sub Refresh() -End Interface \ No newline at end of file diff --git a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb index ba5c05e1..3cb814cf 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb @@ -157,7 +157,9 @@ End Set End Property '内容 Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyRadioBox), New PropertyMetadata(New PropertyChangedCallback( - Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyRadioBox).LabText.Text = e.NewValue))) + Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs) + If Not IsNothing(sender) Then CType(sender, MyRadioBox).LabText.Text = e.NewValue + End Sub))) '点击事件 diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml index aa42f53c..e5753e03 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml +++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml @@ -4,6 +4,6 @@ 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 8d9537be..c147a2f3 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb @@ -117,7 +117,9 @@ End Set End Property '内容 Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyRadioButton), New PropertyMetadata(New PropertyChangedCallback( - Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyRadioButton).LabText.Text = e.NewValue))) + Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs) + If Not IsNothing(sender) Then CType(sender, MyRadioButton).LabText.Text = e.NewValue + End Sub))) Public Enum ColorState White Highlight diff --git a/Plain Craft Launcher 2/Controls/MyScrollViewer.vb b/Plain Craft Launcher 2/Controls/MyScrollViewer.vb index 42da8906..beaeb1c3 100644 --- a/Plain Craft Launcher 2/Controls/MyScrollViewer.vb +++ b/Plain Craft Launcher 2/Controls/MyScrollViewer.vb @@ -1,7 +1,7 @@ Public Class MyScrollViewer Inherits ScrollViewer - Public Property DeltaMult As Double = 1 + Public Property DeltaMuity As Double = 1 Private RealOffset As Double @@ -25,12 +25,10 @@ Next End Sub Public Sub PerformVerticalOffsetDelta(Delta As Double) - AniStart( - AaDouble( - Sub(AnimDelta As Double) - RealOffset = MathClamp(RealOffset + AnimDelta, 0, ExtentHeight - ActualHeight) - ScrollToVerticalOffset(RealOffset) - End Sub, Delta * DeltaMult, 300,, New AniEaseOutFluent(6))) + AniStart(AaDouble(Sub(AnimDelta As Double) + RealOffset = MathClamp(RealOffset + AnimDelta, 0, ExtentHeight - ActualHeight) + ScrollToVerticalOffset(RealOffset) + End Sub, Delta * DeltaMuity, 300,, New AniEaseOutFluent(6))) End Sub Private Sub MyScrollViewer_ScrollChanged(sender As Object, e As ScrollChangedEventArgs) Handles Me.ScrollChanged RealOffset = VerticalOffset @@ -45,7 +43,4 @@ ScrollBar = GetTemplateChild("PART_VerticalScrollBar") End Sub - Private Sub MyScrollViewer_PreviewGotKeyboardFocus(sender As Object, e As KeyboardFocusChangedEventArgs) Handles Me.PreviewGotKeyboardFocus - If e.NewFocus IsNot Nothing AndAlso TypeOf e.NewFocus Is MySlider Then e.Handled = True '#3854,阻止获得焦点时自动滚动 - End Sub End Class diff --git a/Plain Craft Launcher 2/Controls/MyTextButton.vb b/Plain Craft Launcher 2/Controls/MyTextButton.vb index 58fcd6ea..3d8245f8 100644 --- a/Plain Craft Launcher 2/Controls/MyTextButton.vb +++ b/Plain Craft Launcher 2/Controls/MyTextButton.vb @@ -90,21 +90,21 @@ Get Return GetValue(EventTypeProperty) End Get + Set(value As String) SetValue(EventTypeProperty, value) End Set End Property - Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register( - "EventType", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing)) + Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing)) Public Property EventData As String Get Return GetValue(EventDataProperty) End Get + Set(value As String) SetValue(EventDataProperty, value) End Set End Property - Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register( - "EventData", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing)) + Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing)) End Class diff --git a/Plain Craft Launcher 2/FormMain.xaml b/Plain Craft Launcher 2/FormMain.xaml index d0a3a5e5..edebd06e 100644 --- a/Plain Craft Launcher 2/FormMain.xaml +++ b/Plain Craft Launcher 2/FormMain.xaml @@ -104,7 +104,7 @@ - + - + diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb index 862fc716..753679ea 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.vb +++ b/Plain Craft Launcher 2/FormMain.xaml.vb @@ -9,29 +9,7 @@ Public Class FormMain Dim FeatureCount As Integer = 0, BugCount As Integer = 0 Dim FeatureList As New List(Of KeyValuePair(Of Integer, String)) '统计更新日志条目 -#If RELEASE Then - If LastVersion < 350 Then 'Release 2.9.2 - FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持下载资源包和光影包")) - End If - If LastVersion < 349 Then 'Release 2.9.1 - FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "添加了本体更新(实验性)")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "关于页面新增了详细的版本信息")) - End If - If LastVersion < 347 Then 'Release 2.8.12 - FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面添加下载 Mod、安装 Mod 选项")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 详情页面支持按加载器、游戏版本进行分类和筛选")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持安装同时包含 modpack 文件和启动器的懒人包")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化整合包导入流程")) - FeatureCount += 43 - BugCount += 37 - End If - If LastVersion < 342 Then 'Release 2.8.9 - FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持下载原版服务端")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "本地 Mod 的标题支持选择显示 Mod 原始文件名")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复搜索后启用/禁用 Mod 时出错的 Bug")) - FeatureCount += 17 - BugCount += 13 - End If +#If BETA Then If LastVersion < 340 Then 'Release 2.8.8 If LastVersion = 338 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复数个与新正版登录相关的严重 Bug")) FeatureCount += 3 @@ -91,41 +69,84 @@ Public Class FormMain FeatureCount += 10 BugCount += 10 End If -#Else - '5: FEAT+ - '4: IMP+ FEAT* - '3:BUG+ IMP* FEAT- - '2:BUG* IMP- - '1:BUG- - If LastVersion < 350 Then 'Snapshot 2.9.2 - FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持下载资源包和光影包")) + If LastVersion < 317 Then 'Release 2.6.15 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法安装 Forge 的 Bug")) + FeatureCount += 2 + BugCount += 2 + End If + If LastVersion < 315 Then 'Release 2.6.14 + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化 MC 下载,尝试解决各种导致 MC 下载失败的问题")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "由于 MCBBS 关站,移除其相关内容")) + FeatureCount += 17 + BugCount += 16 End If - If LastVersion < 349 Then 'Snapshot 2.9.1 - FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "添加了本体更新(实验性)")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "关于页面新增了详细的版本信息")) + If LastVersion < 313 Then 'Release 2.6.13 + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法启动 Forge 1.18.3+ 的 Bug")) + FeatureCount += 6 + BugCount += 10 End If - If LastVersion < 346 Then 'Snapshot 2.8.12 - If LastVersion = 345 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复帮助页面报错的 Bug")) + If LastVersion < 311 Then 'Release 2.6.12 + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面将显示 Mod 的中文名、图标、标签等信息")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "从 Mod 管理页面查看 Mod 信息时会跳转到其下载详情页面")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "重新设计 Mod 管理页面的交互与样式")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法安装 Forge 1.18.3+ 的 Bug")) + FeatureCount += 27 + BugCount += 25 + End If + If LastVersion < 308 Then 'Release 2.6.10 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "为版本独立设置添加忽略 Java 兼容性警告选项")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复开始或结束游戏时可能报错的 Bug")) + FeatureCount += 31 + BugCount += 37 End If - If LastVersion < 345 Then 'Snapshot 2.8.11 - FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面添加下载 Mod、安装 Mod 选项")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 详情页面支持按加载器、游戏版本进行分类和筛选")) - FeatureCount += 23 - BugCount += 21 + If LastVersion < 302 Then 'Release 2.6.7 + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "再次修复网络条件差时可能无法下载 MC 的 Bug")) + BugCount += 1 End If - If LastVersion < 343 Then 'Snapshot 2.8.10 - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持安装同时包含 modpack 文件和启动器的懒人包")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化整合包导入流程")) - FeatureCount += 20 - BugCount += 16 + If LastVersion < 300 Then 'Release 2.6.6 + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持选择多种预设的主页")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod 管理中允许多选 Mod 进行批量操作")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化崩溃分析,添加多种崩溃情况的判断")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化联网获取的主页的加载与缓存")) + FeatureCount += 40 + BugCount += 34 + End If + If LastVersion < 296 Then 'Release 2.6.3 + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增内存优化功能,可以将所有程序的物理内存占用降低约 1/3")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "在选择 OptiFine 与 Fabric 后会自动选择 OptiFabric")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化崩溃分析,添加多种崩溃情况的判断")) + FeatureCount += 21 + BugCount += 30 + End If + If LastVersion < 293 Then 'Release 2.6.1 + BugCount += 1 End If - If LastVersion < 341 Then 'Snapshot 2.8.9 - FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持下载原版服务端")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "本地 Mod 的标题支持选择显示 Mod 原始文件名")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复搜索后启用/禁用 Mod 时出错的 Bug")) - FeatureCount += 17 - BugCount += 13 + If LastVersion < 292 Then 'Release 2.6.0 + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持在多个正版账号间切换")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "在缺少 Java 时会自动下载所需的 Java")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "重新制作正版登录页面")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "彻底移除 Mojang 登录")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "添加 CurseForge / Modrinth 来源筛选")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "Mod / 整合包下载会单独列出筛选的版本")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "为下载管理和音乐播放按钮添加进度条")) + FeatureCount += 24 + BugCount += 24 End If + If LastVersion < 286 Then 'Release 2.5.2 + FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持搜索、安装 Modrinth 的 Mod 与整合包")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "资源搜索页面支持翻页")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "在全局启动设置中添加了 启动前执行命令 选项")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "重做资源下载的资源项界面")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "在选择下载 Fabric 时会自动选择 Fabric API")) + FeatureCount += 35 + BugCount += 36 + End If +#Else + '5: FEAT+ + '4: IMP+ FEAT* + '3:BUG+ IMP* FEAT- + '2:BUG* IMP- + '1:BUG- If LastVersion < 339 Then 'Snapshot 2.8.8 If LastVersion = 337 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复数个与新正版登录相关的严重 Bug")) FeatureCount += 3 @@ -212,6 +233,117 @@ Public Class FormMain FeatureCount += 10 BugCount += 10 End If + If LastVersion < 316 Then 'Snapshot 2.6.15 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复无法安装 Forge 的 Bug")) + FeatureCount += 2 + BugCount += 2 + End If + If LastVersion < 314 Then 'Snapshot 2.6.14 + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化 MC 下载,尝试解决各种导致 MC 下载失败的问题")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "由于 MCBBS 关站,移除其相关内容")) + FeatureCount += 17 + BugCount += 16 + End If + If LastVersion < 312 Then 'Snapshot 2.6.13 + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法启动 Forge 1.18.3+ 的 Bug")) + FeatureCount += 6 + BugCount += 10 + End If + If LastVersion < 310 Then 'Snapshot 2.6.12 + If LastVersion = 309 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod 管理页面添加启用、禁用单个 Mod 的快捷按钮")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法安装 Forge 1.18.3+ 的 Bug")) + FeatureCount += 13 + BugCount += 12 + End If + If LastVersion < 309 Then 'Snapshot 2.6.11 + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面将显示 Mod 的中文名、图标、标签等信息")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "从 Mod 管理页面查看 Mod 信息时会跳转到其下载详情页面")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "重新设计 Mod 管理页面的交互与样式")) + FeatureCount += 15 + BugCount += 13 + End If + If LastVersion < 307 Then 'Snapshot 2.6.10 + FeatureCount += 2 + BugCount += 3 + End If + If LastVersion < 306 Then 'Snapshot 2.6.9 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "为版本独立设置添加忽略 Java 兼容性警告选项")) + FeatureCount += 9 + BugCount += 11 + End If + If LastVersion < 305 Then 'Snapshot 2.6.8 + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复开始或结束游戏时可能报错的 Bug")) + FeatureCount += 20 + BugCount += 25 + End If + If LastVersion < 303 Then 'Snapshot 2.6.7 + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "再次修复网络条件差时可能无法下载 MC 的 Bug")) + BugCount += 1 + End If + If LastVersion < 301 Then 'Snapshot 2.6.6 + FeatureCount += 4 + BugCount += 2 + End If + If LastVersion < 299 Then 'Snapshot 2.6.5 + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持选择多种预设的主页")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化联网获取的主页的加载与缓存")) + FeatureCount += 18 + BugCount += 13 + End If + If LastVersion < 298 Then 'Snapshot 2.6.4 + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod 管理中允许多选 Mod 进行批量操作")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化崩溃分析,添加多种崩溃情况的判断")) + FeatureCount += 18 + BugCount += 19 + End If + If LastVersion < 297 Then 'Snapshot 2.6.3 + FeatureCount += 12 + BugCount += 14 + End If + If LastVersion < 294 Then 'Snapshot 2.6.2 + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增内存优化功能,可以将所有程序的物理内存占用降低约 1/3")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "在选择 OptiFine 与 Fabric 后会自动选择 OptiFabric")) + FeatureCount += 9 + BugCount += 16 + End If + If LastVersion < 291 Then 'Snapshot 2.6.0 + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持在多个正版账号间切换")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "Mod / 整合包下载会单独列出筛选的版本")) + FeatureCount += 10 + BugCount += 2 + End If + If LastVersion < 289 Then 'Snapshot 2.5.4 + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "重新制作正版登录页面")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "彻底移除 Mojang 登录")) + FeatureCount += 6 + BugCount += 14 + End If + If LastVersion < 288 Then 'Snapshot 2.5.3 + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "在缺少 Java 时会自动下载所需的 Java")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "添加 CurseForge / Modrinth 来源筛选")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "为下载管理和音乐播放按钮添加进度条")) + FeatureCount += 8 + BugCount += 8 + End If + If LastVersion < 285 Then 'Snapshot 2.5.2 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "重做资源下载的资源项界面")) + If LastVersion = 284 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复打开部分帮助报错的 Bug")) + FeatureCount += 8 + BugCount += 8 + End If + If LastVersion < 284 Then 'Snapshot 2.5.1 + If LastVersion >= 275 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "在全局启动设置中添加了 启动前执行命令 选项")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "在选择下载 Fabric 时会自动选择 Fabric API")) + FeatureCount += 22 + BugCount += 21 + End If + If LastVersion < 283 Then 'Snapshot 2.5.0 + FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持搜索、下载 Modrinth 中的 Mod 与整合包")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "资源搜索页面支持翻页")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持安装 Modrinth 整合包")) + FeatureCount += 5 + BugCount += 5 + End If #End If '整理更新日志文本 Dim ContentList As New List(Of String) @@ -254,6 +386,9 @@ Public Class FormMain '触发降级 DowngradeSub(LastVersion) End If + ''刷新语言 + 'Lang = ReadReg("Lang", "zh_CN") + 'Application.Current.Resources.MergedDictionaries(1) = New ResourceDictionary With {.Source = New Uri("Resources\Language\" & Lang & ".xaml", UriKind.Relative)} '刷新主题 ThemeCheckAll(False) Setup.Load("UiLauncherTheme") @@ -271,9 +406,7 @@ Public Class FormMain If Not IsNothing(FrmLaunchLeft.Parent) Then FrmLaunchLeft.SetValue(ContentPresenter.ContentProperty, Nothing) If Not IsNothing(FrmLaunchRight.Parent) Then FrmLaunchRight.SetValue(ContentPresenter.ContentProperty, Nothing) PanMainLeft.Child = FrmLaunchLeft - PageLeft = FrmLaunchLeft PanMainRight.Child = FrmLaunchRight - PageRight = FrmLaunchRight FrmLaunchRight.PageState = MyPageRight.PageStates.ContentStay '模式提醒 #If DEBUG Then @@ -318,17 +451,17 @@ Public Class FormMain '加载窗口 ThemeRefreshMain() Try - Height = Setup.Get("WindowHeight") - Width = Setup.Get("WindowWidth") + Height = ReadReg("WindowHeight", MinHeight + 50) + Width = ReadReg("WindowWidth", MinWidth + 50) Catch ex As Exception '修复 #2019 Log(ex, "读取窗口默认大小失败", LogLevel.Hint) - Height = MinHeight + 100 - Width = MinWidth + 100 + Height = MinHeight + 50 + Width = MinWidth + 50 End Try - '#If DEBUG Then - ' MinHeight = 50 - ' MinWidth = 50 - '#End If +#If DEBUG Then + MinHeight = 50 + MinWidth = 50 +#End If Topmost = False If FrmStart IsNot Nothing Then FrmStart.Close(New TimeSpan(0, 0, 0, 0, 400 / AniSpeed)) '更改窗口 @@ -359,7 +492,7 @@ Public Class FormMain 'EULA 提示 If Not Setup.Get("SystemEula") Then Select Case MyMsgBox("在使用 PCL 前,请同意 PCL 的用户协议与免责声明。", "协议授权", "同意", "拒绝", "查看用户协议与免责声明", - Button3Action:=Sub() OpenWebsite("https://shimo.im/docs/rGrd8pY8xWkt6ryW")) + Button3Action:=Sub() OpenWebsite("https://shimo.im/docs/rGrd8pY8xWkt6ryW")) Case 1 Setup.Set("SystemEula", True) Case 2 @@ -456,16 +589,6 @@ Public Class FormMain Setup.Set("UiHiddenOtherHelp", False) Log("[Start] 已解除帮助页面的隐藏") End If - '单向迁移微软登录结果(#4836) - If Not Setup.Get("CacheMsV2Migrated") Then - Setup.Set("CacheMsV2Migrated", True) - Setup.Set("CacheMsV2OAuthRefresh", Setup.Get("CacheMsOAuthRefresh")) - Setup.Set("CacheMsV2Access", Setup.Get("CacheMsAccess")) - Setup.Set("CacheMsV2ProfileJson", Setup.Get("CacheMsProfileJson")) - Setup.Set("CacheMsV2Uuid", Setup.Get("CacheMsUuid")) - Setup.Set("CacheMsV2Name", Setup.Get("CacheMsName")) - Log("[Start] 已从老版本迁移微软登录结果") - End If '输出更新日志 If LastVersionCode = 0 Then Exit Sub If LowerVersionCode >= VersionCode Then Exit Sub @@ -507,35 +630,35 @@ Public Class FormMain End If '关闭 RunInUiWait( - Sub() - IsHitTestVisible = False - If PanBack.RenderTransform Is Nothing Then - Dim TransformPos As New TranslateTransform(0, 0) - Dim TransformRotate As New RotateTransform(0) - Dim TransformScale As New ScaleTransform(1, 1) - PanBack.RenderTransform = New TransformGroup() With {.Children = New TransformCollection({TransformRotate, TransformPos, TransformScale})} - AniStart({ - AaOpacity(Me, -Opacity, 140, 40, New AniEaseOutFluent(AniEasePower.Weak)), - AaDouble( - Sub(i) - TransformScale.ScaleX += i - TransformScale.ScaleY += i - End Sub, 0.88 - TransformScale.ScaleX, 180), - AaDouble(Sub(i) TransformPos.Y += i, 20 - TransformPos.Y, 180, 0, New AniEaseOutFluent(AniEasePower.Weak)), - AaDouble(Sub(i) TransformRotate.Angle += i, 0.6 - TransformRotate.Angle, 180, 0, New AniEaseInoutFluent(AniEasePower.Weak)), - AaCode( - Sub() - IsHitTestVisible = False - Top = -10000 - ShowInTaskbar = False - End Sub, 210), - AaCode(AddressOf EndProgramForce, 230) - }, "Form Close") - Else - EndProgramForce() - End If - Log("[System] 收到关闭指令") - End Sub) + Sub() + IsHitTestVisible = False + If PanBack.RenderTransform Is Nothing Then + Dim TransformPos As New TranslateTransform(0, 0) + Dim TransformRotate As New RotateTransform(0) + Dim TransformScale As New ScaleTransform(1, 1) + PanBack.RenderTransform = New TransformGroup() With {.Children = New TransformCollection({TransformRotate, TransformPos, TransformScale})} + AniStart({ + AaOpacity(Me, -Opacity, 140, 40, New AniEaseOutFluent(AniEasePower.Weak)), + AaDouble( + Sub(i) + TransformScale.ScaleX += i + TransformScale.ScaleY += i + End Sub, 0.88 - TransformScale.ScaleX, 180), + AaDouble(Sub(i) TransformPos.Y += i, 20 - TransformPos.Y, 180, 0, New AniEaseOutFluent(AniEasePower.Weak)), + AaDouble(Sub(i) TransformRotate.Angle += i, 0.6 - TransformRotate.Angle, 180, 0, New AniEaseInoutFluent(AniEasePower.Weak)), + AaCode( + Sub() + IsHitTestVisible = False + Top = -10000 + ShowInTaskbar = False + End Sub, 210), + AaCode(AddressOf EndProgramForce, 230) + }, "Form Close") + Else + EndProgramForce() + End If + Log("[System] 收到关闭指令") + End Sub) End Sub Private Shared IsLogShown As Boolean = False Public Shared Sub EndProgramForce(Optional ReturnCode As Result = Result.Success) @@ -580,8 +703,8 @@ Public Class FormMain Public IsSizeSaveable As Boolean = False Private Sub FormMain_SizeChanged() Handles Me.SizeChanged, Me.Loaded If IsSizeSaveable Then - Setup.Set("WindowHeight", Height) - Setup.Set("WindowWidth", Width) + WriteReg("WindowHeight", Height) + WriteReg("WindowWidth", Width) End If RectForm.Rect = New Rect(0, 0, BorderForm.ActualWidth, BorderForm.ActualHeight) PanForm.Width = BorderForm.ActualWidth + 0.001 @@ -639,12 +762,6 @@ Public Class FormMain PageSetupUI.HiddenRefresh() Exit Sub End If - '按 F5 刷新页面 - If e.Key = Key.F5 Then - If TypeOf PageLeft Is IRefreshable Then CType(PageLeft, IRefreshable).Refresh() - If TypeOf PageRight Is IRefreshable Then CType(PageRight, IRefreshable).Refresh() - Exit Sub - End If '调用启动游戏 If e.Key = Key.Enter AndAlso PageCurrent = FormMain.PageType.Launch Then If IsAprilEnabled AndAlso Not IsAprilGiveup Then @@ -782,14 +899,14 @@ Public Class FormMain If FilePathList.Count > 1 Then '必须要求全部为 Jar 文件 For Each File In FilePathList - If Not {"jar", "litemod", "disabled", "old"}.Contains(File.AfterLast(".").ToLower) Then + If Not {"jar", "litemod", "disabled", "old"}.Contains(File.After(".").ToLower) Then Hint("一次请只拖入一个文件!", HintType.Critical) Exit Sub End If Next End If '自定义主页 - Dim Extension As String = FilePath.AfterLast(".").ToLower + Dim Extension As String = FilePath.After(".").ToLower If Extension = "xaml" Then Log("[System] 文件后缀为 XAML,作为自定义主页加载") If File.Exists(Path & "PCL\Custom.xaml") Then @@ -798,27 +915,53 @@ Public Class FormMain End If End If CopyFile(FilePath, Path & "PCL\Custom.xaml") - RunInUi( - Sub() - Setup.Set("UiCustomType", 1) - FrmLaunchRight.ForceRefresh() - Hint("已加载主页自定义文件!", HintType.Finish) - End Sub) + RunInUi(Sub() + Setup.Set("UiCustomType", 1) + FrmLaunchRight.ForceRefresh() + Hint("已加载主页自定义文件!", HintType.Finish) + End Sub) + Exit Sub + End If + 'Mod 安装 + If {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then + Log("[System] 文件为 jar/litemod 格式,尝试作为 Mod 安装") + '获取并检查目标版本 + Dim TargetVersion As McVersion = McVersionCurrent + If PageCurrent = PageType.VersionSetup Then TargetVersion = PageVersionLeft.Version + If PageCurrent = PageType.VersionSelect OrElse TargetVersion Is Nothing OrElse Not TargetVersion.Modable Then + '正在选择版本,或当前版本不能安装 Mod + Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!") + ElseIf Not (PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionMod) Then + '未处于 Mod 管理页面 + If MyMsgBox($"是否要将这{If(FilePathList.Count = 1, "个", "些")}文件作为 Mod 安装到 {TargetVersion.Name}?", "Mod 安装确认", "确定", "取消") = 1 Then GoTo Install + Else + '处于 Mod 管理页面 +Install: + Try + For Each ModFile In FilePathList + Dim NewFileName = GetFileNameFromPath(ModFile).Replace(".disabled", "") + If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227 + CopyFile(ModFile, TargetVersion.PathIndie & "mods\" & NewFileName) + Next + If FilePathList.Count = 1 Then + Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "")}!", HintType.Finish) + Else + Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Finish) + End If + '刷新列表 + If PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionMod Then + LoaderFolderRun(McModLoader, TargetVersion.PathIndie & "mods\", LoaderFolderRunType.ForceRun) + End If + Catch ex As Exception + Log(ex, "复制 Mod 文件失败", LogLevel.Msgbox) + End Try + End If Exit Sub End If - '安装 Mod - If PageVersionMod.InstallMods(FilePathList) Then Exit Sub '安装整合包 If {"zip", "rar", "mrpack"}.Any(Function(t) t = Extension) Then '部分压缩包是 zip 格式但后缀为 rar,总之试一试 Log("[System] 文件为压缩包,尝试作为整合包安装") - Try - ModpackInstall(FilePath) - Exit Sub - Catch ex As CancelledException - Exit Sub '用户主动取消 - Catch ex As Exception - '安装失败,继续往后尝试 - End Try + If ModpackInstall(FilePath, ShowHint:=False) IsNot Nothing Then Exit Sub End If 'RAR 处理 If Extension = "rar" Then @@ -1060,6 +1203,9 @@ Public Class FormMain Case PageType.Download If FrmDownloadLeft Is Nothing Then FrmDownloadLeft = New PageDownloadLeft Return FrmDownloadLeft.PageID + Case PageType.Link + If FrmLinkLeft Is Nothing Then FrmLinkLeft = New PageLinkLeft + Return FrmLinkLeft.PageID Case PageType.Setup If FrmSetupLeft Is Nothing Then FrmSetupLeft = New PageSetupLeft Return FrmSetupLeft.PageID @@ -1128,6 +1274,9 @@ Public Class FormMain CType(PanTitleSelect.Children(Stack), MyRadioButton).SetChecked(True, True, PageNameGet(PageCurrent) = "") IsChangingPage = False Select Case Stack.Page + Case PageType.Link + If FrmLinkLeft Is Nothing Then FrmLinkLeft = New PageLinkLeft + CType(FrmLinkLeft.PanItem.Children(SubType), MyListItem).SetChecked(True, True, Stack = PageCurrent) Case PageType.Download If FrmDownloadLeft Is Nothing Then FrmDownloadLeft = New PageDownloadLeft CType(FrmDownloadLeft.PanItem.Children(SubType), MyListItem).SetChecked(True, True, Stack = PageCurrent) @@ -1156,6 +1305,14 @@ Public Class FormMain If IsChangingPage Then Exit Sub PageChangeActual(Val(sender.Tag)) End Sub + Private Sub CancelLink(sender As Object, e As RouteEventArgs) Handles BtnTitleSelect2.PreviewClick + If MyMsgBox("由于联机提供商要求新联机强制付费,且高度商业化,PCL 将暂时关闭联机功能,不再使用该联机模块。" & vbCrLf & + "PCL、HMCL、BakaXL 将合作开发新的跨启动器联机功能,在开发结束后将同步开放,请各位多多理解。", + "联机功能已暂时关闭", "查看详情", "确定") = 1 Then + OpenWebsite("https://www.bilibili.com/read/cv19845645") + End If + e.Handled = True + End Sub ''' ''' 通过点击返回按钮或手动触发返回来改变页面。 ''' @@ -1186,9 +1343,9 @@ Public Class FormMain If PageStack.Any Then '子页面 → 另一个子页面,更新 AniStart({ - AaOpacity(LabTitleInner, -LabTitleInner.Opacity, 130), - AaCode(Sub() LabTitleInner.Text = PageName,, True), - AaOpacity(LabTitleInner, 1, 150, 30) + AaOpacity(LabTitleInner, -LabTitleInner.Opacity, 130), + AaCode(Sub() LabTitleInner.Text = PageName,, True), + AaOpacity(LabTitleInner, 1, 150, 30) }, "FrmMain Titlebar SubLayer") If PageStack.Contains(Stack) Then '返回到更上层的子页面 @@ -1282,41 +1439,37 @@ Public Class FormMain AniControlEnabled -= 1 '执行动画 AniStart({ - AaCode( - Sub() - AniControlEnabled += 1 - '把新页面添加进容器 - PanMainLeft.Child = PageLeft - PageLeft.Opacity = 0 - PanMainLeft.Background = Nothing - AniControlEnabled -= 1 - RunInUi(Sub() PanMainLeft_Resize(PanMainLeft.ActualWidth), True) - End Sub, 130), - AaCode( - Sub() - '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理 - PageLeft.Opacity = 1 - PageLeft.TriggerShowAnimation() - End Sub, 30, True) + AaCode(Sub() + AniControlEnabled += 1 + '把新页面添加进容器 + PanMainLeft.Child = PageLeft + PageLeft.Opacity = 0 + PanMainLeft.Background = Nothing + AniControlEnabled -= 1 + RunInUi(Sub() PanMainLeft_Resize(PanMainLeft.ActualWidth), True) + End Sub, 130), + AaCode(Sub() + '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理 + PageLeft.Opacity = 1 + PageLeft.TriggerShowAnimation() + End Sub, 30, True) }, "FrmMain PageChangeLeft") AniStart({ - AaCode( - Sub() - AniControlEnabled += 1 - CType(PanMainRight.Child, MyPageRight).PageOnForceExit() - '把新页面添加进容器 - PanMainRight.Child = PageRight - PageRight.Opacity = 0 - PanMainRight.Background = Nothing - AniControlEnabled -= 1 - RunInUi(Sub() BtnExtraBack.ShowRefresh(), True) - End Sub, 130), - AaCode( - Sub() - '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理 - PageRight.Opacity = 1 - PageRight.PageOnEnter() - End Sub, 30, True) + AaCode(Sub() + AniControlEnabled += 1 + CType(PanMainRight.Child, MyPageRight).PageOnForceExit() + '把新页面添加进容器 + PanMainRight.Child = PageRight + PageRight.Opacity = 0 + PanMainRight.Background = Nothing + AniControlEnabled -= 1 + RunInUi(Sub() BtnExtraBack.ShowRefresh(), True) + End Sub, 130), + AaCode(Sub() + '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理 + PageRight.Opacity = 1 + PageRight.PageOnEnter() + End Sub, 30, True) }, "FrmMain PageChangeRight") End Sub ''' @@ -1329,12 +1482,12 @@ Public Class FormMain PanTitleMain.IsHitTestVisible = True PanTitleInner.IsHitTestVisible = False AniStart({ - AaOpacity(PanTitleInner, -PanTitleInner.Opacity, 150), - AaX(PanTitleInner, -18 - PanTitleInner.Margin.Left, 150,, New AniEaseInFluent), - AaOpacity(PanTitleMain, 1 - PanTitleMain.Opacity, 150, 200), - AaX(PanTitleMain, -PanTitleMain.Margin.Left, 350, 200, New AniEaseOutBack(AniEasePower.Weak)), - AaCode(Sub() PanTitleInner.Visibility = Visibility.Collapsed,, True) - }, "FrmMain Titlebar FirstLayer") + AaOpacity(PanTitleInner, -PanTitleInner.Opacity, 150), + AaX(PanTitleInner, -18 - PanTitleInner.Margin.Left, 150,, New AniEaseInFluent), + AaOpacity(PanTitleMain, 1 - PanTitleMain.Opacity, 150, 200), + AaX(PanTitleMain, -PanTitleMain.Margin.Left, 350, 200, New AniEaseOutBack(AniEasePower.Weak)), + AaCode(Sub() PanTitleInner.Visibility = Visibility.Collapsed,, True) + }, "FrmMain Titlebar FirstLayer") PageStack.Clear() Else '主页面 → 主页面,无事发生 @@ -1353,16 +1506,16 @@ Public Class FormMain If NewWidth > 0 Then '宽度足够,显示 AniStart({ - AaWidth(RectLeftBackground, NewWidth - RectLeftBackground.Width, 400,, New AniEaseOutFluent(AniEasePower.ExtraStrong)), - AaOpacity(RectLeftShadow, 1 - RectLeftShadow.Opacity, 200), - AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 250) + AaWidth(RectLeftBackground, NewWidth - RectLeftBackground.Width, 400,, New AniEaseOutFluent(AniEasePower.ExtraStrong)), + AaOpacity(RectLeftShadow, 1 - RectLeftShadow.Opacity, 200), + AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 250) }, "FrmMain LeftChange", True) Else '宽度不足,隐藏 AniStart({ - AaWidth(RectLeftBackground, -RectLeftBackground.Width, 200,, New AniEaseOutFluent), - AaOpacity(RectLeftShadow, -RectLeftShadow.Opacity, 200), - AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 170) + AaWidth(RectLeftBackground, -RectLeftBackground.Width, 200,, New AniEaseOutFluent), + AaOpacity(RectLeftShadow, -RectLeftShadow.Opacity, 200), + AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 170) }, "FrmMain LeftChange", True) End If Else diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb index 9f9179ce..33e33fb1 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModBase.vb @@ -12,14 +12,13 @@ Public Module ModBase #Region "声明" '下列版本信息由更新器自动修改 - Public Const VersionBaseName As String = "2.9.2" '不含分支前缀的显示用版本名 - Public Const VersionStandardCode As String = "2.9.2." & VersionBranchCode '标准格式的四段式版本号 + Public Const VersionBaseName As String = "2.8.8" '不含分支前缀的显示用版本名 + Public Const VersionStandardCode As String = "2.8.8." & VersionBranchCode '标准格式的四段式版本号 Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换 - Public Const UpstreamVersion As String = "2.8.12" '上游版本 -#If RELEASE Then - Public Const VersionCode As Integer = 350 'Release +#If BETA Then + Public Const VersionCode As Integer = 340 'Release #Else - Public Const VersionCode As Integer = 350 'Snapshot + Public Const VersionCode As Integer = 339 'Snapshot #End If '自动生成的版本信息 Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName @@ -177,14 +176,6 @@ Public Module ModBase ''' Public Const IconButtonOffline As String = "M533.293176 788.841412a60.235294 60.235294 0 1 1 85.202824 85.202823l-42.616471 42.586353c-129.355294 129.385412-339.124706 129.385412-468.510117 0-129.385412-129.385412-129.385412-339.124706 0-468.510117l42.586353-42.616471a60.235294 60.235294 0 1 1 85.202823 85.202824l-42.61647 42.586352a210.823529 210.823529 0 1 0 298.164706 298.164706l42.586352-42.61647z m255.548236-255.548236l42.61647-42.586352a210.823529 210.823529 0 1 0-298.164706-298.164706l-42.586352 42.61647a60.235294 60.235294 0 1 1-85.202824-85.202823l42.616471-42.586353c129.355294-129.385412 339.124706-129.385412 468.510117 0 129.385412 129.385412 129.385412 339.124706 0 468.510117l-42.586353 42.616471a60.235294 60.235294 0 1 1-85.202823-85.202824zM192.542118 192.542118a60.235294 60.235294 0 0 1 85.202823 0l553.712941 553.712941a60.235294 60.235294 0 0 1-85.202823 85.202823L192.542118 277.744941a60.235294 60.235294 0 0 1 0-85.202823z" ''' - ''' 图标,服务端,1x - ''' - Public Const IconButtonServer As String = "M224 160a64 64 0 0 0-64 64v576a64 64 0 0 0 64 64h576a64 64 0 0 0 64-64V224a64 64 0 0 0-64-64H224z m0 384h576v256H224v-256z m192 96v64h320v-64H416z m-128 0v64h64v-64H288zM224 224h576v256H224V224z m192 96v64h320v-64H416z m-128 0v64h64v-64H288z" - ''' - ''' 图标按钮,复制 - ''' - Public Const IconButtonCopy As String = "M394.666667 106.666667h448a74.666667 74.666667 0 0 1 74.666666 74.666666v448a74.666667 74.666667 0 0 1-74.666666 74.666667H394.666667a74.666667 74.666667 0 0 1-74.666667-74.666667V181.333333a74.666667 74.666667 0 0 1 74.666667-74.666666z m0 64a10.666667 10.666667 0 0 0-10.666667 10.666666v448a10.666667 10.666667 0 0 0 10.666667 10.666667h448a10.666667 10.666667 0 0 0 10.666666-10.666667V181.333333a10.666667 10.666667 0 0 0-10.666666-10.666666H394.666667z m245.333333 597.333333a32 32 0 0 1 64 0v74.666667a74.666667 74.666667 0 0 1-74.666667 74.666666H181.333333a74.666667 74.666667 0 0 1-74.666666-74.666666V394.666667a74.666667 74.666667 0 0 1 74.666666-74.666667h74.666667a32 32 0 0 1 0 64h-74.666667a10.666667 10.666667 0 0 0-10.666666 10.666667v448a10.666667 10.666667 0 0 0 10.666666 10.666666h448a10.666667 10.666667 0 0 0 10.666667-10.666666v-74.666667z" - ''' ''' 图标,音符,1x ''' Public Const IconMusic As String = "M348.293565 716.53287V254.797913c0-41.672348 28.004174-78.358261 68.919652-90.37913L815.994435 40.826435c62.775652-18.610087 125.907478 26.579478 125.907478 89.933913v539.158261c8.013913 42.25113-8.94887 89.177043-47.014956 127.109565a232.848696 232.848696 0 0 1-170.785392 65.758609c-61.885217-2.938435-111.081739-33.435826-129.113043-80.050087-18.031304-46.614261-2.137043-102.177391 41.672348-145.853218a232.848696 232.848696 0 0 1 170.785391-65.80313c21.014261 1.024 40.514783 5.164522 57.878261 12.065391V233.338435c0-12.109913-10.551652-20.034783-20.569044-20.034783a24.620522 24.620522 0 0 0-5.787826 0.934957L439.785739 338.18713a19.545043 19.545043 0 0 0-14.825739 19.144348v438.984348H423.846957c11.53113 43.987478-5.164522 94.208-45.412174 134.322087a232.848696 232.848696 0 0 1-170.785392 65.758609c-61.885217-2.938435-111.081739-33.435826-129.113043-80.050087-18.031304-46.614261-2.137043-102.177391 41.672348-145.853218a232.848696 232.848696 0 0 1 170.785391-65.80313c20.791652 1.024 40.069565 5.075478 57.299478 11.842783z" @@ -976,7 +967,7 @@ Public Module ModBase End Using End Function ''' - ''' 弹出选取文件对话框,要求选择一个文件。 + ''' 弹出选取文件对话框并且要求选取文件。 ''' ''' 要求的格式。如:“常用图片文件(*.png;*.jpg)|*.png;*.jpg”。 ''' 弹窗的标题。 @@ -990,32 +981,12 @@ Public Module ModBase fileDialog.Title = Title fileDialog.ValidateNames = True fileDialog.ShowDialog() - Log("[UI] 选择单个文件返回:" & fileDialog.FileName) - Return fileDialog.FileName - End Using - End Function - ''' - ''' 弹出选取文件对话框,要求选择多个文件。 - ''' - ''' 要求的格式。如:“常用图片文件(*.png;*.jpg)|*.png;*.jpg”。 - ''' 弹窗的标题。 - Public Function SelectFiles(FileFilter As String, Title As String) As String() - Using fileDialog As New Forms.OpenFileDialog - fileDialog.AddExtension = True - fileDialog.AutoUpgradeEnabled = True - fileDialog.CheckFileExists = True - fileDialog.Filter = FileFilter - fileDialog.Multiselect = True - fileDialog.Title = Title - fileDialog.ValidateNames = True - fileDialog.ShowDialog() - Log("[UI] 选择多个文件返回:" & fileDialog.FileNames.Join(",")) - Return fileDialog.FileNames + SelectFile = fileDialog.FileName + Log("[UI] 选择文件返回:" & SelectFile) End Using End Function ''' - ''' 弹出选取文件夹对话框,要求选取文件夹。 - ''' 返回以 \ 结尾的完整路径,如果没有选择则返回空字符串。 + ''' 弹出选取文件夹对话框并且要求选取文件夹。如果没有选择就返回空字符串。 ''' Public Function SelectFolder(Optional Title As String = "选择文件夹") As String Dim folderDialog As New Ookii.Dialogs.Wpf.VistaFolderBrowserDialog With {.ShowNewFolderButton = True, .RootFolder = Environment.SpecialFolder.Desktop, .Description = Title, .UseDescriptionForTitle = True} @@ -1232,8 +1203,7 @@ Re: ''' 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 Jar 以 zip 方式解压。 ''' 会尝试创建,但不会清空目标文件夹。 ''' - Public Sub ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing, - Optional ProgressIncrementHandler As Action(Of Double) = Nothing) + Public Sub ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing) Directory.CreateDirectory(DestDirectory) If CompressFilePath.EndsWithF(".gz", True) Then '以 gz 方式解压 @@ -1249,9 +1219,7 @@ Re: Else '以 zip 方式解压 Using Archive = ZipFile.Open(CompressFilePath, ZipArchiveMode.Read, If(Encode, Encoding.GetEncoding("GB18030"))) - Dim TotalCount As Integer = Archive.Entries.Count For Each Entry As ZipArchiveEntry In Archive.Entries - If ProgressIncrementHandler IsNot Nothing Then ProgressIncrementHandler(1 / TotalCount) Dim DestinationPath As String = IO.Path.Combine(DestDirectory, Entry.FullName) If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then Continue For '不创建空文件夹 @@ -1321,16 +1289,13 @@ RetryDir: ''' ''' 复制文件夹,失败会抛出异常。 ''' - Public Sub CopyDirectory(FromPath As String, ToPath As String, Optional ProgressIncrementHandler As Action(Of Double) = Nothing) + Public Sub CopyDirectory(FromPath As String, ToPath As String) FromPath = FromPath.Replace("/", "\") If Not FromPath.EndsWithF("\") Then FromPath &= "\" ToPath = ToPath.Replace("/", "\") If Not ToPath.EndsWithF("\") Then ToPath &= "\" - Dim AllFiles = EnumerateFiles(FromPath).ToList - Dim FileCount As Integer = AllFiles.Count - For Each File In AllFiles + For Each File In EnumerateFiles(FromPath) CopyFile(File.FullName, File.FullName.Replace(FromPath, ToPath)) - If ProgressIncrementHandler IsNot Nothing Then ProgressIncrementHandler(1 / FileCount) Next End Sub ''' @@ -1379,8 +1344,8 @@ RetryDir: '常见错误(记得同时修改下面的) Dim CommonReason As String = Nothing - If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is BadImageFormatException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then - CommonReason = "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。" + If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then + CommonReason = "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。" ElseIf TypeOf InnerEx Is UnauthorizedAccessException Then CommonReason = "PCL 的权限不足。请尝试右键 PCL,选择以管理员身份运行。" ElseIf TypeOf InnerEx Is OutOfMemoryException Then @@ -1399,7 +1364,7 @@ RetryDir: If CommonReason Is Nothing Then Return Desc & Stack & TypeDesc Else - Dim Result As String = CommonReason & vbCrLf & DescList.First & vbCrLf & "————————————" & vbCrLf + Dim Result As String = DescList.First & vbCrLf & CommonReason & vbCrLf & "————————————" & vbCrLf DescList(0) = "详细错误信息:" Return Result & Join(DescList, vbCrLf & "→ ") & Stack & TypeDesc End If @@ -1427,8 +1392,8 @@ RetryDir: '常见错误(记得同时修改上面的) Dim CommonReason As String = Nothing - If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is BadImageFormatException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then - CommonReason = "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。" + If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then + CommonReason = "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。" ElseIf TypeOf InnerEx Is UnauthorizedAccessException Then CommonReason = "PCL 的权限不足。请尝试右键 PCL,选择以管理员身份运行。" ElseIf TypeOf InnerEx Is OutOfMemoryException Then @@ -1442,7 +1407,7 @@ RetryDir: '构造输出信息 If CommonReason IsNot Nothing Then - Return CommonReason & "详细错误:" & DescList.First + Return DescList.First & ":" & CommonReason Else DescList.Reverse() '让最深层错误在最左边 Return Join(DescList, " → ") @@ -1583,10 +1548,10 @@ RetryDir: End Function ''' - ''' 获取在子字符串第一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024。 - ''' 如果未找到子字符串则不裁切。 + ''' 获取在子字符串之前的部分。 + ''' 会裁切尽可能多的内容,但如果未找到子字符串则不裁切。 ''' - Public Function BeforeFirst(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String + Public Function Before(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String Dim Pos As Integer = If(String.IsNullOrEmpty(Text), -1, Str.IndexOfF(Text, IgnoreCase)) If Pos >= 0 Then Return Str.Substring(0, Pos) @@ -1595,23 +1560,11 @@ RetryDir: End If End Function ''' - ''' 获取在子字符串最后一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024/11。 - ''' 如果未找到子字符串则不裁切。 + ''' 获取在子字符串之后的部分。 + ''' 会裁切尽可能多的内容,但如果未找到子字符串则不裁切。 ''' - Public Function BeforeLast(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String + Public Function After(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String Dim Pos As Integer = If(String.IsNullOrEmpty(Text), -1, Str.LastIndexOfF(Text, IgnoreCase)) - If Pos >= 0 Then - Return Str.Substring(0, Pos) - Else - Return Str - End If - End Function - ''' - ''' 获取在子字符串第一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 11/08。 - ''' 如果未找到子字符串则不裁切。 - ''' - Public Function AfterFirst(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String - Dim Pos As Integer = If(String.IsNullOrEmpty(Text), -1, Str.IndexOfF(Text, IgnoreCase)) If Pos >= 0 Then Return Str.Substring(Pos + Text.Length) Else @@ -1619,20 +1572,8 @@ RetryDir: End If End Function ''' - ''' 获取在子字符串最后一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 08。 - ''' 如果未找到子字符串则不裁切。 - ''' - Public Function AfterLast(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String - Dim Pos As Integer = If(String.IsNullOrEmpty(Text), -1, Str.LastIndexOfF(Text, IgnoreCase)) - If Pos >= 0 Then - Return Str.Substring(Pos + Text.Length) - Else - Return Str - End If - End Function - ''' - ''' 获取处于两个子字符串之间的部分,裁切尽可能多的内容。 - ''' 如果未找到子字符串则不裁切。 + ''' 获取处于两个子字符串之间的部分。 + ''' 会裁切尽可能多的内容:匹配开始使用 LastIndexOf,匹配结束使用 IndexOf,但如果未找到子字符串则不裁切。 ''' Public Function Between(Str As String, After As String, Before As String, Optional IgnoreCase As Boolean = False) As String Dim StartPos As Integer = If(String.IsNullOrEmpty(After), -1, Str.LastIndexOfF(After, IgnoreCase)) @@ -1776,6 +1717,16 @@ RetryDir: Public Function RegexReplaceEach(Input As String, Replacement As MatchEvaluator, Regex As String, Optional options As RegexOptions = RegularExpressions.RegexOptions.None) As String Return RegularExpressions.Regex.Replace(Input, Regex, Replacement, options) End Function + ''' + ''' 检查传入字符串会不会引发 Issue #4505 + ''' + Public Function Ntfs83NameCheck(name As String) As Boolean + Dim regex As New Regex("(.*)~(\d*)") + Dim namePart As Byte() = Encoding.UTF8.GetBytes(regex.Match(name).Groups(1).Value) + Dim numPart As Integer = regex.Match(name).Groups(2).Value.Length + + Return namePart.Length >= 6 AndAlso numPart = 1 + End Function #End Region @@ -1867,10 +1818,10 @@ RetryDir: '进行搜索,获取相似信息 For Each Entry In Entries Entry.Similarity = SearchSimilarityWeighted(Entry.SearchSource, Query) - Entry.AbsoluteRight = - Query.Split(" ").All( '对于按空格分割的每一段 - Function(QueryPart) Entry.SearchSource.Any( '若与任意一个搜索源完全匹配,则标记为完全匹配项 - Function(Source) Source.Key.Replace(" ", "").ContainsF(QueryPart, True))) + Entry.AbsoluteRight = False + For Each Pair In Entry.SearchSource + If Pair.Key.Replace(" ", "").ContainsF(Query.Replace(" ", ""), True) Then Entry.AbsoluteRight = True + Next Next '按照相似度进行排序 Entries = Sort(Entries, @@ -1899,65 +1850,10 @@ RetryDir: #Region "系统" - ''' - ''' 线程安全的,可以直接使用 For Each 的 List。 - ''' 在使用 For Each 循环时,列表的结果可能并非最新,但不会抛出异常。 - ''' - Public Class SafeList(Of T) - Inherits SynchronizedCollection(Of T) - Implements IEnumerable, IEnumerable(Of T) - '构造函数 - Public Sub New() - MyBase.New() - End Sub - Public Sub New(Data As IEnumerable(Of T)) - MyBase.New(New Object, Data) - End Sub - Public Shared Widening Operator CType(Data As List(Of T)) As SafeList(Of T) - Return New SafeList(Of T)(Data) - End Operator - Public Shared Widening Operator CType(Data As SafeList(Of T)) As List(Of T) - Return New List(Of T)(Data) - End Operator - '基于 SyncLock 覆写 - Public Overloads Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator - SyncLock SyncRoot - Return Items.ToList.GetEnumerator() - End SyncLock - End Function - Private Overloads Function GetEnumeratorGeneral() As IEnumerator Implements IEnumerable.GetEnumerator - SyncLock SyncRoot - Return Items.ToList.GetEnumerator() - End SyncLock - End Function - End Class - - ''' - ''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。 - ''' - Public PathPure As String = GetPureASCIIDir() - Private Function GetPureASCIIDir() As String - If (Path & "PCL").IsASCII() Then - Return Path & "PCL\" - ElseIf PathAppdata.IsASCII() Then - Return PathAppdata - ElseIf PathTemp.IsASCII() Then - Return PathTemp - Else - Return OsDrive & "ProgramData\PCL\" - End If - End Function - ''' ''' 指示接取到这个异常的函数进行重试。 ''' - Public Class RestartException - Inherits Exception - End Class - ''' - ''' 指示用户手动取消了操作,或用户已知晓操作被取消的原因。 - ''' - Public Class CancelledException + Public Class RetryException Inherits Exception End Class @@ -2077,10 +1973,10 @@ NextElement: '12~60 月,“1 年 2 个月” GetTimeSpanString = Math.Floor(TotalMonthes / 12) & " 年" & If((TotalMonthes Mod 12) > 0, " " & (TotalMonthes Mod 12) & " 个月", "") ElseIf TotalMonthes >= 4 Then - '4~11 月,“5 个月” - GetTimeSpanString = TotalMonthes & " 个月" + '4~11 月,“5 月” + GetTimeSpanString = TotalMonthes & " 月" ElseIf TotalMonthes >= 1 Then - '1~4 月,“2 个月 13 天” + '1~4 月,“2 月 13 天” GetTimeSpanString = TotalMonthes & " 月" & If((Span.Days Mod 30) > 0, " " & (Span.Days Mod 30) & " 天", "") ElseIf Span.TotalDays >= 4 Then '4~30 天,“23 天” @@ -2202,7 +2098,7 @@ NextElement: ''' ''' 在新的工作线程中执行代码。 ''' - Public Function RunInNewThread(Action As Action, Optional Name As String = Nothing, Optional Priority As ThreadPriority = ThreadPriority.Normal) As Thread + Public Function RunInNewThread(Action As Action, Name As String, Optional Priority As ThreadPriority = ThreadPriority.Normal) As Thread Dim th As New Thread( Sub() Try @@ -2212,7 +2108,7 @@ NextElement: Catch ex As Exception Log(ex, Name & ":线程执行失败", LogLevel.Feedback) End Try - End Sub) With {.Name = If(Name, "Runtime New Invoke " & GetUuid() & "#"), .Priority = Priority} + End Sub) With {.Name = Name, .Priority = Priority} th.Start() Return th End Function diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb index f0698828..e824443d 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb @@ -568,7 +568,7 @@ Restart: End Class '任务栏进度条 - Public LoaderTaskbar As New SafeList(Of LoaderBase) + Public LoaderTaskbar As New SynchronizedCollection(Of LoaderBase) Public LoaderTaskbarProgress As Double = 0 '平滑后的进度 Private LoaderTaskbarProgressLast As Shell.TaskbarItemProgressState = Shell.TaskbarItemProgressState.None diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb index 3a2baed7..4af4571e 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModNet.vb @@ -707,7 +707,7 @@ RequestFinished: ''' ''' 所属的文件列表任务。 ''' - Public Tasks As New SafeList(Of LoaderDownload) + Public Tasks As New SynchronizedCollection(Of LoaderDownload) ''' ''' 所有下载源。 ''' @@ -936,7 +936,7 @@ RequestFinished: '条件检测 If NetTaskThreadCount >= NetTaskThreadLimit OrElse IsSourceFailed() OrElse - (IsNoSplit AndAlso Threads IsNot Nothing AndAlso Threads.State <> NetState.Error) Then Return Nothing + (IsNoSplit AndAlso Threads IsNot Nothing AndAlso Threads.State <> NetState.Error) Then Return Nothing If State >= NetState.Merge OrElse State = NetState.WaitForCheck Then Return Nothing SyncLock LockState If State < NetState.Connect Then State = NetState.Connect @@ -945,6 +945,7 @@ RequestFinished: Dim StartPosition As Long, StartSource As NetSource = Nothing Dim Th As Thread, ThreadInfo As NetThread SyncLock LockChain + '获取线程起点与下载源 '不分割 If IsNoSplit Then GoTo Capture @@ -980,8 +981,7 @@ Capture: Next '是否禁用多线程,以及规定碎片大小 Dim TargetUrl As String = GetSource().Url - If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("mcimirror") OrElse TargetUrl.Contains("github.com") OrElse - TargetUrl.Contains("optifine.net") OrElse TargetUrl.Contains("modrinth") Then Return Nothing + If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("gitcode.net") OrElse TargetUrl.Contains("github.com") OrElse TargetUrl.Contains("modrinth") Then Return Nothing '寻找最大碎片 'FUTURE: 下载引擎重做,计算下载源平均链接时间和线程下载速度,按最高时间节省来开启多线程 Dim FilePieceMax As NetThread = Threads @@ -1055,15 +1055,6 @@ StartThread: If ModeDebug AndAlso HttpResponse.ResponseUri.OriginalString <> Info.Source.Url Then Log($"[Download] {LocalName} {Info.Uuid}#:重定向至 {HttpResponse.ResponseUri.OriginalString}") End If - ''从响应头获取文件名 - 'If Info.IsFirstThread Then - ' Dim FileName As String = GetFileNameFromResponse(HttpResponse) - ' If ModeDebug Then Log($"[Download] {LocalName} {Info.Uuid}#:远程文件名:{If(FileName, "未提供")}") - ' If FileName IsNot Nothing AndAlso LocalName = "待定" Then - ' LocalName = FileName - ' Log($"[Download] {LocalName} {Info.Uuid}#:从响应头获取到文件名") - ' End If - 'End If '文件大小校验 ContentLength = HttpResponse.ContentLength If ContentLength = -1 Then @@ -1148,7 +1139,7 @@ NotSupportRange: If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft -= RealDataCount End SyncLock Dim DeltaTime = GetTimeTick() - Info.LastReceiveTime - If DeltaTime > 1000000 Then DeltaTime = 1 '时间刻反转导致出现极大值 + If DeltaTime > 1000000 Then DeltaTime = 0 '时间刻反转导致出现极大值 If RealDataCount > 0 Then '有数据 If Info.DownloadDone = 0 Then @@ -1189,7 +1180,7 @@ NotSupportRange: ResultStream.Write(HttpData, 0, RealDataCount) End If '检查速度是否过慢 - If DeltaTime > 1500 AndAlso DeltaTime > RealDataCount Then '数据包间隔大于 1.5s,且速度小于 1.5K/s + If DeltaTime > 1000 AndAlso DeltaTime > RealDataCount Then '数据包间隔大于 1s,且速度小于 1K/s Throw New TimeoutException("由于速度过慢断开链接,下载 " & RealDataCount & " B,消耗 " & DeltaTime & " ms。") End If Info.LastReceiveTime = GetTimeTick() @@ -1301,17 +1292,6 @@ Wrong: If ((FileSize >= 0 AndAlso DownloadDone >= FileSize) OrElse (FileSize = -1 AndAlso DownloadDone > 0)) AndAlso State < NetState.Merge Then Merge() End Try End Sub - ''' - ''' 从 HTTP 响应头中获取文件名。 - ''' 如果没有,返回 Nothing。 - ''' - Private Function GetFileNameFromResponse(response As HttpWebResponse) As String - Dim header As String = response.Headers("Content-Disposition") - If String.IsNullOrEmpty(header) Then Return Nothing - 'attachment; filename="filename.ext" - If Not header.Contains("filename=") Then Return Nothing - Return header.AfterLast("filename=").Trim(""""c, " "c).BeforeFirst(";") - End Function '下载文件的最终收束事件 ''' @@ -1476,7 +1456,8 @@ Retry: ''' ''' 需要下载的文件。 ''' - Public Files As SafeList(Of NetFile) + Public Files As List(Of NetFile) + Private ReadOnly FilesLock As New Object ''' ''' 剩余未完成的文件数。(用于减轻 FilesLock 的占用) ''' @@ -1489,7 +1470,9 @@ Retry: Public Overrides Property Progress As Double Get If State >= LoadState.Finished Then Return 1 - If Not Files.Any() Then Return 0 '必须返回 0,否则在获取列表的时候会错觉已经下载完了 + SyncLock FilesLock + If Not Files.Any() Then Return 0 '必须返回 0,否则在获取列表的时候会错觉已经下载完了 + End SyncLock Return _Progress End Get Set(value As Double) @@ -1511,14 +1494,16 @@ Retry: Log("[Download] 由于同加载器中失败次数过多引发强制失败:连续失败了 " & value & " 次", LogLevel.Debug) On Error Resume Next Dim ExList As New List(Of Exception) - For Each File In Files - For Each Source In File.Sources - If Source.Ex IsNot Nothing Then - ExList.Add(Source.Ex) - If ExList.Count > 10 Then GoTo FinishExCatch - End If + SyncLock FilesLock + For Each File In Files + For Each Source In File.Sources + If Source.Ex IsNot Nothing Then + ExList.Add(Source.Ex) + If ExList.Count > 10 Then GoTo FinishExCatch + End If + Next Next - Next + End SyncLock FinishExCatch: OnFail(ExList) End If @@ -1535,15 +1520,17 @@ FinishExCatch: '计算进度 Dim NewProgress As Double = 0 Dim TotalProgress As Double = 0 - For Each File In Files - If File.IsCopy Then - NewProgress += File.Progress * 0.2 - TotalProgress += 0.2 - Else - NewProgress += File.Progress - TotalProgress += 1 - End If - Next + SyncLock FilesLock + For Each File In Files + If File.IsCopy Then + NewProgress += File.Progress * 0.2 + TotalProgress += 0.2 + Else + NewProgress += File.Progress + TotalProgress += 1 + End If + Next + End SyncLock If TotalProgress > 0 Then NewProgress /= TotalProgress '刷新进度 If NewProgress < 1 AndAlso NewProgress > 0 Then NewProgress = 2 * (NewProgress ^ 3) - 3 * (NewProgress ^ 2) + 2 * NewProgress '2x^3-3x^2+2x,模拟开头和结尾更慢的情况 @@ -1552,25 +1539,27 @@ FinishExCatch: Public Sub New(Name As String, FileTasks As List(Of NetFile)) Me.Name = Name - Files = New SafeList(Of NetFile)(FileTasks) + Files = FileTasks End Sub Public Overrides Sub Start(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = False) - If Input IsNot Nothing Then Files = New SafeList(Of NetFile)(Input) - '去重 - Dim ResultArray As New SafeList(Of NetFile) - For i = 0 To Files.Count - 1 - For ii = i + 1 To Files.Count - 1 - If Files(i).LocalPath = Files(ii).LocalPath Then GoTo NextElement - Next - ResultArray.Add(Files(i)) + SyncLock FilesLock + If Input IsNot Nothing Then Files = Input + '去重 + Dim ResultArray As New List(Of NetFile) + For i = 0 To Files.Count - 1 + For ii = i + 1 To Files.Count - 1 + If Files(i).LocalPath = Files(ii).LocalPath Then GoTo NextElement + Next + ResultArray.Add(Files(i)) NextElement: - Next - Files = ResultArray - '设置剩余文件数 - SyncLock FileRemainLock - For Each File In Files - If File.State <> NetState.Finish Then FileRemain += 1 - Next + Next i + Files = ResultArray + '设置剩余文件数 + SyncLock FileRemainLock + For Each File In Files + If File.State <> NetState.Finish Then FileRemain += 1 + Next + End SyncLock End SyncLock State = LoadState.Loading '开始执行 @@ -1613,23 +1602,25 @@ NextElement: Next End If '最多 5 个线程,最少每个线程分配 10 个文件 - Dim FilesPerThread As Integer = Math.Max(5, Files.Count / 10 + 1) - Dim FilesInThread As New List(Of NetFile) - For Each File In Files - FilesInThread.Add(File) - If FilesInThread.Count = FilesPerThread Then + SyncLock FilesLock + Dim FilesPerThread As Integer = Math.Max(5, Files.Count / 10 + 1) + Dim FilesInThread As New List(Of NetFile) + For Each File In Files + FilesInThread.Add(File) + If FilesInThread.Count = FilesPerThread Then + Dim FilesToRun As New List(Of NetFile) + FilesToRun.AddRange(FilesInThread) + RunInNewThread(Sub() StartCopy(FilesToRun, FoldersFinal), "NetTask FileCopy " & Uuid) + FilesInThread.Clear() + End If + Next + If FilesInThread.Any Then Dim FilesToRun As New List(Of NetFile) FilesToRun.AddRange(FilesInThread) RunInNewThread(Sub() StartCopy(FilesToRun, FoldersFinal), "NetTask FileCopy " & Uuid) FilesInThread.Clear() End If - Next - If FilesInThread.Any Then - Dim FilesToRun As New List(Of NetFile) - FilesToRun.AddRange(FilesInThread) - RunInNewThread(Sub() StartCopy(FilesToRun, FoldersFinal), "NetTask FileCopy " & Uuid) - FilesInThread.Clear() - End If + End SyncLock Catch ex As Exception OnFail(New List(Of Exception) From {ex}) End Try @@ -1724,20 +1715,24 @@ Retry: Dim UsefulExs = ExList.Where(Function(e) Not e.Message.Contains("(404)")).ToList [Error] = If(UsefulExs.Any, UsefulExs(0), ExList(0)) '获取实际失败的文件 - For Each File In Files - If File.State = NetState.Error Then - [Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf & Join( - File.Sources.Select(Function(s) If(s.Ex Is Nothing, s.Url, s.Ex.Message & "(" & s.Url & ")")), vbCrLf), [Error]) - Exit For - End If - Next + SyncLock FilesLock + For Each File In Files + If File.State = NetState.Error Then + [Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf & Join( + File.Sources.Select(Function(s) If(s.Ex Is Nothing, s.Url, s.Ex.Message & "(" & s.Url & ")")), vbCrLf), [Error]) + Exit For + End If + Next + End SyncLock '在设置 Error 对象后再更改为失败,避免 WaitForExit 无法捕获错误 State = LoadState.Failed End SyncLock '中断所有文件 - For Each TaskFile In Files - If TaskFile.State < NetState.Merge Then TaskFile.State = NetState.Error - Next + SyncLock FilesLock + For Each TaskFile In Files + If TaskFile.State < NetState.Merge Then TaskFile.State = NetState.Error + Next + End SyncLock '在退出同步锁后再进行日志输出 Dim ErrOutput As New List(Of String) For Each Ex As Exception In ExList @@ -1752,9 +1747,11 @@ Retry: End SyncLock Log("[Download] " & Name & " 已取消!") '中断所有文件 - For Each TaskFile In Files - TaskFile.Abort(Me) - Next + SyncLock FilesLock + For Each TaskFile In Files + TaskFile.Abort(Me) + Next + End SyncLock End Sub End Class @@ -1776,7 +1773,8 @@ Retry: ''' ''' 当前的所有下载任务。 ''' - Public Tasks As New SafeList(Of LoaderDownload) + Public Tasks As New List(Of LoaderDownload) + Private ReadOnly LockTasks As New Object ''' ''' 已下载完成的大小。 @@ -1849,9 +1847,11 @@ Retry: End If #End Region #Region "刷新下载任务属性" - For Each Task In Tasks - Task.RefreshStat() - Next + SyncLock LockTasks + For Each Task In Tasks + Task.RefreshStat() + Next + End SyncLock #End Region Catch ex As Exception Log(ex, "刷新下载公开属性失败") @@ -1997,7 +1997,9 @@ Retry: Task.Files(i) = File '回设 Next End SyncLock - Tasks.Add(Task) + SyncLock LockTasks + Tasks.Add(Task) + End SyncLock End Sub End Class diff --git a/Plain Craft Launcher 2/Modules/Base/ModValidate.vb b/Plain Craft Launcher 2/Modules/Base/ModValidate.vb index 03940607..0321004b 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModValidate.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModValidate.vb @@ -233,8 +233,8 @@ Public Class ValidateFolderName '检查特殊字符串 Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!", True).Validate(Str) If Not InvalidStrCheck = "" Then Return InvalidStrCheck - '检查 NTFS 8.3 文件名(#4505) - If RegexCheck(Str, ".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!" + '检查 NTFS 8.3 (issue #4505) + If Ntfs83NameCheck(Str) Then Return "文件夹名不能是一个有效的 NTFS 8.3 文件名!" '检查文件夹重名 Dim Arr As New List(Of String) If PathIgnore IsNot Nothing Then @@ -288,8 +288,8 @@ Public Class ValidateFileName '检查特殊字符串 Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件名不可为 %!", True).Validate(Str) If Not InvalidStrCheck = "" Then Return InvalidStrCheck - '检查 NTFS 8.3 文件名(#4505) - If RegexCheck(Str, ".{2,}~\d") Then Return "文件名不能包含这一特殊格式!" + '检查 NTFS 8.3 (issue #4505) + If Ntfs83NameCheck(Str) Then Return "文件名不能是一个有效的 NTFS 8.3 文件名!" '检查文件重名 If ParentFolder IsNot Nothing Then Dim DirInfo As New DirectoryInfo(ParentFolder) @@ -355,9 +355,9 @@ Fin: '检查特殊字符串 Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(SubStr) If Not InvalidStrCheck = "" Then Return InvalidStrCheck - '检查 NTFS 8.3 文件名(#4505) - If RegexCheck(Str, ".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!" + '检查 NTFS 8.3 (issue #4505) + If Ntfs83NameCheck(Str) Then Return "文件夹名不能是一个有效的 NTFS 8.3 文件名!" Next Return "" End Function -End Class +End Class \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb b/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb index c5303d60..e60d27a8 100644 --- a/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb +++ b/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb @@ -7,7 +7,7 @@ Public Class MyBitmap ''' ''' 位图缓存。 ''' - Public Shared BitmapCache As New Concurrent.ConcurrentDictionary(Of String, MyBitmap) + Public Shared BitmapCache As New Dictionary(Of String, MyBitmap) ''' ''' 存储的图片 @@ -17,19 +17,15 @@ Public Class MyBitmap '自动类型转换 '支持的类:Image,ImageSource,Bitmap,ImageBrush,BitmapSource Public Shared Widening Operator CType(Image As System.Drawing.Image) As MyBitmap - If Image Is Nothing Then Return Nothing Return New MyBitmap(Image) End Operator Public Shared Widening Operator CType(Image As MyBitmap) As System.Drawing.Image - If Image Is Nothing Then Return Nothing Return Image.Pic End Operator Public Shared Widening Operator CType(Image As ImageSource) As MyBitmap - If Image Is Nothing Then Return Nothing Return New MyBitmap(Image) End Operator Public Shared Widening Operator CType(Image As MyBitmap) As ImageSource - If Image Is Nothing Then Return Nothing Dim Bitmap = Image.Pic Dim rect = New System.Drawing.Rectangle(0, 0, Bitmap.Width, Bitmap.Height) Dim bitmapData = Bitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb) @@ -41,19 +37,15 @@ Public Class MyBitmap End Try End Operator Public Shared Widening Operator CType(Image As System.Drawing.Bitmap) As MyBitmap - If Image Is Nothing Then Return Nothing Return New MyBitmap(Image) End Operator Public Shared Widening Operator CType(Image As MyBitmap) As System.Drawing.Bitmap - If Image Is Nothing Then Return Nothing Return Image.Pic End Operator Public Shared Widening Operator CType(Image As ImageBrush) As MyBitmap - If Image Is Nothing Then Return Nothing Return New MyBitmap(Image) End Operator Public Shared Widening Operator CType(Image As MyBitmap) As ImageBrush - If Image Is Nothing Then Return Nothing Return New ImageBrush(New MyBitmap(Image.Pic)) End Operator @@ -69,7 +61,7 @@ Public Class MyBitmap Pic = BitmapCache(FilePathOrResourceName).Pic Else Pic = New MyBitmap(CType((New ImageSourceConverter).ConvertFromString(FilePathOrResourceName), ImageSource)) - BitmapCache.TryAdd(FilePathOrResourceName, Pic) + BitmapCache.Add(FilePathOrResourceName, Pic) End If Else '使用这种自己接管 FileStream 的方法加载才能解除文件占用 @@ -80,9 +72,11 @@ Public Class MyBitmap InputStream.Seek(0, SeekOrigin.Begin) If Header(0) = 82 AndAlso Header(1) = 73 Then '读取 WebP + If Is32BitSystem Then Throw New Exception("不支持在 32 位系统下加载 WebP 图片。") Dim FileBytes(InputStream.Length - 1) As Byte InputStream.Read(FileBytes, 0, FileBytes.Length) - Pic = WebPDecoder.DecodeFromBytes(FileBytes) '将代码隔离在另外一个类中,这样只要不走进这个分支就不会加载 Imazen.WebP.dll + Dim Decoder As New Imazen.WebP.SimpleDecoder() + Pic = Decoder.DecodeFromBytes(FileBytes, FileBytes.Length) Else Pic = New System.Drawing.Bitmap(InputStream) End If @@ -92,9 +86,10 @@ Public Class MyBitmap Pic = My.Application.TryFindResource(FilePathOrResourceName) If Pic Is Nothing Then Pic = New System.Drawing.Bitmap(1, 1) - Throw New Exception($"加载 MyBitmap 失败({FilePathOrResourceName})", ex) + Log(ex, $"加载位图失败({FilePathOrResourceName})") + Throw Else - Log(ex, $"指定类型有误的 MyBitmap 加载({FilePathOrResourceName})", LogLevel.Developer) + Log(ex, $"指定类型有误的位图加载({FilePathOrResourceName})", LogLevel.Developer) Exit Try End If End Try @@ -121,13 +116,6 @@ Public Class MyBitmap Pic = New System.Drawing.Bitmap(MS) End Using End Sub - Private Class WebPDecoder '将代码隔离在另外一个类中,这样只要不调用这个方法就不会加载 Imazen.WebP.dll - Public Shared Function DecodeFromBytes(Bytes As Byte()) As System.Drawing.Bitmap - If Is32BitSystem Then Throw New Exception("不支持在 32 位系统下加载 WebP 图片。") - Dim Decoder As New Imazen.WebP.SimpleDecoder() - Return Decoder.DecodeFromBytes(Bytes, Bytes.Length) - End Function - End Class ''' ''' 获取裁切的图片,这个方法不会导致原对象改变且会返回一个新的对象。 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb index 66a03147..cbfcdf16 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb @@ -275,7 +275,7 @@ Next CurseForgeFileIds = Files.Select(Function(f) f.Key).Distinct.ToList GameVersions = Files.SelectMany(Function(f) f.Value).Where(Function(v) v.StartsWithF("1.")). - Select(Function(v) CInt(Val(v.Split(".")(1).BeforeFirst("-")))).Where(Function(v) v > 0). + Select(Function(v) CInt(Val(v.Split(".")(1).Before("-")))).Where(Function(v) v > 0). Distinct.OrderByDescending(Function(v) v).ToList ModLoaders = ModLoaders.Distinct.OrderBy(Of Integer)(Function(t) t).ToList 'Type @@ -376,7 +376,7 @@ '搜索结果的键为 versions,获取特定工程的键为 game_versions GameVersions = If(CType(If(Data("game_versions"), Data("versions")), JArray), New JArray). Select(Function(v) v.ToString).Where(Function(v) v.StartsWithF("1.")). - Select(Of Integer)(Function(v) Val(v.Split(".")(1).BeforeFirst("-"))).Where(Function(v) v > 0). + Select(Of Integer)(Function(v) Val(v.Split(".")(1).Before("-"))).Where(Function(v) v > 0). Distinct.OrderByDescending(Function(v) v).ToList 'Type Select Case Data("project_type").ToString @@ -542,14 +542,14 @@ If StartVersion = EndVersion Then SpaVersions.Add("1." & StartVersion) ElseIf McVersionHighest > -1 AndAlso StartVersion >= McVersionHighest Then - If EndVersion < 10 Then + If EndVersion <= 10 Then SpaVersions.Clear() SpaVersions.Add("全版本") Exit For Else SpaVersions.Add("1." & EndVersion & "+") End If - ElseIf EndVersion < 10 Then + ElseIf EndVersion <= 10 Then SpaVersions.Add("1." & StartVersion & "-") Exit For ElseIf StartVersion - EndVersion = 1 Then @@ -562,31 +562,25 @@ End If '获取 Mod 加载器描述 Dim ModLoaderDescriptionFull As String, ModLoaderDescriptionPart As String - Dim ModLoadersForDesc As New List(Of CompModLoaderType)(ModLoaders) - If Setup.Get("ToolDownloadIgnoreQuilt") Then ModLoadersForDesc.Remove(CompModLoaderType.Quilt) - Select Case ModLoadersForDesc.Count + Select Case ModLoaders.Count Case 0 - If ModLoaders.Count = 1 Then - ModLoaderDescriptionFull = "仅 " & ModLoaders.Single.ToString - ModLoaderDescriptionPart = ModLoaders.Single.ToString - Else - ModLoaderDescriptionFull = "未知" - ModLoaderDescriptionPart = "" - End If + ModLoaderDescriptionFull = "未知" + ModLoaderDescriptionPart = "" Case 1 - ModLoaderDescriptionFull = "仅 " & ModLoadersForDesc.Single.ToString - ModLoaderDescriptionPart = ModLoadersForDesc.Single.ToString - Case Else - If ModLoaders.Contains(CompModLoaderType.Forge) AndAlso - (GameVersions.Max < 14 OrElse ModLoaders.Contains(CompModLoaderType.Fabric)) AndAlso - (GameVersions.Max < 20 OrElse ModLoaders.Contains(CompModLoaderType.NeoForge)) AndAlso - (GameVersions.Max < 14 OrElse ModLoaders.Contains(CompModLoaderType.Quilt) OrElse Setup.Get("ToolDownloadIgnoreQuilt")) Then + ModLoaderDescriptionFull = "仅 " & ModLoaders.Single.ToString + ModLoaderDescriptionPart = ModLoaders.Single.ToString + Case 2, 3 + If Setup.Get("ToolDownloadIgnoreQuilt") AndAlso + ModLoaders.Contains(CompModLoaderType.Forge) AndAlso ModLoaders.Contains(CompModLoaderType.Fabric) Then ModLoaderDescriptionFull = "任意" ModLoaderDescriptionPart = "" Else - ModLoaderDescriptionFull = ModLoadersForDesc.Join(" / ") - ModLoaderDescriptionPart = ModLoadersForDesc.Join(" / ") + ModLoaderDescriptionFull = ModLoaders.Join(" / ") + ModLoaderDescriptionPart = ModLoaders.Join(" / ") End If + Case Else + ModLoaderDescriptionFull = "任意" + ModLoaderDescriptionPart = "" End Select '实例化 UI Dim NewItem As New MyCompItem With {.Tag = Me, .Logo = GetControlLogo()} @@ -682,9 +676,9 @@ '有中文翻译 '尝试将文本分为三段:Title (EnglishName) - Suffix '检查时注意 Carpet:它没有中文译名,但有 Suffix - Title = TranslatedName.BeforeFirst(" (").BeforeFirst(" - ") + Title = TranslatedName.Before(" (").Before(" - ") Dim Suffix As String = "" - If TranslatedName.AfterLast(")").Contains(" - ") Then Suffix = TranslatedName.AfterLast(")").AfterLast(" - ") + If TranslatedName.After(")").Contains(" - ") Then Suffix = TranslatedName.After(")").After(" - ") Dim EnglishName As String = TranslatedName If Suffix <> "" Then EnglishName = EnglishName.Replace(" - " & Suffix, "") EnglishName = EnglishName.Replace(Title, "").Trim("("c, ")"c, " "c) @@ -859,7 +853,7 @@ NoSubtitle: Case CompType.Shader Address += "&classId=6552" End Select - Address += "&categoryId=" & If(Tag = "", "0", Tag.BeforeFirst("/")) + Address += "&categoryId=" & If(Tag = "", "0", Tag.Before("/")) If ModLoader <> CompModLoaderType.Any Then Address += "&modLoaderType=" & CType(ModLoader, Integer) If Not String.IsNullOrEmpty(GameVersion) Then Address += "&gameVersion=" & GameVersion If Not String.IsNullOrEmpty(SearchText) Then Address += "&searchFilter=" & Net.WebUtility.UrlEncode(SearchText) @@ -880,7 +874,7 @@ NoSubtitle: 'facets=[["categories:'game-mechanics'"],["categories:'forge'"],["versions:1.19.3"],["project_type:mod"]] Dim Facets As New List(Of String) Facets.Add($"[""project_type:{GetStringFromEnum(Type).ToLower}""]") - If Not String.IsNullOrEmpty(Tag) Then Facets.Add($"[""categories:'{Tag.AfterLast("/")}'""]") + If Not String.IsNullOrEmpty(Tag) Then Facets.Add($"[""categories:'{Tag.After("/")}'""]") If ModLoader <> CompModLoaderType.Any Then Facets.Add($"[""categories:'{GetStringFromEnum(ModLoader).ToLower}'""]") If Not String.IsNullOrEmpty(GameVersion) Then Facets.Add($"[""versions:'{GameVersion}'""]") Address += "&facets=[" & String.Join(",", Facets) & "]" @@ -988,7 +982,7 @@ NoSubtitle: If Not SearchResults(i).AbsoluteRight AndAlso i >= Math.Min(2, SearchResults.Count - 1) Then Exit For '把 3 个结果拼合以提高准确度 If SearchResults(i).Item.CurseForgeSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.CurseForgeSlug.Replace("-", " ").Replace("/", " ") & " " If SearchResults(i).Item.ModrinthSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.ModrinthSlug.Replace("-", " ").Replace("/", " ") & " " - SearchResult += SearchResults(i).Item.ChineseName.AfterLast(" (").TrimEnd(") ").BeforeFirst(" - "). + SearchResult += SearchResults(i).Item.ChineseName.After(" (").TrimEnd(") ").Before(" - "). Replace(":", "").Replace("(", "").Replace(")", "").ToLower.Replace("/", " ") & " " Next Log("[Comp] 中文搜索原始关键词:" & SearchResult, LogLevel.Developer) @@ -1257,7 +1251,7 @@ Retry: ''' Public ReadOnly ModLoaders As List(Of CompModLoaderType) ''' - ''' 支持的游戏版本列表。类型包括:"1.18.5","1.18","1.18 预览版","21w15a","未知版本"。 + ''' 支持的游戏版本列表。类型包括:"1.18.5","1.18","1.18 快照","21w15a","未知版本"。 ''' Public ReadOnly GameVersions As List(Of String) ''' @@ -1373,7 +1367,7 @@ Retry: End If 'GameVersions Dim RawVersions As List(Of String) = Data("gameVersions").Select(Function(t) t.ToString.Trim.ToLower).ToList - GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.")).Select(Function(v) v.Replace("-snapshot", " 预览版")).ToList + GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.")).Select(Function(v) v.Replace("-snapshot", " 快照")).ToList If GameVersions.Count > 1 Then GameVersions = Sort(GameVersions, AddressOf VersionSortBoolean).ToList If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)} @@ -1414,7 +1408,7 @@ Retry: 'GameVersions Dim RawVersions As List(Of String) = Data("game_versions").Select(Function(t) t.ToString.Trim.ToLower).ToList GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.") OrElse v.StartsWithF("b1.")). - Select(Function(v) If(v.Contains("-"), v.BeforeFirst("-") & " 预览版", If(v.StartsWithF("b1."), "远古版本", v))).ToList + Select(Function(v) If(v.Contains("-"), v.Before("-") & " 快照", If(v.StartsWithF("b1."), "远古版本", v))).ToList If GameVersions.Count > 1 Then GameVersions = Sort(GameVersions, AddressOf VersionSortBoolean).ToList If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)} @@ -1463,26 +1457,28 @@ Retry: Optional BadDisplayName As Boolean = False) As MyListItem '获取描述信息 - Dim Title As String = If(BadDisplayName, FileName, DisplayName) - Dim Info As New List(Of String) - If Title <> FileName.BeforeLast(".") Then Info.Add(FileName.BeforeLast(".")) + Dim Info As String = "" Select Case Type Case CompType.Mod - If Dependencies.Any Then Info.Add(Dependencies.Count & " 个前置 Mod") + Info += If(ModLoaders.Any, + "适用于 " & Join(ModLoaders.Select(Function(m) GetStringFromEnum(m)).ToList, "/") & ",", "") + Info += If(ModeDebug AndAlso Dependencies.Any, Dependencies.Count & " 个前置 Mod,", "") Case CompType.ModPack - If GameVersions.All(Function(v) v.Contains("w")) Then Info.Add($"游戏版本 {Join(GameVersions, "、")}") + If GameVersions.All(Function(v) v.Contains("w")) Then + Info += $"游戏版本 {Join(GameVersions, "、")}," + End If End Select If DownloadCount > 0 Then 'CurseForge 的下载次数经常错误地返回 0 - Info.Add("下载 " & If(DownloadCount > 100000, Math.Round(DownloadCount / 10000) & " 万次", DownloadCount & " 次")) + Info += If(DownloadCount > 100000, Math.Round(DownloadCount / 10000) & " 万次下载,", DownloadCount & " 次下载,") End If - Info.Add("更新于 " & GetTimeSpanString(ReleaseDate - Date.Now, False)) - If Status <> CompFileStatus.Release Then Info.Add(StatusDescription) + Info += GetTimeSpanString(ReleaseDate - Date.Now, False) & "更新" + Info += If(Status = CompFileStatus.Release, "", "," & StatusDescription) '建立控件 Dim NewItem As New MyListItem With { - .Title = Title, + .Title = If(BadDisplayName, FileName, DisplayName), .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Me, - .Info = Info.Join(",") + .Info = Info } Select Case Status Case CompFileStatus.Release @@ -1521,12 +1517,14 @@ Retry: ''' ''' 已知文件信息的缓存。 ''' - Public CompFilesCache As New Dictionary(Of String, List(Of CompFile)) + Private CompFilesCache As New Dictionary(Of String, List(Of CompFile)) ''' ''' 获取某个工程下的全部文件列表。 ''' 必须在工作线程执行,失败会抛出异常。 ''' Public Function CompFilesGet(ProjectId As String, FromCurseForge As Boolean) As List(Of CompFile) + '使用缓存 + If CompFilesCache.ContainsKey(ProjectId) Then Return CompFilesCache(ProjectId) '获取工程对象 Dim TargetProject As CompProject If CompProjectCache.ContainsKey(ProjectId) Then '存在缓存 @@ -1537,26 +1535,25 @@ Retry: TargetProject = New CompProject(DlModRequest("https://api.modrinth.com/v2/project/" & ProjectId, IsJson:=True)) End If '获取工程对象的文件列表 - If Not CompFilesCache.ContainsKey(ProjectId) Then '有缓存也不能直接返回,这时候前置 Mod 可能没获取(#5173) - Log("[Comp] 开始获取文件列表:" & ProjectId) - Dim ResultJsonArray As JArray - If FromCurseForge Then - 'CurseForge - If TargetProject.Type = CompType.Mod Then 'Mod 使用每个版本最新的文件 - ResultJsonArray = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(TargetProject.CurseForgeFileIds, ",") & "]}", "application/json"))("data") - Else '否则使用全部文件 - ResultJsonArray = DlModRequest($"https://api.curseforge.com/v1/mods/{ProjectId}/files?pageSize=999", IsJson:=True)("data") - End If - Else - 'Modrinth - ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version", IsJson:=True) + Log("[Comp] 开始获取文件列表:" & ProjectId) + Dim ResultJsonArray As JArray + If FromCurseForge Then + 'CurseForge + If TargetProject.Type = CompType.Mod Then 'Mod 使用每个版本最新的文件 + ResultJsonArray = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(TargetProject.CurseForgeFileIds, ",") & "]}", "application/json"))("data") + Else '否则使用全部文件 + ResultJsonArray = DlModRequest($"https://api.curseforge.com/v1/mods/{ProjectId}/files?pageSize=999", IsJson:=True)("data") End If - CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)). - Where(Function(a) a.Available).ToList.Distinct(Function(a, b) a.Id = b.Id) 'CurseForge 可能会重复返回相同项(#1330) + Else + 'Modrinth + ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version", IsJson:=True) End If + CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)). + Where(Function(a) a.Available).ToList.Distinct(Function(a, b) a.Id = b.Id) 'CurseForge 可能会重复返回相同项(#1330) '获取前置 Mod 列表 If TargetProject.Type <> CompType.Mod Then Return CompFilesCache(ProjectId) - Dim Deps As List(Of String) = CompFilesCache(ProjectId).SelectMany(Function(f) f.RawDependencies).Distinct().ToList + Dim Deps As List(Of String) = CompFilesCache(ProjectId). + SelectMany(Function(f) f.RawDependencies).Distinct().ToList Dim UndoneDeps = Deps.Where(Function(f) Not CompProjectCache.ContainsKey(f)).ToList '获取前置 Mod 工程信息 If UndoneDeps.Any Then diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb index a3b3c614..f1f070e0 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb @@ -381,7 +381,6 @@ Extracted: 没有可用的分析文件 使用32位Java导致JVM无法分配足够多的内存 Mod重复安装 - Mod互不兼容 OptiFine与Forge不兼容 Fabric报错 Fabric报错并给出解决方案 @@ -390,7 +389,7 @@ Extracted: 版本Json中存在多个Forge Mod过多导致超出ID限制 NightConfig的Bug - ShadersMod与OptiFine同时安装 + ShadersMod与Optifine同时安装 Forge安装不完整 Mod需要Java11 Mod缺少前置或MC版本错误 @@ -414,7 +413,7 @@ Extracted: '崩溃日志 If LogCrash IsNot Nothing Then Log("[Crash] 开始进行崩溃日志堆栈分析") - Keywords.AddRange(AnalyzeStackKeyword(LogCrash.BeforeFirst("System Details"))) + Keywords.AddRange(AnalyzeStackKeyword(LogCrash.Before("System Details"))) End If 'Minecraft 日志 If LogMc IsNot Nothing Then @@ -517,7 +516,7 @@ Done: If LogMc.Contains("java.lang.ClassNotFoundException: org.spongepowered.asm.launch.MixinTweaker") Then AppendReason(CrashReason.MixinBootstrap缺失) If LogMc.Contains("Couldn't set pixel format") Then AppendReason(CrashReason.显卡驱动不支持导致无法设置像素格式) If LogMc.Contains("java.lang.OutOfMemoryError") OrElse LogMc.Contains("an out of memory error") Then AppendReason(CrashReason.内存不足) - If LogMc.Contains("java.lang.RuntimeException: Shaders Mod detected. Please remove it, OptiFine has built-in support for shaders.") Then AppendReason(CrashReason.ShadersMod与OptiFine同时安装) + If LogMc.Contains("java.lang.RuntimeException: Shaders Mod detected. Please remove it, OptiFine has built-in support for shaders.") Then AppendReason(CrashReason.ShadersMod与Optifine同时安装) If LogMc.Contains("java.lang.NoSuchMethodError: sun.security.util.ManifestEntryVerifier") Then AppendReason(CrashReason.低版本Forge与高版本Java不兼容) If LogMc.Contains("1282: Invalid operation") Then AppendReason(CrashReason.光影或资源包导致OpenGL1282错误) If LogMc.Contains("signer information does not match signer information of other classes in the same package") Then AppendReason(CrashReason.文件或内容校验失败, If(RegexSeek(LogMc, "(?<=class "")[^']+(?=""'s signer information)"), "").TrimEnd(vbCrLf)) @@ -526,7 +525,6 @@ Done: If LogMc.Contains("Unsupported class file major version") Then AppendReason(CrashReason.Java版本不兼容) If LogMc.Contains("com.electronwill.nightconfig.core.io.ParsingException: Not enough data available") Then AppendReason(CrashReason.NightConfig的Bug) If LogMc.Contains("Cannot find launch target fmlclient, unable to launch") Then AppendReason(CrashReason.Forge安装不完整) - If LogMc.Contains("Invalid paths argument, contained no existing paths") AndAlso LogMc.Contains("libraries\net\minecraftforge\fmlcore") Then AppendReason(CrashReason.Forge安装不完整) If LogMc.Contains("Invalid module name: '' is not a Java identifier") Then AppendReason(CrashReason.Mod名称包含特殊字符) If LogMc.Contains("has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to") Then AppendReason(CrashReason.Mod需要Java11) If LogMc.Contains("java.lang.RuntimeException: java.lang.NoSuchMethodException: no such method: sun.misc.Unsafe.defineAnonymousClass(Class,byte[],Object[])Class/invokeVirtual") Then AppendReason(CrashReason.Mod需要Java11) @@ -542,14 +540,12 @@ Done: End If '确定的 Mod 导致崩溃 If LogMc.Contains("Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(RegexSeek(LogMc, "(?<=Caught exception from )[^\n]+?")?.TrimEnd((vbCrLf & " ").ToCharArray))) - 'Mod 重复 / 前置问题 + 'Mod 重复安装 If LogMc.Contains("DuplicateModsFoundException") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(LogMc, "(?<=\n\t[\w]+ : [A-Z]{1}:[^\n]+(/|\\))[^/\\\n]+?.jar", RegularExpressions.RegexOptions.IgnoreCase)) If LogMc.Contains("Found a duplicate mod") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(If(RegexSeek(LogMc, "Found a duplicate mod[^\n]+"), ""), "[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase)) If LogMc.Contains("Found duplicate mods") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(LogMc, "(?<=Mod ID: ')\w+?(?=' from mod files:)").Distinct.ToList) If LogMc.Contains("ModResolutionException: Duplicate") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(If(RegexSeek(LogMc, "ModResolutionException: Duplicate[^\n]+"), ""), "[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase)) - If LogMc.Contains("Incompatible mods found!") Then '#5006 - AppendReason(CrashReason.Mod互不兼容, If(RegexSeek(LogMc, "(?<=Incompatible mods found![\s\S]+: )[\s\S]+?(?=\tat )"), "")) - End If + 'Mod 缺少前置 If LogMc.Contains("Missing or unsupported mandatory dependencies:") Then AppendReason(CrashReason.Mod缺少前置或MC版本错误, RegexSearch(LogMc, "(?<=Missing or unsupported mandatory dependencies:)([\n\r]+\t(.*))+", RegularExpressions.RegexOptions.IgnoreCase). @@ -595,57 +591,40 @@ Done: ''' Private Sub AnalyzeCrit2() - 'Mixin 分析 - Dim MixinAnalyze = - Function(LogText As String) As Boolean - Dim IsMixin As Boolean = - LogText.Contains("Mixin prepare failed ") OrElse LogText.Contains("Mixin apply failed ") OrElse - LogText.Contains("MixinApplyError") OrElse LogText.Contains("MixinTransformerError") OrElse - LogText.Contains("mixin.injection.throwables.") OrElse LogText.Contains(".json] FAILED during )") - If Not IsMixin Then Return False - 'Mod 名称匹配 - Dim ModName As String = RegexSeek(LogText, "(?<=from mod )[^.\/ ]+(?=\] from)") - If ModName Is Nothing Then ModName = RegexSeek(LogText, "(?<=for mod )[^.\/ ]+(?= failed)") - If ModName IsNot Nothing Then - AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(ModName.TrimEnd((vbCrLf & " ").ToCharArray))) - Return True - End If - 'JSON 名称匹配 - For Each JsonName In RegexSearch(LogText, "(?<=^[^\t]+[ \[{(]{1})[^ \[{(]+\.[^ ]+(?=\.json)", RegularExpressions.RegexOptions.Multiline) - AppendReason(CrashReason.ModMixin失败, - TryAnalyzeModName(JsonName.Replace("mixins", "mixin").Replace(".mixin", "").Replace("mixin.", ""))) - Return True - Next - '没有明确匹配 - AppendReason(CrashReason.ModMixin失败) - Return True - End Function - '游戏日志分析 If LogMc IsNot Nothing Then - 'Mixin 崩溃 - Dim IsMixin As Boolean = MixinAnalyze(LogMc) '常规信息 If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf)) If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf)) If LogMc.Contains("A potential solution has been determined, this may resolve your problem:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined, this may resolve your problem:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf)) If LogMc.Contains("确定了一种可能的解决方法,这样做可能会解决你的问题:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=确定了一种可能的解决方法,这样做可能会解决你的问题:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf)) - If Not IsMixin AndAlso LogMc.Contains("due to errors, provided by ") Then '在 #3104 的情况下,这一句导致 OptiFabric 的 Mixin 失败错判为 Fabric Loader 加载失败 - AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) + 'Mixin 崩溃 + If LogMc.Contains("Mixin prepare failed ") OrElse LogMc.Contains("Mixin apply failed ") OrElse LogMc.Contains("MixinApplyError") OrElse + LogMc.Contains("mixin.injection.throwables.") OrElse LogMc.Contains(".json] FAILED during )") Then + Dim ModId As String = RegexSeek(LogMc, "(?<=in )[^./ ]+(?=.mixins.json.+failed injection check)") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=in mixins.)[^./ ]+(?=.json.+failed injection check)") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in )[^./ ]+(?=.mixins.json)") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in mixins.)[^./ ]+(?=.json)") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed mixins.)[^./ ]+(?=.json:)") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[)[^./ ]+(?=.mixins.json\] FAILED during )") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[mixins.)[^./ ]+(?=.json\] FAILED during )") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=from mod )[^./ ]+(?=\] from)") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=for mod )[^./ ]+(?= failed)") + '兜底名称判断 + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "[^./ \]]+(?=.mixins.json)") + If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=mixins.)[^./ \]]+(?=.json)") + AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(If(ModId, "").TrimEnd((vbCrLf & " ").ToCharArray))) + Else + '在 #3104 的情况下,这一句导致 OptiFabric 的 Mixin 失败错判为 Fabric Loader 加载失败 + If LogMc.Contains("due to errors, provided by ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) End If End If '崩溃报告分析 If LogCrash IsNot Nothing Then - 'Mixin 崩溃 - MixinAnalyze(LogCrash) - '常规信息 If LogCrash.Contains("Suspected Mod") Then - Dim SuspectsRaw As String = LogCrash.Between("Suspected Mod", "Stacktrace") - If Not SuspectsRaw.StartsWithF("s: None") Then 'Suspected Mods: None - Dim Suspects = RegexSearch(SuspectsRaw, "(?<=\n\t[^(\t]+\()[^)\n]+") - If Suspects.Any Then AppendReason(CrashReason.怀疑Mod导致游戏崩溃, TryAnalyzeModName(Suspects)) - End If + Dim Suspects = RegexSearch(LogCrash.Between("Suspected Mod", "Stacktrace"), "(?<=\n\t[^(\t]+\()[^)\n]+") + If Suspects.Any Then AppendReason(CrashReason.怀疑Mod导致游戏崩溃, TryAnalyzeModName(Suspects)) End If End If @@ -661,8 +640,6 @@ Done: If Not (LogMc.Contains("at net.") OrElse LogMc.Contains("INFO]")) AndAlso LogHs Is Nothing AndAlso LogCrash Is Nothing AndAlso LogMc.Length < 100 Then AppendReason(CrashReason.极短的程序输出, LogMc) End If - 'Mod 解析错误(常见于 Fabric 前置校验失败) - If LogMc.Contains("Mod resolution failed") Then AppendReason(CrashReason.Mod加载器报错) 'Mixin 失败可以导致大量 Mod 实例创建失败 If LogMc.Contains("Failed to create mod instance.") Then AppendReason(CrashReason.Mod初始化失败, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModID: )[^,]+"), If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModId )[^\n]+(?= for )"), "")).TrimEnd(vbCrLf))) '注意:Fabric 的 Warnings were found! 不一定是崩溃原因,它可能是单纯的警报 @@ -718,7 +695,7 @@ NextStack: If {"com", "org", "net", "asm", "fml", "mod", "jar", "sun", "lib", "map", "gui", "dev", "nio", "api", "dsi", "top", "mcp", "core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base", "oshi", "impl", "data", "pool", "task", "forge", "setup", "block", "model", "mixin", "event", "unimi", "netty", "world", - "gitlab", "common", "server", "config", "mixins", "compat", "loader", "launch", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events", + "gitlab", "common", "server", "config", "loader", "launch", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events", "preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content", "systems", "modules", "service", "fastutil", "optifine", "internal", "platform", "override", "fabricmc", "neoforge", "injection", "listeners", "scheduler", "minecraft", "transformer", "transformers", "neoforged", "universal", "multipart", "minecraftforge", "blockentity", "spongepowered", "electronwill" @@ -761,13 +738,13 @@ NextStack: Details = Details.Replace("Fabric Mods", "¨") Log("[Crash] 崩溃报告中检测到 Fabric Mod 信息格式") End If - Details = Details.AfterLast("¨") + Details = Details.After("¨") '[Forge] 获取所有包含 .jar 的行 '[Fabric] 获取所有包含 Mod 信息的行 Dim ModNameLines As New List(Of String) For Each Line In Details.Split(vbLf) - If (Line.ContainsF(".jar", True) AndAlso Line.Length - Line.Replace(".jar", "").Length = 4) OrElse '只有一个 .jar + If Line.ContainsF(".jar", True) OrElse (IsFabricDetail AndAlso Line.StartsWithF(vbTab & vbTab) AndAlso Not RegexCheck(Line, "\t\tfabric[\w-]*: Fabric")) Then ModNameLines.Add(Line) Next Log("[Crash] 崩溃报告中找到 " & ModNameLines.Count & " 个可能的 Mod 项目行") @@ -896,23 +873,19 @@ NextStack: If ExtraFiles IsNot Nothing Then OutputFiles.AddRange(ExtraFiles) For Each OutputFile In OutputFiles Dim FileName As String = GetFileNameFromPath(OutputFile) - Dim FileEncoding As Encoding = Nothing Select Case FileName Case "LatestLaunch.bat" FileName = "启动脚本.bat" Case "Log1.txt" FileName = "PCL 启动器日志.txt" - FileEncoding = Encoding.UTF8 Case "RawOutput.log" FileName = "游戏崩溃前的输出.txt" - FileEncoding = Encoding.UTF8 End Select If File.Exists(OutputFile) Then - If FileEncoding Is Nothing Then FileEncoding = GetEncoding(ReadFileBytes(OutputFile)) + Dim FileEncoding As Encoding = GetEncoding(ReadFileBytes(OutputFile)) WriteFile(TempFolder & "Report\" & FileName, SecretFilter(ReadFile(OutputFile, FileEncoding), If(FileName = "启动脚本.bat", "F", "*")), Encoding:=FileEncoding) - Log($"[Crash] 导出文件:{FileName},编码:{FileEncoding.HeaderName}") End If Next '导出报告 @@ -936,7 +909,7 @@ NextStack: If IsHandAnalyze Then Return "很抱歉,PCL 无法确定错误原因。" Else - Return $"很抱歉,你的游戏出现了一些问题……{vbCrLf}如果要寻求帮助,请把错误报告文件发给对方,而不是发送这个窗口的照片或者截图。" + Return $"很抱歉,你的游戏出现了一些问题……{vbCrLf}如果要寻求帮助,请导出错误报告并发给他人,而不是发送这个窗口的截图。" End If End If @@ -969,9 +942,9 @@ NextStack: End If Case CrashReason.Mod缺少前置或MC版本错误 If Additional.Any Then - Results.Add("由于未安装正确的前置 Mod,导致游戏退出。\n缺失的依赖项:\n - " & Join(Additional, "\n - ") & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") + Results.Add("由于未满足 Mod 的依赖项,导致游戏退出。\n未满足的依赖项:\n - " & Join(Additional, "\n - ") & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Else - Results.Add("由于未安装正确的前置 Mod,导致游戏退出。\n请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") + Results.Add("由于未满足 Mod 的依赖项,导致游戏退出。\n请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") End If Case CrashReason.堆栈分析发现关键字 If Additional.Count = 1 Then @@ -992,9 +965,7 @@ NextStack: Results.Add("以下 Mod 导致了游戏出错:\n - " & Join(Additional, "\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h") End If Case CrashReason.ModMixin失败 - If Additional.Count = 0 Then - Results.Add("部分 Mod 注入失败,导致游戏出错。\n这一般代表着部分 Mod 与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试逐步禁用 Mod,然后观察游戏是否还会崩溃,以此定位导致崩溃的 Mod。\n\e\h") - ElseIf Additional.Count = 1 Then + If Additional.Count = 1 Then Results.Add("名为 " & Additional.First & " 的 Mod 注入失败,导致游戏出错。\n这一般代表着它与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h") Else Results.Add("以下 Mod 导致了游戏出错:\n - " & Join(Additional, "\n - ") & "\n这一般代表着它们与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h") @@ -1009,7 +980,7 @@ NextStack: If Additional.Count = 1 Then Results.Add("名为 " & Additional.First & " 的 Mod 初始化失败,导致游戏无法继续加载。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h") Else - Results.Add("以下 Mod 初始化失败,导致游戏出错:\n - " & Join(Additional, "\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h") + Results.Add("以下 Mod 初始化失败,导致游戏无法继续加载:\n - " & Join(Additional, "\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h") End If Case CrashReason.特定方块导致崩溃 If Additional.Count = 1 Then @@ -1021,7 +992,7 @@ NextStack: If Additional.Count >= 2 Then Results.Add("你重复安装了多个相同的 Mod:\n - " & Join(Additional, "\n - ") & "\n\n每个 Mod 只能出现一次,请删除重复的 Mod,然后再启动游戏。") Else - Results.Add("你可能重复安装了多个相同的 Mod,导致游戏出错。\n\n每个 Mod 只能出现一次,请删除重复的 Mod,然后再启动游戏。\e\h") + Results.Add("你可能重复安装了多个相同的 Mod,导致游戏无法继续加载。\n\n每个 Mod 只能出现一次,请删除重复的 Mod,然后再启动游戏。\e\h") End If Case CrashReason.特定实体导致崩溃 If Additional.Count = 1 Then @@ -1031,12 +1002,12 @@ NextStack: End If Case CrashReason.OptiFine与Forge不兼容 Results.Add("由于 OptiFine 与当前版本的 Forge 不兼容,导致了游戏崩溃。\n\n请前往 OptiFine 官网(https://optifine.net/downloads)查看 OptiFine 所兼容的 Forge 版本,并严格按照对应版本重新安装游戏。") - Case CrashReason.ShadersMod与OptiFine同时安装 - Results.Add("无需同时安装 Optifine 和 Shaders Mod,OptiFine 已经集成了 Shaders Mod 的功能。\n在删除 Shaders Mod 后,游戏即可正常运行。") + Case CrashReason.ShadersMod与Optifine同时安装 + Results.Add("无需同时安装 Optifine 和 Shaders Mod,Optifine 已经集成了 Shaders Mod 的功能。\n在删除 Shaders Mod 后,游戏即可正常运行。") Case CrashReason.低版本Forge与高版本Java不兼容 Results.Add("由于低版本 Forge 与当前 Java 不兼容,导致了游戏崩溃。\n\n请尝试以下解决方案:\n - 更新 Forge 到 36.2.26 或更高版本\n - 换用版本低于 1.8.0.320 的 Java") Case CrashReason.版本Json中存在多个Forge - Results.Add("可能由于其他启动器修改了 Forge 版本,当前版本的文件存在异常,导致了游戏崩溃。\n请尝试重新全新安装 Forge,而非使用其他启动器修改 Forge 版本。") + Results.Add("可能由于使用其他启动器修改了 Forge 版本,当前版本的文件存在异常,导致了游戏崩溃。\n请尝试重新全新安装 Forge,而非使用其他启动器修改 Forge 版本。") Case CrashReason.玩家手动触发调试崩溃 Results.Add("* 事实上,你的游戏没有任何问题,这是你自己触发的崩溃。\n* 你难道没有更重要的事要做吗?") Case CrashReason.Mod需要Java11 @@ -1062,36 +1033,30 @@ NextStack: Case CrashReason.文件或内容校验失败 Results.Add("部分文件或内容校验失败,导致游戏出现了问题。\n\n请尝试删除游戏(包括 Mod)并重新下载,或尝试在重新下载时使用 VPN。\h") Case CrashReason.Forge安装不完整 - Results.Add("由于安装的 Forge 文件丢失,导致游戏无法正常运行。\n请重新安装一次相同版本的 Forge,然后再启动游戏。\n在打包游戏时删除 libraries 文件夹可能导致此错误。\h") + Results.Add("由于 Forge 安装不完整,导致游戏无法正常运行。\n请尝试重新安装 Forge。\h") Case CrashReason.Fabric报错 If Additional.Count = 1 Then Results.Add("Fabric 提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Else - Results.Add("Fabric 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") - End If - Case CrashReason.Mod互不兼容 - If Additional.Count = 1 Then - Results.Add("你所安装的 Mod 不兼容:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") - Else - Results.Add("你所安装的 Mod 不兼容,Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") + Results.Add("Fabric 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h") End If Case CrashReason.Mod加载器报错 If Additional.Count = 1 Then Results.Add("Mod 加载器提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Else - Results.Add("Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") + Results.Add("Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h") End If Case CrashReason.Fabric报错并给出解决方案 If Additional.Count = 1 Then Results.Add("Fabric 提供了以下解决方案:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Else - Results.Add("Fabric 可能已经提供了解决方案,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") + Results.Add("Fabric 可能已经提供了解决方案,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h") End If Case CrashReason.Forge报错 If Additional.Count = 1 Then Results.Add("Forge 提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Else - Results.Add("Forge 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") + Results.Add("Forge 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h") End If Case CrashReason.没有可用的分析文件 Results.Add("你的游戏出现了一些问题,但 PCL 未能找到相关记录文件,因此无法进行分析。\h") @@ -1107,7 +1072,7 @@ NextStack: Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, vbCrLf). Trim(vbCrLf.ToCharArray) & If(Not Results.Any(Function(r) r.EndsWithF("\h")) OrElse IsHandAnalyze, "", - vbCrLf & "如果要寻求帮助,请把错误报告文件发给对方,而不是发送这个窗口的照片或者截图。" & + vbCrLf & "如果要寻求帮助,请向他人发送错误报告文件,而不是发送这个窗口的截图。" & If(If(PageSetupSystem.IsLauncherNewest(), True), "", vbCrLf & vbCrLf & "此外,你正在使用老版本 PCL,更新 PCL 或许也能解决这个问题。" & vbCrLf & "你可以点击 设置 → 启动器 → 检查更新 来更新 PCL。")) End Function diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb index 8f9e3fab..f972ddf8 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb @@ -167,25 +167,24 @@ End Structure ''' ''' Minecraft 客户端 版本列表,主加载器。 - ''' 若要求镜像源必须包含某个版本,则将该版本 ID 作为输入(#5195)。 ''' - Public DlClientListLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Main", AddressOf DlClientListMain) - Private Sub DlClientListMain(Loader As LoaderTask(Of String, DlClientListResult)) + Public DlClientListLoader As New LoaderTask(Of Integer, DlClientListResult)("DlClientList Main", AddressOf DlClientListMain) + Private Sub DlClientListMain(Loader As LoaderTask(Of Integer, DlClientListResult)) Select Case Setup.Get("ToolDownloadVersion") Case 0 - DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From { - New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 30), - New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 30 + 60) + DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)) From { + New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListBmclapiLoader, 30), + New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListMojangLoader, 60) }, Loader.IsForceRestarting) Case 1 - DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From { - New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 5), - New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 5 + 30) + DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)) From { + New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListMojangLoader, 5), + New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListBmclapiLoader, 35) }, Loader.IsForceRestarting) Case Else - DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From { - New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 60), - New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 60 + 60) + DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)) From { + New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListMojangLoader, 60), + New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListBmclapiLoader, 60) }, Loader.IsForceRestarting) End Select End Sub @@ -194,9 +193,9 @@ ''' ''' Minecraft 客户端 版本列表,Mojang 官方源加载器。 ''' - Public DlClientListMojangLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Mojang", AddressOf DlClientListMojangMain) + Public DlClientListMojangLoader As New LoaderTask(Of Integer, DlClientListResult)("DlClientList Mojang", AddressOf DlClientListMojangMain) Private IsNewClientVersionHinted As Boolean = False - Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult)) + Private Sub DlClientListMojangMain(Loader As LoaderTask(Of Integer, DlClientListResult)) Dim Json As JObject = NetGetCodeByRequestRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json", IsJson:=True) Try Dim Versions As JArray = Json("versions") @@ -226,21 +225,14 @@ ''' ''' Minecraft 客户端 版本列表,BMCLAPI 源加载器。 ''' - Public DlClientListBmclapiLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain) - Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of String, DlClientListResult)) + Public DlClientListBmclapiLoader As New LoaderTask(Of Integer, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain) + Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of Integer, DlClientListResult)) Dim Json As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json", IsJson:=True) Try Dim Versions As JArray = Json("versions") If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")") '添加 PCL 特供项 If File.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(ReadFile(PathTemp & "Cache\download.json"))) - '检查是否有要求的版本(#5195) - If Not String.IsNullOrEmpty(Loader.Input) Then - Dim Id = Loader.Input - If Not DlClientListLoader.Output.Value("versions").Any(Function(v) v("id") = Id) Then - Throw New Exception("BMCLAPI 源未包含目标版本 " & Id) - End If - End If '返回 Loader.Output = New DlClientListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Json} Catch ex As Exception @@ -253,31 +245,26 @@ ''' Public Function DlClientListGet(Id As String) Try - '确认版本格式标准 - Id = Id.Replace("_", "-") '1.7.10_pre4 在版本列表中显示为 1.7.10-pre4 - If Id <> "1.0" AndAlso Id.EndsWithF(".0") Then Id = Left(Id, Id.Length - 2) 'OptiFine 1.8 的下载会触发此问题,显示版本为 1.8.0 - '获取 Minecraft 版本列表 + '确认 Minecraft 版本列表已完成获取 Select Case DlClientListLoader.State - Case LoadState.Finished - '从当前的结果获取目标版本… - For Each Version As JObject In DlClientListLoader.Output.Value("versions") - If Version("id") = Id Then Return Version("url").ToString - Next - '…如果没有,则重新尝试获取(在版本刚更新时可能出现这种情况,#5195) - DlClientListLoader.WaitForExit(Id, IsForceRestart:=True) Case LoadState.Loading - DlClientListLoader.WaitForExit(Id) + DlClientListLoader.WaitForExit() Case LoadState.Failed, LoadState.Aborted, LoadState.Waiting - DlClientListLoader.WaitForExit(Id, IsForceRestart:=True) + DlClientListLoader.WaitForExit(IsForceRestart:=True) End Select - '重新查找版本 + '确认版本格式标准 + Id = Id.Replace("_", "-") '1.7.10_pre4 在版本列表中显示为 1.7.10-pre4 + If Id <> "1.0" AndAlso Id.EndsWithF(".0") Then Id = Left(Id, Id.Length - 2) 'OptiFine 1.8 的下载会触发此问题,显示版本为 1.8.0 + '查找版本并开始 For Each Version As JObject In DlClientListLoader.Output.Value("versions") - If Version("id") = Id Then Return Version("url").ToString + If Version("id") = Id Then + Return Version("url").ToString + End If Next - Log($"未发现版本 {Id} 的 json 下载地址,版本列表返回为:{vbCrLf}{DlClientListLoader.Output.Value.ToString}", LogLevel.Debug) + Log("未发现版本 " & Id & " 的 json 下载地址,版本列表返回为:" & vbCrLf & DlClientListLoader.Output.Value.ToString, LogLevel.Debug) Return Nothing Catch ex As Exception - Log(ex, $"获取版本 {Id} 的 json 下载地址失败") + Log(ex, "获取版本 " & Id & " 的 json 下载地址失败") Return Nothing End Try End Function @@ -350,17 +337,17 @@ Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 30), - New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 30 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 60) }, Loader.IsForceRestarting) Case 1 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 5), - New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 5 + 30) + New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 35) }, Loader.IsForceRestarting) Case Else DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 60), - New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 60 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 60) }, Loader.IsForceRestarting) End Select End Sub @@ -456,17 +443,17 @@ Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 30), - New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 30 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 60) }, Loader.IsForceRestarting) Case 1 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 5), - New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 5 + 30) + New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 35) }, Loader.IsForceRestarting) Case Else DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 60), - New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 60 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 60) }, Loader.IsForceRestarting) End Select End Sub @@ -601,17 +588,17 @@ Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From { New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 30), - New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 30 + 60) + New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 60) }, Loader.IsForceRestarting) Case 1 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From { New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 5), - New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 5 + 30) + New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 35) }, Loader.IsForceRestarting) Case Else DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From { New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 60), - New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 60 + 60) + New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 60) }, Loader.IsForceRestarting) End Select End Sub @@ -793,7 +780,7 @@ Inherit = "1.20.1" Else '20.4.30-beta VersionName = ApiName - Version = New Version(ApiName.BeforeFirst("-")) + Version = New Version(ApiName.Before("-")) Inherit = $"1.{Version.Major}" & If(Version.Minor = 0, "", "." & Version.Minor) End If End Sub @@ -808,17 +795,17 @@ Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 30), - New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 30 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 60) }, Loader.IsForceRestarting) Case 1 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 5), - New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 5 + 30) + New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 35) }, Loader.IsForceRestarting) Case Else DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 60), - New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 60 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 60) }, Loader.IsForceRestarting) End Select End Sub @@ -933,17 +920,17 @@ Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 30), - New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 30 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 60) }, Loader.IsForceRestarting) Case 1 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 5), - New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 5 + 30) + New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 35) }, Loader.IsForceRestarting) Case Else DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 60), - New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 60 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 60) }, Loader.IsForceRestarting) End Select End Sub @@ -1032,17 +1019,17 @@ Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 30), - New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 30 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 60) }, Loader.IsForceRestarting) Case 1 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 5), - New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 5 + 30) + New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 35) }, Loader.IsForceRestarting) Case Else DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 60), - New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 60 + 60) + New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 60) }, Loader.IsForceRestarting) End Select End Sub @@ -1180,7 +1167,7 @@ Dim Urls As New List(Of KeyValuePair(Of String, Integer)) If McimUrl <> Url Then Select Case Setup.Get("ToolDownloadMod") - 'TODO: 在 MCIM 源稳定后回调 + 'UNDONE: 在 MCIM 源稳定后回调 Case 0 If ModeDebug Then Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10)) @@ -1229,7 +1216,7 @@ Dim Urls As New List(Of KeyValuePair(Of String, Integer)) If McimUrl <> Url Then Select Case Setup.Get("ToolDownloadMod") - 'TODO: 在 MCIM 源稳定后回调 + 'UNDONE: 在 MCIM 源稳定后回调 Case 0 If ModeDebug Then Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10)) @@ -1326,63 +1313,71 @@ Optional IsForceRestart As Boolean = False) Dim WaitCycle As Integer = 0 Do While True - '检查状态 - Dim BeforeLoadersAllFailed As Boolean = True + '检查加载结束 + Dim IsAllFailed As Boolean = True For Each SubLoader In LoaderList - If WaitCycle = 0 Then '判断是否可以不加载,直接使用已经加载好的结果 - If IsForceRestart Then Continue For '强制刷新,不行 + If WaitCycle = 0 Then + '如果要强制刷新,就不使用已经加载好的值 + If IsForceRestart Then Exit For + '如果输入不一样,就不使用已经加载好的值 If (SubLoader.Key.Input Is Nothing Xor MainLoader.Input Is Nothing) OrElse - (SubLoader.Key.Input IsNot Nothing AndAlso Not SubLoader.Key.Input.Equals(MainLoader.Input)) Then Continue For '父子加载器的输入不一样,也不行 + (SubLoader.Key.Input IsNot Nothing AndAlso Not SubLoader.Key.Input.Equals(MainLoader.Input)) Then Continue For End If - If SubLoader.Key.State <> LoadState.Failed Then BeforeLoadersAllFailed = False + If SubLoader.Key.State <> LoadState.Failed Then IsAllFailed = False If SubLoader.Key.State = LoadState.Finished Then - '检查加载器成功 MainLoader.Output = SubLoader.Key.Output DlSourceLoaderAbort(LoaderList) Exit Sub - ElseIf BeforeLoadersAllFailed Then - '此前的加载器全部失败,直接启动后续加载器 + ElseIf IsAllFailed Then If WaitCycle < SubLoader.Value * 100 Then WaitCycle = SubLoader.Value * 100 End If + '由于 Forge BMCLAPI 没有可用版本导致强制失败 + '在没有可用版本时,官方源会一直卡住,直接使用 BMCLAPI 判定失败即可 + If SubLoader.Key.Error IsNot Nothing AndAlso SubLoader.Key.Error.Message.Contains("没有可用版本") Then + For Each SubLoader2 In LoaderList + If WaitCycle < SubLoader2.Value * 100 Then WaitCycle = SubLoader2.Value * 100 + Next + End If Next - '第一轮时:既然不直接使用已经加载好的结果,那就启动第一个加载器 + '启动加载源 If WaitCycle = 0 Then - LoaderList.First.Key.Start(MainLoader.Input, IsForceRestart) - For Each Loader In LoaderList.Skip(1) - Loader.Key.State = LoadState.Waiting '将其他源标记为未启动,以确保可以切换下载源(#184) + '启动第一个源 + LoaderList(0).Key.Start(MainLoader.Input, IsForceRestart) + '将其他源标记为未启动,以确保可以切换下载源(#184) + For i = 1 To LoaderList.Count - 1 + LoaderList(i).Key.State = LoadState.Waiting Next End If - '检查加载器失败或超时 For i = 0 To LoaderList.Count - 1 - If WaitCycle <> LoaderList(i).Value * 100 Then Continue For - If i < LoaderList.Count - 1 AndAlso Not LoaderList.All(Function(l) l.Key.State = LoadState.Failed) Then - '若还有下一个源,则启动下一个源 - LoaderList(i + 1).Key.Start(MainLoader.Input, IsForceRestart) - Else - '若没有,则失败 - Dim ErrorInfo As Exception = Nothing - For ii = 0 To LoaderList.Count - 1 - LoaderList(ii).Key.Input = Nothing '重置输入,以免以同样的输入“重试加载”时直接失败 - If LoaderList(ii).Key.Error IsNot Nothing Then - If ErrorInfo Is Nothing OrElse LoaderList(ii).Key.Error.Message.Contains("没有可用版本") Then - ErrorInfo = LoaderList(ii).Key.Error + If WaitCycle = LoaderList(i).Value * 100 Then + If i < LoaderList.Count - 1 Then + '启动下一个源 + LoaderList(i + 1).Key.Start(MainLoader.Input, IsForceRestart) + Else + '失败 + Dim ErrorInfo As Exception = Nothing + For ii = 0 To LoaderList.Count - 1 + LoaderList(ii).Key.Input = Nothing '重置输入,以免以同样的输入“重试加载”时直接失败 + If LoaderList(ii).Key.Error IsNot Nothing Then + If ErrorInfo Is Nothing OrElse LoaderList(ii).Key.Error.Message.Contains("没有可用版本") Then + ErrorInfo = LoaderList(ii).Key.Error + End If End If - End If - Next - If ErrorInfo Is Nothing Then ErrorInfo = New TimeoutException("下载源连接超时") - DlSourceLoaderAbort(LoaderList) - Throw ErrorInfo + Next + If ErrorInfo Is Nothing Then ErrorInfo = New TimeoutException("下载源连接超时") + DlSourceLoaderAbort(LoaderList) + Throw ErrorInfo + End If + Exit For End If - Exit For Next '计时 - Thread.Sleep(10) - WaitCycle += 1 - '检查父加载器中断 If MainLoader.IsAborted Then DlSourceLoaderAbort(LoaderList) Exit Sub End If + Thread.Sleep(10) + WaitCycle += 1 Loop End Sub Private Sub DlSourceLoaderAbort(Of InputType, OutputType)(LoaderList As List(Of KeyValuePair(Of LoaderTask(Of InputType, OutputType), Integer))) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb index d11075e0..af527eff 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb @@ -489,18 +489,16 @@ NoUserJava: Public JavaSearchLoader As New LoaderTask(Of Integer, Integer)("查找 Java", AddressOf JavaSearchLoaderSub) With {.ProgressWeight = 2} Private Sub JavaSearchLoaderSub(Loader As LoaderTask(Of Integer, Integer)) If FrmSetupLaunch IsNot Nothing Then - RunInUiWait( - Sub() - FrmSetupLaunch.ComboArgumentJava.Items.Clear() - FrmSetupLaunch.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True}) - End Sub) + RunInUiWait(Sub() + FrmSetupLaunch.ComboArgumentJava.Items.Clear() + FrmSetupLaunch.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True}) + End Sub) End If If FrmVersionSetup IsNot Nothing Then - RunInUiWait( - Sub() - FrmVersionSetup.ComboArgumentJava.Items.Clear() - FrmVersionSetup.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True}) - End Sub) + RunInUiWait(Sub() + FrmVersionSetup.ComboArgumentJava.Items.Clear() + FrmVersionSetup.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True}) + End Sub) End If Try @@ -522,7 +520,6 @@ NoUserJava: Next '查找磁盘中的 Java For Each Disk As DriveInfo In DriveInfo.GetDrives() - If Disk.DriveType = DriveType.Network Then Continue For '跳过网络驱动器(#3705) JavaSearchFolder(Disk.Name, JavaPreList, False) Next '查找 APPDATA 文件夹中的 Java @@ -684,8 +681,8 @@ Wait: For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接 Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).ToLower '用于搜索的字符串 - If IsFullSearch OrElse - FolderInfo.Parent.Name.ToLower = "users" OrElse Val(SearchEntry) > 0 OrElse Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then + If IsFullSearch OrElse FolderInfo.Parent.Name.ToLower = "users" OrElse + Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then JavaSearchFolder(FolderInfo, Results, Source) End If Next diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index daaba4d7..d11d65f1 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -225,9 +225,9 @@ NextInner: Select Case Setup.Get("SystemLaunchCount") Case 10, 20, 40, 60, 80, 100, 120, 150, 200, 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000 If MyMsgBox("PCL 已经为你启动了 " & Setup.Get("SystemLaunchCount") & " 次游戏啦!" & vbCrLf & - "如果 PCL 还算好用的话,能不能考虑赞助一下 PCL……" & vbCrLf & - "如果没有大家的支持,PCL 很难在免费、无任何广告的情况下维持数年的更新(磕头)……!", - Setup.Get("SystemLaunchCount") & " 次启动!", "支持 PCL!", "但是我拒绝") = 1 Then + "如果觉得 PCL 还算好用的话,也可以考虑赞助一下作者……一点心意也行……" & vbCrLf & + "毕竟一个人开发也不容易(悲)……", + "求赞助啦……", "这就赞助!", "但是我拒绝") = 1 Then OpenWebsite("https://afdian.com/a/LTCat") End If End Select @@ -237,10 +237,10 @@ NextInner: If Not Setup.Get("HintBuy") AndAlso Setup.Get("LoginType") <> McLoginType.Ms Then If IsSystemLanguageChinese() Then Select Case Setup.Get("SystemLaunchCount") - Case 3, 8, 15, 30, 50, 70, 90, 110, 130, 180, 220, 280, 330, 380, 450, 550, 660, 750, 880, 950, 1100, 1300, 1500, 1700, 1900 + Case 2, 5, 10, 15, 20, 40, 60, 80, 100, 125, 150, 175, 200, 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000 If MyMsgBox("你已经启动了 " & Setup.Get("SystemLaunchCount") & " 次 Minecraft 啦!" & vbCrLf & - "如果觉得 Minecraft 还不错,可以购买正版支持一下,毕竟开发游戏也真的很不容易……不要一直白嫖啦。" & vbCrLf & vbCrLf & - "在登录一次正版账号后,就不会再出现这个提示了!", + "如果觉得 Minecraft 还不错,可以购买正版支持一下,毕竟开发游戏也真的很不容易……" & vbCrLf & vbCrLf & + "在你登录一次正版账号后,就不会再出现这个提示了!", "考虑一下正版?", "支持正版游戏!", "下次一定") = 1 Then OpenWebsite("https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj") End If @@ -378,19 +378,19 @@ NextInner: '根据当前登录方式优先返回 Select Case Setup.Get("LoginType") Case McLoginType.Ms - If Setup.Get("CacheMsV2Name") <> "" Then Return Setup.Get("CacheMsV2Name") + If Setup.Get("CacheMsName") <> "" Then Return Setup.Get("CacheMsName") Case McLoginType.Legacy - If Setup.Get("LoginLegacyName") <> "" Then Return Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨") + If Setup.Get("LoginLegacyName") <> "" Then Return Setup.Get("LoginLegacyName").ToString.Before("¨") Case McLoginType.Nide If Setup.Get("CacheNideName") <> "" Then Return Setup.Get("CacheNideName") Case McLoginType.Auth If Setup.Get("CacheAuthName") <> "" Then Return Setup.Get("CacheAuthName") End Select '查找所有可能的项 - If Setup.Get("CacheMsV2Name") <> "" Then Return Setup.Get("CacheMsV2Name") + If Setup.Get("CacheMsName") <> "" Then Return Setup.Get("CacheMsName") If Setup.Get("CacheNideName") <> "" Then Return Setup.Get("CacheNideName") If Setup.Get("CacheAuthName") <> "" Then Return Setup.Get("CacheAuthName") - If Setup.Get("LoginLegacyName") <> "" Then Return Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨") + If Setup.Get("LoginLegacyName") <> "" Then Return Setup.Get("LoginLegacyName").ToString.Before("¨") Return Nothing End Function ''' @@ -399,7 +399,7 @@ NextInner: Public Function McLoginAble() As String Select Case Setup.Get("LoginType") Case McLoginType.Ms - If Setup.Get("CacheMsV2OAuthRefresh") = "" Then + If Setup.Get("CacheMsOAuthRefresh") = "" Then Return FrmLoginMs.IsVaild() Else Return "" @@ -450,7 +450,7 @@ NextInner: Case McLoginType.Legacy LoginData = PageLoginLegacy.GetLoginData() Case McLoginType.Ms - If Setup.Get("CacheMsV2OAuthRefresh") = "" Then + If Setup.Get("CacheMsOAuthRefresh") = "" Then LoginData = PageLoginMs.GetLoginData() Else LoginData = PageLoginMsSkin.GetLoginData() @@ -552,11 +552,11 @@ Relogin: Dim Result = MsLoginStep6(AccessToken) Data.Progress = 0.98 '输出登录结果 - Setup.Set("CacheMsV2OAuthRefresh", OAuthRefreshToken) - Setup.Set("CacheMsV2Access", AccessToken) - Setup.Set("CacheMsV2Uuid", Result(0)) - Setup.Set("CacheMsV2Name", Result(1)) - Setup.Set("CacheMsV2ProfileJson", Result(2)) + Setup.Set("CacheMsOAuthRefresh", OAuthRefreshToken) + Setup.Set("CacheMsAccess", AccessToken) + Setup.Set("CacheMsUuid", Result(0)) + Setup.Set("CacheMsName", Result(1)) + Setup.Set("CacheMsProfileJson", Result(2)) Dim MsJson As JObject = GetJson(Setup.Get("LoginMsJson")) MsJson.Remove(Input.UserName) '如果更改了玩家名…… MsJson(Result(1)) = OAuthRefreshToken @@ -949,19 +949,7 @@ LoginFinish: ErrorMessage = GetJson(DirectCast(ex, ResponsedWebException).Response)("errorMessage") Catch End Try - If Not String.IsNullOrWhiteSpace(ErrorMessage) Then - If ErrorMessage.Contains("密码错误") OrElse ErrorMessage.ContainsF("Incorrect username or password", True) Then - '密码错误,退出登录 (#5090) - McLaunchLog("密码错误,退出登录") - Select Case Data.Input.Type - Case McLoginType.Auth - RunInUi(AddressOf PageLoginAuthSkin.ExitLogin) - Case McLoginType.Nide - RunInUi(AddressOf PageLoginNideSkin.ExitLogin) - End Select - End If - Throw New Exception("$登录失败:" & ErrorMessage) - End If + If Not String.IsNullOrWhiteSpace(ErrorMessage) Then Throw New Exception("$登录失败:" & ErrorMessage) End If '通用关键字检测 If AllMessage.Contains("403") Then @@ -1006,7 +994,7 @@ Retry: While Converter.Result Is Nothing Thread.Sleep(100) End While - If TypeOf Converter.Result Is RestartException Then + If TypeOf Converter.Result Is RetryException Then If MyMsgBox($"请在登录时选择 {vbLQ}其他登录方法{vbRQ},然后选择 {vbLQ}使用我的密码{vbRQ}。{vbCrLf}如果没有该选项,请选择 {vbLQ}设置密码{vbRQ},设置完毕后再登录。", "需要使用密码登录", "重新登录", "设置密码", "取消", Button2Action:=Sub() OpenWebsite("https://account.live.com/password/Change")) = 1 Then @@ -1421,7 +1409,8 @@ Retry: ''' 释放 Java Wrapper 并返回完整文件路径。 ''' Public Function ExtractJavaWrapper() As String - Dim WrapperPath As String = PathPure & "JavaWrapper.jar" + Dim BaseDir As String = GetPureASCIIDir() + Dim WrapperPath As String = BaseDir & "\JavaWrapper.jar" Log("[Java] 选定的 Java Wrapper 路径:" & WrapperPath) SyncLock ExtractJavaWrapperLock '避免 OptiFine 和 Forge 安装时同时释放 Java Wrapper 导致冲突 Try @@ -1435,7 +1424,7 @@ Retry: WriteFile(WrapperPath, GetResources("JavaWrapper")) Catch ex2 As Exception Log(ex2, "Java Wrapper 文件重新释放失败,将尝试更换文件名重新生成", LogLevel.Developer) - WrapperPath = PathPure & "JavaWrapper2.jar" + WrapperPath = BaseDir & "\JavaWrapper2.jar" Try WriteFile(WrapperPath, GetResources("JavaWrapper")) Catch ex3 As Exception @@ -1451,6 +1440,22 @@ Retry: End Function Private ExtractJavaWrapperLock As New Object + ''' + ''' 获取一个可用于临时存放文件的,不含任何特殊字符的文件夹路径。 + ''' 返回值不以 \ 结尾。 + ''' + Public Function GetPureASCIIDir() As String + If (Path & "PCL").IsASCII() Then + Return Path & "PCL" + ElseIf PathAppdata.IsASCII() Then + Return PathAppdata.TrimEnd("\") + ElseIf PathTemp.IsASCII() Then + Return PathTemp.TrimEnd("\") + Else + Return OsDrive & "ProgramData\PCL" + End If + End Function + '主方法,合并 Jvm、Game、Replace 三部分的参数数据 Private Sub McLaunchArgumentMain(Loader As LoaderTask(Of String, List(Of McLibToken))) McLaunchLog("开始获取 Minecraft 启动参数") @@ -1550,7 +1555,7 @@ Retry: Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent)) Try Dim Response As String = NetGetCodeByRequestRetry(Server, Encoding.UTF8) - DataList.Insert(0, "-javaagent:""" & PathPure & "authlib-injector.jar""=" & Server & + DataList.Insert(0, "-javaagent:""" & PathAppdata & "authlib-injector.jar""=" & Server & " -Dauthlibinjector.side=client" & " -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response))) Catch ex As Exception @@ -1560,7 +1565,7 @@ Retry: '添加 Java Wrapper 作为主 Jar If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED") - DataList.Add("-Doolloo.jlw.tmpdir=""" & PathPure.TrimEnd("\") & """") + DataList.Add("-Doolloo.jlw.tmpdir=""" & GetPureASCIIDir() & """") DataList.Add("-jar """ & ExtractJavaWrapper() & """") '添加 MainClass @@ -1617,7 +1622,7 @@ NextVersion: Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent)) Try Dim Response As String = NetGetCodeByRequestRetry(Server, Encoding.UTF8) - DataList.Insert(0, "-javaagent:""" & PathPure & "authlib-injector.jar""=" & Server & + DataList.Insert(0, "-javaagent:""" & PathAppdata & "authlib-injector.jar""=" & Server & " -Dauthlibinjector.side=client" & " -Dauthlibinjector.yggdrasil.prefetched=" & Convert.ToBase64String(Encoding.UTF8.GetBytes(Response))) Catch ex As Exception @@ -1627,7 +1632,7 @@ NextVersion: '添加 Java Wrapper 作为主 Jar If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED") - DataList.Add("-Doolloo.jlw.tmpdir=""" & PathPure.TrimEnd("\") & """") + DataList.Add("-Doolloo.jlw.tmpdir=""" & GetPureASCIIDir() & """") DataList.Add("-jar """ & ExtractJavaWrapper() & """") '将 "-XXX" 与后面 "XXX" 合并到一起 @@ -1802,11 +1807,8 @@ NextVersion: GameSize = New Size(875 - 2, 540 - 2) End Select GameSize.Height -= 29.5 * DPI / 96 '标题栏高度 - If McVersionCurrent.Version.McCodeMain <= 12 AndAlso - McLaunchJavaSelected.VersionCode <= 8 AndAlso McLaunchJavaSelected.Version.Revision >= 200 AndAlso McLaunchJavaSelected.Version.Revision <= 321 AndAlso - Not McVersionCurrent.Version.HasOptiFine AndAlso Not McVersionCurrent.Version.HasForge Then - '修复 #3463:1.12.2-,JRE 8u200~321 下窗口大小为设置大小的 DPI% 倍 - McLaunchLog($"已应用窗口大小过大修复({McLaunchJavaSelected.Version.Revision})") + If McVersionCurrent.Version.McCodeMain <= 12 AndAlso McLaunchJavaSelected.VersionCode <= 8 AndAlso + Not McVersionCurrent.Version.HasOptiFine AndAlso Not McVersionCurrent.Version.HasForge Then '修复 #3463:1.12.2-,JRE 8 下窗口大小为设置大小的 DPI% 倍 GameSize.Width /= DPI / 96 GameSize.Height /= DPI / 96 End If diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb index 3b43e9b7..c84ed662 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb @@ -85,7 +85,7 @@ Public Module ModMinecraft Next If Not Renamed Then CacheMcFolderList.Add(New McFolder With {.Name = Name, .Path = Path, .Type = McFolderType.Custom}) Else - Hint("无法访问 Minecraft 文件夹:" & Path, HintType.Critical) + Hint("无效的 Minecraft 文件夹:" & Path, HintType.Critical) End If Next @@ -1284,8 +1284,9 @@ OnLoaded: Dim VersionList As New List(Of McVersion) #Region "循环加载每个版本的信息" - For Each Folder As DirectoryInfo In New DirectoryInfo(Path & "versions").GetDirectories - If Not Folder.Exists OrElse Not Folder.EnumerateFiles.Any Then + Dim Dirs As DirectoryInfo() = New DirectoryInfo(Path & "versions").GetDirectories + For Each Folder As DirectoryInfo In Dirs + If Not Folder.EnumerateFiles.Any Then Log("[Minecraft] 跳过空文件夹:" & Folder.FullName) Continue For End If @@ -1319,11 +1320,8 @@ OnLoaded: '单独列出收藏的版本 Dim StaredVersions As New List(Of McVersion) - For Each Version As McVersion In VersionList.ToList - If Version.IsStar AndAlso Not Version.DisplayType = McVersionCardType.Hidden Then - StaredVersions.Add(Version) - VersionList.Remove(Version) - End If + For Each Version As McVersion In VersionList + If Version.IsStar AndAlso Not Version.DisplayType = McVersionCardType.Hidden Then StaredVersions.Add(Version) Next If StaredVersions.Any Then VersionListOriginal.Add(McVersionCardType.Star, StaredVersions) @@ -1560,7 +1558,7 @@ OnLoaded: ''' 要求玩家选择一个皮肤文件,并进行相关校验。 ''' Public Function McSkinSelect() As McSkinInfo - Dim FileName As String = SelectFile("皮肤文件(*.png;*.jpg;*.webp)|*.png;*.jpg;*.webp", "选择皮肤文件") + Dim FileName As String = SelectFile("皮肤文件(*.png)|*.png", "选择皮肤文件") '验证有效性 If FileName = "" Then Return New McSkinInfo With {.IsVaild = False} @@ -1967,7 +1965,7 @@ OnLoaded: ''' ''' 获取版本缺失的支持库文件所对应的 NetTaskFile。 ''' - Public Function McLibFix(Version As McVersion) As List(Of NetFile) + Public Function McLibFix(Version As McVersion, Optional CoreJarOnly As Boolean = False) As List(Of NetFile) If Not Version.IsLoaded Then Version.Load() '确保例如 JumpLoader 等项被合并入 Json Dim Result As New List(Of NetFile) @@ -1980,6 +1978,7 @@ OnLoaded: Catch ex As Exception Log(ex, "版本缺失主 Jar 文件所必须的信息", LogLevel.Developer) End Try + If CoreJarOnly Then Return Result 'Library 文件 Result.AddRange(McLibFixFromLibToken(McLibListGet(Version, False), JumpLoaderFolder:=Version.PathIndie & ".jumploader\")) @@ -1988,15 +1987,15 @@ OnLoaded: If Setup.Get("VersionServerLogin", Version:=Version) = 3 Then Dim TargetFile = PathAppdata & "nide8auth.jar" Dim DownloadInfo As JObject = Nothing - '获取下载信息 - Try - Log("[Minecraft] 开始获取统一通行证下载信息") - '测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/ - DownloadInfo = GetJson(NetGetCodeByDownload({ + '获取下载信息 + Try + Log("[Minecraft] 开始获取统一通行证下载信息") + '测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/ + DownloadInfo = GetJson(NetGetCodeByDownload({ "https://auth.mc-user.com:233/" & Setup.Get("VersionServerNide", Version:=Version)}, IsJson:=True)) - Catch ex As Exception - Log(ex, "获取统一通行证下载信息失败") - End Try + Catch ex As Exception + Log(ex, "获取统一通行证下载信息失败") + End Try '校验文件 If DownloadInfo IsNot Nothing Then Dim Checker As New FileChecker(Hash:=DownloadInfo("jarHash").ToString) @@ -2009,8 +2008,9 @@ OnLoaded: End If 'Authlib-Injector 文件 - If Setup.Get("VersionServerLogin", Version:=Version) = 4 Then - Dim TargetFile = PathPure & "\authlib-injector.jar" + If Setup.Get("VersionServerLogin", Version:=Version) = 4 OrElse + (PageLinkHiper.HiperState = LoadState.Finished AndAlso Setup.Get("LoginType") = McLoginType.Legacy) Then 'HiPer 登录转接 + Dim TargetFile = PathAppdata & "authlib-injector.jar" Dim DownloadInfo As JObject = Nothing '获取下载信息 Try @@ -2031,9 +2031,9 @@ OnLoaded: Replace("bmclapi2.bangbang93.com/mirrors/authlib-injector", "authlib-injector.yushi.moe") Log("[Minecraft] Authlib-Injector 需要更新:" & DownloadAddress, LogLevel.Developer) Result.Add(New NetFile({ - DownloadAddress, - DownloadAddress.Replace("authlib-injector.yushi.moe", "bmclapi2.bangbang93.com/mirrors/authlib-injector") - }, TargetFile, New FileChecker(Hash:=DownloadInfo("checksums")("sha256").ToString))) + DownloadAddress, + DownloadAddress.Replace("authlib-injector.yushi.moe", "bmclapi2.bangbang93.com/mirrors/authlib-injector") + }, TargetFile, New FileChecker(Hash:=DownloadInfo("checksums")("sha256").ToString))) End If End If End If @@ -2338,8 +2338,8 @@ OnLoaded: End If Left = Left.ToLowerInvariant Right = Right.ToLowerInvariant - Dim Lefts = RegexSearch(Left.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+") - Dim Rights = RegexSearch(Right.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+") + Dim Lefts = RegexSearch(Left.Replace("快照", "snapshot"), "[a-z]+|[0-9]+") + Dim Rights = RegexSearch(Right.Replace("快照", "snapshot"), "[a-z]+|[0-9]+") Dim i As Integer = 0 While True '两边均缺失,感觉是一个东西 @@ -2388,11 +2388,15 @@ NextEntry: ''' ''' 比较两个版本名的排序器。 ''' - Public Class VersionComparer + Public Class VersionSorter Implements IComparer(Of String) + Public IsDecreased As Boolean = True Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare - Return VersionSortInteger(x, y) + Return VersionSortInteger(x, y) * If(IsDecreased, -1, 1) End Function + Public Sub New(Optional IsDecreased As Boolean = True) + Me.IsDecreased = IsDecreased + End Sub End Class ''' diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb index c8c671ce..e0e4c3e8 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb @@ -688,7 +688,7 @@ Finished: ''' Public ReadOnly Property CanUpdate As Boolean Get - Return Not Setup.Get("UiHiddenFunctionModUpdate") AndAlso ChangelogUrls.Any() + Return ChangelogUrls.Any() End Get End Property @@ -702,7 +702,7 @@ Finished: Dim Info As New FileInfo(Path) Dim CacheKey As String = GetHash($"{RawPath}-{Info.LastWriteTime.ToLongTimeString}-{Info.Length}-C") Dim Cached As String = ReadIni(PathTemp & "Cache\ModHash.ini", CacheKey) - If Cached <> "" AndAlso RegexCheck(Cached, "^\d+$") Then '#5062 + If Cached <> "" Then _CurseForgeHash = Cached Return _CurseForgeHash End If @@ -825,7 +825,6 @@ Finished: Finally RunInUiWait(Sub() If FrmVersionMod IsNot Nothing Then FrmVersionMod.Load.Text = "正在加载 Mod 列表") End Try - FrmVersionMod.LoaderRun(LoaderFolderRunType.UpdateOnly) End If '获取 Mod 文件夹下的可用文件列表 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb index 2d9bc586..1457b6b2 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb @@ -1,5 +1,4 @@ Imports System.IO.Compression -Imports System.Linq.Expressions Public Module ModModpack @@ -10,22 +9,13 @@ Public Module ModModpack Public Sub ModpackInstall() Dim File As String = SelectFile("整合包文件(*.rar;*.zip;*.mrpack)|*.rar;*.zip;*.mrpack", "选择整合包压缩文件") '选择整合包文件 If String.IsNullOrEmpty(File) Then Exit Sub - RunInThread( - Sub() - Try - ModpackInstall(File) - Catch ex As CancelledException - Catch ex As Exception - Log(ex, "手动安装整合包失败", LogLevel.Msgbox) - End Try - End Sub) + RunInThread(Sub() ModpackInstall(File)) End Sub ''' - ''' 构建并启动安装给定的整合包文件的加载器,并返回该加载器。若失败则抛出异常。 + ''' 安装一个给定的整合包文件,返回启动的安装加载器,如果未成功启动则返回 Nothing。 ''' 必须在工作线程执行。 ''' - ''' - Public Function ModpackInstall(File As String, Optional VersionName As String = Nothing, Optional Logo As String = Nothing) As LoaderCombo(Of String) + Public Function ModpackInstall(File As String, Optional VersionName As String = Nothing, Optional ShowHint As Boolean = True, Optional Logo As String = Nothing) As LoaderCombo(Of String) Log("[ModPack] 整合包安装请求:" & If(File, "null")) Dim Archive As ZipArchive = Nothing Dim ArchiveBaseFolder As String = "" @@ -33,7 +23,7 @@ Public Module ModModpack '获取整合包种类与关键 Json Dim PackType As Integer = -1 Try - Archive = New ZipArchive(New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.Read)) + Archive = New ZipArchive(New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) '从根目录判断整合包类型 If Archive.GetEntry("mcbbs.packmeta") IsNot Nothing Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断) If Archive.GetEntry("mmc-pack.json") IsNot Nothing Then PackType = 2 : Exit Try 'MMC 整合包(优先于 manifest.json 判断,#4194) @@ -47,11 +37,11 @@ Public Module ModModpack End If End If If Archive.GetEntry("modpack.json") IsNot Nothing Then PackType = 1 : Exit Try 'HMCL 整合包 - If Archive.GetEntry("modpack.zip") IsNot Nothing OrElse Archive.GetEntry("modpack.mrpack") IsNot Nothing Then PackType = 9 : Exit Try '带启动器的压缩包 '从一级目录判断整合包类型 For Each Entry In Archive.Entries Dim FullNames As String() = Entry.FullName.Split("/") ArchiveBaseFolder = FullNames(0) & "/" + If Entry.FullName.EndsWithF("/versions/") AndAlso FullNames.Count = 3 Then PackType = 9 : Exit Try '压缩包 '确定为一级目录下 If FullNames.Count <> 2 Then Continue For '判断是否为关键文件 @@ -67,15 +57,17 @@ Public Module ModModpack End If End If If FullNames(1) = "modpack.json" Then PackType = 1 : Exit Try 'HMCL 整合包 - If FullNames(1) = "modpack.zip" OrElse FullNames(1) = "modpack.mrpack" Then PackType = 9 : Exit Try '带启动器的压缩包 Next Catch ex As Exception If GetExceptionDetail(ex, True).Contains("Error.WinIOError") Then - Throw New Exception("打开整合包文件失败", ex) + Log(ex, "打开整合包文件失败", If(ShowHint, LogLevel.Hint, LogLevel.Normal)) + Return Nothing ElseIf File.EndsWithF(".rar", True) Then - Throw New Exception("PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", ex) + Log(ex, "PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", If(ShowHint, LogLevel.Hint, LogLevel.Normal)) + Return Nothing Else - Throw New Exception("打开整合包文件失败,文件可能损坏或为不支持的压缩包格式", ex) + Log(ex, "打开整合包文件失败,文件可能损坏或为不支持的压缩包格式", If(ShowHint, LogLevel.Hint, LogLevel.Normal)) + Return Nothing End If End Try '执行对应的安装方法 @@ -96,12 +88,21 @@ Public Module ModModpack Log("[ModPack] 整合包种类:Modrinth") Return InstallPackModrinth(File, Archive, ArchiveBaseFolder, VersionName, Logo) Case 9 - Log("[ModPack] 整合包种类:带启动器的压缩包") - Return InstallPackLauncherPack(File, Archive, ArchiveBaseFolder) + Log("[ModPack] 整合包种类:压缩包") + Archive.Dispose() + Archive = Nothing + Return InstallPackCompress(File, ArchiveBaseFolder) Case Else - Log("[ModPack] 整合包种类:未能识别,假定为压缩包") - Return InstallPackCompress(File, Archive) + If ShowHint Then + Hint("未能识别该整合包的种类,无法安装!", HintType.Critical) + Else + Log("[ModPack] 未能识别该整合包的种类,无法安装!") + End If + Return Nothing End Select + Catch ex As Exception + Log(ex, "准备安装整合包失败", LogLevel.Feedback) + Return Nothing Finally If Archive IsNot Nothing Then Archive.Dispose() End Try @@ -110,7 +111,7 @@ Public Module ModModpack '整合包缓存清理 Private IsInstallCacheCleared As Boolean = False Private IsInstallCacheClearing As Boolean = False - Private Sub ExtractModpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase, LoaderProgressDelta As Double) + Private Sub UnpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase) '清理缓存文件夹 If Not IsInstallCacheCleared Then IsInstallCacheCleared = True @@ -137,7 +138,7 @@ Public Module ModModpack Retry: '完全不知道为啥会出现文件正在被另一进程使用的问题,总之多试试 DeleteDirectory(InstallTemp) - ExtractFile(FileAddress, InstallTemp, Encode, ProgressIncrementHandler:=Sub(Delta) Loader.Progress += Delta * LoaderProgressDelta) + ExtractFile(FileAddress, InstallTemp, Encode) Catch ex As Exception Log(ex, "第 " & RetryCount & " 次解压尝试失败") If TypeOf ex Is ArgumentException Then @@ -150,7 +151,7 @@ Retry: RetryCount += 1 GoTo Retry Else - Throw New Exception("解压整合包文件失败", ex) + Throw End If End Try End Sub @@ -165,18 +166,20 @@ Retry: Dim Json As JObject Try Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "manifest.json").Open)) + If Json("minecraft") Is Nothing OrElse Json("minecraft")("version") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息") Catch ex As Exception - Throw New Exception("CurseForge 整合包安装信息存在问题", ex) + Log(ex, "CurseForge 整合包安装信息存在问题", LogLevel.Hint) + Return Nothing End Try - If Json("minecraft") Is Nothing OrElse Json("minecraft")("version") Is Nothing Then Throw New Exception("CurseForge 整合包未提供 Minecraft 版本信息") '获取版本名 + Dim ShowRibble As Boolean = VersionName Is Nothing If VersionName Is Nothing Then VersionName = If(Json("name"), "") Dim Validate As New ValidateFolderName(PathMcFolder & "versions") If Validate.Validate(VersionName) <> "" Then VersionName = "" If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate}) - If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException + If String.IsNullOrEmpty(VersionName) Then Return Nothing End If '获取 Mod API 版本信息 @@ -188,13 +191,26 @@ Retry: Dim Id As String = If(Entry("id"), "").ToString.ToLower If Id.StartsWithF("forge-") Then 'Forge 指定 - If Id.Contains("recommended") Then Throw New Exception("该整合包版本过老,已不支持进行安装!") - Log("[ModPack] 整合包 Forge 版本:" & Id) - ForgeVersion = Id.Replace("forge-", "") + If Id.Contains("recommended") Then + Log("[ModPack] 该整合包版本过老,已不支持进行安装!", LogLevel.Hint) + Return Nothing + End If + Try + Log("[ModPack] 整合包 Forge 版本:" & Id) + ForgeVersion = Id.Replace("forge-", "") + Exit For + Catch ex As Exception + Log(ex, "读取整合包 Forge 版本失败:" & Id) + End Try ElseIf Id.StartsWithF("neoforge-") Then 'NeoForge 指定 - Log("[ModPack] 整合包 NeoForge 版本:" & Id) - NeoForgeVersion = Id.Replace("neoforge-", "") + Try + Log("[ModPack] 整合包 NeoForge 版本:" & Id) + NeoForgeVersion = Id.Replace("neoforge-", "") + Exit For + Catch ex As Exception + Log(ex, "读取整合包 NeoForge 版本失败:" & Id) + End Try ElseIf Id.StartsWithF("fabric-") Then 'Fabric 指定 Try @@ -204,15 +220,6 @@ Retry: Catch ex As Exception Log(ex, "读取整合包 Fabric 版本失败:" & Id) End Try - ElseIf Id.StartsWithF("quilt-") Then - 'Quilt 指定 - Try - Log("[ModPack] 整合包 Quilt 版本:" & Id) - QuiltVersion = Id.Replace("quilt-", "") - Exit For - Catch ex As Exception - Log(ex, "读取整合包 Quilt 版本失败:" & Id) - End Try End If Next '解压与配置文件 @@ -222,17 +229,17 @@ Retry: If OverrideHome <> "" Then InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件", Sub(Task As LoaderTask(Of String, Integer)) - ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6) - Task.Progress = 0.6 + UnpackFiles(InstallTemp, FileAddress, Task) + Task.Progress = 0.5 Dim OverridePath As String = InstallTemp & ArchiveBaseFolder & OverrideHome '复制结果 If Directory.Exists(OverridePath) Then - CopyDirectory(OverridePath, PathMcFolder & "versions\" & VersionName, Sub(Delta) Task.Progress += Delta * 0.35) + CopyDirectory(OverridePath, PathMcFolder & "versions\" & VersionName) Log($"[ModPack] 整合包 override 复制:{OverridePath} -> {PathMcFolder & "versions\" & VersionName}") Else Log($"[ModPack] 整合包中未找到 overrides 文件夹:{OverridePath}") End If - Task.Progress = 0.95 + Task.Progress = 0.9 '开启版本隔离 WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1) End Sub) With { @@ -254,11 +261,9 @@ Retry: '获取 Mod 下载信息 ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息", Sub(Task As LoaderTask(Of Integer, JArray)) - '由于 MCIM 缺少下载信息,只使用官方源获取列表 - 'TODO: 在 MCIM 源稳定后回调回 DlModRequest - Task.Output = GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json"))("data") + Task.Output = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json"))("data") '如果文件已被删除,则 API 会跳过那一项 - If ModList.Count > Task.Output.Count Then Throw New Exception("整合包中的部分 Mod 版本已被 Mod 作者删除,所以没法继续安装了,请向整合包作者反馈该问题") + If ModList.Count > Task.Output.Count Then Throw New Exception("整合包所需要的部分 Mod 版本已被 Mod 作者删除,因此无法完成整合包安装,请联系整合包作者更新整合包中的 Mod 版本") End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s '构造 NetFile ModDownloadLoaders.Add(New LoaderTask(Of JArray, List(Of NetFile))("构造 Mod 下载信息", @@ -317,6 +322,7 @@ Retry: .QuiltVersion = QuiltVersion } Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True) + If MergeLoaders Is Nothing Then Return Nothing '构造 Libraries 加载器 Dim LoadersLib As New List(Of LoaderBase) LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False}) @@ -338,8 +344,8 @@ Retry: End If '删除原始整合包文件 For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"} - If File.Exists(Target) Then - Log("[ModPack] 删除原始整合包文件:" & Target) + If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then + Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target) File.Delete(Target) End If Next @@ -349,7 +355,7 @@ Retry: Dim LoaderName As String = "CurseForge 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then Hint("该整合包正在安装中!", HintType.Critical) - Throw New CancelledException + Return Nothing End If '启动 @@ -357,7 +363,7 @@ Retry: Loader.Start(Request.TargetVersionFolder) LoaderTaskbarAdd(Loader) FrmMain.BtnExtraDownload.ShowRefresh() - RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager)) + If ShowRibble Then FrmMain.BtnExtraDownload.Ribble() Return Loader End Function @@ -368,10 +374,11 @@ Retry: Dim Json As JObject Try Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modrinth.index.json").Open)) + If Json("dependencies") Is Nothing OrElse Json("dependencies")("minecraft") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息") Catch ex As Exception - Throw New Exception("Modrinth 整合包安装信息存在问题", ex) + Log(ex, "整合包安装信息存在问题", LogLevel.Hint) + Return Nothing End Try - If Json("dependencies") Is Nothing OrElse Json("dependencies")("minecraft") Is Nothing Then Throw New Exception("Modrinth 整合包未提供 Minecraft 版本信息") '获取 Mod API 版本信息 Dim MinecraftVersion As String = Nothing Dim ForgeVersion As String = Nothing @@ -391,41 +398,41 @@ Retry: Case "fabric-loader" 'eg. 0.14.14 FabricVersion = Entry.Value.ToString Log("[ModPack] 整合包 Fabric 版本:" & FabricVersion) - Case "quilt-loader" 'eg. 0.26.0 - QuiltVersion = Entry.Value.ToString - Log("[ModPack] 整合包 Quilt 版本:" & QuiltVersion) + Case "quilt-loader" 'eg. 1.0.0 + Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical) + Return Nothing Case Else - Hint($"无法安装整合包,其中出现了未知的 Mod 加载器 {Entry.Name}(版本为 {Entry.Value.ToString})!", HintType.Critical) + Hint($"无法安装整合包,其中出现了未知的 Mod 加载器 {Entry.Value}!", HintType.Critical) + Return Nothing End Select Next '获取版本名 + Dim ShowRibble As Boolean = VersionName Is Nothing If VersionName Is Nothing Then VersionName = If(Json("name"), "") Dim Validate As New ValidateFolderName(PathMcFolder & "versions") If Validate.Validate(VersionName) <> "" Then VersionName = "" If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate}) - If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException + If String.IsNullOrEmpty(VersionName) Then Return Nothing End If '解压和配置文件 Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\" Dim InstallLoaders As New List(Of LoaderBase) InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件", Sub(Task As LoaderTask(Of String, Integer)) - ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6) - Task.Progress = 0.6 + UnpackFiles(InstallTemp, FileAddress, Task) + Task.Progress = 0.5 '复制 overrides 文件夹和 client-overrides 文件夹 If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then - CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName, - Sub(Delta) Task.Progress += Delta * 0.25) + CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName) Else Log("[ModPack] 整合包中未找到 override 目录,已跳过") End If - Task.Progress = 0.85 + Task.Progress = 0.8 If Directory.Exists(InstallTemp & ArchiveBaseFolder & "client-overrides") Then - CopyDirectory(InstallTemp & ArchiveBaseFolder & "client-overrides", PathMcFolder & "versions\" & VersionName, - Sub(Delta) Task.Progress += Delta * 0.1) + CopyDirectory(InstallTemp & ArchiveBaseFolder & "client-overrides", PathMcFolder & "versions\" & VersionName) End If - Task.Progress = 0.95 + Task.Progress = 0.9 '开启版本隔离 WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1) End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s @@ -466,6 +473,7 @@ Retry: .QuiltVersion = QuiltVersion } Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True) + If MergeLoaders Is Nothing Then Return Nothing '构造 Libraries 加载器 Dim LoadersLib As New List(Of LoaderBase) LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False}) @@ -487,8 +495,8 @@ Retry: End If '删除原始整合包文件 For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"} - If File.Exists(Target) Then - Log("[ModPack] 删除原始整合包文件:" & Target) + If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then + Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target) File.Delete(Target) End If Next @@ -498,7 +506,7 @@ Retry: Dim LoaderName As String = "Modrinth 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then Hint("该整合包正在安装中!", HintType.Critical) - Throw New CancelledException + Return Nothing End If '启动 @@ -506,8 +514,9 @@ Retry: Loader.Start(Request.TargetVersionFolder) LoaderTaskbarAdd(Loader) FrmMain.BtnExtraDownload.ShowRefresh() - RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager)) + If ShowRibble Then FrmMain.BtnExtraDownload.Ribble() Return Loader + End Function 'HMCL @@ -517,39 +526,44 @@ Retry: Try Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modpack.json").Open, Encoding.UTF8)) Catch ex As Exception - Throw New Exception("HMCL 整合包安装信息存在问题", ex) + Log(ex, "整合包安装信息存在问题", LogLevel.Hint) + Return Nothing End Try '获取版本名 Dim VersionName As String = If(Json("name"), "") Dim Validate As New ValidateFolderName(PathMcFolder & "versions") If Validate.Validate(VersionName) <> "" Then VersionName = "" If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate}) - If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException + If String.IsNullOrEmpty(VersionName) Then Return Nothing '解压与配置文件 Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\" Dim InstallLoaders As New List(Of LoaderBase) InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件", Sub(Task As LoaderTask(Of String, Integer)) - ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6) - Task.Progress = 0.6 + UnpackFiles(InstallTemp, FileAddress, Task) + Task.Progress = 0.5 '复制结果 If Directory.Exists(InstallTemp & ArchiveBaseFolder & "minecraft") Then - CopyDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", PathMcFolder & "versions\" & VersionName, Sub(Delta) Task.Progress += Delta * 0.35) + CopyDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", PathMcFolder & "versions\" & VersionName) Else Log("[ModPack] 整合包中未找到 minecraft overrides 目录,已跳过") End If - Task.Progress = 0.95 + Task.Progress = 0.9 '开启版本隔离 WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1) End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s '构造加载器 - If Json("gameVersion") Is Nothing Then Throw New Exception("该 HMCL 整合包未提供游戏版本信息,无法安装!") + If Json("gameVersion") Is Nothing Then + Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical) + Return Nothing + End If Dim Request As New McInstallRequest With { .TargetVersionName = VersionName, .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\", .MinecraftName = Json("gameVersion").ToString } Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True) + If MergeLoaders Is Nothing Then Return Nothing '构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件) Dim LoadersLib As New List(Of LoaderBase) LoadersLib.Add(New LoaderTask(Of String, String)("重命名版本 Json(副加载器)", @@ -579,7 +593,7 @@ Retry: Dim LoaderName As String = "HMCL 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then Hint("该整合包正在安装中!", HintType.Critical) - Throw New CancelledException + Return Nothing End If '启动 @@ -588,7 +602,7 @@ Retry: Loader.Start(Request.TargetVersionFolder) LoaderTaskbarAdd(Loader) FrmMain.BtnExtraDownload.ShowRefresh() - RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager)) + FrmMain.BtnExtraDownload.Ribble() Return Loader End Function @@ -600,29 +614,30 @@ Retry: PackJson = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "mmc-pack.json").Open, Encoding.UTF8)) PackInstance = ReadFile(Archive.GetEntry(ArchiveBaseFolder & "instance.cfg").Open, Encoding.UTF8) Catch ex As Exception - Throw New Exception("MMC 整合包安装信息存在问题", ex) + Log(ex, "整合包安装信息存在问题", LogLevel.Hint) + Return Nothing End Try '获取版本名 Dim VersionName As String = If(RegexSeek(PackInstance, "(?<=\nname\=)[^\n]+"), "") Dim Validate As New ValidateFolderName(PathMcFolder & "versions") If Validate.Validate(VersionName) <> "" Then VersionName = "" If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate}) - If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException + If String.IsNullOrEmpty(VersionName) Then Return Nothing '解压、配置设置文件 Dim InstallTemp As String = $"{PathTemp}PackInstall\{RandomInteger(0, 100000)}\" Dim SetupFile As String = $"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini" Dim InstallLoaders As New List(Of LoaderBase) InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件", Sub(Task As LoaderTask(Of String, Integer)) - ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6) - Task.Progress = 0.6 + UnpackFiles(InstallTemp, FileAddress, Task) + Task.Progress = 0.5 '复制结果 If Directory.Exists(InstallTemp & ArchiveBaseFolder & ".minecraft") Then - CopyDirectory(InstallTemp & ArchiveBaseFolder & ".minecraft", PathMcFolder & "versions\" & VersionName, Sub(Delta) Task.Progress += Delta * 0.35) + CopyDirectory(InstallTemp & ArchiveBaseFolder & ".minecraft", PathMcFolder & "versions\" & VersionName) Else Log("[ModPack] 整合包中未找到 overrides .minecraft 目录,已跳过") End If - Task.Progress = 0.95 + Task.Progress = 0.9 '开启版本隔离 WriteIni(SetupFile, "VersionArgumentIndie", 1) '读取 MMC 设置文件(#2655) @@ -665,7 +680,10 @@ Retry: End Try End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s '构造版本安装请求 - If PackJson("components") Is Nothing Then Throw New Exception("该 MMC 整合包未提供游戏版本信息,无法安装!") + If PackJson("components") Is Nothing Then + Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical) + Return Nothing + End If Dim Request As New McInstallRequest With {.TargetVersionName = VersionName, .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\"} For Each Component In PackJson("components") Select Case If(Component("uid"), "").ToString @@ -679,12 +697,14 @@ Retry: Request.NeoForgeVersion = Component("version") Case "net.fabricmc.fabric-loader" Request.FabricVersion = Component("version") - Case "org.quiltmc.quilt-loader" - Request.QuiltVersion = Component("version") + Case "org.quiltmc.quilt-loader" 'eg. 1.0.0 + Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical) + Return Nothing End Select Next '构造加载器 Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True) + If MergeLoaders Is Nothing Then Return Nothing '构造 Libraries 加载器 Dim LoadersLib As New List(Of LoaderBase) LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False}) @@ -699,7 +719,7 @@ Retry: Dim LoaderName As String = "MMC 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then Hint("该整合包正在安装中!", HintType.Critical) - Throw New CancelledException + Return Nothing End If '启动 @@ -707,7 +727,7 @@ Retry: Loader.Start(Request.TargetVersionFolder) LoaderTaskbarAdd(Loader) FrmMain.BtnExtraDownload.ShowRefresh() - RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager)) + FrmMain.BtnExtraDownload.Ribble() Return Loader End Function @@ -720,36 +740,40 @@ Retry: Dim Entry = If(Archive.GetEntry(ArchiveBaseFolder & "mcbbs.packmeta"), Archive.GetEntry(ArchiveBaseFolder & "manifest.json")) Json = GetJson(ReadFile(Entry.Open, Encoding.UTF8)) Catch ex As Exception - Throw New Exception("MCBBS 整合包安装信息存在问题", ex) + Log(ex, "整合包安装信息存在问题", LogLevel.Hint) + Return Nothing End Try '获取版本名 + Dim ShowRibble As Boolean = VersionName Is Nothing If VersionName Is Nothing Then VersionName = If(Json("name"), "") Dim Validate As New ValidateFolderName(PathMcFolder & "versions") If Validate.Validate(VersionName) <> "" Then VersionName = "" If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate}) - If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException + If String.IsNullOrEmpty(VersionName) Then Return Nothing End If '解压与配置文件 Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\" Dim InstallLoaders As New List(Of LoaderBase) InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件", Sub(Task As LoaderTask(Of String, Integer)) - ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6) - Task.Progress = 0.6 + UnpackFiles(InstallTemp, FileAddress, Task) + Task.Progress = 0.5 '复制结果 If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then - CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName, - Sub(Delta) Task.Progress += 0.35 * Delta) + CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName) Else Log("[ModPack] 整合包中未找到 overrides 目录,已跳过") End If - Task.Progress = 0.95 + Task.Progress = 0.9 '开启版本隔离 WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1) End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s '构造加载器 - If Json("addons") Is Nothing Then Throw New Exception("该 MCBBS 整合包未提供游戏版本附加信息,无法安装!") + If Json("addons") Is Nothing Then + Hint("该整合包未提供游戏版本附加信息,无法安装!", HintType.Critical) + Return Nothing + End If Dim Addons As New Dictionary(Of String, String) For Each Entry In Json("addons") Addons.Add(Entry("id"), Entry("version")) @@ -758,6 +782,10 @@ Retry: Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical) Return Nothing End If + If Addons.ContainsKey("quilt") Then + Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical) + Return Nothing + End If Dim Request As New McInstallRequest With { .TargetVersionName = VersionName, .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\", @@ -769,6 +797,7 @@ Retry: .QuiltVersion = If(Addons.ContainsKey("quilt"), Addons("quilt"), Nothing) } Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True) + If MergeLoaders Is Nothing Then Return Nothing '构造 Libraries 加载器 Dim LoadersLib As New List(Of LoaderBase) LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False}) @@ -783,7 +812,7 @@ Retry: Dim LoaderName As String = "MCBBS 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then Hint("该整合包正在安装中!", HintType.Critical) - Throw New CancelledException + Return Nothing End If '启动 @@ -792,101 +821,31 @@ Retry: Loader.Start(Request.TargetVersionFolder) LoaderTaskbarAdd(Loader) FrmMain.BtnExtraDownload.ShowRefresh() - RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager)) - Return Loader - End Function - - '带启动器的压缩包 - Private Function InstallPackLauncherPack(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String) As LoaderCombo(Of String) - '获取解压路径 - MyMsgBox("接下来请选择一个空文件夹,它会被安装到这个文件夹里。", "安装", "继续", ForceWait:=True) - Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)") - If String.IsNullOrEmpty(TargetFolder) Then Throw New CancelledException - If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Throw New CancelledException - If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Throw New CancelledException - '解压 - Dim Loader As New LoaderCombo(Of String)("解压压缩包", { - New LoaderTask(Of String, Integer)("解压压缩包", - Sub(Task As LoaderTask(Of String, Integer)) - ExtractModpackFiles(TargetFolder, FileAddress, Task, 0.9) - Thread.Sleep(400) '避免文件争用 - '查找解压后的 exe 文件 - Dim Launcher As String = Nothing - For Each ExeFile In Directory.GetFiles(TargetFolder, "*.exe", SearchOption.AllDirectories) - Dim Info = FileVersionInfo.GetVersionInfo(ExeFile) - Log($"[Modpack] 文件 {ExeFile} 的产品名标识为 {Info.ProductName}") - If Info.ProductName = "Plain Craft Launcher" Then - Launcher = ExeFile - ElseIf (Info.ProductName.ContainsF("Launcher", True) OrElse Info.ProductName.ContainsF("启动器", True)) AndAlso - Not Info.ProductName = "Plain Craft Launcher Admin Manager" Then - If Launcher Is Nothing Then Launcher = ExeFile - End If - Next - Task.Progress = 0.95 - '尝试使用附带的启动器打开 - If Launcher IsNot Nothing Then - Log("[Modpack] 找到压缩包中附带的启动器:" & Launcher) - If MyMsgBox($"整合包中似乎自带了启动器,是否换用它继续安装?{vbCrLf}通常推荐这样做,以获得最佳体验。{vbCrLf}即将打开:{Launcher}", "换用整合包启动器?", "继续", "取消") = 1 Then - ShellOnly(Launcher, "--wait") - Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序") - FrmMain.EndProgram(False) - Return - End If - Else - Log("[Modpack] 未找到压缩包中附带的启动器") - End If - '加入文件夹列表 - Dim VersionName As String = GetFolderNameFromPath(TargetFolder) - PageSelectLeft.AddFolder( - TargetFolder & ArchiveBaseFolder.Replace("/", "\").TrimStart("\"), '格式例如:包裹文件夹\.minecraft\(最短为空字符串) - VersionName, False) - '调用 modpack 文件进行安装 - Dim ModpackFile = Directory.GetFiles(TargetFolder, "modpack.*", SearchOption.AllDirectories).First - Log("[Modpack] 调用 modpack 文件继续安装:" & ModpackFile) - ModpackInstall(ModpackFile, VersionName) - End Sub) - }) - Loader.Start(TargetFolder) - LoaderTaskbarAdd(Loader) - FrmMain.BtnExtraDownload.ShowRefresh() - FrmMain.BtnExtraDownload.Ribble() + If ShowRibble Then FrmMain.BtnExtraDownload.Ribble() Return Loader End Function '普通压缩包 - Private Function InstallPackCompress(FileAddress As String, Archive As Compression.ZipArchive) As LoaderCombo(Of String) - '尝试定位 .minecraft 文件夹:寻找形如 “/versions/XXX/XXX.json” 的路径 - Dim Match As RegularExpressions.Match = Nothing - Dim Regex As New RegularExpressions.Regex("^.*\/(?=versions\/(?[^\/]+)\/(\k)\.json$)", RegularExpressions.RegexOptions.IgnoreCase) - For Each Entry In Archive.Entries - Dim EntryMatch = Regex.Match("/" & Entry.FullName) - If EntryMatch.Success Then - Match = EntryMatch - Exit For - End If - Next - If Match Is Nothing Then Throw New Exception("未能找到适合的文件结构,这可能不是一个 MC 压缩包") '没有匹配 - Dim ArchiveBaseFolder As String = Match.Value.Replace("/", "\").TrimStart("\") '格式例如:包裹文件夹\.minecraft\(最短为空字符串) - Dim VersionName As String = Match.Groups(1).Value - Log("[ModPack] 检测到压缩包的 .minecraft 根目录:" & ArchiveBaseFolder & ",命中的版本名:" & VersionName) + Private Function InstallPackCompress(FileAddress As String, ArchiveBaseFolder As String) As LoaderCombo(Of String) + MyMsgBox("请在接下来打开的窗口中选择安装目标文件夹,它必须是一个空文件夹。", "安装提示", "继续", ForceWait:=True) '获取解压路径 - MyMsgBox("接下来请选择一个空文件夹,它会被安装到这个文件夹里。", "安装", "继续", ForceWait:=True) Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)") - If String.IsNullOrEmpty(TargetFolder) Then Throw New CancelledException - If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Throw New CancelledException - If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Throw New CancelledException + If String.IsNullOrEmpty(TargetFolder) Then Return Nothing + If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Return Nothing + If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Return Nothing + '要求显示名称 + Dim NewName As String = MyMsgBoxInput("输入显示名称", "输入该文件夹在左边栏列表中显示的名称。", GetFolderNameFromPath(TargetFolder), + New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})}) + If String.IsNullOrWhiteSpace(NewName) Then Return Nothing '解压 - Dim Loader As New LoaderCombo(Of String)("解压压缩包", { - New LoaderTask(Of String, Integer)("解压压缩包", - Sub(Task As LoaderTask(Of String, Integer)) - ExtractModpackFiles(TargetFolder, FileAddress, Task, 0.95) - '加入文件夹列表 - PageSelectLeft.AddFolder(TargetFolder & ArchiveBaseFolder, GetFolderNameFromPath(TargetFolder), False) - Thread.Sleep(400) '避免文件争用 - RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.VersionSelect)) - End Sub) - }) With {.OnStateChanged = AddressOf McInstallState} - Loader.Start(TargetFolder) + Dim Loader As New LoaderCombo(Of String)("安装压缩包", { + New LoaderTask(Of String, Integer)("安装压缩包", + Sub() + UnpackFiles(TargetFolder, FileAddress, Nothing) + PageSelectLeft.AddFolder(TargetFolder, NewName, False) '加入文件夹列表 + End Sub) + }) + Loader.Start() LoaderTaskbarAdd(Loader) FrmMain.BtnExtraDownload.ShowRefresh() FrmMain.BtnExtraDownload.Ribble() diff --git a/Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml b/Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml index 7524a36c..8fd7baec 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml +++ b/Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml @@ -1,7 +1,6 @@  @@ -24,7 +23,7 @@ - + $"{PathTemp}CompLogo\{GetHash(_Logo)}.png" Then Exit Sub + '在完成正常加载后才保存缓存图片 + PathLogo.Source = New MyBitmap(LocalFileAddress & DownloadEnd) + Catch ex As Exception + Log(ex, $"读取资源工程图标失败({LocalFileAddress})") + File.Delete(LocalFileAddress & DownloadEnd) + LoadError = ex + End Try + End Sub) + If LoadError IsNot Nothing Then Throw LoadError + If File.Exists(LocalFileAddress) Then + File.Delete(LocalFileAddress & DownloadEnd) + Else + FileIO.FileSystem.MoveFile(LocalFileAddress & DownloadEnd, LocalFileAddress) + End If + Catch ex As Exception + If Not Retried Then + Retried = True + GoTo RetryStart + Else + Log(ex, $"下载资源工程图标失败({_Logo})") + RunInUi(Sub() PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")) + End If + End Try + End Sub '标题 Public Property Title As String @@ -96,7 +169,7 @@ '记录当前展开的卡片标题(#2712) Dim Titles As New List(Of String) If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then - For Each Card As MyCard In FrmDownloadCompDetail.PanResults.Children + For Each Card As MyCard In FrmDownloadCompDetail.PanMain.Children If Card.Title <> "" AndAlso Not Card.IsSwaped Then Titles.Add(Card.Title) Next Log("[Comp] 记录当前已展开的卡片:" & String.Join("、", Titles)) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml index 445f44b8..ce687e89 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml +++ b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml @@ -24,18 +24,18 @@ - + - + - + @@ -52,6 +52,6 @@ --> diff --git a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb index f826928d..316d5e3f 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb @@ -6,14 +6,88 @@ Public Class MyLocalModItem Public Uuid As Integer = GetUuid() 'Logo + Private _Logo As String = "" Public Property Logo As String Get - Return PathLogo.Source + Return _Logo End Get Set(value As String) - PathLogo.Source = value + If _Logo = value OrElse value Is Nothing Then Exit Property + _Logo = value + If ModeDebug AndAlso Not _Logo = PathImage & "Icons/NoIcon.png" Then Log($"[LocalModItem] Mod {Title} 的图标:{value}") + Dim FileAddress = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png" + Try + If _Logo.StartsWithF("http", True) Then + '网络图片 + If File.Exists(FileAddress) Then + PathLogo.Source = New MyBitmap(FileAddress) + Else + PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png") + RunInNewThread(Sub() LogoLoader(FileAddress), "Comp Logo Loader " & Uuid & "#", ThreadPriority.BelowNormal) + End If + Else + '位图 + PathLogo.Source = New MyBitmap(_Logo) + End If + Catch ex As IOException + Log(ex, "加载本地 Mod 图标时读取失败(" & FileAddress & ")") + Catch ex As ArgumentException + '考虑缓存的图片本身可能有误 + Log(ex, "可视化本地 Mod 图标失败(" & FileAddress & ")") + Try + File.Delete(FileAddress) + Log("[LocalModItem] 已清理损坏的本地 Mod 图标:" & FileAddress) + Catch exx As Exception + Log(exx, "清理损坏的本地 Mod 图标缓存失败(" & FileAddress & ")", LogLevel.Hint) + End Try + Catch ex As Exception + Log(ex, "加载本地 Mod 图标失败(" & value & ")") + End Try End Set End Property + '后台加载 Logo + Private Sub LogoLoader(LocalFileAddress As String) + Dim Retried As Boolean = False + Dim DownloadEnd As String = GetUuid() +RetryStart: + Try + 'CurseForge 图片使用缩略图 + Dim Url As String = _Logo + If Url.Contains("/256/256/") AndAlso GetPixelSize(1) <= 1.25 AndAlso Not Retried Then '#3075:部分 Mod 不存在 64x64 图标,所以重试时不再缩小 + Url = Url.Replace("/256/256/", "/64/64/") + End If + '下载图片 + NetDownload(Url, LocalFileAddress & DownloadEnd, True) + Dim LoadError As Exception = Nothing + RunInUiWait( + Sub() + Try + '在地址更换时取消加载 + If LocalFileAddress <> $"{PathTemp}CompLogo\{GetHash(_Logo)}.png" Then Exit Sub + '在完成正常加载后才保存缓存图片 + PathLogo.Source = New MyBitmap(LocalFileAddress & DownloadEnd) + Catch ex As Exception + Log(ex, "读取本地 Mod 图标失败(" & LocalFileAddress & ")") + File.Delete(LocalFileAddress & DownloadEnd) + LoadError = ex + End Try + End Sub) + If LoadError IsNot Nothing Then Throw LoadError + If File.Exists(LocalFileAddress) Then + File.Delete(LocalFileAddress & DownloadEnd) + Else + FileIO.FileSystem.MoveFile(LocalFileAddress & DownloadEnd, LocalFileAddress) + End If + Catch ex As Exception + If Not Retried Then + Retried = True + GoTo RetryStart + Else + Log(ex, $"下载本地 Mod 图标失败({_Logo})") + RunInUi(Sub() PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")) + End If + End Try + End Sub '标题 Private _Title As String @@ -69,9 +143,9 @@ Public Class MyLocalModItem For Each TagText In value Dim NewTag = GetObjectFromXML( " - + ") PanTags.Children.Add(NewTag) Next @@ -303,75 +377,57 @@ Public Class MyLocalModItem #End Region - Private Function GetUpdateCompareDescription() As String - Dim CurrentName = Entry.CompFile.FileName.Replace(".jar", "") - Dim NewestName = Entry.UpdateFile.FileName.Replace(".jar", "") - '简化名称对比 - Dim CurrentSegs = CurrentName.Split("-"c).ToList() - Dim NewestSegs = NewestName.Split("-"c).ToList() - Dim Shortened As Boolean = False - For Each Seg In CurrentSegs.ToList() - If Not NewestSegs.Contains(Seg) Then Continue For - CurrentSegs.Remove(Seg) - NewestSegs.Remove(Seg) - Shortened = True - Next - If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then - CurrentName = Join(CurrentSegs, "-") - NewestName = Join(NewestSegs, "-") - Entry._Version = CurrentName '使用网络信息作为显示的版本号 - End If - Return $"当前版本:{CurrentName}({GetTimeSpanString(Entry.CompFile.ReleaseDate - Date.Now, False)}){vbCrLf}最新版本:{NewestName}({GetTimeSpanString(Entry.UpdateFile.ReleaseDate - Date.Now, False)})" - End Function - Public Sub Refresh() Handles Me.Loaded + Public Sub Refresh() RunInUi( Sub() '更新 If Entry.CanUpdate Then BtnUpdate.Visibility = Visibility.Visible - BtnUpdate.ToolTip = $"{GetUpdateCompareDescription()}{vbCrLf}点击以更新,右键查看更新日志。" + Dim CurrentName = Entry.CompFile.FileName.Replace(".jar", "") + Dim NewestName = Entry.UpdateFile.FileName.Replace(".jar", "") + '简化名称对比 + Dim CurrentSegs = CurrentName.Split("-"c).ToList() + Dim NewestSegs = NewestName.Split("-"c).ToList() + Dim Shortened As Boolean = False + For Each Seg In CurrentSegs.ToList() + If Not NewestSegs.Contains(Seg) Then Continue For + CurrentSegs.Remove(Seg) + NewestSegs.Remove(Seg) + Shortened = True + Next + If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then + CurrentName = Join(CurrentSegs, "-") + NewestName = Join(NewestSegs, "-") + Entry._Version = CurrentName '使用网络信息作为显示的版本号 + End If + BtnUpdate.ToolTip = $"当前版本:{CurrentName} ({Entry.CompFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}最新版本:{NewestName} ({Entry.UpdateFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}点击以更新,右键查看更新日志。" Else BtnUpdate.Visibility = Visibility.Collapsed End If - '标题与描述 - Dim DescFileName As String + '标题 + If Entry.Comp Is Nothing Then + Title = Entry.Name + SubTitle = If(Entry.Version Is Nothing, "", " | " & Entry.Version) + Else + Dim Titles = Entry.Comp.GetControlTitle(False) + Title = Titles.Key + SubTitle = Titles.Value & If(Entry.Version Is Nothing, "", " | " & Entry.Version) + End If + If Checked Then + LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush2", "ColorBrush5")) + Else + LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush1", "ColorBrushGray4")) + End If + '描述 + Dim NewDescription As String Select Case Entry.State Case McMod.McModState.Fine - DescFileName = GetFileNameWithoutExtentionFromPath(Entry.Path) + NewDescription = GetFileNameWithoutExtentionFromPath(Entry.Path) Case McMod.McModState.Disabled - DescFileName = GetFileNameWithoutExtentionFromPath(Entry.Path.Replace(".disabled", "").Replace(".old", "")) + NewDescription = GetFileNameWithoutExtentionFromPath(Entry.Path.Replace(".disabled", "").Replace(".old", "")) Case Else 'McMod.McModState.Unavailable - DescFileName = GetFileNameFromPath(Entry.Path) + NewDescription = GetFileNameFromPath(Entry.Path) End Select - Dim NewDescription As String - If Setup.Get("ToolModLocalNameStyle") = 1 Then - '标题显示文件名,详情显示译名 - '标题 - Title = DescFileName - SubTitle = "" - '描述 - If Entry.Comp Is Nothing Then - NewDescription = Entry.Name - Else - Dim Titles = Entry.Comp.GetControlTitle(False) - NewDescription = Titles.Key & Titles.Value - End If - NewDescription = NewDescription.Replace(" | ", " / ") - If Entry.Version IsNot Nothing Then NewDescription &= $" ({Entry.Version})" - Else - '标题显示译名,详情显示文件名 - '标题 - If Entry.Comp Is Nothing Then - Title = Entry.Name - SubTitle = If(Entry.Version Is Nothing, "", " | " & Entry.Version) - Else - Dim Titles = Entry.Comp.GetControlTitle(False) - Title = Titles.Key - SubTitle = Titles.Value & If(Entry.Version Is Nothing, "", " | " & Entry.Version) - End If - '描述 - NewDescription = DescFileName - End If If Entry.Comp IsNot Nothing Then NewDescription += ": " & Entry.Comp.Description.Replace(vbCr, "").Replace(vbLf, "") ElseIf Entry.Description IsNot Nothing Then @@ -380,11 +436,6 @@ Public Class MyLocalModItem NewDescription += ": " & "存在错误,无法获取信息" End If Description = NewDescription - If Checked Then - LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush2", "ColorBrush5")) - Else - LabTitle.SetResourceReference(TextBlock.ForegroundProperty, If(Entry.State = McMod.McModState.Fine, "ColorBrush1", "ColorBrushGray4")) - End If '主 Logo Logo = If(Entry.Comp Is Nothing, PathImage & "Icons/NoIcon.png", Entry.Comp.GetControlLogo()) '图标右下角的 Logo @@ -479,57 +530,20 @@ Public Class MyLocalModItem '触发更新 Private Sub BtnUpdate_Click(sender As Object, e As EventArgs) Handles BtnUpdate.Click - If MyMsgBox($"是否要更新 {Entry.Name}?{vbCrLf}{vbCrLf}{GetUpdateCompareDescription()}", "Mod 更新确认", "更新", "取消") = 2 Then Return FrmVersionMod.UpdateMods({Entry}) End Sub '自适应(#4465) - Private Sub PanTitle_SizeChanged() Handles PanTitle.SizeChanged - '0:全部舒展:Auto - Auto - (Auto) - 1* - '1:压缩 Subtitle:Auto - 1* - (Auto) - 0 - '2:继续压缩 Title:1* - 0 - (Auto) - 0 - Dim CurrentCompressLevel As Integer = - If(ColumnExtend.Width.IsStar, 0, If(ColumnTitle.Width.IsStar, 2, 1)) 'Subtitle 可能是 Collapsed - Dim NewCompressLevel As Integer - Select Case CurrentCompressLevel - Case 0 - If ColumnExtend.ActualWidth < 0.5 Then - NewCompressLevel = If(LabSubtitle.Visibility = Visibility.Collapsed, 2, 1) - Else - Return - End If - Case 1 - If ColumnSubtitle.ActualWidth < 0.5 Then - NewCompressLevel = 2 - ElseIf Not LabSubtitle.IsTextTrimmed Then - NewCompressLevel = 0 - Else - Return - End If - Case 2 - If Not LabTitle.IsTextTrimmed Then - NewCompressLevel = If(LabSubtitle.Visibility = Visibility.Collapsed, 0, 1) - Else - Return - End If - End Select - Select Case NewCompressLevel - Case 0 - '全部舒展:Auto - Auto - (Auto) - 1* - ColumnTitle.Width = GridLength.Auto - ColumnSubtitle.Width = GridLength.Auto - ColumnExtend.Width = New GridLength(1, GridUnitType.Star) - Case 1 - '压缩 Subtitle:Auto - 1* - (Auto) - 0 - ColumnTitle.Width = GridLength.Auto - ColumnSubtitle.Width = New GridLength(1, GridUnitType.Star) - ColumnExtend.Width = New GridLength(0, GridUnitType.Pixel) - Case 2 - '继续压缩 Title:1* - 0 - (Auto) - 0 - ColumnTitle.Width = New GridLength(1, GridUnitType.Star) - ColumnSubtitle.Width = New GridLength(0, GridUnitType.Pixel) - ColumnExtend.Width = New GridLength(0, GridUnitType.Pixel) - End Select + Private Sub PanTitle_SizeChanged(sender As Object, e As SizeChangedEventArgs) Handles PanTitle.SizeChanged + If ColumnExtend.Width.IsStar AndAlso ColumnExtend.ActualWidth < 0.5 Then + '压缩 Subtitle + ColumnSubtitle.Width = New GridLength(1, GridUnitType.Star) + ColumnExtend.Width = New GridLength(0, GridUnitType.Pixel) + ElseIf Not ColumnExtend.Width.IsStar AndAlso Not LabSubtitle.IsTextTrimmed Then + '向右展开 Subtitle + ColumnSubtitle.Width = GridLength.Auto + ColumnExtend.Width = New GridLength(1, GridUnitType.Star) + End If End Sub End Class diff --git a/Plain Craft Launcher 2/Modules/ModEvent.vb b/Plain Craft Launcher 2/Modules/ModEvent.vb index be69955b..e5282a97 100644 --- a/Plain Craft Launcher 2/Modules/ModEvent.vb +++ b/Plain Craft Launcher 2/Modules/ModEvent.vb @@ -92,18 +92,7 @@ MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL 不支持其他乱七八糟的下载协议。", "事件执行失败") Exit Sub End If - Try - Select Case Data.Length - Case 1 - PageOtherTest.StartCustomDownload(Data(0), GetFileNameFromPath(Data(0))) - Case 2 - PageOtherTest.StartCustomDownload(Data(0), Data(1)) - Case Else - PageOtherTest.StartCustomDownload(Data(0), Data(1), Data(2)) - End Select - Catch - PageOtherTest.StartCustomDownload(Data(0), "未知") - End Try + PageOtherTest.StartCustomDownload(Data(0), GetFileNameFromPath(Data(0))) Case Else MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败") @@ -139,6 +128,7 @@ Dim LocalTemp1 As String = PathTemp & "CustomEvent\" & RawFileName Dim LocalTemp2 As String = PathTemp & "CustomEvent\" & RawFileName.Replace(".json", ".xaml") Log("[Event] 转换网络资源:" & RelativeUrl & " -> " & LocalTemp1) + Hint("正在获取资源,请稍候……") Try NetDownload(RelativeUrl, LocalTemp1) NetDownload(RelativeUrl.Replace(".json", ".xaml"), LocalTemp1.Replace(".json", ".xaml")) diff --git a/Plain Craft Launcher 2/Modules/ModMain.vb b/Plain Craft Launcher 2/Modules/ModMain.vb index b5b6bbe0..c5a24256 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.vb +++ b/Plain Craft Launcher 2/Modules/ModMain.vb @@ -456,10 +456,6 @@ EndHint: #Region "帮助" Public Class HelpEntry - ''' - ''' 原始信息路径。用于刷新。 - ''' - Public RawPath As String '基础 @@ -518,7 +514,6 @@ EndHint: ''' 从文件初始化 HelpEntry 对象,失败会抛出异常。 ''' Public Sub New(FilePath As String) - RawPath = FilePath Dim JsonData As JObject = GetJson(HelpArgumentReplace(ReadFile(FilePath))) If JsonData Is Nothing Then Throw New FileNotFoundException("未找到帮助文件:" & FilePath, FilePath) '加载常规信息 @@ -616,7 +611,7 @@ EndHint: '加载忽略列表 Log("[Help] 发现 .helpignore 文件:" & File.FullName) For Each Line In ReadFile(File.FullName).Split(vbCrLf.ToCharArray) - Dim RealString As String = Line.BeforeFirst("#").Trim + Dim RealString As String = Line.Before("#").Trim If String.IsNullOrWhiteSpace(RealString) Then Continue For IgnoreList.Add(RealString) If ModeDebug Then Log("[Help] > " & RealString) diff --git a/Plain Craft Launcher 2/Modules/ModMusic.vb b/Plain Craft Launcher 2/Modules/ModMusic.vb index 6a7e34d1..52a87a85 100644 --- a/Plain Craft Launcher 2/Modules/ModMusic.vb +++ b/Plain Craft Launcher 2/Modules/ModMusic.vb @@ -14,8 +14,8 @@ ''' 初始化音乐播放列表。 ''' ''' 强制全部重新载入列表。 - ''' 在重载列表时避免让某项成为第一项。 - Private Sub MusicListInit(ForceReload As Boolean, Optional PreventFirst As String = Nothing) + ''' 在重载列表时避免让某项成为第一项。 + Private Sub MusicListInit(ForceReload As Boolean, Optional IgnoreFirst As String = "") If ForceReload Then MusicAllList = Nothing Try '初始化全部可用音乐列表 @@ -31,10 +31,10 @@ End If '打乱顺序播放 MusicWaitingList = If(Setup.Get("UiMusicRandom"), Shuffle(New List(Of String)(MusicAllList)), New List(Of String)(MusicAllList)) - If PreventFirst IsNot Nothing AndAlso MusicWaitingList.FirstOrDefault = PreventFirst Then + If Not IgnoreFirst = "" AndAlso Not Not MusicWaitingList.Any() AndAlso MusicWaitingList(0) = IgnoreFirst Then '若需要避免成为第一项的为第一项,则将它放在最后 MusicWaitingList.RemoveAt(0) - MusicWaitingList.Add(PreventFirst) + MusicWaitingList.Add(IgnoreFirst) End If Catch ex As Exception Log(ex, "初始化音乐列表失败", LogLevel.Feedback) @@ -42,18 +42,13 @@ End Sub ''' ''' 获取下一首播放的音乐路径并将其从列表中移除。 - ''' 如果没有,可能会返回 Nothing。 ''' Private Function DequeueNextMusicAddress() As String '初始化,确保存在音乐 If MusicAllList Is Nothing OrElse Not MusicAllList.Any() OrElse Not MusicWaitingList.Any() Then MusicListInit(False) '出列下一个音乐,如果出列结束则生成新列表 - If MusicWaitingList.Any() Then - DequeueNextMusicAddress = MusicWaitingList(0) - MusicWaitingList.RemoveAt(0) - Else - DequeueNextMusicAddress = Nothing - End If + DequeueNextMusicAddress = MusicWaitingList(0) + MusicWaitingList.RemoveAt(0) If Not MusicWaitingList.Any() Then MusicListInit(False, DequeueNextMusicAddress) End Function @@ -65,45 +60,44 @@ ''' 刷新背景音乐按钮 UI 与设置页 UI。 ''' Private Sub MusicRefreshUI() - RunInUi( - Sub() - Try + RunInUi(Sub() + Try - If Not MusicAllList.Any() Then - '无背景音乐 - FrmMain.BtnExtraMusic.Show = False - Else - '有背景音乐 - FrmMain.BtnExtraMusic.Show = True - Dim ToolTipText As String - If MusicState = MusicStates.Pause Then - FrmMain.BtnExtraMusic.Logo = Logo.IconPlay - FrmMain.BtnExtraMusic.LogoScale = 0.8 - ToolTipText = "已暂停:" & GetFileNameWithoutExtentionFromPath(MusicCurrent) - If MusicAllList.Count > 1 Then - ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。" + If Not MusicAllList.Any() Then + '无背景音乐 + FrmMain.BtnExtraMusic.Show = False Else - ToolTipText += vbCrLf & "左键恢复播放,右键重新从头播放。" + '有背景音乐 + FrmMain.BtnExtraMusic.Show = True + Dim ToolTipText As String + If MusicState = MusicStates.Pause Then + FrmMain.BtnExtraMusic.Logo = Logo.IconPlay + FrmMain.BtnExtraMusic.LogoScale = 0.8 + ToolTipText = "已暂停:" & GetFileNameWithoutExtentionFromPath(MusicCurrent) + If MusicAllList.Count > 1 Then + ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。" + Else + ToolTipText += vbCrLf & "左键恢复播放,右键重新从头播放。" + End If + Else + FrmMain.BtnExtraMusic.Logo = Logo.IconMusic + FrmMain.BtnExtraMusic.LogoScale = 1 + ToolTipText = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent) + If MusicAllList.Count > 1 Then + ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。" + Else + ToolTipText += vbCrLf & "左键暂停,右键重新从头播放。" + End If + End If + FrmMain.BtnExtraMusic.ToolTip = ToolTipText + ToolTipService.SetVerticalOffset(FrmMain.BtnExtraMusic, If(ToolTipText.Contains(vbLf), 10, 16)) End If - Else - FrmMain.BtnExtraMusic.Logo = Logo.IconMusic - FrmMain.BtnExtraMusic.LogoScale = 1 - ToolTipText = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent) - If MusicAllList.Count > 1 Then - ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。" - Else - ToolTipText += vbCrLf & "左键暂停,右键重新从头播放。" - End If - End If - FrmMain.BtnExtraMusic.ToolTip = ToolTipText - ToolTipService.SetVerticalOffset(FrmMain.BtnExtraMusic, If(ToolTipText.Contains(vbLf), 10, 16)) - End If - If FrmSetupUI IsNot Nothing Then FrmSetupUI.MusicRefreshUI() + If FrmSetupUI IsNot Nothing Then FrmSetupUI.MusicRefreshUI() - Catch ex As Exception - Log(ex, "刷新背景音乐 UI 失败", LogLevel.Feedback) - End Try - End Sub) + Catch ex As Exception + Log(ex, "刷新背景音乐 UI 失败", LogLevel.Feedback) + End Try + End Sub) End Sub ''' @@ -134,12 +128,8 @@ Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Finish) Else Dim Address As String = DequeueNextMusicAddress() - If Address Is Nothing Then - Hint("没有可以播放的音乐!", HintType.Critical) - Else - MusicStartPlay(Address) - Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish) - End If + MusicStartPlay(Address) + Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish) End If MusicRefreshUI() End Sub @@ -189,15 +179,11 @@ End If Else Dim Address As String = DequeueNextMusicAddress() - If Address Is Nothing Then - If ShowHint Then Hint("没有可以播放的音乐!", HintType.Critical) - Else - Try - MusicStartPlay(Address, IsFirstLoad) - If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Finish, False) - Catch - End Try - End If + Try + MusicStartPlay(Address, IsFirstLoad) + If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Finish, False) + Catch + End Try End If MusicRefreshUI() @@ -209,7 +195,6 @@ ''' 开始播放音乐。 ''' Private Sub MusicStartPlay(Address As String, Optional IsFirstLoad As Boolean = False) - If Address Is Nothing Then Return Log("[Music] 播放开始:" & Address) MusicCurrent = Address RunInNewThread(Sub() MusicLoop(IsFirstLoad), "Music", ThreadPriority.BelowNormal) @@ -302,21 +287,15 @@ End If If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 不支持播放音频属性在中途发生变化的音乐", HintType.Critical) - ElseIf Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse - ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4) + ElseIf Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) Then Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Critical) Else Log(ex, "播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & ")", LogLevel.Hint) End If - '将播放错误的音乐从列表中移除 - MusicAllList.Remove(MusicCurrent) - MusicWaitingList.Remove(MusicCurrent) - MusicRefreshUI() - '等待 2 秒后继续播放 - Thread.Sleep(2000) + Thread.Sleep(1000) If TypeOf ex Is FileNotFoundException Then MusicRefreshPlay(True, IsFirstLoad) - Else + ElseIf MusicAllList.Count > 1 Then MusicStartPlay(DequeueNextMusicAddress(), IsFirstLoad) End If Finally diff --git a/Plain Craft Launcher 2/Modules/ModSecret.vb b/Plain Craft Launcher 2/Modules/ModSecret.vb index f4e80892..698c7af4 100644 --- a/Plain Craft Launcher 2/Modules/ModSecret.vb +++ b/Plain Craft Launcher 2/Modules/ModSecret.vb @@ -106,29 +106,29 @@ PCL-Community 及其成员与龙腾猫跃无从属关系,且均不会为您的 ''' 设置 Headers 的 UA、Referer。 ''' Friend Sub SecretHeadersSign(Url As String, ByRef Client As WebClient, Optional UseBrowserUserAgent As Boolean = False) - If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then - Client.Headers("User-Agent") = "LogStatistic" '#4951 + If Url.Contains("modrinth.com") Then '根据 #4334,不添加 PCL 的 UA 反而能正常访问 + Client.Headers("User-Agent") = "Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36" ElseIf UseBrowserUserAgent Then Client.Headers("User-Agent") = "PCL2/" & VersionStandardCode & " Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36" Else Client.Headers("User-Agent") = "PCL2/" & VersionStandardCode End If Client.Headers("Referer") = "http://" & VersionCode & ".pcl2.open.server/" - If Url.Contains("api.curseforge.com") Then Client.Headers("x-api-key") = CurseForgeAPIKey + Client.Headers("x-api-key") = CurseForgeAPIKey End Sub ''' ''' 设置 Headers 的 UA、Referer。 ''' Friend Sub SecretHeadersSign(Url As String, ByRef Request As HttpWebRequest, Optional UseBrowserUserAgent As Boolean = False) - If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then - Request.UserAgent = "LogStatistic" '#4951 + If Url.Contains("modrinth.com") Then '根据 #4334,不添加 PCL 的 UA 反而能正常访问 + Request.UserAgent = "Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36" ElseIf UseBrowserUserAgent Then Request.UserAgent = "PCL2/" & VersionStandardCode & " Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36" Else Request.UserAgent = "PCL2/" & VersionStandardCode End If Request.Referer = "http://" & VersionCode & ".pcl2.open.server/" - If Url.Contains("api.curseforge.com") Then Request.Headers("x-api-key") = CurseForgeAPIKey + Request.Headers("x-api-key") = CurseForgeAPIKey End Sub #End Region diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb index c5cbc7b0..59171f6c 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/PageDownload/ModDownloadLib.vb b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb index 078fb785..9189c903 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb @@ -1,5 +1,4 @@ Imports System.IO.Compression -Imports System.Net.Http Public Module ModDownloadLib @@ -72,7 +71,7 @@ Public Module ModDownloadLib VersionFolder = VersionFolder & Id & "\" '重复任务检查 - For Each OngoingLoader In LoaderTaskbar + For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"Minecraft {Id} 下载" Then Continue For If Behaviour = NetPreDownloadBehaviour.ExitWhileExistsOrDownloading Then Exit Sub Hint("该版本正在下载中!", HintType.Critical) @@ -81,14 +80,14 @@ Public Module ModDownloadLib Dim Loaders As New List(Of LoaderBase) '下载版本 Json 文件 - Loaders.Add(New LoaderDownload("下载版本 Json 文件", New List(Of NetFile) From { + Loaders.Add(New LoaderDownload("下载版本 json 文件", New List(Of NetFile) From { New NetFile(DlSourceLauncherOrMetaGet(JsonUrl), VersionFolder & Id & ".json", New FileChecker(CanUseExistsFile:=False, IsJson:=True)) }) With {.ProgressWeight = 2}) '获取支持库文件地址 - Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析核心 Jar 文件下载地址", - Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 0.5, .Show = False}) + Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析核心 jar 文件下载地址", + Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder), True)) With {.ProgressWeight = 0.5, .Show = False}) '下载支持库文件 - Loaders.Add(New LoaderDownload("下载核心 Jar 文件", New List(Of NetFile)) With {.ProgressWeight = 5}) + Loaders.Add(New LoaderDownload("下载核心 jar 文件", New List(Of NetFile)) With {.ProgressWeight = 5}) '启动 Dim Loader As New LoaderCombo(Of String)("Minecraft " & Id & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave} @@ -208,12 +207,7 @@ Public Module ModDownloadLib ToolTipService.SetVerticalOffset(BtnInfo, 30) ToolTipService.SetHorizontalOffset(BtnInfo, 2) AddHandler BtnInfo.Click, AddressOf McDownloadMenuLog - Dim BtnServer As New MyIconButton With {.LogoScale = 1, .Logo = Logo.IconButtonServer, .ToolTip = "下载服务端"} - ToolTipService.SetPlacement(BtnServer, Primitives.PlacementMode.Center) - ToolTipService.SetVerticalOffset(BtnServer, 30) - ToolTipService.SetHorizontalOffset(BtnServer, 2) - AddHandler BtnServer.Click, AddressOf McDownloadMenuSaveServer - sender.Buttons = {BtnServer, BtnInfo} + sender.Buttons = {BtnInfo} End Sub Private Sub McDownloadMenuBuild(sender As Object, e As EventArgs) Dim BtnSave As New MyIconButton With {.Logo = Logo.IconButtonSave, .ToolTip = "另存为"} @@ -226,12 +220,7 @@ Public Module ModDownloadLib ToolTipService.SetVerticalOffset(BtnInfo, 30) ToolTipService.SetHorizontalOffset(BtnInfo, 2) AddHandler BtnInfo.Click, AddressOf McDownloadMenuLog - Dim BtnServer As New MyIconButton With {.LogoScale = 1, .Logo = Logo.IconButtonServer, .ToolTip = "下载服务端"} - ToolTipService.SetPlacement(BtnServer, Primitives.PlacementMode.Center) - ToolTipService.SetVerticalOffset(BtnServer, 30) - ToolTipService.SetHorizontalOffset(BtnServer, 2) - AddHandler BtnServer.Click, AddressOf McDownloadMenuSaveServer - sender.Buttons = {BtnSave, BtnInfo, BtnServer} + sender.Buttons = {BtnSave, BtnInfo} End Sub Private Sub McDownloadMenuLog(sender As Object, e As RoutedEventArgs) Dim Version As JToken @@ -244,83 +233,6 @@ Public Module ModDownloadLib End If McUpdateLogShow(Version) End Sub - Private Sub McDownloadMenuSaveServer(sender As Object, e As RoutedEventArgs) - Dim Version As MyListItem - If TypeOf sender Is MyListItem Then - Version = sender - ElseIf TypeOf sender.Parent Is MyListItem Then - Version = sender.Parent - Else - Version = sender.Parent.Parent - End If - Try - Dim Id = Version.Title - Dim JsonUrl = Version.Tag("url").ToString - Dim VersionFolder As String = SelectFolder() - If Not VersionFolder.Contains("\") Then Exit Sub - VersionFolder = VersionFolder & Id & "\" - - '重复任务检查 - For Each OngoingLoader In LoaderTaskbar.ToList() - If OngoingLoader.Name <> $"Minecraft {Id} 服务端下载" Then Continue For - Hint("该服务端正在下载中!", HintType.Critical) - Exit Sub - Next - - Dim Loaders As New List(Of LoaderBase) - '下载版本 JSON 文件 - Loaders.Add(New LoaderDownload("下载版本 JSON 文件", New List(Of NetFile) From { - New NetFile(DlSourceLauncherOrMetaGet(JsonUrl), VersionFolder & Id & ".json", New FileChecker(CanUseExistsFile:=False, IsJson:=True)) - }) With {.ProgressWeight = 2}) - '构建服务端 - Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("构建服务端", - Sub(Task As LoaderTask(Of String, List(Of NetFile))) - '分析服务端 JAR 文件下载地址 - Dim McVersion As New McVersion(VersionFolder) - If McVersion.JsonObject("downloads") Is Nothing OrElse McVersion.JsonObject("downloads")("server") Is Nothing OrElse McVersion.JsonObject("downloads")("server")("url") Is Nothing Then - File.Delete(VersionFolder & Id & ".json") - If Not New DirectoryInfo(VersionFolder).GetFileSystemInfos.Any() Then Directory.Delete(VersionFolder) - Task.Output = New List(Of NetFile) - Hint($"Mojang 没有给 Minecraft {Id} 提供官方服务端下载,没法下,撤退!", HintType.Critical) - Thread.Sleep(2000) '等玩家把上一个提示看完 - Task.Abort() - Exit Sub - End If - Dim JarUrl As String = McVersion.JsonObject("downloads")("server")("url") - Dim Checker As New FileChecker(MinSize:=1024, ActualSize:=If(McVersion.JsonObject("downloads")("server")("size"), -1), Hash:=McVersion.JsonObject("downloads")("server")("sha1")) - Task.Output = New List(Of NetFile) From {New NetFile(DlSourceLauncherOrMetaGet(JarUrl), VersionFolder & Id & "-server.jar", Checker)} - '添加启动脚本 - Dim Bat As String = -$"@echo off -title {Id} 原版服务端 -echo 如果服务端立即停止,请右键编辑该脚本,将下一行开头的 java 替换为适合该 Minecraft 版本的完整 java.exe 的路径。 -echo 你可以在 PCL 的 [设置 → 启动选项] 中查看已安装的 java,所需的 java.exe 一般在其中的 bin 文件夹下。 -echo ------------------------------ -echo 如果提示 ""You need to agree to the EULA in order to run the server"",请打开 eula.txt,按说明阅读并同意 Minecraft EULA 后,将该文件最后一行中的 eula=false 改为 eula=true。 -echo ------------------------------ -""java"" -server -XX:+UseG1GC -Xmx4096M -Xms1024M -XX:+UseCompressedOops -jar {Id}-server.jar nogui -echo ---------------------- -echo 服务端已停止。 -pause" - WriteFile(VersionFolder & "Launch Server.bat", Bat, - Encoding:=If(Encoding.Default.Equals(Encoding.UTF8), Encoding.UTF8, Encoding.GetEncoding("GB18030"))) - '删除版本 JSON - File.Delete(VersionFolder & Id & ".json") - End Sub - ) With {.ProgressWeight = 0.5, .Show = False}) - '下载服务端文件 - Loaders.Add(New LoaderDownload("下载服务端文件", New List(Of NetFile)) With {.ProgressWeight = 5}) - - '启动 - Dim Loader As New LoaderCombo(Of String)("Minecraft " & Id & " 服务端下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave} - Loader.Start(Id) - LoaderTaskbarAdd(Loader) - FrmMain.BtnExtraDownload.ShowRefresh() - FrmMain.BtnExtraDownload.Ribble() - Catch ex As Exception - Log(ex, "开始 Minecraft 服务端下载失败", LogLevel.Feedback) - End Try - End Sub Public Sub McDownloadMenuSave(sender As Object, e As RoutedEventArgs) Dim Version As MyListItem If TypeOf sender Is MyListItem Then @@ -330,41 +242,7 @@ pause" Else Version = sender.Parent.Parent End If - Try - Dim Id = Version.Title - Dim JsonUrl = Version.Tag("url").ToString - Dim VersionFolder As String = SelectFolder() - If Not VersionFolder.Contains("\") Then Exit Sub - VersionFolder = VersionFolder & Id & "\" - - '重复任务检查 - For Each OngoingLoader In LoaderTaskbar.ToList() - If OngoingLoader.Name <> $"Minecraft {Id} 下载" Then Continue For - Hint("该版本正在下载中!", HintType.Critical) - Exit Sub - Next - - Dim Loaders As New List(Of LoaderBase) - '下载版本 JSON 文件 - Loaders.Add(New LoaderDownload("下载版本 JSON 文件", New List(Of NetFile) From { - New NetFile(DlSourceLauncherOrMetaGet(JsonUrl), VersionFolder & Id & ".json", New FileChecker(CanUseExistsFile:=False, IsJson:=True)) - }) With {.ProgressWeight = 2}) - '获取支持库文件地址 - Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析核心 JAR 文件下载地址", - Sub(Task) Task.Output = New List(Of NetFile) From {DlClientJarGet(New McVersion(VersionFolder), False)} - ) With {.ProgressWeight = 0.5, .Show = False}) - '下载支持库文件 - Loaders.Add(New LoaderDownload("下载核心 JAR 文件", New List(Of NetFile)) With {.ProgressWeight = 5}) - - '启动 - Dim Loader As New LoaderCombo(Of String)("Minecraft " & Id & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave} - Loader.Start(Id) - LoaderTaskbarAdd(Loader) - FrmMain.BtnExtraDownload.ShowRefresh() - FrmMain.BtnExtraDownload.Ribble() - Catch ex As Exception - Log(ex, "开始 Minecraft 下载失败", LogLevel.Feedback) - End Try + McDownloadClientCore(Version.Title, Version.Tag("url").ToString, NetPreDownloadBehaviour.HintWhileExists) End Sub ''' ''' 显示某 Minecraft 版本的更新日志。 @@ -519,7 +397,7 @@ pause" '添加 Java Wrapper 作为主 Jar Dim Arguments As String If UseJavaWrapper Then - Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -Duser.home=""{BaseMcFolderHome}"" -cp ""{Target}"" -jar ""{ExtractJavaWrapper()}"" optifine.Installer" + Arguments = $"-Doolloo.jlw.tmpdir=""{GetPureASCIIDir()}"" -Duser.home=""{BaseMcFolderHome}"" -cp ""{Target}"" -jar ""{ExtractJavaWrapper()}"" optifine.Installer" Else Arguments = $"-Duser.home=""{BaseMcFolderHome}"" -cp ""{Target}"" optifine.Installer" End If @@ -638,12 +516,10 @@ pause" Task.Progress = 0.1 Dim Sources As New List(Of String) 'BMCLAPI 源 - Dim BmclapiInherit As String = DownloadInfo.Inherit - If BmclapiInherit = "1.8" OrElse BmclapiInherit = "1.9" Then BmclapiInherit &= ".0" '#4281 If DownloadInfo.IsPreview Then - Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & BmclapiInherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/")) + Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/")) Else - Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & BmclapiInherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "")) + Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "")) End If '官方源 Dim PageData As String @@ -651,10 +527,12 @@ pause" PageData = NetGetCodeByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile, New UTF8Encoding(False), 15000, "text/html", True) Task.Progress = 0.8 Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0)) - Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last) + Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources(0)) Catch ex As Exception Log(ex, "获取 OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址失败") End Try + 'OptiFine 中文镜像源 + Sources.Add("https://optifine.cn/download/" & DownloadInfo.NameFile) '构造文件请求 Task.Output = New List(Of NetFile) From {New NetFile(Sources.ToArray, Target, New FileChecker(MinSize:=300 * 1024))} End Sub) With {.ProgressWeight = 8}) @@ -801,12 +679,10 @@ Retry: Sub(Task As LoaderTask(Of DlOptiFineListEntry, List(Of NetFile))) Dim Sources As New List(Of String) 'BMCLAPI 源 - Dim BmclapiInherit As String = DownloadInfo.Inherit - If BmclapiInherit = "1.8" OrElse BmclapiInherit = "1.9" Then BmclapiInherit &= ".0" '#4281 If DownloadInfo.IsPreview Then - Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & BmclapiInherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/")) + Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/")) Else - Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & BmclapiInherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "")) + Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "")) End If '官方源 Dim PageData As String @@ -814,7 +690,7 @@ Retry: PageData = NetGetCodeByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile, New UTF8Encoding(False), 15000, "text/html", True) Task.Progress = 0.8 Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0)) - Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last) + Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources(0)) Catch ex As Exception Log(ex, "获取 OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址失败") End Try @@ -1188,7 +1064,7 @@ Retry: '添加 Java Wrapper 作为主 Jar Dim Arguments As String If UseJavaWrapper Then - Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{ExtractJavaWrapper()}"" com.bangbang93.ForgeInstaller ""{McFolder}" + Arguments = $"-Doolloo.jlw.tmpdir=""{GetPureASCIIDir()}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{ExtractJavaWrapper()}"" com.bangbang93.ForgeInstaller ""{McFolder}" Else Arguments = $"-cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" com.bangbang93.ForgeInstaller ""{McFolder}" End If @@ -1337,8 +1213,8 @@ Retry: End If If Not IsNeoForge AndAlso LoaderVersion.StartsWithF("1.") AndAlso LoaderVersion.Contains("-") Then '类似 1.19.3-41.2.8 格式,优先使用 Version 中要求的版本而非 Inherit(例如 1.19.3 却使用了 1.19 的 Forge) - Inherit = LoaderVersion.BeforeFirst("-") - LoaderVersion = LoaderVersion.AfterLast("-") + Inherit = LoaderVersion.Before("-") + LoaderVersion = LoaderVersion.After("-") End If Dim LoaderName As String = If(IsNeoForge, "NeoForge", "Forge") Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder @@ -1398,7 +1274,7 @@ Retry: Loaders.Add(New LoaderDownload($"下载 {LoaderName} 主文件", New List(Of NetFile)) With {.ProgressWeight = 9}) '安装(仅在新版安装时需要原版 Jar) - If IsNeoForge OrElse LoaderVersion.BeforeFirst(".") >= 20 Then + If IsNeoForge OrElse LoaderVersion.Before(".") >= 20 Then Log($"[Download] 检测为{If(IsNeoForge, " Neo", "新版 ")}Forge:" & LoaderVersion) Dim Libs As List(Of McLibToken) = Nothing Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"分析 {LoaderName} 支持库文件", @@ -1420,7 +1296,7 @@ Retry: Task.Progress = 0.4 Dim RawJson As JObject = GetJson(NetGetCodeByDownload(DlSourceLauncherOrMetaGet(DlClientListGet(Inherit)), IsJson:=True)) '[net.minecraft:client:1.17.1-20210706.113038:mappings@txt] 或 @tsrg] - Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).BeforeFirst("@") + Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Before("@") Dim Address = McLibGet(OriginalName).Replace(".jar", "-mappings." & Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(1)) Dim ClientMappings As JToken = RawJson("downloads")("client_mappings") Libs.Add(New McLibToken With { @@ -1543,6 +1419,8 @@ Retry: '没有新增文件夹 Log("[Download] 未找到新增的版本文件夹") End If + '新建 mods 文件夹 + Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\") Catch ex As Exception Throw New Exception($"安装新 {LoaderName} 版本失败", ex) Finally @@ -1558,52 +1436,54 @@ Retry: Else Log("[Download] 检测为非新版 Forge:" & LoaderVersion) Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)($"安装 {LoaderName}(方式 B)", - Sub(Task As LoaderTask(Of List(Of NetFile), Boolean)) - Dim Installer As ZipArchive = Nothing - Try - '解压并获取信息 - Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open)) - Task.Progress = 0.2 - Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open)) - Task.Progress = 0.4 - '新建版本文件夹 - Directory.CreateDirectory(VersionFolder) - Task.Progress = 0.5 - If Json("install") Is Nothing Then - '中版:Legacy 方式 1 - Log("[Download] 开始进行 Forge 安装,Legacy 方式 1:" & InstallerAddress) - '建立 Json 文件 - Dim JsonVersion As JObject = GetJson(ReadFile(Installer.GetEntry(Json("json").ToString.TrimStart("/")).Open)) - JsonVersion("id") = TargetVersion - WriteFile(VersionFolder & TargetVersion & ".json", JsonVersion.ToString) - Task.Progress = 0.6 - '解压支持库文件 - Installer.Dispose() - ExtractFile(InstallerAddress, InstallerAddress & "_unrar\") - CopyDirectory(InstallerAddress & "_unrar\maven\", McFolder & "libraries\") - DeleteDirectory(InstallerAddress & "_unrar\") - Else - '旧版:Legacy 方式 2 - Log("[Download] 开始进行 Forge 安装,Legacy 方式 2:" & InstallerAddress) - '解压 Jar 文件 - Dim JarAddress As String = McLibGet(Json("install")("path"), CustomMcFolder:=McFolder) - If File.Exists(JarAddress) Then File.Delete(JarAddress) - WriteFile(JarAddress, Installer.GetEntry(Json("install")("filePath")).Open) - Task.Progress = 0.9 - '建立 Json 文件 - Json("versionInfo")("id") = TargetVersion - If Json("versionInfo")("inheritsFrom") Is Nothing Then CType(Json("versionInfo"), JObject).Add("inheritsFrom", Inherit) - WriteFile(VersionFolder & TargetVersion & ".json", Json("versionInfo").ToString) - End If - Catch ex As Exception - Throw New Exception("非新版方式安装 Forge 失败", ex) - Finally - Try - '清理文件 - If Installer IsNot Nothing Then Installer.Dispose() - If File.Exists(InstallerAddress) Then File.Delete(InstallerAddress) - If Directory.Exists(InstallerAddress & "_unrar\") Then DeleteDirectory(InstallerAddress & "_unrar\") - Catch ex As Exception +Sub(Task As LoaderTask(Of List(Of NetFile), Boolean)) + Dim Installer As ZipArchive = Nothing + Try + '解压并获取信息 + Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open)) + Task.Progress = 0.2 + Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open)) + Task.Progress = 0.4 + '新建版本文件夹 + Directory.CreateDirectory(VersionFolder) + Task.Progress = 0.5 + If Json("install") Is Nothing Then + '中版:Legacy 方式 1 + Log("[Download] 开始进行 Forge 安装,Legacy 方式 1:" & InstallerAddress) + '建立 Json 文件 + Dim JsonVersion As JObject = GetJson(ReadFile(Installer.GetEntry(Json("json").ToString.TrimStart("/")).Open)) + JsonVersion("id") = TargetVersion + WriteFile(VersionFolder & TargetVersion & ".json", JsonVersion.ToString) + Task.Progress = 0.6 + '解压支持库文件 + Installer.Dispose() + ExtractFile(InstallerAddress, InstallerAddress & "_unrar\") + CopyDirectory(InstallerAddress & "_unrar\maven\", McFolder & "libraries\") + DeleteDirectory(InstallerAddress & "_unrar\") + Else + '旧版:Legacy 方式 2 + Log("[Download] 开始进行 Forge 安装,Legacy 方式 2:" & InstallerAddress) + '解压 Jar 文件 + Dim JarAddress As String = McLibGet(Json("install")("path"), CustomMcFolder:=McFolder) + If File.Exists(JarAddress) Then File.Delete(JarAddress) + WriteFile(JarAddress, Installer.GetEntry(Json("install")("filePath")).Open) + Task.Progress = 0.9 + '建立 Json 文件 + Json("versionInfo")("id") = TargetVersion + If Json("versionInfo")("inheritsFrom") Is Nothing Then CType(Json("versionInfo"), JObject).Add("inheritsFrom", Inherit) + WriteFile(VersionFolder & TargetVersion & ".json", Json("versionInfo").ToString) + End If + '新建 mods 文件夹 + Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\") + Catch ex As Exception + Throw New Exception("非新版方式安装 Forge 失败", ex) + Finally + Try + '清理文件 + If Installer IsNot Nothing Then Installer.Dispose() + If File.Exists(InstallerAddress) Then File.Delete(InstallerAddress) + If Directory.Exists(InstallerAddress & "_unrar\") Then DeleteDirectory(InstallerAddress & "_unrar\") + Catch ex As Exception Log(ex, "非新版方式安装 Forge 清理文件时出错") End Try End Try @@ -1923,6 +1803,8 @@ Retry: "https://bmclapi2.bangbang93.com/fabric-meta/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json", "https://meta.fabricmc.net/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json" }, VersionFolder & Id & ".json", New FileChecker(IsJson:=True))} + '新建 mods 文件夹 + Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\") End Sub) With {.ProgressWeight = 0.5}) Loaders.Add(New LoaderDownload("下载 Fabric 主文件", New List(Of NetFile)) With {.ProgressWeight = 2.5}) @@ -1954,7 +1836,7 @@ Retry: Public Function FabricApiDownloadListItem(Entry As CompFile, OnClick As MyListItem.ClickEventHandler) As MyListItem '建立控件 Dim NewItem As New MyListItem With { - .Title = Entry.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").BeforeFirst("+").Trim, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, + .Title = Entry.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").Before("+").Trim, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .Info = Entry.StatusDescription & ",发布于 " & Entry.ReleaseDate.ToString("yyyy'/'MM'/'dd HH':'mm"), .Logo = PathImage & "Blocks/Fabric.png" } @@ -2234,8 +2116,6 @@ Retry: FrmMain.BtnExtraDownload.Ribble() Return True - Catch ex As CancelledException - Return False Catch ex As Exception Log(ex, "开始合并安装失败", LogLevel.Feedback) Return False @@ -2243,8 +2123,8 @@ Retry: End Function ''' ''' 获取合并安装加载器列表,并进行前期的缓存清理与 Java 检查工作。 + ''' 如果出现已知问题且已提示用户,则返回 Nothing。出现异常则直接抛出。 ''' - ''' Public Function McInstallLoader(Request As McInstallRequest, Optional DontFixLibraries As Boolean = False) As List(Of LoaderBase) '获取缓存目录 Dim PathInstallTemp As String @@ -2256,10 +2136,11 @@ Retry: '清理缓存 Try - If IsInstallTempCleared Then Exit Try - IsInstallTempCleared = True - DeleteDirectory(PathInstallTemp, True) - Log("[Download] 已清理合并安装缓存") + If Not IsInstallTempCleared Then + IsInstallTempCleared = True + DeleteDirectory(PathInstallTemp, True) + Log("[Download] 已清理合并安装缓存") + End If Catch ex As Exception Log(ex, "清理合并安装缓存失败") End Try @@ -2270,7 +2151,7 @@ Retry: If Directory.Exists(TempMcFolder) Then DeleteDirectory(TempMcFolder) Dim OptiFineFolder As String = Nothing If Request.OptiFineVersion IsNot Nothing Then - If Request.OptiFineVersion.Contains("_HD_U_") Then Request.OptiFineVersion = "HD_U_" & Request.OptiFineVersion.AfterLast("_HD_U_") '#735 + If Request.OptiFineVersion.Contains("_HD_U_") Then Request.OptiFineVersion = "HD_U_" & Request.OptiFineVersion.After("_HD_U_") '#735 Request.OptiFineEntry = New DlOptiFineListEntry With { .NameDisplay = Request.MinecraftName & " " & Request.OptiFineVersion.Replace("HD_U_", "").Replace("_", "").Replace("pre", " pre"), .Inherit = Request.MinecraftName, @@ -2299,11 +2180,9 @@ Retry: Dim OptiFineAsMod As Boolean = Request.OptiFineEntry IsNot Nothing AndAlso '1. 选择了 OptiFine (Request.FabricVersion IsNot Nothing OrElse '2. 选择了 Fabric... (Request.ForgeEntry IsNot Nothing AndAlso MinecraftCode >= 14 AndAlso MinecraftCode <= 15)) '...或者 Forge 1.14~15(#4134) - Dim ModsFolder As String = New McVersion(OutputFolder).GetPathIndie(True) & "mods\" - If OptiFineAsMod Then Log("[Download] OptiFine 将作为 Mod 进行下载") - OptiFineFolder = ModsFolder + OptiFineFolder = New McVersion(OutputFolder).GetPathIndie(True) & "mods\" End If '记录日志 @@ -2318,7 +2197,7 @@ Retry: '重复版本检查 If File.Exists(OutputFolder & Request.TargetVersionName & ".json") Then Hint("版本 " & Request.TargetVersionName & " 已经存在!", HintType.Critical) - Throw New CancelledException + Return Nothing End If Dim LoaderList As New List(Of LoaderBase) @@ -2326,15 +2205,11 @@ Retry: LoaderList.Add(New LoaderTask(Of Integer, Integer)("添加忽略标识", Sub() WriteFile(OutputFolder & ".pclignore", "用于临时地在 PCL 的版本列表中屏蔽此版本。")) With {.Show = False, .Block = False}) 'Fabric API If Request.FabricApi IsNot Nothing Then - LoaderList.Add(New LoaderDownload("下载 Fabric API", New List(Of NetFile) From {Request.FabricApi.ToNetFile(ModsFolder)}) With {.ProgressWeight = 3, .Block = False}) - End If - 'Quilted Fabric API (QFAPI) / Quilt Standard Libraries (QSL) - If Request.QSL IsNot Nothing Then - LoaderList.Add(New LoaderDownload("下载 QFAPI / QSL", New List(Of NetFile) From {Request.QSL.ToNetFile(New McVersion(OutputFolder).GetPathIndie(True) & "mods\")}) With {.ProgressWeight = 3, .Block = False}) + LoaderList.Add(New LoaderDownload("下载 Fabric API", New List(Of NetFile) From {Request.FabricApi.ToNetFile(New McVersion(OutputFolder).GetPathIndie(True) & "mods\")}) With {.ProgressWeight = 3, .Block = False}) End If 'OptiFabric If Request.OptiFabric IsNot Nothing Then - LoaderList.Add(New LoaderDownload("下载 OptiFabric", New List(Of NetFile) From {Request.OptiFabric.ToNetFile(ModsFolder)}) With {.ProgressWeight = 3, .Block = False}) + LoaderList.Add(New LoaderDownload("下载 OptiFabric", New List(Of NetFile) From {Request.OptiFabric.ToNetFile(New McVersion(OutputFolder).GetPathIndie(True) & "mods\")}) With {.ProgressWeight = 3, .Block = False}) End If '原版 Dim ClientLoader = New LoaderCombo(Of String)("下载原版 " & Request.MinecraftName, McDownloadClientLoader(Request.MinecraftName, Request.MinecraftJson, Request.TargetVersionName)) With {.Show = False, .ProgressWeight = 39, .Block = Request.ForgeVersion Is Nothing AndAlso Request.OptiFineEntry Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing} @@ -2373,16 +2248,11 @@ Retry: InstallMerge(OutputFolder, OutputFolder, OptiFineFolder, OptiFineAsMod, ForgeFolder, Request.ForgeVersion, NeoForgeFolder, Request.NeoForgeVersion, FabricFolder, QuiltFolder, LiteLoaderFolder) Task.Progress = 0.3 If Directory.Exists(TempMcFolder & "libraries") Then CopyDirectory(TempMcFolder & "libraries", PathMcFolder & "libraries") - If Directory.Exists(TempMcFolder & "mods") Then CopyDirectory(TempMcFolder & "mods", ModsFolder) - '新建 mods 文件夹 - If Request.ForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.NeoForgeEntry IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing Then - Directory.CreateDirectory(ModsFolder) - Log("[Download] 自动创建 mods 文件夹:" & ModsFolder) - End If + If Directory.Exists(TempMcFolder & "mods") Then CopyDirectory(TempMcFolder & "mods", PathMcFolder & "mods") End Sub) With {.ProgressWeight = 2, .Block = True}) '补全文件 If Not DontFixLibraries AndAlso - (Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.Split(".")(0) >= 20) OrElse Request.NeoForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.QuiltVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing) Then + (Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.Before(".") >= 20) OrElse Request.NeoForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing) Then Dim LoadersLib As New List(Of LoaderBase) LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(OutputFolder))) With {.ProgressWeight = 1, .Show = False}) LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False}) diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml index 8fc4d338..bc4b2ef5 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml @@ -23,13 +23,8 @@ - - - - - - - + + diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb index 2b6218d1..bad9f0e4 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb @@ -34,121 +34,41 @@ End Select End Sub '结果 UI 化 - Private Class CardSorter + Private Class VersionSorterWithSelect Implements IComparer(Of String) - Public Topmost As String = "" + Public Top As String = "" Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare - '相同 If x = y Then Return 0 - '置顶 - If x = Topmost Then Return -1 - If y = Topmost Then Return 1 - '特殊版本 - Dim IsXSpecial As Boolean = x.EndsWithF("版本") - Dim IsYSpecial As Boolean = y.EndsWithF("版本") - If IsXSpecial AndAlso IsYSpecial Then Return x.CompareTo(y) - If IsXSpecial Then Return 1 - If IsYSpecial Then Return -1 - '比较版本号 - Dim VersionCodeSort = -VersionSortInteger(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", "")) - If VersionCodeSort <> 0 Then Return VersionCodeSort - '比较全部 + If x = Top Then Return -1 + If y = Top Then Return 1 Return -VersionSortInteger(x, y) End Function - Public Sub New(Optional Topmost As String = "") - Me.Topmost = If(Topmost, "") + Public Sub New(Optional Top As String = "") + Me.Top = If(Top, "") End Sub End Class - - Private VersionFilter As String - Private IsMajorVersionFilter As Boolean '是否按大版本号筛选(1.21 / 1.20 / 1.19 / ...)而非小版本号(1.21.1 / 1.21 / 1.20.4 / ...) Private Sub Load_OnFinish() - '初始化筛选器 - Dim VersionFilters As List(Of String) - - '按小版本号筛选? - IsMajorVersionFilter = False - VersionFilters = CompFileLoader.Output.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True)). - Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList - '按大版本号筛选? - If VersionFilters.Count >= 9 Then - IsMajorVersionFilter = True - VersionFilters = CompFileLoader.Output.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True)). - Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList - End If - - 'UI 化筛选器 - PanFilter.Children.Clear() - If VersionFilters.Count <= 2 Then - CardFilter.Visibility = Visibility.Collapsed - VersionFilter = Nothing - Else - CardFilter.Visibility = Visibility.Visible - VersionFilters.Insert(0, "全部") - '转化为按钮 - For Each Version As String In VersionFilters - Dim NewButton As New MyRadioButton With { - .Text = Version, .Margin = New Thickness(2, 0, 2, 0), .ColorType = MyRadioButton.ColorState.Highlight} - NewButton.LabText.Margin = New Thickness(-2, 0, 8, 0) - AddHandler NewButton.Check, - Sub(sender As MyRadioButton, raiseByMouse As Boolean) - PanScroll.ScrollToHome() - VersionFilter = If(sender.Text = "全部", Nothing, sender.Text) - UpdateFilterResult() - End Sub - PanFilter.Children.Add(NewButton) - Next - '自动选择 - Dim ToCheck As MyRadioButton = Nothing - If TargetVersion <> "" Then - Dim TargetFile = CompFileLoader.Output.FirstOrDefault(Function(v) v.GameVersions.Contains(TargetVersion)) - If TargetFile IsNot Nothing Then - Dim TargetGroup = GetGroupedVersionName(TargetVersion, IsMajorVersionFilter, True) - For Each Button As MyRadioButton In PanFilter.Children - If Button.Text <> TargetGroup Then Continue For - ToCheck = Button - Exit For - Next - End If - End If - If ToCheck Is Nothing Then ToCheck = PanFilter.Children(0) - ToCheck.Checked = True - End If - - '更新筛选结果(文件列表 UI 化) - UpdateFilterResult() - End Sub - Private Sub UpdateFilterResult() Dim TargetCardName As String = If(TargetVersion <> "" OrElse TargetLoader <> CompModLoaderType.Any, - $"所选版本:{If(TargetLoader <> CompModLoaderType.Any, TargetLoader.ToString & " ", "")}{TargetVersion}", "") - '归类到卡片下 - Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New CardSorter(TargetCardName)) - Dict.Add("其他版本", New List(Of CompFile)) - Dim SupportedLoaders As New List(Of Integer)([Enum].GetValues(GetType(CompModLoaderType))) + $"所选版本:{TargetVersion} {If(TargetLoader <> CompModLoaderType.Any, TargetLoader, "")}", "") + '初始化字典 + Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New VersionSorterWithSelect(TargetCardName)) + Dict.Add("未知版本", New List(Of CompFile)) For Each Version As CompFile In CompFileLoader.Output For Each GameVersion In Version.GameVersions - '检查是否符合版本筛选器 - If VersionFilter IsNot Nothing AndAlso - GetGroupedVersionName(GameVersion, IsMajorVersionFilter, True) <> VersionFilter Then Continue For - '决定添加到哪个卡片 - Dim Ver As String = GetGroupedVersionName(GameVersion, False, False) - '遍历加入的加载器列表 - Dim Loaders As New List(Of String) - If Project.ModLoaders.Count > 1 AndAlso '至少有两个加载器 - Project.Type = CompType.Mod AndAlso '是 Mod - Ver.StartsWith("1.") Then '不是 “快照版本” 之类的 - For Each Loader In Version.ModLoaders - If Loader = CompModLoaderType.Quilt AndAlso Setup.Get("ToolDownloadIgnoreQuilt") Then Continue For - If SupportedLoaders.Contains(Loader) Then Loaders.Add(Loader.ToString & " ") - Next + '决定添加到哪个版本 + Dim TargetCard As String + If GameVersion Is Nothing Then + TargetCard = "未知版本" + ElseIf GameVersion.Contains("w") OrElse GameVersion.Contains("pre") OrElse GameVersion.Contains("rc") Then + TargetCard = "快照版本" + ElseIf GameVersion.StartsWith("1.0") Then + TargetCard = "远古版本" + Else + TargetCard = GameVersion End If - If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里 - '实际添加 - For Each Loader In Loaders - Dim TargetCard As String = Loader & Ver - If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile)) - If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version) - Next + '实际进行添加 + If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile)) + If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version) Next Next '添加筛选的版本的卡片 @@ -157,16 +77,16 @@ For Each Version As CompFile In CompFileLoader.Output If Version.GameVersions.Contains(TargetVersion) AndAlso (TargetLoader = CompModLoaderType.Any OrElse Version.ModLoaders.Contains(TargetLoader)) Then - '检查是否符合版本筛选器 - If VersionFilter IsNot Nothing AndAlso - Not Version.GameVersions.Any(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True) = VersionFilter) Then Continue For If Not Dict(TargetCardName).Contains(Version) Then Dict(TargetCardName).Add(Version) End If Next End If - '转化为 UI + +#Region "转化为 UI" Try - PanResults.Children.Clear() + '清空当前 + PanMain.Children.Clear() + '转化为 UI For Each Pair As KeyValuePair(Of String, List(Of CompFile)) In Dict If Not Pair.Value.Any() Then Continue For '增加卡片 @@ -174,7 +94,7 @@ Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value} NewCard.Children.Add(NewStack) NewCard.SwapControl = NewStack - PanResults.Children.Add(NewCard) + PanMain.Children.Add(NewCard) '确定卡片是否展开 If Pair.Key = TargetCardName OrElse (FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761 @@ -184,29 +104,20 @@ NewCard.IsSwaped = True End If '增加提示 - If Pair.Key = "其他版本" Then - NewStack.Children.Add(New MyHint With {.Text = "由于版本信息更新缓慢,可能无法识别刚更新的 MC 版本,只需等待几天即可自动恢复正常。", .IsWarn = False, .Margin = New Thickness(0, 0, 0, 7)}) + If Pair.Key = "未知版本" Then + NewStack.Children.Add(New MyHint With {.Text = "由于 API 的版本信息更新缓慢,可能无法识别刚更新不久的 MC 版本,只需等待几天即可自动恢复正常。", .IsWarn = False, .Margin = New Thickness(0, 0, 0, 7)}) End If Next '如果只有一张卡片,展开第一张卡片 - If PanResults.Children.Count = 1 Then - CType(PanResults.Children(0), MyCard).IsSwaped = False + If PanMain.Children.Count = 1 Then + CType(PanMain.Children(0), MyCard).IsSwaped = False End If Catch ex As Exception Log(ex, "可视化工程下载列表出错", LogLevel.Feedback) End Try +#End Region + End Sub - Private Function GetGroupedVersionName(Name As String, MajorOnly As Boolean, FoldOldRelease As Boolean) As String - If Name Is Nothing Then - Return "其他版本" - ElseIf Name.Contains("w") Then - Return "快照版本" - ElseIf Name.StartsWith("1.0") OrElse Not Name.StartsWith("1.") OrElse (FoldOldRelease AndAlso Val(Name.Split(".")(1)) < 10) Then - Return "远古版本" - Else - Return If(MajorOnly, "1." & Name.Split(".")(1).BeforeFirst(" "), Name) - End If - End Function #End Region @@ -256,10 +167,14 @@ '构造步骤加载器 Dim Loaders As New List(Of LoaderBase) Dim Target As String = $"{PathMcFolder}versions\{VersionName}\原始整合包.{If(Project.FromCurseForge, "zip", "mrpack")}" - Dim LogoFileAddress As String = MyImage.GetTempPath(CompItem.Logo) + Dim LogoFileAddress As String = PathTemp & "CompLogo\" & GetHash(CompItem.Logo) & ".png" Loaders.Add(New LoaderDownload("下载整合包文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 10, .Block = True}) Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包", - Sub() ModpackInstall(Target, VersionName, If(IO.File.Exists(LogoFileAddress), LogoFileAddress, Nothing))) With {.ProgressWeight = 0.1}) + Sub() + If ModpackInstall(Target, VersionName, Logo:=If(IO.File.Exists(LogoFileAddress), LogoFileAddress, Nothing)) Is Nothing Then + Throw New Exception("整合包安装出现异常!") + End If + End Sub) With {.ProgressWeight = 0.1}) '启动 Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = @@ -320,7 +235,7 @@ If Not Version.IsLoaded Then Version.Load() If Not Version.Modable Then Return False If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso - Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v = Version.Version.McName) Then Return False + Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v.Split(".")(1) = Version.Version.McCodeMain.ToString) Then Return False If AllowForge Is Nothing OrElse AllowFabric Is Nothing Then Return True If AllowForge AndAlso (Version.Version.HasForge OrElse Version.Version.HasNeoForge) Then Return True If AllowFabric AndAlso Version.Version.HasFabric Then Return True @@ -368,7 +283,7 @@ If Project.TranslatedName = Project.RawName Then FileName = File.FileName Else - Dim ChineseName As String = Project.TranslatedName.BeforeFirst(" (").BeforeFirst(" - "). + Dim ChineseName As String = Project.TranslatedName.Before(" (").Before(" - "). Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":") Select Case Setup.Get("ToolDownloadTranslate") Case 0 @@ -386,10 +301,10 @@ '弹窗要求选择保存位置 Dim Target As String Target = SelectAs("选择保存位置", FileName, - Desc & "文件|" & - If(Project.Type = CompType.Mod, - If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"), - If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder) + Desc & "文件|" & + If(Project.Type = CompType.Mod, + If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"), + If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder) If Not Target.Contains("\") Then Exit Sub '构造步骤加载器 Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " " diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb index 8adda0a8..d039c56a 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb @@ -1208,12 +1208,12 @@ Public Class PageDownloadInstall If DisplayName.StartsWith("[" & MinecraftVersion & "]") Then Return True If Not DisplayName.Contains("/") OrElse Not DisplayName.Contains("]") Then Return False '直接的判断(例如 1.18.1/22w03a) - For Each Part As String In DisplayName.BeforeFirst("]").TrimStart("[").Split("/") + For Each Part As String In DisplayName.Before("]").TrimStart("[").Split("/") If Part = MinecraftVersion Then Return True Next '将版本名分割语素(例如 1.16.4/5) - Dim Lefts = RegexSearch(DisplayName.BeforeFirst("]"), "[a-z/]+|[0-9/]+") - Dim Rights = RegexSearch(MinecraftVersion.BeforeFirst("]"), "[a-z/]+|[0-9/]+") + Dim Lefts = RegexSearch(DisplayName.Before("]"), "[a-z/]+|[0-9/]+") + Dim Rights = RegexSearch(MinecraftVersion.Before("]"), "[a-z/]+|[0-9/]+") '对每段进行判断 Dim i As Integer = 0 While True diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml index 5db75e85..8a646677 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml @@ -2,128 +2,88 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PCL" AnimatedControl="{Binding ElementName=PanItem, Mode=OneWay}"> - - + - - + - - - - - - - + + + + + + - - + - - - - - - - - --> + + + + + + + - - - - - - - - --> + + + + + + + - - - - - - - - --> + + + + + + + - - - - - - - - + - + - + - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - + - - + - + - - - - - - - - - - + diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb index f226814f..d8d53598 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb @@ -1,5 +1,4 @@ Public Class PageDownloadLeft - Implements IRefreshable #Region "页面切换" @@ -74,7 +73,7 @@ PageChangeRun(PageGet(ID)) PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", LogLevel.Feedback) + Log(ex, "切换设置分页面失败(ID " & ID & ")", LogLevel.Feedback) Finally AniControlEnabled -= 1 End Try @@ -104,13 +103,7 @@ '强制刷新 Public Sub Refresh(sender As Object, e As EventArgs) '由边栏按钮匿名调用 - Refresh(Val(sender.Tag)) - End Sub - Public Sub Refresh() Implements IRefreshable.Refresh - Refresh(FrmMain.PageCurrentSub) - End Sub - Public Sub Refresh(SubType As FormMain.PageSubType) - Select Case SubType + Select Case Val(sender.Tag) Case FormMain.PageSubType.DownloadInstall DlClientListLoader.Start(IsForceRestart:=True) DlOptiFineListLoader.Start(IsForceRestart:=True) @@ -127,14 +120,12 @@ PageDownloadMod.Storage = New CompProjectStorage PageDownloadMod.Page = 0 CompProjectCache.Clear() - CompFilesCache.Clear() If FrmDownloadMod IsNot Nothing Then FrmDownloadMod.PageLoaderRestart() ItemMod.Checked = True Case FormMain.PageSubType.DownloadPack PageDownloadPack.Storage = New CompProjectStorage PageDownloadPack.Page = 0 CompProjectCache.Clear() - CompFilesCache.Clear() If FrmDownloadPack IsNot Nothing Then FrmDownloadPack.PageLoaderRestart() ItemPack.Checked = True Case FormMain.PageSubType.DownloadResourcePack diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml index bcfb6375..978b37de 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml @@ -33,17 +33,20 @@ - + + + + diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb index e9d83970..9c383f1d 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb @@ -1,62 +1,24 @@ Public Class PageDownloadMod Public Const PageSize = 40 - ''' - ''' 在切换到该页面时自动设置的目标版本。 - ''' - Public Shared TargetVersion As McVersion = Nothing '加载器信息 Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject Mod", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000} Public Shared Storage As New CompProjectStorage Public Shared Page As Integer = 0 - Private IsLoaderInited As Boolean = False - Private Sub PageDownloadMod_Inited(sender As Object, e As EventArgs) Handles Me.Loaded - '不知道从 Initialized 改成 Loaded 会不会有问题,但用 Initialized 会导致初始的筛选器修改被覆盖回默认值 - If TargetVersion IsNot Nothing Then - '设置目标 - ResetFilter() '重置筛选器 - TextSearchVersion.Text = TargetVersion.Version.McName - Dim GetTargetItemByName = - Function(Name As String) As MyComboBoxItem - For Each Item As MyComboBoxItem In ComboSearchLoader.Items - If Item.Content = Name Then Return Item - Next - Return ComboSearchLoader.Items(0) - End Function - If TargetVersion.Version.HasForge Then - ComboSearchLoader.SelectedItem = GetTargetItemByName("Forge") - ElseIf TargetVersion.Version.HasFabric Then - ComboSearchLoader.SelectedItem = GetTargetItemByName("Fabric") - ElseIf TargetVersion.Version.HasNeoForge Then - ComboSearchLoader.SelectedItem = GetTargetItemByName("NeoForge") - End If - TargetVersion = Nothing - '如果已经完成请求,则重新开始 - If IsLoaderInited Then StartNewSearch() - PanScroll.ScrollToHome() - End If - '加载器初始化 - If IsLoaderInited Then Return - IsLoaderInited = True + Private Sub PageDownloadMod_Inited(sender As Object, e As EventArgs) Handles Me.Initialized PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput) If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1))) End Sub Private Shared Function LoaderInput() As CompProjectRequest Dim Request As New CompProjectRequest(CompType.Mod, Storage, (Page + 1) * PageSize) If FrmDownloadMod IsNot Nothing Then - Dim ModLoader As CompModLoaderType = Val(FrmDownloadMod.ComboSearchLoader.SelectedItem.Tag) - Dim GameVersion As String = If(FrmDownloadMod.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing, - If(FrmDownloadMod.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadMod.TextSearchVersion.Text.Contains("w"), FrmDownloadMod.TextSearchVersion.Text, Nothing)) - If GameVersion IsNot Nothing AndAlso GameVersion.Contains(".") AndAlso Val(GameVersion.Split(".")(1)) < 14 AndAlso '1.14- - ModLoader = CompModLoaderType.Forge Then '选择了 Forge - ModLoader = CompModLoaderType.Any '此时,视作没有筛选 Mod Loader(因为部分老 Mod 没有设置自己支持的加载器) - End If With Request .SearchText = FrmDownloadMod.TextSearchName.Text - .GameVersion = GameVersion + .GameVersion = If(FrmDownloadMod.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing, + If(FrmDownloadMod.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadMod.TextSearchVersion.Text.Contains("w"), FrmDownloadMod.TextSearchVersion.Text, Nothing)) .Tag = FrmDownloadMod.ComboSearchTag.SelectedItem.Tag - .ModLoader = ModLoader + .ModLoader = Val(FrmDownloadMod.ComboSearchLoader.SelectedItem.Tag) .Source = CType(Val(FrmDownloadMod.ComboSearchSource.SelectedItem.Tag), CompSourceType) End With End If @@ -150,7 +112,7 @@ End Sub '重置按钮 - Private Sub ResetFilter() Handles BtnSearchReset.Click + Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click TextSearchName.Text = "" TextSearchVersion.Text = "全部 (也可自行输入)" TextSearchVersion.SelectedIndex = 0 diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml index 79b34ab5..1ca5eb02 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml @@ -8,12 +8,14 @@ - + + - + + diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb index f843529b..27c2fd4a 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb @@ -49,5 +49,8 @@ Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click OpenWebsite("https://www.optifine.net/") End Sub + Private Sub BtnChina_Click(sender As Object, e As EventArgs) Handles BtnChina.Click + OpenWebsite("https://optifine.cn/home") + End Sub End Class diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml index 5ad426df..dae03423 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml @@ -32,17 +32,20 @@ - + + + + diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml index 1144f092..0da64cec 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml @@ -24,7 +24,7 @@ + VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMuity="0.7"> diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb index 313db37c..1ac218e7 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb @@ -144,7 +144,7 @@ Finished(New Exception("$登录用时太长啦,重新试试吧!")) Return ElseIf ex.Message.Contains("AADSTS70000") Then '可能不能判 “invalid_grant”,见 #269 - Finished(New RestartException) + Finished(New RetryException) Return ElseIf ex.Message.Contains("authorization_pending") Then Thread.Sleep(2000) diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb index 6d1ef201..068a40a5 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb @@ -177,8 +177,8 @@ Sub() Try '更新缓存 - WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Setup.Get("CacheMsV2Uuid"), SkinAddress) - Log(String.Format("[Skin] 已写入皮肤地址缓存 {0} -> {1}", Setup.Get("CacheMsV2Uuid"), SkinAddress)) + WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Setup.Get("CacheMsUuid"), SkinAddress) + Log(String.Format("[Skin] 已写入皮肤地址缓存 {0} -> {1}", Setup.Get("CacheMsUuid"), SkinAddress)) '刷新控件 For Each SkinLoader In {PageLaunchLeft.SkinMs, PageLaunchLeft.SkinLegacy} SkinLoader.WaitForExit(IsForceRestart:=True) @@ -242,7 +242,7 @@ Retry: {"Vanilla", "原版披风"}, {"Minecon2011", "Minecon 2011 参与者披风"}, {"Minecon2012", "Minecon 2012 参与者披风"}, {"Minecon2013", "Minecon 2013 参与者披风"}, {"Minecon2015", "Minecon 2015 参与者披风"}, {"Minecon2016", "Minecon 2016 参与者披风"}, {"Cherry Blossom", "樱花披风"}, {"15th Anniversary", "15 周年纪念披风"}, {"Purple Heart", "紫色心形披风"}, - {"Follower's", "追随者披风"}, {"MCC 15th Year", "MCC 15 周年披风"}, {"Minecraft Experience", "村民救援披风"} + {"Follower's", "追随者披风"}, {"MCC 15th Year", "MCC 15 周年披风"} } Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}} For Each Cape In SkinData("capes") diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb index 416bdcf1..9d5b534c 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb @@ -26,15 +26,21 @@ If File.Exists(Path & "modpack.zip") Then PackInstallPath = Path & "modpack.zip" If File.Exists(Path & "modpack.mrpack") Then PackInstallPath = Path & "modpack.mrpack" If PackInstallPath IsNot Nothing Then - Log("[Launch] 需自动安装整合包:" & PackInstallPath, LogLevel.Debug) - Setup.Set("LaunchFolderSelect", "$.minecraft\") - If Not Directory.Exists(Path & ".minecraft\") Then - Directory.CreateDirectory(Path & ".minecraft\") - Directory.CreateDirectory(Path & ".minecraft\versions\") - McFolderLauncherProfilesJsonCreate(Path & ".minecraft\") + If MyMsgBox($"PCL 即将在当前文件夹下自动安装整合包。", "自动安装", "继续", "取消") = 1 Then + '确认自动安装 + Log("[Launch] 需自动安装整合包:" & PackInstallPath, LogLevel.Debug) + Setup.Set("LaunchFolderSelect", "$.minecraft\") + If Not Directory.Exists(Path & ".minecraft\") Then + Directory.CreateDirectory(Path & ".minecraft\") + Directory.CreateDirectory(Path & ".minecraft\versions\") + McFolderLauncherProfilesJsonCreate(Path & ".minecraft\") + End If + McFolderListLoader.WaitForExit(IsForceRestart:=True) + Else + '取消自动安装 + Log("[Launch] 取消自动安装整合包:" & PackInstallPath, LogLevel.Debug) + PackInstallPath = Nothing End If - PageSelectLeft.AddFolder(Path & ".minecraft\", GetFolderNameFromPath(Path), False) - McFolderListLoader.WaitForExit() End If '确认 Minecraft 文件夹存在 PathMcFolder = Setup.Get("LaunchFolderSelect").ToString.Replace("$", Path) @@ -52,19 +58,18 @@ If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000)) '自动整合包安装 If PackInstallPath IsNot Nothing Then - Try - Dim InstallLoader = ModpackInstall(PackInstallPath, GetFolderNameFromPath(Path)) - Log("[Launch] 自动安装整合包已开始:" & PackInstallPath) + Dim InstallLoader = ModpackInstall(PackInstallPath) + If InstallLoader Is Nothing Then + Log("[Launch] 自动安装整合包失败:" & PackInstallPath) + Else + Log("[Launch] 自动安装整合包开始:" & PackInstallPath) + RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager)) InstallLoader.WaitForExit() If InstallLoader.State = LoadState.Finished Then Log("[Launch] 自动安装整合包成功,删除安装包:" & PackInstallPath) File.Delete(PackInstallPath) End If - Catch ex As CancelledException - Log(ex, "自动安装整合包被用户取消:" & PackInstallPath) - Catch ex As Exception - Log(ex, "自动安装整合包失败:" & PackInstallPath, LogLevel.Msgbox) - End Try + End If End If '确认 Minecraft 版本存在 Dim Selection As String = Setup.Get("LaunchVersionSelect") @@ -291,7 +296,7 @@ Case 0 '正版或离线 UnknownType: If RadioLoginType5.Checked Then - If Setup.Get("CacheMsV2Access") = "" Then + If Setup.Get("CacheMsAccess") = "" Then Type = PageType.Ms Else Type = PageType.MsSkin @@ -306,7 +311,7 @@ UnknownType: RadioLoginType5.Visibility = Visibility.Visible RadioLoginType0.Visibility = Visibility.Visible Case 1 '仅正版 - If Setup.Get("CacheMsV2Access") = "" Then + If Setup.Get("CacheMsAccess") = "" Then Type = PageType.Ms Else Type = PageType.MsSkin @@ -370,7 +375,7 @@ UnknownType: Public Shared SkinMs As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Ms", AddressOf SkinMsLoad, AddressOf SkinMsInput, ThreadPriority.AboveNormal) Private Shared Function SkinMsInput() As EqualableList(Of String) '获取名称 - Return New EqualableList(Of String) From {Setup.Get("CacheMsV2Name"), Setup.Get("CacheMsV2Uuid")} + Return New EqualableList(Of String) From {Setup.Get("CacheMsName"), Setup.Get("CacheMsUuid")} End Function Private Shared Sub SkinMsLoad(Data As LoaderTask(Of EqualableList(Of String), String)) '清空已有皮肤 @@ -426,7 +431,7 @@ Finish: ElseIf Setup.Get("LoginLegacyName") = "" Then Return New EqualableList(Of String) From {0, ""} Else - Return New EqualableList(Of String) From {0, If(Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨"), "")} + Return New EqualableList(Of String) From {0, If(Setup.Get("LoginLegacyName").ToString.Before("¨"), "")} End If Case 3 Return New EqualableList(Of String) From {3, Setup.Get("LaunchSkinID")} diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb index 296f74ac..4c8df300 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb @@ -1,5 +1,4 @@ Public Class PageLaunchRight - Implements IRefreshable Private Sub Init() Handles Me.Loaded PanBack.ScrollToHome() @@ -89,7 +88,7 @@ Download: GoTo Download Case 3 Log("[Page] 主页预设:简单主页") - Url = "https://raw.gitcode.com/mfn233/PCL-Mainpage/raw/main/Custom.xaml" + Url = "https://gitee.com/mfn233/PCL-Mainpage/raw/main/Custom.xaml" GoTo Download Case 4 Log("[Page] 主页预设:每日整合包推荐") @@ -101,7 +100,7 @@ Download: GoTo Download Case 6 Log("[Page] 主页预设:OpenBMCLAPI 仪表盘 Lite") - Url = "https://pcl-bmcl.milu.ink/" + Url = "https://pcl-bmcl.milulu.xyz/" GoTo Download Case 7 Log("[Page] 主页预设:主页市场") @@ -111,18 +110,6 @@ Download: Log("[Page] 主页预设:更新日志") Url = "https://updatehomepage.pages.dev/UpdateHomepage.xaml" GoTo Download - Case 9 - Log("[Page] 主页预设:PCL 新功能说明书") - Url = "https://raw.gitcode.com/WForst-Breeze/WhatsNewPCL/raw/main/Custom.xaml" - GoTo Download - Case 10 - Log("[Page] 主页预设:OpenMCIM Dashboard") - Url = "https://files.mcimirror.top/PCL" - GoTo Download - Case 11 - Log("[Page] 主页预设:杂志主页") - Url = "http://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Ext1nguisher/Custom.xaml" - GoTo Download End Select End Select RunInUi(Sub() LoadContent(Content)) @@ -139,10 +126,10 @@ Download: If Address.Contains(".xaml") Then VersionAddress = Address.Replace(".xaml", ".xaml.ini") Else - VersionAddress = Address.BeforeFirst("?") + VersionAddress = Address.Before("?") If Not VersionAddress.EndsWith("/") Then VersionAddress += "/" VersionAddress += "version" - If Address.Contains("?") Then VersionAddress += Address.AfterLast("?") + If Address.Contains("?") Then VersionAddress += Address.After("?") End If '校验版本 Dim Version As String = "" @@ -184,7 +171,7 @@ Download: ''' 立即强制刷新自定义主页。 ''' 必须在 UI 线程调用。 ''' - Public Sub ForceRefresh() Implements IRefreshable.Refresh + Public Sub ForceRefresh() Log("[Page] 要求强制刷新自定义主页") ClearCache() '实际的刷新 diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb index fa10925b..00249505 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb @@ -17,8 +17,8 @@ ComboName.ItemsSource = Nothing Else ComboName.ItemsSource = Setup.Get("LoginAuthEmail").ToString.Split("¨") - ComboName.Text = Setup.Get("LoginAuthEmail").ToString.BeforeFirst("¨") - If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginAuthPass").ToString.BeforeFirst("¨").Trim + ComboName.Text = Setup.Get("LoginAuthEmail").ToString.Before("¨") + If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginAuthPass").ToString.Before("¨").Trim End If End If IsFirstLoad = False diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb index fec81e62..ca21ffa7 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb @@ -70,11 +70,9 @@ End Try End Sub) End Sub - Public Shared Sub ExitLogin() Handles BtnExit.Click + Private Sub BtnExit_Click() Handles BtnExit.Click Setup.Set("CacheAuthAccess", "") Setup.Set("CacheAuthUuid", "") - Setup.Set("CacheAuthName", "") - McLoginAuthLoader.Input = Nothing '防止因为输入的用户名密码相同,直接使用了上次登录的加载器结果 FrmLaunchLeft.RefreshPage(False, True) End Sub diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb index ed916841..0c478822 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb @@ -26,7 +26,7 @@ Public Class PageLoginLegacy ComboName.ItemsSource = Nothing Else ComboName.ItemsSource = Setup.Get("LoginLegacyName").ToString.Split("¨") - ComboName.Text = Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨").Trim + ComboName.Text = Setup.Get("LoginLegacyName").ToString.Before("¨").Trim End If End If IsReloaded = True diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb index a7f98300..e61fa4ef 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb @@ -37,7 +37,7 @@ ''' 获取当前页面的登录信息。 ''' Public Shared Function GetLoginData() As McLoginMs - If FrmLoginMs Is Nothing Then Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsV2OAuthRefresh"), .UserName = Setup.Get("CacheMsV2Name")} + If FrmLoginMs Is Nothing Then Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName")} Dim Result As McLoginMs = Nothing RunInUiWait( Sub() diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb index e7ecc6c4..b3f47ae0 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb @@ -12,7 +12,7 @@ ''' 刷新页面显示的所有信息。 ''' Public Sub Reload(KeepInput As Boolean) - TextName.Text = Setup.Get("CacheMsV2Name") + TextName.Text = Setup.Get("CacheMsName") '皮肤在 Loaded 加载 End Sub ''' @@ -20,9 +20,9 @@ ''' Public Shared Function GetLoginData() As McLoginMs If McLoginMsLoader.State = LoadState.Finished Then - Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsV2OAuthRefresh"), .UserName = Setup.Get("CacheMsV2Name"), .AccessToken = Setup.Get("CacheMsV2Access"), .Uuid = Setup.Get("CacheMsV2Uuid"), .ProfileJson = Setup.Get("CacheMsV2ProfileJson")} + Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName"), .AccessToken = Setup.Get("CacheMsAccess"), .Uuid = Setup.Get("CacheMsUuid"), .ProfileJson = Setup.Get("CacheMsProfileJson")} Else - Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsV2OAuthRefresh"), .UserName = Setup.Get("CacheMsV2Name")} + Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsOAuthRefresh"), .UserName = Setup.Get("CacheMsName")} End If End Function @@ -50,11 +50,11 @@ '退出登录 Private Sub BtnExit_Click() Handles BtnExit.Click - Setup.Set("CacheMsV2OAuthRefresh", "") - Setup.Set("CacheMsV2Access", "") - Setup.Set("CacheMsV2ProfileJson", "") - Setup.Set("CacheMsV2Uuid", "") - Setup.Set("CacheMsV2Name", "") + Setup.Set("CacheMsOAuthRefresh", "") + Setup.Set("CacheMsAccess", "") + Setup.Set("CacheMsProfileJson", "") + Setup.Set("CacheMsUuid", "") + Setup.Set("CacheMsName", "") McLoginMsLoader.Abort() FrmLaunchLeft.RefreshPage(False, True) End Sub @@ -90,8 +90,8 @@ Try Retry: If McLoginMsLoader.State = LoadState.Loading Then McLoginMsLoader.WaitForExit() '等待登录结束 - Dim AccessToken As String = Setup.Get("CacheMsV2Access") - Dim Uuid As String = Setup.Get("CacheMsV2Uuid") + Dim AccessToken As String = Setup.Get("CacheMsAccess") + Dim Uuid As String = Setup.Get("CacheMsUuid") Dim Client As New Net.Http.HttpClient With {.Timeout = New TimeSpan(0, 0, 30)} Client.DefaultRequestHeaders.Authorization = New Net.Http.Headers.AuthenticationHeaderValue("Bearer", AccessToken) diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb index 3b478333..0e327d0c 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb @@ -17,8 +17,8 @@ ComboName.ItemsSource = Nothing Else ComboName.ItemsSource = Setup.Get("LoginNideEmail").ToString.Split("¨") - ComboName.Text = Setup.Get("LoginNideEmail").ToString.BeforeFirst("¨") - If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginNidePass").ToString.BeforeFirst("¨").Trim + ComboName.Text = Setup.Get("LoginNideEmail").ToString.Before("¨") + If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginNidePass").ToString.Before("¨").Trim End If End If IsFirstLoad = False diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb index 84fa7730..bceb7c86 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb @@ -47,9 +47,8 @@ Private Sub BtnEdit_Click(sender As Object, e As EventArgs) Handles BtnEdit.Click OpenWebsite("https://login.mc-user.com:233/account/changepw") End Sub - Public Shared Sub ExitLogin() Handles BtnExit.Click + Private Sub BtnExit_Click() Handles BtnExit.Click Setup.Set("CacheNideAccess", "") - McLoginNideLoader.Input = Nothing '防止因为输入的用户名密码相同,直接使用了上次登录的加载器结果 FrmLaunchLeft.RefreshPage(False, True) End Sub diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb b/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb index f1e63121..f0a318f6 100644 --- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb @@ -111,6 +111,8 @@ Public Class PageLinkIoi End Sub '复制联机码 Public Shared Sub BtnLeftCopy_Click() Handles BtnLeftCopy.Click + ClipboardSet(IoiId.Substring(4) & SecretEncrypt(GetPlayerName), False) + Hint("已复制联机码!", HintType.Finish) End Sub #End Region @@ -417,6 +419,75 @@ Public Class PageLinkIoi '获取数据包 Public Shared Sub ReceiveJson(JsonData As JObject, Optional NewSocket As Socket = Nothing) + '获取数据 + Dim Id As String = JsonData("id"), Type As String = JsonData("type") + Select Case Type + Case "connect" + Dim DisplayName As String = JsonData("name") + Dim User As New LinkUserIoi(Id, DisplayName, NewSocket) + '如果发生了双向连接 + If UserList.ContainsKey(Id) Then + If Id > IoiId Then + Log("[IOI] 双向连接,应当抛弃当前用户(" & DisplayName & ")") + For Each Pair In UserList(User.Id).Ports.ToList + User.Ports(Pair.Key) = Pair.Value + Next + UserList(Id).Dispose() + Else + '应当保留当前用户 + Log("[IOI] 双向连接,应当保留当前用户(" & DisplayName & ")") + NewSocket.Dispose() + Exit Sub + End If + End If + '加入列表 + UserList.Add(Id, User) + '返回请求 + User.RelativeThread = RunInNewThread(Sub() + SendPortsubBack(User, JsonData("version").ToObject(Of Integer)) + End Sub, "Link Connect " & DisplayName) + '更新时间 + User.LastReceive = Date.Now + Case "update" + If Not UserList.ContainsKey(Id) Then Throw New Exception("未在列表中的用户发送了更新请求:" & Id) + Dim User = UserList(Id) + '拉满进度(该请求也作为反向连接回应出现,用于向正向连接方传达连接已完成信号) + User.Progress = 1 + '更新名称 + Dim DisplayName As String = JsonData("name") + User.DisplayName = DisplayName + '更新房间列表 + If JsonData("rooms") IsNot Nothing Then + User.Rooms = New List(Of RoomEntry) + For Each RoomObject In JsonData("rooms") + User.Rooms.Add(New RoomEntry(RoomObject("port"), RoomObject("name"), User)) + Next + End If + '更新 Ping + Dim Stage As Integer = JsonData("stage"), Unique As Long = JsonData("unique") + If Stage > 1 Then + User.PingRecord.Enqueue((Date.Now - User.PingPending(Unique)).TotalMilliseconds / 2) + If User.PingRecord.Count > 5 Then User.PingRecord.Dequeue() + User.PingPending.Remove(Unique) + End If + '返回请求 + If Stage > 0 AndAlso Stage < 3 Then RunInNewThread(Sub() + Try + SendUpdateRequest(User, Stage + 1, Unique) + Catch ex As Exception + Log(ex, "发送回程请求失败") + End Try + End Sub, "Link Update " & DisplayName) + '更新时间 + User.LastReceive = Date.Now + Case "disconnect" + '断开连接 + If Not UserList.ContainsKey(Id) Then Exit Sub + UserRemove(UserList(Id), ShowLeaveMessage:=JsonData("message") Is Nothing) + If JsonData("message") IsNot Nothing Then Hint(JsonData("message").ToString, If(JsonData("isError").ToObject(Of Boolean), HintType.Critical, HintType.Info)) + Case Else + Throw New Exception("未知的操作种类:" & Type) + End Select End Sub ''' ''' 从用户列表中移除一位用户。提示信息视作该用户主动离开。 diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml.vb index 38fd50ff..7d62918d 100644 --- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkLeft.xaml.vb @@ -63,7 +63,7 @@ PageChangeRun(PageGet(ID)) PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", LogLevel.Feedback) + Log(ex, "切换设置分页面失败(ID " & ID & ")", LogLevel.Feedback) Finally AniControlEnabled -= 1 End Try diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml index f0f925c9..43099a0c 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml @@ -104,107 +104,108 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb index 46a8bf4c..d8c0a68c 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb @@ -1,5 +1,4 @@ Public Class PageOtherHelp - Implements IRefreshable #Region "初始化" @@ -80,35 +79,31 @@ End Try End Sub Public Shared Sub EnterHelpPage(Location As String) - RunInThread( - Sub() - If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid) - Dim Entry As New HelpEntry(Location) - RunInUi( - Sub() - Dim FrmHelpDetail As New PageOtherHelpDetail - If FrmHelpDetail.Init(Entry) Then - FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}}) - Else - Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", LogLevel.Debug) - End If - End Sub) - End Sub) + RunInThread(Sub() + If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid) + Dim Entry As New HelpEntry(Location) + RunInUi(Sub() + Dim FrmHelpDetail As New PageOtherHelpDetail + If FrmHelpDetail.Init(Entry) Then + FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}}) + Else + Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", LogLevel.Debug) + End If + End Sub) + End Sub) End Sub Public Shared Sub EnterHelpPage(Entry As HelpEntry) - RunInThread( - Sub() - If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid) - RunInUi( - Sub() - Dim FrmHelpDetail As New PageOtherHelpDetail - If FrmHelpDetail.Init(Entry) Then - FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}}) - Else - Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", LogLevel.Debug) - End If - End Sub) - End Sub) + RunInThread(Sub() + If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid) + RunInUi(Sub() + Dim FrmHelpDetail As New PageOtherHelpDetail + If FrmHelpDetail.Init(Entry) Then + FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}}) + Else + Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", LogLevel.Debug) + End If + End Sub) + End Sub) End Sub Public Shared Function GetHelpPage(Location As String) As PageOtherHelpDetail If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid) @@ -127,15 +122,14 @@ If String.IsNullOrWhiteSpace(SearchBox.Text) Then '隐藏 AniStart({ - AaOpacity(PanSearch, -PanSearch.Opacity, 100), - AaCode( - Sub() - PanSearch.Height = 0 - PanSearch.Visibility = Visibility.Collapsed - PanList.Visibility = Visibility.Visible - End Sub,, True), - AaOpacity(PanList, 1 - PanList.Opacity, 150, 30) - }, "FrmOtherHelp Search Switch") + AaOpacity(PanSearch, -PanSearch.Opacity, 100), + AaCode(Sub() + PanSearch.Height = 0 + PanSearch.Visibility = Visibility.Collapsed + PanList.Visibility = Visibility.Visible + End Sub,, True), + AaOpacity(PanList, 1 - PanList.Opacity, 150, 30) + }, "FrmOtherHelp Search Switch") Else '构造请求 Dim QueryList As New List(Of SearchEntry(Of HelpEntry)) @@ -169,19 +163,15 @@ End If '显示 AniStart({ - AaOpacity(PanList, -PanList.Opacity, 100), - AaCode( - Sub() - PanList.Visibility = Visibility.Collapsed - PanSearch.Visibility = Visibility.Visible - PanSearch.TriggerForceResize() - End Sub,, True), - AaOpacity(PanSearch, 1 - PanSearch.Opacity, 150, 30) - }, "FrmOtherHelp Search Switch") + AaOpacity(PanList, -PanList.Opacity, 100), + AaCode(Sub() + PanList.Visibility = Visibility.Collapsed + PanSearch.Visibility = Visibility.Visible + PanSearch.TriggerForceResize() + End Sub,, True), + AaOpacity(PanSearch, 1 - PanSearch.Opacity, 150, 30) + }, "FrmOtherHelp Search Switch") End If End Sub - Public Sub Refresh() Implements IRefreshable.Refresh - PageOtherLeft.RefreshHelp() - End Sub End Class diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb index fda05ce1..79aecfd3 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb @@ -1,11 +1,6 @@ Public Class PageOtherHelpDetail - Implements IRefreshable Public Entry As HelpEntry - Public Sub Refresh() Implements IRefreshable.Refresh - Init(New HelpEntry(Entry.RawPath)) - End Sub - Private Sub PageOtherHelpDetail_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded PanBack.ScrollToTop() End Sub diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb index e6c53af9..4b1695f7 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb @@ -89,7 +89,7 @@ PageChangeRun(PageGet(ID)) PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", LogLevel.Feedback) + Log(ex, "切换设置分页面失败(ID " & ID & ")", LogLevel.Feedback) Finally AniControlEnabled -= 1 End Try @@ -133,8 +133,8 @@ '打开网页 Public Shared Sub TryFeedback() 'Handles ItemFeedback.Click If Not CanFeedback(True) Then Exit Sub - Select Case MyMsgBox("在提交新反馈前,建议先搜索反馈列表,以避免重复提交。" & vbCrLf & "如果无法打开该网页,请尝试使用加速器或 VPN。", - "反馈", "提交新反馈", "查看反馈列表", "取消") + Select Case MyMsgBox("是否要打开反馈列表网页?" & vbCrLf & "如果无法打开该网页,请尝试使用加速器或 VPN。", + "反馈提示", "提交新反馈", "查看反馈列表", "取消") Case 1 Feedback(True, False) Case 2 @@ -143,7 +143,7 @@ End Sub Public Shared Sub TryVote() 'Handles ItemVote.Click If MyMsgBox("是否要打开新功能投票网页?" & vbCrLf & "如果无法打开该网页,请尝试使用加速器或 VPN。", - "新功能投票", "打开", "取消") = 2 Then Exit Sub + "提醒", "打开", "取消") = 2 Then Exit Sub OpenWebsite("https://github.com/Hex-Dragon/PCL2/discussions/categories/%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8?discussions_q=category%3A%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8+sort%3Adate_created") End Sub diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherTest.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherTest.xaml.vb index 041421a7..af35b458 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherTest.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherTest.xaml.vb @@ -12,7 +12,7 @@ Public Shared Sub MemoryOptimize(ShowHint As Boolean) If ShowHint Then Hint("为便于维护,开源内容中不包含百宝箱功能……") End Sub - Public Shared Sub MemoryOptimizeInternal(ShowHint As Boolean) + Public Shared Sub MemoryOptimizeInternal() End Sub Public Shared Function GetRandomCave() As String Return "为便于维护,开源内容中不包含百宝箱功能……" diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml index 2dfe9032..97e9c546 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml +++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml @@ -9,7 +9,7 @@ - + diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb index 2b5177ad..1ef40df5 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb @@ -1,5 +1,4 @@ Public Class PageSelectLeft - Implements IRefreshable Private Sub PageSelectLeft_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized AddHandler McFolderListLoader.PreviewFinish, Sub() If FrmSelectLeft IsNot Nothing Then RunInUiWait(AddressOf McFolderListUI) @@ -296,7 +295,7 @@ For i = 0 To Folders.Count - 1 If Folders(i) = "" Then Exit For If Folders(i).ToString.EndsWith(Folder.Path) Then - Name = Folders(i).ToString.BeforeFirst(">") + Name = Folders(i).ToString.Before(">") Folders.RemoveAt(i) Exit For End If @@ -348,14 +347,8 @@ End Sub Public Sub Refresh_Click(sender As Object, e As RoutedEventArgs) Dim Data As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag - RefreshCurrent(Data.Path) - End Sub - Public Sub RefreshCurrent() Implements IRefreshable.Refresh - RefreshCurrent(PathMcFolder) - End Sub - Public Shared Sub RefreshCurrent(Folder As String) - WriteIni(Folder & "PCL.ini", "VersionCache", "") '删除缓存以强制要求下一次加载时更新列表 - If Folder = PathMcFolder Then LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") + WriteIni(Data.Path & "PCL.ini", "VersionCache", "") '删除缓存以强制要求下一次加载时更新列表 + If Data.Path = PathMcFolder Then LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") End Sub Public Sub Rename_Click(sender As Object, e As RoutedEventArgs) Dim Folder As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag diff --git a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb index 1c01353b..1bcbf49f 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb @@ -171,16 +171,14 @@ ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center) ToolTipService.SetVerticalOffset(BtnCont, 30) ToolTipService.SetHorizontalOffset(BtnCont, 2) - AddHandler BtnCont.Click, - Sub() - PageVersionLeft.Version = Version - FrmMain.PageChange(FormMain.PageType.VersionSetup, 0) - End Sub - AddHandler sender.MouseRightButtonUp, - Sub() - PageVersionLeft.Version = Version - FrmMain.PageChange(FormMain.PageType.VersionSetup, 0) - End Sub + AddHandler BtnCont.Click, Sub() + PageVersionLeft.Version = Version + FrmMain.PageChange(FormMain.PageType.VersionSetup, 0) + End Sub + AddHandler sender.MouseRightButtonUp, Sub() + PageVersionLeft.Version = Version + FrmMain.PageChange(FormMain.PageType.VersionSetup, 0) + End Sub sender.Buttons = {BtnStar, BtnDel, BtnCont} Else Dim BtnCont As New MyIconButton With {.LogoScale = 1.15, .Logo = Logo.IconButtonOpen} @@ -188,8 +186,12 @@ ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center) ToolTipService.SetVerticalOffset(BtnCont, 30) ToolTipService.SetHorizontalOffset(BtnCont, 2) - AddHandler BtnCont.Click, Sub() PageVersionOverall.OpenVersionFolder(Version) - AddHandler sender.MouseRightButtonUp, Sub() PageVersionOverall.OpenVersionFolder(Version) + AddHandler BtnCont.Click, Sub() + PageVersionOverall.OpenVersionFolder(Version) + End Sub + AddHandler sender.MouseRightButtonUp, Sub() + PageVersionOverall.OpenVersionFolder(Version) + End Sub sender.Buttons = {BtnStar, BtnDel, BtnCont} End If End Sub diff --git a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb index dcb95f8e..2ed97dfc 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb @@ -9,8 +9,6 @@ ''' Private ReadOnly SetupDict As New Dictionary(Of String, SetupEntry) From { {"Identify", New SetupEntry("", Source:=SetupSource.Registry)}, - {"WindowHeight", New SetupEntry(550)}, - {"WindowWidth", New SetupEntry(900)}, {"HintDownloadThread", New SetupEntry(False, Source:=SetupSource.Registry)}, {"HintNotice", New SetupEntry(0, Source:=SetupSource.Registry)}, {"HintDownload", New SetupEntry(0, Source:=SetupSource.Registry)}, @@ -44,12 +42,6 @@ {"CacheMsProfileJson", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsUuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsName", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, - {"CacheMsV2Migrated", New SetupEntry(False, Source:=SetupSource.Registry)}, - {"CacheMsV2OAuthRefresh", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, - {"CacheMsV2Access", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, - {"CacheMsV2ProfileJson", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, - {"CacheMsV2Uuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, - {"CacheMsV2Name", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheNideAccess", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheNideClient", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheNideUuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, @@ -117,10 +109,10 @@ {"ToolDownloadSpeed", New SetupEntry(42, Source:=SetupSource.Registry)}, {"ToolDownloadVersion", New SetupEntry(0, Source:=SetupSource.Registry)}, {"ToolDownloadTranslate", New SetupEntry(0, Source:=SetupSource.Registry)}, + {"ToolDownloadKeepModpack", New SetupEntry(False, Source:=SetupSource.Registry)}, {"ToolDownloadIgnoreQuilt", New SetupEntry(True, Source:=SetupSource.Registry)}, {"ToolDownloadCert", New SetupEntry(False, Source:=SetupSource.Registry)}, {"ToolDownloadMod", New SetupEntry(1, Source:=SetupSource.Registry)}, - {"ToolModLocalNameStyle", New SetupEntry(0, Source:=SetupSource.Registry)}, {"ToolUpdateAlpha", New SetupEntry(0, Source:=SetupSource.Registry, Encoded:=True)}, {"ToolUpdateRelease", New SetupEntry(False, Source:=SetupSource.Registry)}, {"ToolUpdateSnapshot", New SetupEntry(False, Source:=SetupSource.Registry)}, @@ -157,7 +149,6 @@ {"UiHiddenPageSetup", New SetupEntry(False)}, {"UiHiddenPageOther", New SetupEntry(False)}, {"UiHiddenFunctionSelect", New SetupEntry(False)}, - {"UiHiddenFunctionModUpdate", New SetupEntry(False)}, {"UiHiddenFunctionHidden", New SetupEntry(False)}, {"UiHiddenSetupLaunch", New SetupEntry(False)}, {"UiHiddenSetupUi", New SetupEntry(False)}, @@ -205,19 +196,15 @@ '加载状态:0/未读取 1/已读取未处理 2/已处理 Public State As Byte = 0 - Public Type As Type + Public Type Public Sub New(Value, Optional Source = SetupSource.Normal, Optional Encoded = False) - Try - Me.DefaultValue = Value - Me.Encoded = Encoded - Me.Value = Value - Me.Source = Source - Me.Type = If(Value, New Object).GetType - Me.DefaultValueEncoded = If(Encoded, SecretEncrypt(Value, "PCL" & UniqueAddress), Value) - Catch ex As Exception - Log(ex, "初始化 SetupEntry 失败", LogLevel.Feedback) '#5095 的 fallback - End Try + Me.DefaultValue = Value + Me.DefaultValueEncoded = If(Encoded, SecretEncrypt(Value, "PCL" & UniqueAddress), Value) + Me.Encoded = Encoded + Me.Value = Value + Me.Source = Source + Type = If(Value, New Object).GetType End Sub End Class @@ -319,12 +306,6 @@ Dim E As SetupEntry = SetupDict(Key) [Set](Key, E.DefaultValue, E, ForceReload, Version) End Sub - ''' - ''' 获取某个设置项的默认值。 - ''' - Public Function GetDefault(Key As String) As String - Return SetupDict(Key).DefaultValue - End Function Private Sub Read(Key As String, ByRef E As SetupEntry, Version As McVersion) Try @@ -613,7 +594,7 @@ FrmSetupUI.PanLogoChange.Visibility = Visibility.Visible End If Try - FrmMain.ImageTitleLogo.Source = Path & "PCL\Logo.png" + FrmMain.ImageTitleLogo.Source = New MyBitmap(Path & "PCL\Logo.png") Catch ex As Exception FrmMain.ImageTitleLogo.Source = Nothing Log(ex, "显示标题栏图片失败", LogLevel.Msgbox) @@ -645,9 +626,6 @@ Public Sub UiHiddenFunctionSelect(Value As Boolean) PageSetupUI.HiddenRefresh() End Sub - Public Sub UiHiddenFunctionModUpdate(Value As Boolean) - PageSetupUI.HiddenRefresh() - End Sub Public Sub UiHiddenFunctionHidden(Value As Boolean) PageSetupUI.HiddenRefresh() End Sub diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml index 7d66af79..afa2aba6 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml @@ -7,7 +7,54 @@ PanScroll="{Binding ElementName=PanBack}"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -170,57 +217,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -232,19 +232,14 @@ - - - - - + + ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。 可以使用以下替换标记实现相对路径(路径均以 \ 结尾): · {path}:PCL 的 exe 文件所在的文件夹 · {minecraft}:.minecraft 文件夹 · {verpath}:版本文件夹(.minecraft\versions\版本名\) · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹 · {java}:游戏运行时的 Java 文件夹 除此之外,也支持以下替换标记: · {user}:玩家名字 · {login}:玩家的登录方式 · {uuid}:玩家的 UUID · {name}:游戏版本名 · {date}、{time}:当前的系统时间 · {version}:游戏对应的原版版本号 例如: · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar · notepad "{verindie}option.txt" :使用记事本打开该版本的设置文件 涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。 执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" /> diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb index a30267bd..d9dc7d2f 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb @@ -214,7 +214,7 @@ If(RamGame <> RamGameActual, " (可用 " & If(RamGameActual = Math.Floor(RamGameActual), RamGameActual & ".0", RamGameActual) & " GB)", "") LabRamUsed.Text = If(RamUsed = Math.Floor(RamUsed), RamUsed & ".0", RamUsed) & " GB" LabRamTotal.Text = " / " & If(RamTotal = Math.Floor(RamTotal), RamTotal & ".0", RamTotal) & " GB" - LabRamWarn.Visibility = If(RamGame = 1 AndAlso Not JavaIs64Bit() AndAlso Not Is32BitSystem AndAlso JavaList.Any, Visibility.Visible, Visibility.Collapsed) + LabRamWarn.Visibility = If(RamGame = 1 AndAlso Not JavaIs64Bit() AndAlso Not Is32BitSystem, Visibility.Visible, Visibility.Collapsed) If ShowAnim Then '宽度动画 AniStart({ @@ -551,17 +551,15 @@ PreFin: End Sub '版本隔离警告 - Private IsReverting As Boolean = False Private Sub ComboArgumentIndie_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ComboArgumentIndie.SelectionChanged If AniControlEnabled <> 0 Then Exit Sub - If IsReverting Then Exit Sub If MyMsgBox("调整版本隔离后,你可能得把游戏存档、Mod 等文件手动迁移到新的游戏文件夹中。" & vbCrLf & "如果修改后发现存档消失,把这项设置改回来就能恢复。" & vbCrLf & "如果你不会迁移存档,不建议修改这项设置!", "警告", "我知道我在做什么", "取消", IsWarn:=True) = 2 Then - IsReverting = True + AniControlEnabled += 1 ComboArgumentIndie.SelectedItem = e.RemovedItems(0) - IsReverting = False + AniControlEnabled -= 1 End If End Sub @@ -573,15 +571,6 @@ PreFin: CheckAdvanceRunWait.Visibility = If(TextAdvanceRun.Text = "", Visibility.Collapsed, Visibility.Visible) End Sub - 'JVM 参数重设 - Private Sub TextAdvanceJvm_TextChanged() Handles TextAdvanceJvm.ValidatedTextChanged - BtnAdvanceJvmReset.Visibility = If(TextAdvanceJvm.Text = Setup.GetDefault("LaunchAdvanceJvm"), Visibility.Hidden, Visibility.Visible) - End Sub - Private Sub BtnAdvanceJvmReset_Click(sender As Object, e As EventArgs) Handles BtnAdvanceJvmReset.Click - Setup.Reset("LaunchAdvanceJvm") - Reload() - End Sub - #End Region End Class diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb index 9c98d0b7..17873167 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb @@ -115,7 +115,7 @@ PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", LogLevel.Feedback) + Log(ex, "切换设置分页面失败(ID " & ID & ")", LogLevel.Feedback) Finally AniControlEnabled -= 1 End Try diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml index bf1c1da0..20ac75c5 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml @@ -7,79 +7,66 @@ PanScroll="{Binding ElementName=PanBack}"> + - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + - - - - - - + + + + + + + + + diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb index 44edb287..fe5ebd14 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb @@ -1,5 +1,33 @@ Class PageSetupSystem +#Region "语言" + 'Private Sub PageSetupUI_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded + ' AniControlEnabled -= 1 + + ' '读取设置 + ' Select Case Lang + ' Case "zh_CN" + ' ComboLang.SelectedIndex = 0 + ' Case "zh_HK" + ' ComboLang.SelectedIndex = 1 + ' Case "en_US" + ' ComboLang.SelectedIndex = 2 + ' End Select + ' CheckDebug.Checked = ReadReg("SystemDebugMode", "False") + + ' AniControlEnabled += 1 + 'End Sub + + 'Private Sub RefreshLang() Handles ComboLang.SelectionChanged + ' If IsLoaded Then + ' If Not ComboLang.IsLoaded Then Exit Sub + ' Lang = CType(ComboLang.SelectedItem, MyComboBoxItem).Tag + ' Application.Current.Resources.MergedDictionaries(1) = New ResourceDictionary With {.Source = New Url("Languages\" & Lang & ".xaml", UrlKind.Relative)} + ' WriteReg("Lang", Lang) + ' End If + 'End Sub +#End Region + Private Shadows IsLoaded As Boolean = False Private Sub PageSetupSystem_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded @@ -30,13 +58,11 @@ SliderDownloadThread.Value = Setup.Get("ToolDownloadThread") SliderDownloadSpeed.Value = Setup.Get("ToolDownloadSpeed") ComboDownloadVersion.SelectedIndex = Setup.Get("ToolDownloadVersion") - CheckDownloadCert.Checked = Setup.Get("ToolDownloadCert") - - 'Mod 与整合包 ComboDownloadTranslate.SelectedIndex = Setup.Get("ToolDownloadTranslate") ComboDownloadMod.SelectedIndex = Setup.Get("ToolDownloadMod") - ComboModLocalNameStyle.SelectedIndex = Setup.Get("ToolModLocalNameStyle") + CheckDownloadKeepModpack.Checked = Setup.Get("ToolDownloadKeepModpack") CheckDownloadIgnoreQuilt.Checked = Setup.Get("ToolDownloadIgnoreQuilt") + CheckDownloadCert.Checked = Setup.Get("ToolDownloadCert") 'Minecraft 更新提示 CheckUpdateRelease.Checked = Setup.Get("ToolUpdateRelease") @@ -65,10 +91,10 @@ Setup.Reset("ToolDownloadSpeed") Setup.Reset("ToolDownloadVersion") Setup.Reset("ToolDownloadTranslate") + Setup.Reset("ToolDownloadKeepModpack") Setup.Reset("ToolDownloadIgnoreQuilt") Setup.Reset("ToolDownloadCert") Setup.Reset("ToolDownloadMod") - Setup.Reset("ToolModLocalNameStyle") Setup.Reset("ToolUpdateRelease") Setup.Reset("ToolUpdateSnapshot") Setup.Reset("ToolHelpChinese") @@ -90,13 +116,13 @@ End Sub '将控件改变路由到设置改变 - Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckDebugMode.Change, CheckDebugDelay.Change, CheckDebugSkipCopy.Change, CheckUpdateRelease.Change, CheckUpdateSnapshot.Change, CheckHelpChinese.Change, CheckDownloadIgnoreQuilt.Change, CheckDownloadCert.Change + Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckDebugMode.Change, CheckDebugDelay.Change, CheckDebugSkipCopy.Change, CheckUpdateRelease.Change, CheckUpdateSnapshot.Change, CheckHelpChinese.Change, CheckDownloadKeepModpack.Change, CheckDownloadIgnoreQuilt.Change, CheckDownloadCert.Change If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked) End Sub Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderDebugAnim.Change, SliderDownloadThread.Change, SliderDownloadSpeed.Change If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value) End Sub - Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboDownloadVersion.SelectionChanged, ComboModLocalNameStyle.SelectionChanged, ComboDownloadTranslate.SelectionChanged, ComboSystemUpdate.SelectionChanged, ComboSystemActivity.SelectionChanged, ComboDownloadMod.SelectionChanged + Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboDownloadVersion.SelectionChanged, ComboDownloadTranslate.SelectionChanged, ComboSystemUpdate.SelectionChanged, ComboSystemActivity.SelectionChanged, ComboDownloadMod.SelectionChanged If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex) End Sub Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextSystemCache.ValidatedTextChanged diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml index 0e2f9127..aeb3ae4e 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml @@ -72,10 +72,10 @@ - + - - + + @@ -225,7 +225,6 @@ - @@ -246,9 +245,6 @@ - - - @@ -292,9 +288,8 @@ - - - + + diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb index f48e8eaf..45c03a7f 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb @@ -25,15 +25,14 @@ Next End If - AniControlEnabled += 1 - Reload() '#4826,在每次进入页面时都刷新一下 - AniControlEnabled -= 1 - '非重复加载部分 If IsLoaded Then Exit Sub IsLoaded = True + AniControlEnabled += 1 SliderLoad() + Reload() + AniControlEnabled -= 1 #If BETA Then PanLauncherHide.Visibility = Visibility.Visible @@ -98,7 +97,6 @@ CheckHiddenPageSetup.Checked = Setup.Get("UiHiddenPageSetup") CheckHiddenPageOther.Checked = Setup.Get("UiHiddenPageOther") CheckHiddenFunctionSelect.Checked = Setup.Get("UiHiddenFunctionSelect") - CheckHiddenFunctionModUpdate.Checked = Setup.Get("UiHiddenFunctionModUpdate") CheckHiddenFunctionHidden.Checked = Setup.Get("UiHiddenFunctionHidden") CheckHiddenSetupLaunch.Checked = Setup.Get("UiHiddenSetupLaunch") CheckHiddenSetupUI.Checked = Setup.Get("UiHiddenSetupUi") @@ -149,7 +147,6 @@ Setup.Reset("UiHiddenPageSetup") Setup.Reset("UiHiddenPageOther") Setup.Reset("UiHiddenFunctionSelect") - Setup.Reset("UiHiddenFunctionModUpdate") Setup.Reset("UiHiddenFunctionHidden") Setup.Reset("UiHiddenSetupLaunch") Setup.Reset("UiHiddenSetupUi") @@ -177,7 +174,7 @@ Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboBackgroundSuit.SelectionChanged, ComboCustomPreset.SelectionChanged If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex) End Sub - Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckMusicStop.Change, CheckMusicRandom.Change, CheckMusicAuto.Change, CheckBackgroundColorful.Change, CheckLogoLeft.Change, CheckLauncherLogo.Change, CheckHiddenFunctionHidden.Change, CheckHiddenFunctionSelect.Change, CheckHiddenFunctionModUpdate.Change, CheckHiddenPageDownload.Change, CheckHiddenPageLink.Change, CheckHiddenPageOther.Change, CheckHiddenPageSetup.Change, CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change, CheckHiddenOtherHelp.Change, CheckHiddenOtherTest.Change, CheckMusicStart.Change, CheckLauncherEmail.Change + Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckMusicStop.Change, CheckMusicRandom.Change, CheckMusicAuto.Change, CheckBackgroundColorful.Change, CheckLogoLeft.Change, CheckLauncherLogo.Change, CheckHiddenFunctionHidden.Change, CheckHiddenFunctionSelect.Change, CheckHiddenPageDownload.Change, CheckHiddenPageLink.Change, CheckHiddenPageOther.Change, CheckHiddenPageSetup.Change, CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change, CheckHiddenOtherHelp.Change, CheckHiddenOtherTest.Change, CheckMusicStart.Change, CheckLauncherEmail.Change If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked) End Sub Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextLogoText.ValidatedTextChanged, TextCustomNet.ValidatedTextChanged @@ -272,16 +269,17 @@ End Try End Sub + '顶部栏 Private Sub BtnLogoChange_Click(sender As Object, e As EventArgs) Handles BtnLogoChange.Click - Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.gif;*.webp)|*.png;*.jpg;*.gif;*.webp", "选择图片") + Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.gif)|*.png;*.jpg;*.gif", "选择图片") If FileName = "" Then Exit Sub Try '拷贝文件 File.Delete(Path & "PCL\Logo.png") CopyFile(FileName, Path & "PCL\Logo.png") '设置当前显示 - FrmMain.ImageTitleLogo.Source = Path & "PCL\Logo.png" + FrmMain.ImageTitleLogo.Source = New MyBitmap(Path & "PCL\Logo.png") Catch ex As Exception If ex.Message.Contains("参数无效") Then Log("改变标题栏图片失败,该图片文件可能并非标准格式。" & vbCrLf & @@ -298,7 +296,7 @@ Refresh: '已有图片则不再选择 If File.Exists(Path & "PCL\Logo.png") Then Try - FrmMain.ImageTitleLogo.Source = Path & "PCL\Logo.png" + FrmMain.ImageTitleLogo.Source = New MyBitmap(Path & "PCL\Logo.png") Catch ex As Exception If ex.Message.Contains("参数无效") Then Log("调整标题栏图片失败,该图片文件可能并非标准格式。" & vbCrLf & @@ -317,7 +315,7 @@ Refresh: Exit Sub End If '没有图片则要求选择 - Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.gif;*.webp)|*.png;*.jpg;*.gif;*.webp", "选择图片") + Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.gif)|*.png;*.jpg;*.gif", "选择图片") If FileName = "" Then FrmMain.ImageTitleLogo.Source = Nothing e.Handled = True @@ -430,8 +428,8 @@ Refresh: RadioLauncherTheme5Gray.Opacity -= 0.23 RadioLauncherTheme5.Opacity += 0.23 AniStart({ - AaOpacity(RadioLauncherTheme5Gray, 1, 1000 * AniSpeed), - AaOpacity(RadioLauncherTheme5, -1, 1000 * AniSpeed) + AaOpacity(RadioLauncherTheme5Gray, 1, 1000), + AaOpacity(RadioLauncherTheme5, -1, 1000) }, "ThemeUnlock") If RadioLauncherTheme5Gray.Opacity < 0.08 Then ThemeUnlock(5, UnlockHint:="隐藏主题 玄素黑 已解锁!") @@ -452,10 +450,10 @@ Refresh: End If End If End Sub - Private Sub LabLauncherTheme8Copy_MouseRightButtonUp() Handles LabLauncherTheme8Copy.MouseRightButtonUp, RadioLauncherTheme8.MouseRightButtonUp + Private Sub LabLauncherTheme8Copy_MouseRightButtonUp() Handles LabLauncherTheme8Copy.MouseRightButtonUp OpenWebsite("https://afdian.com/a/LTCat") End Sub - Private Sub LabLauncherTheme9Copy_MouseRightButtonUp() Handles LabLauncherTheme9Copy.MouseRightButtonUp, RadioLauncherTheme9.MouseRightButtonUp + Private Sub LabLauncherTheme9Copy_MouseRightButtonUp() Handles LabLauncherTheme9Copy.MouseRightButtonUp PageOtherLeft.TryFeedback() End Sub @@ -675,26 +673,24 @@ Refresh: SliderLauncherOpacity.GetHintText = Function(v) Math.Round(40 + v * 0.1) & "%" SliderLauncherHue.GetHintText = Function(v) v & "°" SliderLauncherSat.GetHintText = Function(v) v & "%" - SliderLauncherDelta.GetHintText = - Function(Value As Integer) - If Value > 90 Then - Return "+" & (Value - 90) - ElseIf Value = 90 Then - Return 0 - Else - Return Value - 90 - End If - End Function - SliderLauncherLight.GetHintText = - Function(Value As Integer) - If Value > 20 Then - Return "+" & (Value - 20) - ElseIf Value = 20 Then - Return 0 - Else - Return Value - 20 - End If - End Function + SliderLauncherDelta.GetHintText = Function(Value As Integer) + If Value > 90 Then + Return "+" & (Value - 90) + ElseIf Value = 90 Then + Return 0 + Else + Return Value - 90 + End If + End Function + SliderLauncherLight.GetHintText = Function(Value As Integer) + If Value > 20 Then + Return "+" & (Value - 20) + ElseIf Value = 20 Then + Return 0 + Else + Return Value - 20 + End If + End Function SliderBackgroundOpacity.GetHintText = Function(v) Math.Round(v * 0.1) & "%" SliderBackgroundBlur.GetHintText = Function(v) v & " 像素" End Sub diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb index a53362b6..d69ac034 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb @@ -75,7 +75,7 @@ Public Class PageVersionLeft PageChangeRun(PageGet(ID)) PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", LogLevel.Feedback) + Log(ex, "切换设置分页面失败(ID " & ID & ")", LogLevel.Feedback) Finally AniControlEnabled -= 1 End Try @@ -102,18 +102,17 @@ Public Class PageVersionLeft #End Region Public Sub Refresh(sender As Object, e As EventArgs) '由边栏按钮匿名调用 - Select Case Val(sender.Tag) - Case FormMain.PageSubType.VersionMod - PageVersionMod.Refresh() - Case FormMain.PageSubType.VersionScreenshot - PageVersionScreenshot.Refresh() - Case FormMain.PageSubType.VersionWorld - PageVersionWorld.Refresh() - Case FormMain.PageSubType.VersionResourcePack - PageVersionResourcePack.Refresh() - Case FormMain.PageSubType.VersionShader - PageVersionShader.Refresh() - End Select + '强制刷新 + Try + CompProjectCache.Clear() + File.Delete(PathTemp & "Cache\LocalMod.json") + Log("[Mod] 由于点击刷新按钮,清理本地 Mod 信息缓存") + Catch ex As Exception + Log(ex, "强制刷新时清理本地 Mod 信息缓存失败") + End Try + If FrmVersionMod IsNot Nothing Then FrmVersionMod.ReloadModList(True) '无需 Else,还没加载刷个鬼的新 + ItemMod.Checked = True + Hint("正在刷新……", Log:=False) End Sub Public Sub Reset(sender As Object, e As EventArgs) diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml index d00296d6..854458ef 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml @@ -16,13 +16,11 @@ - - - - - - + + + + @@ -39,19 +37,10 @@ - + - - - - - - - - - - - + + diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb index 459a65bd..372b6a7a 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb @@ -1,5 +1,4 @@ Public Class PageVersionMod - Implements IRefreshable #Region "初始化" @@ -31,43 +30,22 @@ ''' 刷新 Mod 列表。 ''' Public Sub ReloadModList(Optional ForceReload As Boolean = False) - If LoaderRun(If(ForceReload, LoaderFolderRunType.ForceRun, LoaderFolderRunType.RunOnUpdated)) Then + If LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", If(ForceReload, LoaderFolderRunType.ForceRun, LoaderFolderRunType.RunOnUpdated)) Then Log("[System] 已刷新 Mod 列表") Filter = FilterType.All PanBack.ScrollToHome() SearchBox.Text = "" End If End Sub - '强制刷新 - Private Sub RefreshSelf() Implements IRefreshable.Refresh - Refresh() - End Sub - Public Shared Sub Refresh() - '强制刷新 - Try - CompProjectCache.Clear() - CompFilesCache.Clear() - File.Delete(PathTemp & "Cache\LocalMod.json") - Log("[Mod] 由于点击刷新按钮,清理本地 Mod 信息缓存") - Catch ex As Exception - Log(ex, "强制刷新时清理本地 Mod 信息缓存失败") - End Try - If FrmVersionMod IsNot Nothing Then FrmVersionMod.ReloadModList(True) '无需 Else,还没加载刷个鬼的新 - FrmVersionLeft.ItemMod.Checked = True - Hint("正在刷新……", Log:=False) - End Sub Private Sub LoaderInit() Handles Me.Initialized PageLoaderInit(Load, PanLoad, PanAllBack, Nothing, McModLoader, AddressOf LoadUIFromLoaderOutput, AutoRun:=False) End Sub Private Sub Load_Click(sender As Object, e As MouseButtonEventArgs) Handles Load.Click If McModLoader.State = LoadState.Failed Then - LoaderRun(LoaderFolderRunType.ForceRun) + LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.ForceRun) End If End Sub - Public Function LoaderRun(Type As LoaderFolderRunType) As Boolean - Return LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", Type) - End Function #End Region @@ -155,13 +133,13 @@ ''' Public Sub RefreshUI() If PanList Is Nothing Then Exit Sub - Dim ShowingMods = If(IsSearching, SearchResult, If(McModLoader.Output, New List(Of McMod))).Where(Function(m) CanPassFilter(m)).ToList + Dim ShowMods = GetShowingMods(True).ToList() '重新列出列表 AniControlEnabled += 1 - If ShowingMods.Any() Then + If ShowMods.Any() Then PanList.Visibility = Visibility.Visible PanList.Children.Clear() - For Each TargetMod In ShowingMods + For Each TargetMod In ShowMods Dim Item As MyLocalModItem = ModItems(TargetMod.RawFileName) Item.Checked = SelectedMods.Contains(TargetMod.RawFileName) '更新选中状态 PanList.Children.Add(Item) @@ -170,7 +148,7 @@ PanList.Visibility = Visibility.Collapsed End If AniControlEnabled -= 1 - SelectedMods = SelectedMods.Where(Function(m) ShowingMods.Any(Function(s) s.RawFileName = m)).ToList '取消选中已经不显示的 Mod + SelectedMods = SelectedMods.Where(Function(m) ShowMods.Any(Function(s) s.RawFileName = m)).ToList '取消选中已经不显示的 Mod RefreshBars() End Sub @@ -188,7 +166,7 @@ Dim DisabledCount As Integer = 0 Dim UpdateCount As Integer = 0 Dim UnavalialeCount As Integer = 0 - For Each ModItem In If(IsSearching, SearchResult, If(McModLoader.Output, New List(Of McMod))) + For Each ModItem In GetShowingMods(False) AnyCount += 1 If ModItem.CanUpdate Then UpdateCount += 1 If ModItem.State.Equals(McMod.McModState.Fine) Then EnabledCount += 1 @@ -317,71 +295,14 @@ ''' 全选。 ''' Private Sub BtnManageSelectAll_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageSelectAll.Click - ChangeAllSelected(SelectedMods.Count < PanList.Children.Count) + ChangeAllSelected(SelectedMods.Count < GetShowingMods(True).Count) End Sub ''' ''' 安装 Mod。 ''' - Private Sub BtnManageInstall_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageInstall.Click, BtnHintInstall.Click - Dim FileList = SelectFiles("Mod 文件(*.jar;*.litemod;*.disabled;*.old)|*.jar;*.litemod;*.disabled;*.old", "选择要安装的 Mod") - If Not FileList.Any Then Return - InstallMods(FileList) - End Sub - ''' - ''' 尝试安装 Mod。 - ''' 返回输入的文件是否为一个 Mod 文件,仅用于判断拖拽行为。 - ''' - Public Shared Function InstallMods(FilePathList As IEnumerable(Of String)) As Boolean - Dim Extension As String = FilePathList.First.AfterLast(".").ToLower - '检查文件扩展名 - If Not {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then Return False - Log("[System] 文件为 jar/litemod 格式,尝试作为 Mod 安装") - '检查回收站:回收站中的文件有错误的文件名 - If FilePathList.First.Contains(":\$RECYCLE.BIN\") Then - Hint("请先将文件从回收站还原,再尝试安装!", HintType.Critical) - Return True - End If - '获取并检查目标版本 - Dim TargetVersion As McVersion = McVersionCurrent - If FrmMain.PageCurrent = FormMain.PageType.VersionSetup Then TargetVersion = PageVersionLeft.Version - If FrmMain.PageCurrent = FormMain.PageType.VersionSelect OrElse TargetVersion Is Nothing OrElse Not TargetVersion.Modable Then - '正在选择版本,或当前版本不能安装 Mod - Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!") - ElseIf Not (FrmMain.PageCurrent = FormMain.PageType.VersionSetup AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.VersionMod) Then - '未处于 Mod 管理页面 - If MyMsgBox($"是否要将这{If(FilePathList.Count = 1, "个", "些")}文件作为 Mod 安装到 {TargetVersion.Name}?", "Mod 安装确认", "确定", "取消") = 1 Then GoTo Install - Else - '处于 Mod 管理页面 -Install: - Try - For Each ModFile In FilePathList - Dim NewFileName = GetFileNameFromPath(ModFile).Replace(".disabled", "") - If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227 - CopyFile(ModFile, TargetVersion.PathIndie & "mods\" & NewFileName) - Next - If FilePathList.Count = 1 Then - Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "")}!", HintType.Finish) - Else - Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Finish) - End If - '刷新列表 - If FrmMain.PageCurrent = FormMain.PageType.VersionSetup AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.VersionMod Then - LoaderFolderRun(McModLoader, TargetVersion.PathIndie & "mods\", LoaderFolderRunType.ForceRun) - End If - Catch ex As Exception - Log(ex, "复制 Mod 文件失败", LogLevel.Msgbox) - End Try - End If - Return True - End Function - - ''' - ''' 下载 Mod。 - ''' - Private Sub BtnManageDownload_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageDownload.Click, BtnHintDownload.Click - PageDownloadMod.TargetVersion = PageVersionLeft.Version '将当前版本设置为筛选器 - FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadMod) + Private Sub BtnManageInstall_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageInstall.Click + Hint("将 Mod 文件直接拖入 PCL 窗口即可安装!") End Sub #End Region @@ -408,11 +329,9 @@ Install: Private Sub ChangeAllSelected(Value As Boolean) AniControlEnabled += 1 SelectedMods.Clear() - For Each Item As MyLocalModItem In ModItems.Values - '#4992,Mod 从过滤器看可能不应在列表中,但因为刚切换状态所以依然保留在列表中,所以应该从列表 UI 判断,而非从过滤器判断 - Dim ShouldSelected As Boolean = Value AndAlso PanList.Children.Contains(Item) - Item.Checked = ShouldSelected - If ShouldSelected Then SelectedMods.Add(Item.Entry.RawFileName) + For Each Item As MyLocalModItem In GetShowingMods(True).Select(Function(m) ModItems(m.RawFileName)) + Item.Checked = Value + If Value Then SelectedMods.Add(Item.Entry.RawFileName) Next AniControlEnabled -= 1 RefreshBars() @@ -462,6 +381,14 @@ Install: Unavailable = 4 End Enum + ''' + ''' 获取所有应该显示在 UI 中的 Mod。 + ''' + Private Function GetShowingMods(ApplyFilter As Boolean) As IEnumerable(Of McMod) + If McModLoader.Output Is Nothing Then Return New List(Of McMod) + Return If(IsSearching, SearchResult, McModLoader.Output).Where(Function(m) Not ApplyFilter OrElse CanPassFilter(m)) + End Function + ''' ''' 检查该 Mod 项是否符合当前筛选的类别。 ''' @@ -540,12 +467,10 @@ Install: '更改 Loader 中的列表 Dim NewModEntity As New McMod(NewPath) NewModEntity.FromJson(ModEntity.ToJson) - If McModLoader.Output.Contains(ModEntity) Then - Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity) - McModLoader.Output.RemoveAt(IndexOfLoader) - McModLoader.Output.Insert(IndexOfLoader, NewModEntity) - End If - If SearchResult IsNot Nothing AndAlso SearchResult.Contains(ModEntity) Then '#4862 + Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity) + McModLoader.Output.RemoveAt(IndexOfLoader) + McModLoader.Output.Insert(IndexOfLoader, NewModEntity) + If SearchResult IsNot Nothing Then Dim IndexOfResult As Integer = SearchResult.IndexOf(ModEntity) SearchResult.Remove(ModEntity) SearchResult.Insert(IndexOfResult, NewModEntity) @@ -564,7 +489,6 @@ Install: Hint("由于文件被占用,Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical) ReloadModList(True) End If - LoaderRun(LoaderFolderRunType.UpdateOnly) End Sub '更新 @@ -580,8 +504,8 @@ Install: Public Shared UpdatingVersions As New List(Of String) Public Sub UpdateMods(ModList As IEnumerable(Of McMod)) '更新前警告 - If Not Setup.Get("HintUpdateMod") OrElse ModList.Count >= 15 Then - If MyMsgBox($"新版本 Mod 可能不兼容旧存档或者其他 Mod,这可能导致游戏崩溃,甚至永久损坏存档!{vbCrLf}如果你在游玩整合包,请千万不要自行更新 Mod!{vbCrLf}{vbCrLf}在更新前,请先备份存档,并检查 Mod 的更新日志。{vbCrLf}如果更新后出现问题,你也可以在回收站找回更新前的 Mod。", "Mod 更新警告", "我已了解风险,继续更新", "取消", IsWarn:=True) = 1 Then + If Not Setup.Get("HintUpdateMod") Then + If MyMsgBox($"新版本 Mod 可能不兼容老版本的存档或者其他 Mod,这可能导致游戏崩溃,甚至存档损坏!{vbCrLf}除非整合包作者要求你更新,否则不要私自更新整合包里的 Mod!{vbCrLf}在更新 Mod 前,请先备份存档,并检查它的更新日志!{vbCrLf}更新时,老版本的 Mod 会被移动到回收站,以防万一。{vbCrLf}{vbCrLf}请在认真阅读上述警告后再继续!", "Mod 更新警告", "我已了解上述风险,继续更新", "取消", IsWarn:=True) = 1 Then Setup.Set("HintUpdateMod", True) Else Exit Sub @@ -772,7 +696,6 @@ Install: Log(ex, "删除 Mod 出现未知错误", LogLevel.Feedback) ReloadModList(True) End Try - LoaderRun(LoaderFolderRunType.UpdateOnly) End Sub '取消选择 diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml index 44686fc9..10858086 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml @@ -213,7 +213,7 @@ + ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。 在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。 可以使用以下替换标记实现相对路径(路径均以 \ 结尾): · {path}:PCL 的 exe 文件所在的文件夹 · {minecraft}:.minecraft 文件夹 · {verpath}:版本文件夹(.minecraft\versions\版本名\) · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹 · {java}:游戏运行时的 Java 文件夹 除此之外,也支持以下替换标记: · {user}:玩家名字 · {login}:玩家的登录方式 · {uuid}:玩家的 UUID · {name}:游戏版本名 · {date}、{time}:当前的系统时间 · {version}:游戏对应的原版版本号 例如: · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar · notepad "{verindie}option.txt" :使用记事本打开该版本的设置文件 涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。 执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" /> diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb index bc2ed251..fbf344d9 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb @@ -173,7 +173,7 @@ If(RamGame <> RamGameActual, " (可用 " & If(RamGameActual = Math.Floor(RamGameActual), RamGameActual & ".0", RamGameActual) & " GB)", "") LabRamUsed.Text = If(RamUsed = Math.Floor(RamUsed), RamUsed & ".0", RamUsed) & " GB" LabRamTotal.Text = " / " & If(RamTotal = Math.Floor(RamTotal), RamTotal & ".0", RamTotal) & " GB" - LabRamWarn.Visibility = If(RamGame = 1 AndAlso Not JavaIs64Bit(PageVersionLeft.Version) AndAlso Not Is32BitSystem AndAlso JavaList.Any, Visibility.Visible, Visibility.Collapsed) + LabRamWarn.Visibility = If(RamGame = 1 AndAlso Not JavaIs64Bit(PageVersionLeft.Version) AndAlso Not Is32BitSystem, Visibility.Visible, Visibility.Collapsed) If ShowAnim Then '宽度动画 AniStart({ @@ -488,17 +488,15 @@ PreFin: #Region "其他设置" '版本隔离警告 - Private IsReverting As Boolean = False Private Sub ComboArgumentIndie_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ComboArgumentIndie.SelectionChanged If AniControlEnabled <> 0 Then Exit Sub - If IsReverting Then Exit Sub If MyMsgBox("调整版本隔离后,你可能得把游戏存档、Mod 等文件手动迁移到新的游戏文件夹中。" & vbCrLf & "如果修改后发现存档消失,把这项设置改回来就能恢复。" & vbCrLf & "如果你不会迁移存档,不建议修改这项设置!", "警告", "我知道我在做什么", "取消", IsWarn:=True) = 2 Then - IsReverting = True + AniControlEnabled += 1 ComboArgumentIndie.SelectedItem = e.RemovedItems(0) - IsReverting = False + AniControlEnabled -= 1 End If End Sub diff --git a/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj b/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj index cf7853c3..7bc0640e 100644 --- a/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj +++ b/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj @@ -186,7 +186,6 @@ - diff --git a/Plain Craft Launcher 2/Resources/Custom.xaml b/Plain Craft Launcher 2/Resources/Custom.xaml index 7f81da63..df177e3a 100644 --- a/Plain Craft Launcher 2/Resources/Custom.xaml +++ b/Plain Craft Launcher 2/Resources/Custom.xaml @@ -4,311 +4,311 @@ 你也可以使用 Ctrl + F 快速查找。例如,若需要改变文本颜色,则搜索 “颜色” 即可。 --> - + - + - - - + + - + - + - - + Text="Image 代表图片,你需要在它的 Source 属性中填写一个网址或文件路径,它会从该处获取图片并显示。通常需要使用 Height 限制它的高度。" /> + + - + - - - - + - + - - - - + - + - - - - - + - + - - - - - - + - - + - - - - - - - + - - - - + - - + - - + - - - + + - - - - - - + + + - - - - + + - + - + - + EventType="打开帮助" EventData="帮助/自定义帮助.json" Type="Clickable" /> - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - + - - + + - - + - + - - + - - + - - + - - + - - - - - - - - - + + + + + + + + + - - - - + + - - - + + - - - - - - - - + - - - + + - - +