diff --git a/Plain Craft Launcher 2/Application.xaml.vb b/Plain Craft Launcher 2/Application.xaml.vb
index 6c9a97d..6b7082a 100644
--- a/Plain Craft Launcher 2/Application.xaml.vb
+++ b/Plain Craft Launcher 2/Application.xaml.vb
@@ -19,7 +19,6 @@ Public Class Application
'开始
Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
- ApplicationStartTick = GetTimeTick()
SecretOnApplicationStart()
Try
'检查参数调用
@@ -104,9 +103,10 @@ Public Class Application
'日志初始化
LogStart()
'添加日志
- Log("[Start] 程序版本:" & VersionDisplayName & "(" & VersionCode & ")")
- Log("[Start] 识别码:" & UniqueAddress & If(ThemeCheckOne(9), ",已解锁反馈主题", ""))
- Log("[Start] 程序路径:" & PathWithName)
+ Log($"[Start] 程序版本:{VersionDisplayName} ({VersionCode})")
+ Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}")
+ Log($"[Start] 程序路径:{PathWithName}")
+ Log($"[Start] 系统编码:{Encoding.Default} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})")
'检测压缩包运行
If Path.Contains(IO.Path.GetTempPath()) OrElse Path.Contains("AppData\Local\Temp\") Then
MyMsgBox("PCL 正在临时文件夹运行,设置、游戏存档等很可能无法保存,且部分功能会无法使用或出错。" & vbCrLf & "请将 PCL 从压缩文件中解压,或是更换文件夹后再继续使用!", "环境警告", "我知道了", IsWarn:=True)
@@ -220,7 +220,7 @@ Public Class Application
Names.Remove(sender.Tag)
Setup.Set("LoginLegacyName", Join(Names, "¨"))
FrmLoginLegacy.ComboName.ItemsSource = Names
- FrmLoginLegacy.ComboName.Text = If(Names.Count > 0, Names(0), "")
+ FrmLoginLegacy.ComboName.Text = If(Names.Any, Names(0), "")
Case Else
'第三方
Dim Token As String = GetStringFromEnum(Setup.Get("LoginType"))
@@ -238,12 +238,12 @@ Public Class Application
Select Case Token
Case "Nide"
FrmLoginNide.ComboName.ItemsSource = Dict.Keys
- FrmLoginNide.ComboName.Text = If(Dict.Keys.Count > 0, Dict.Keys(0), "")
- FrmLoginNide.TextPass.Password = If(Dict.Values.Count > 0, Dict.Values(0), "")
+ FrmLoginNide.ComboName.Text = If(Dict.Keys.Any, Dict.Keys(0), "")
+ FrmLoginNide.TextPass.Password = If(Dict.Values.Any, Dict.Values(0), "")
Case "Auth"
FrmLoginAuth.ComboName.ItemsSource = Dict.Keys
- FrmLoginAuth.ComboName.Text = If(Dict.Keys.Count > 0, Dict.Keys(0), "")
- FrmLoginAuth.TextPass.Password = If(Dict.Values.Count > 0, Dict.Values(0), "")
+ FrmLoginAuth.ComboName.Text = If(Dict.Keys.Any, Dict.Keys(0), "")
+ FrmLoginAuth.TextPass.Password = If(Dict.Values.Any, Dict.Values(0), "")
End Select
End Select
End Sub
diff --git a/Plain Craft Launcher 2/Controls/MyScrollViewer.vb b/Plain Craft Launcher 2/Controls/MyScrollViewer.vb
index b341275..beaeb1c 100644
--- a/Plain Craft Launcher 2/Controls/MyScrollViewer.vb
+++ b/Plain Craft Launcher 2/Controls/MyScrollViewer.vb
@@ -8,10 +8,12 @@
Private Sub MyScrollViewer_PreviewMouseWheel(sender As Object, e As MouseWheelEventArgs) Handles Me.PreviewMouseWheel
If e.Delta = 0 OrElse ActualHeight = 0 OrElse ScrollableHeight = 0 Then Exit Sub
Dim SourceType = e.Source.GetType
- If Content.TemplatedParent Is Nothing AndAlso
- ((GetType(ComboBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, ComboBox).IsDropDownOpen) OrElse
- (GetType(TextBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, TextBox).AcceptsReturn) OrElse
- GetType(ComboBoxItem).IsAssignableFrom(SourceType)) Then
+ If Content.TemplatedParent Is Nothing AndAlso (
+ (GetType(ComboBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, ComboBox).IsDropDownOpen) OrElse
+ (GetType(TextBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, TextBox).AcceptsReturn) OrElse
+ GetType(ComboBoxItem).IsAssignableFrom(SourceType) OrElse
+ TypeOf e.Source Is CheckBox
+ ) Then
'如果当前是在对有滚动条的下拉框或文本框执行,则不接管操作
Exit Sub
End If
diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb
index 941e7f6..ee53027 100644
--- a/Plain Craft Launcher 2/FormMain.xaml.vb
+++ b/Plain Craft Launcher 2/FormMain.xaml.vb
@@ -10,6 +10,10 @@ Public Class FormMain
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
'统计更新日志条目
#If BETA Then
+ If LastVersion < 321 Then 'Release 2.7.1
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复启动部分整合包导致设置丢失的 Bug"))
+ BugCount += 1
+ End If
If LastVersion < 319 Then 'Release 2.7.0
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "支持更新 Mod"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持查看可更新的 Mod 的更新日志"))
@@ -96,7 +100,15 @@ Public Class FormMain
'3:BUG+ IMP* FEAT-
'2:BUG* IMP-
'1:BUG-
- If LastVersion < 318 Then 'Snapshot 2.7.1
+ If LastVersion < 322 Then 'Snapshot 2.7.2
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "添加 启动游戏前进行内存优化 设置"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化 MC 性能"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复安装 OptiFine 有概率失败的 Bug"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复启动 Fabric 1.20.5+ 时无法正确选择 Java 的 Bug"))
+ FeatureCount += 18
+ BugCount += 18
+ End If
+ If LastVersion < 320 Then 'Snapshot 2.7.1
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复启动部分整合包导致设置丢失的 Bug"))
BugCount += 1
End If
@@ -430,6 +442,8 @@ Public Class FormMain
Log("[Start] 最高版本号从 " & LowerVersionCode & " 升高到 " & VersionCode)
End If
#End If
+ '被移除的窗口设置选项
+ If Setup.Get("LaunchArgumentWindowType") = 5 Then Setup.Set("LaunchArgumentWindowType", 1)
'修改主题设置项名称
If LowerVersionCode <= 207 Then
Dim UnlockedTheme As New List(Of String) From {"2"}
@@ -653,7 +667,7 @@ Public Class FormMain
If e.ChangedButton = MouseButton.XButton1 OrElse e.ChangedButton = MouseButton.XButton2 Then TriggerPageBack()
End Sub
Private Sub TriggerPageBack()
- If PageCurrent = PageType.Download AndAlso PageCurrentSub = PageSubType.DownloadInstall Then
+ If PageCurrent = PageType.Download AndAlso PageCurrentSub = PageSubType.DownloadInstall AndAlso FrmDownloadInstall.IsInSelectPage Then
FrmDownloadInstall.ExitSelectPage()
Else
PageBack()
@@ -761,7 +775,7 @@ Public Class FormMain
RunInNewThread(
Sub()
Dim FilePath As String = FilePathList.First
- Log("[System] 接受文件拖拽:" & FilePath & If(FilePathList.Count > 0, $" 等 {FilePathList.Count} 个文件", ""), LogLevel.Developer)
+ Log("[System] 接受文件拖拽:" & FilePath & If(FilePathList.Any, $" 等 {FilePathList.Count} 个文件", ""), LogLevel.Developer)
'基础检查
If Directory.Exists(FilePathList.First) AndAlso Not File.Exists(FilePathList.First) Then
Hint("请拖入一个文件,而非文件夹!", HintType.Critical)
@@ -1176,8 +1190,11 @@ Install:
''' 通过点击返回按钮或手动触发返回来改变页面。
'''
Public Sub PageBack() Handles BtnTitleInner.Click
- If Not PageStack.Any() Then Exit Sub
- PageChangeActual(PageStack(0))
+ If PageStack.Any() Then
+ PageChangeActual(PageStack(0))
+ Else
+ PageChange(PageType.Launch)
+ End If
End Sub
'实际处理页面切换
@@ -1357,23 +1374,22 @@ Install:
End Sub
Private Sub PanMainLeft_Resize(NewWidth As Double)
Dim Delta As Double = NewWidth - RectLeftBackground.Width
- If Math.Abs(Delta) < 0.1 Then Exit Sub
- If AniControlEnabled = 0 Then
+ If Math.Abs(Delta) > 0.1 AndAlso AniControlEnabled = 0 Then
If PanMain.Opacity < 0.1 Then PanMainLeft.IsHitTestVisible = False '避免左边栏指向背景未能完美覆盖左边栏
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)
- }, "FrmMain LeftChange", True)
+ 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)
- }, "FrmMain LeftChange", True)
+ AaWidth(RectLeftBackground, -RectLeftBackground.Width, 200,, New AniEaseOutFluent),
+ AaOpacity(RectLeftShadow, -RectLeftShadow.Opacity, 200),
+ AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 170)
+ }, "FrmMain LeftChange", True)
End If
Else
RectLeftBackground.Width = NewWidth
diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb
index 7ec28b6..dfb628d 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModBase.vb
@@ -11,12 +11,12 @@ Public Module ModBase
#Region "声明"
'下列版本信息由更新器自动修改
- Public Const VersionBaseName As String = "2.7.1" '不含分支前缀的显示用版本名
- Public Const VersionStandardCode As String = "2.7.1." & VersionBranchCode '标准格式的四段式版本号
+ Public Const VersionBaseName As String = "2.7.2" '不含分支前缀的显示用版本名
+ Public Const VersionStandardCode As String = "2.7.2." & VersionBranchCode '标准格式的四段式版本号
#If BETA Then
- Public Const VersionCode As Integer = 319 'Release
+ Public Const VersionCode As Integer = 321 'Release
#Else
- Public Const VersionCode As Integer = 320 'Snapshot
+ Public Const VersionCode As Integer = 322 'Snapshot
#End If
'自动生成的版本信息
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -58,7 +58,7 @@ Public Module ModBase
'''
''' 程序的打开计时。
'''
- Public ApplicationStartTick As Long
+ Public ApplicationStartTick As Long = GetTimeTick()
'''
''' 程序打开时的时间。
'''
@@ -76,6 +76,10 @@ Public Module ModBase
'''
Public Is32BitSystem As Boolean = Not Environment.Is64BitOperatingSystem
'''
+ ''' 是否使用 GBK 编码。
+ '''
+ Public IsGBKEncoding As Boolean = Encoding.Default.CodePage = 936
+ '''
''' 操作系统版本。Win10 为 10.0。
'''
Public OsVersion As Version = Environment.OSVersion.Version
@@ -726,8 +730,8 @@ Public Module ModBase
Public Function GetFileNameFromPath(FilePath As String) As String
FilePath = FilePath.Replace("/", "\")
If FilePath.EndsWithF("\") Then Throw New Exception("不包含文件名:" & FilePath)
- If FilePath.Contains("\") Then FilePath = FilePath.Substring(FilePath.LastIndexOfF("\") + 1)
If FilePath.Contains("?") Then FilePath = FilePath.Substring(0, FilePath.IndexOfF("?")) '去掉网络参数后的 ?
+ If FilePath.Contains("\") Then FilePath = FilePath.Substring(FilePath.LastIndexOfF("\") + 1)
Dim length As Integer = FilePath.Length
If length = 0 Then Throw New Exception("不包含文件名:" & FilePath)
If length > 250 Then Throw New PathTooLongException("文件名过长:" & FilePath)
@@ -1215,43 +1219,35 @@ Re:
'''
''' 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 jar 以 zip 方式解压。
''' 会尝试创建,但不会清空目标文件夹。
- ''' 成功返回 True,并非压缩文件或失败返回 False。
'''
- Public Function ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing) As Boolean
- Try
- Directory.CreateDirectory(DestDirectory)
- If CompressFilePath.EndsWithF(".gz", True) Then
- '以 gz 方式解压
- Dim stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.ReadWrite), CompressionMode.Decompress)
- Dim decompressedFile As New FileStream(DestDirectory & GetFileNameFromPath(CompressFilePath).ToLower.Replace(".tar", "").Replace(".gz", ""), FileMode.OpenOrCreate, FileAccess.Write)
- Dim data As Integer = stream.ReadByte()
- While data <> -1
- decompressedFile.WriteByte(data)
- data = stream.ReadByte()
- End While
- decompressedFile.Close()
- stream.Close()
- Return True
- Else
- '以 zip 方式解压
- Using Archive = ZipFile.Open(CompressFilePath, ZipArchiveMode.Read, If(Encode, Encoding.GetEncoding("GB18030")))
- For Each Entry As ZipArchiveEntry In Archive.Entries
- Dim DestinationPath As String = IO.Path.Combine(DestDirectory, Entry.FullName)
- If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then
- Continue For '不创建空文件夹
- Else
- Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
- Entry.ExtractToFile(DestinationPath, True)
- End If
- Next
- End Using
- Return True
- End If
- Catch ex As Exception
- Log(ex, "尝试解压文件失败")
- Return False
- End Try
- End Function
+ Public Sub ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing)
+ Directory.CreateDirectory(DestDirectory)
+ If CompressFilePath.EndsWithF(".gz", True) Then
+ '以 gz 方式解压
+ Dim stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.ReadWrite), CompressionMode.Decompress)
+ Dim decompressedFile As New FileStream(DestDirectory & GetFileNameFromPath(CompressFilePath).ToLower.Replace(".tar", "").Replace(".gz", ""), FileMode.OpenOrCreate, FileAccess.Write)
+ Dim data As Integer = stream.ReadByte()
+ While data <> -1
+ decompressedFile.WriteByte(data)
+ data = stream.ReadByte()
+ End While
+ decompressedFile.Close()
+ stream.Close()
+ Else
+ '以 zip 方式解压
+ Using Archive = ZipFile.Open(CompressFilePath, ZipArchiveMode.Read, If(Encode, Encoding.GetEncoding("GB18030")))
+ For Each Entry As ZipArchiveEntry In Archive.Entries
+ Dim DestinationPath As String = IO.Path.Combine(DestDirectory, Entry.FullName)
+ If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then
+ Continue For '不创建空文件夹
+ Else
+ Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
+ Entry.ExtractToFile(DestinationPath, True)
+ End If
+ Next
+ End Using
+ End If
+ End Sub
'''
''' 删除文件夹,返回删除的文件个数。通过参数选择是否抛出异常。
@@ -1342,7 +1338,7 @@ Re:
Loop
DescList = DescList.Distinct.ToList
Dim Desc As String = Join(DescList, vbCrLf & "→ ")
- Dim Stack As String = If(StackList.Count > 0, vbCrLf & Join(StackList, vbCrLf), "")
+ Dim Stack As String = If(StackList.Any, vbCrLf & Join(StackList, vbCrLf), "")
'常见错误(记得同时修改下面的)
Dim CommonReason As String = Nothing
@@ -1541,6 +1537,12 @@ Re:
Next
Return tmp.ToString()
End Function
+ '''
+ ''' 检查字符串中的字符是否均为 ASCII 字符。
+ '''
+ Public Function IsASCII(Input As String) As Boolean
+ Return Input.All(Function(c) AscW(c) < 128)
+ End Function
'''
''' 高速的 StartsWith。
@@ -2073,7 +2075,7 @@ NextElement:
''' 传入两个对象,若第一个对象应该排在前面,则返回 True。
Public Function Sort(Of T)(List As IList(Of T), SortRule As CompareThreadStart(Of T)) As List(Of T)
Dim NewList As New List(Of T)
- While List.Count > 0
+ While List.Any
Dim Highest = List(0)
For i = 1 To List.Count - 1
If SortRule(List(i), Highest) Then Highest = List(i)
@@ -2646,7 +2648,7 @@ Retry:
'''
Public Function Shuffle(Of T)(array As IList(Of T)) As IList(Of T)
Shuffle = New List(Of T)
- Do While array.Count > 0
+ Do While array.Any
Dim i As Integer = RandomInteger(0, array.Count - 1)
Shuffle.Add(array(i))
array.RemoveAt(i)
diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
index f2bf1b4..9c1c573 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
@@ -571,7 +571,7 @@ Restart:
Public LoaderTaskbarProgress As Double = 0 '平滑后的进度
Private LoaderTaskbarProgressLast As Shell.TaskbarItemProgressState = Shell.TaskbarItemProgressState.None
- Public Sub LoaderTaskbarAdd(Loader As LoaderBase)
+ Public Sub LoaderTaskbarAdd(Of T)(Loader As LoaderCombo(Of T))
If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRemove(Loader)
SyncLock LoaderTaskbarLock
LoaderTaskbar.Add(Loader)
@@ -587,11 +587,11 @@ Restart:
'外显任务是否已经全部完成
Dim IsAllDownloadTaskCompleted As Boolean = True
For Each Loader In LoaderTaskbar
- If Loader.Show AndAlso Loader.State = LoadState.Loading Then IsAllDownloadTaskCompleted = False
+ If Loader.State = LoadState.Loading Then IsAllDownloadTaskCompleted = False
Next
'若单个任务已中止或全部任务已完成,则刷新并移除
For Each Task In LoaderTaskbar.ToList()
- If (IsAllDownloadTaskCompleted OrElse Task.State = LoadState.Aborted OrElse Task.State = LoadState.Waiting) AndAlso Task.Show Then
+ If IsAllDownloadTaskCompleted OrElse Task.State = LoadState.Aborted OrElse Task.State = LoadState.Waiting Then
If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRefresh(Task)
LoaderTaskbar.Remove(Task)
Log($"[Taskbar] {Task.Name} 已移出任务列表")
@@ -628,7 +628,6 @@ Restart:
Dim Total As Double = 0, Count As Integer = 0
SyncLock LoaderTaskbarLock
For Each Task In LoaderTaskbar.ToList
- If Not Task.Show Then Continue For
Total += Task.Progress
Count += 1 '避免多线程影响导致计数出错
Next
diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb
index 5bdf83a..ca3b5a2 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModNet.vb
@@ -1,4 +1,5 @@
Imports System.Net
+Imports PCL.ModNet
Public Module ModNet
Public Const NetDownloadEnd As String = ".PCLDownloading"
@@ -235,11 +236,11 @@ RequestFinished:
''' 以多线程下载网页文件的方式获取网页源代码。
'''
''' 网页的 Url 列表。
- Public Function NetGetCodeByDownload(Urls As String(), Optional Timeout As Integer = 45000, Optional IsJson As Boolean = False, Optional UseBrowserUserAgent As Boolean = False) As String
- Dim Temp As String = PathTemp & "Cache\Code\" & Urls(0).GetHashCode() & "_" & GetUuid()
+ Public Function NetGetCodeByDownload(Urls As IEnumerable(Of String), Optional Timeout As Integer = 45000, Optional IsJson As Boolean = False, Optional UseBrowserUserAgent As Boolean = False) As String
+ Dim Temp As String = PathTemp & "Cache\Code\" & Urls.First.GetHashCode() & "_" & GetUuid()
Dim NewTask As New LoaderDownload("源码获取 " & GetUuid() & "#", New List(Of NetFile) From {New NetFile(Urls, Temp, New FileChecker With {.IsJson = IsJson}, UseBrowserUserAgent)})
Try
- NewTask.WaitForExitTime(Timeout, TimeoutMessage:="连接服务器超时(第一下载源:" & Urls(0) & ")")
+ NewTask.WaitForExitTime(Timeout, TimeoutMessage:="连接服务器超时(第一下载源:" & Urls.First & ")")
NetGetCodeByDownload = ReadFile(Temp)
File.Delete(Temp)
Finally
@@ -448,7 +449,7 @@ RequestFinished:
'''
''' 速度下限。
'''
- Public NetTaskSpeedLimitLow As Long = 1024 * 1024L
+ Public NetTaskSpeedLimitLow As Long = 256 * 1024L '256K/s
'''
''' 速度上限。若无限制则为 -1。
'''
@@ -601,7 +602,7 @@ RequestFinished:
SyncLock Task.LockChain
If NextThread Is Nothing Then
If Task.IsUnknownSize Then
- Return 1024 * 1024 * 1024 '1G
+ Return 5 * 1024 * 1024 * 1024L '5G
Else
Return Task.FileSize - 1
End If
@@ -616,7 +617,7 @@ RequestFinished:
'''
Public ReadOnly Property DownloadUndone As Long
Get
- Return DownloadEnd + 1 - (DownloadStart + DownloadDone)
+ Return DownloadEnd - (DownloadStart + DownloadDone) + 1
End Get
End Property
'''
@@ -715,7 +716,7 @@ RequestFinished:
CurrentSource = Sources(Id)
End While
Return CurrentSource
- ElseIf SourcesOnce.Count > 0 Then
+ ElseIf SourcesOnce.Any Then
'仅存在单线程可用源
Return SourcesOnce(0)
Else
@@ -728,7 +729,7 @@ RequestFinished:
''' 是否已经没有可用源了。
'''
Public Function IsSourceFailed(Optional AllowOnceSource As Boolean = True) As Boolean
- If AllowOnceSource AndAlso SourcesOnce.Count > 0 Then Return False
+ If AllowOnceSource AndAlso SourcesOnce.Any Then Return False
SyncLock LockSource
For Each Source As NetSource In Sources
If Not Source.IsFailed Then Return False
@@ -754,15 +755,12 @@ RequestFinished:
''' 导致下载失败的原因。
'''
Public Ex As New List(Of Exception)
- ''''
- '''' 文件进行整体重试的计数。
- ''''
- 'Private RetryCount As Integer = 0
'''
''' 作为文件组成部分的线程链表。
+ ''' 如果没有线程,可以为 Nothing。
'''
- Private Threads As NetThread
+ Public Threads As NetThread
'''
''' 文件的总大小。若为 -2 则为未获取,若为 -1 则为无法获取准确大小。
@@ -844,10 +842,10 @@ RequestFinished:
Case NetState.Get
Return 0.04
Case NetState.Download
- '正在下载中,对应 5% ~ 99%
+ '正在下载中,对应 5% ~ 98%
Dim OriginalProgress As Double = If(IsUnknownSize, 0.5, DownloadDone / Math.Max(FileSize, 1))
OriginalProgress = 1 - (1 - OriginalProgress) ^ 0.9
- Return OriginalProgress * 0.94 + 0.05
+ Return OriginalProgress * 0.93 + 0.05
Case NetState.Merge
Return 0.99
Case NetState.Finish, NetState.Error
@@ -878,14 +876,13 @@ RequestFinished:
End Property
Private Const FilePieceLimit As Long = 256 * 1024
- Public ReadOnly RandomCode As Integer = RandomInteger(0, 999999)
Public ReadOnly LockCount As New Object
Public ReadOnly LockState As New Object
Public ReadOnly LockChain As New Object
Public ReadOnly LockSource As New Object
Public ReadOnly LockTasks As New Object
- Private ReadOnly Uuid As Integer = GetUuid()
+ Public ReadOnly Uuid As Integer = GetUuid()
Public Overrides Function Equals(obj As Object) As Boolean
Dim file = TryCast(obj, NetFile)
Return file IsNot Nothing AndAlso Uuid = file.Uuid
@@ -914,14 +911,15 @@ RequestFinished:
'''
''' 尝试开始一个新的下载线程。
+ ''' 如果失败,返回 Nothing。
'''
- Public Function TryBeginThread() As Boolean
+ Public Function TryBeginThread() As NetThread
Try
'条件检测
If NetTaskThreadCount >= NetTaskThreadLimit OrElse IsSourceFailed() OrElse
- (IsNoSplit AndAlso Threads IsNot Nothing AndAlso Threads.State <> NetState.Error) Then Return False
- If State >= NetState.Merge OrElse State = NetState.WaitForCheck Then Return False
+ (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
End SyncLock
@@ -936,7 +934,7 @@ RequestFinished:
'单线程
If IsSourceFailed(False) Then
'确认没有其他线程正使用此点
- If SourcesOnce(0).Thread IsNot Nothing AndAlso SourcesOnce(0).Thread.State <> NetState.Error Then Return False
+ If SourcesOnce(0).Thread IsNot Nothing AndAlso SourcesOnce(0).Thread.State <> NetState.Error Then Return Nothing
'占用此点
Capture:
SmailFileCache = Nothing
@@ -952,14 +950,8 @@ Capture:
If Threads Is Nothing Then
StartPosition = 0
StartSource = GetSource(FirstThreadSource)
- If StartSource Is Nothing Then
- '没有可用源了
- Throw New Exception("无可用源,请反馈此问题。")
- Else
- '有可用源
- FirstThreadSource = StartSource.Id + 1
- GoTo StartThread
- End If
+ FirstThreadSource = StartSource.Id + 1
+ GoTo StartThread
End If
'寻找失败点
For Each Thread As NetThread In Threads
@@ -971,24 +963,25 @@ Capture:
Next
'是否禁用多线程,以及规定碎片大小
Dim TargetUrl As String = GetSource().Url
- If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("gitcode.net") OrElse TargetUrl.Contains("github.com") Then Return False
+ If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("gitcode.net") OrElse TargetUrl.Contains("github.com") OrElse TargetUrl.Contains("modrinth.com") Then Return Nothing
'寻找最大碎片
+ 'FUTURE: 下载引擎重做,计算下载源平均链接时间和线程下载速度,按最高时间节省来开启多线程
Dim FilePieceMax As NetThread = Threads
For Each Thread As NetThread In Threads
If Thread.DownloadUndone > FilePieceMax.DownloadUndone Then FilePieceMax = Thread
Next
- If FilePieceMax Is Nothing OrElse FilePieceMax.DownloadUndone < FilePieceLimit Then Return False
+ If FilePieceMax Is Nothing OrElse FilePieceMax.DownloadUndone < FilePieceLimit Then Return Nothing
StartPosition = FilePieceMax.DownloadEnd - FilePieceMax.DownloadUndone * 0.4
StartSource = GetSource()
'开始线程
StartThread:
- If (StartPosition > FileSize AndAlso FileSize >= 0 AndAlso Not IsUnknownSize) OrElse StartPosition < 0 OrElse IsNothing(StartSource) Then Return False
+ If (StartPosition > FileSize AndAlso FileSize >= 0 AndAlso Not IsUnknownSize) OrElse StartPosition < 0 OrElse IsNothing(StartSource) Then Return Nothing
'构建线程
Dim ThreadUuid As Integer = GetUuid()
SyncLock LockTasks
- If Not Tasks.Any() Then Return False '由于中断,已没有可用任务
- Th = New Thread(AddressOf Thread) With {.Name = "NetTask " & Tasks(0).Uuid & "/" & Uuid & " Download " & ThreadUuid & "#", .Priority = ThreadPriority.BelowNormal}
+ If Not Tasks.Any() Then Return Nothing '由于中断,已没有可用任务
+ Th = New Thread(AddressOf Thread) With {.Name = $"NetTask {Tasks(0).Uuid}/{Uuid} Download {ThreadUuid}#", .Priority = ThreadPriority.BelowNormal}
End SyncLock
ThreadInfo = New NetThread With {.Uuid = ThreadUuid, .DownloadStart = StartPosition, .Thread = Th, .Source = StartSource, .Task = Me, .State = NetState.WaitForDownload}
'链表处理
@@ -1012,11 +1005,11 @@ StartThread:
If IsSourceFailed(False) Then SourcesOnce(0).Thread = ThreadInfo
End SyncLock
Th.Start(ThreadInfo)
- Return True
+ Return ThreadInfo
Catch ex As Exception
Log(ex, "尝试开始下载线程失败(" & If(LocalName, "Nothing") & ")", LogLevel.Hint)
- Return False
+ Return Nothing
End Try
End Function
'''
@@ -1040,35 +1033,44 @@ StartThread:
HttpRequest.Timeout = Timeout
HttpRequest.AddRange(Info.DownloadStart)
SecretHeadersSign(Info.Source.Url, HttpRequest, UseBrowserUserAgent)
+ Dim ContentLength As Long = 0
Using HttpResponse As HttpWebResponse = HttpRequest.GetResponse()
+ If ModeDebug AndAlso HttpResponse.ResponseUri.OriginalString <> Info.Source.Url Then
+ Log($"[Download] {LocalName} {Info.Uuid}#:重定向至 {HttpResponse.ResponseUri.OriginalString}")
+ End If
'文件大小校验
- Dim ThreadFileSize = HttpResponse.ContentLength
- If ThreadFileSize = -1 Then
+ ContentLength = HttpResponse.ContentLength
+ If ContentLength = -1 Then
If FileSize > 1 Then
- Log("[Download] " & LocalName & " " & Info.Uuid & "#:文件大小未知,但已从其他下载源获取,不作处理")
+ If Info.DownloadStart = 0 Then
+ Log($"[Download] {LocalName} {Info.Uuid}#:文件大小未知,但已从其他下载源获取,不作处理")
+ Else
+ Log($"[Download] {LocalName} {Info.Uuid}#:ContentLength 返回了 -1,无法确定是否支持分段下载,视作不支持")
+ GoTo NotSupportRange
+ End If
Else
FileSize = -1 : IsUnknownSize = True
- Log("[Download] " & LocalName & " " & Info.Uuid & "#:文件大小未知")
+ Log($"[Download] {LocalName} {Info.Uuid}#:文件大小未知")
End If
- ElseIf ThreadFileSize < 0 Then
- Throw New Exception("获取片大小失败,结果为 " & ThreadFileSize & "。")
+ ElseIf ContentLength < 0 Then
+ Throw New Exception("获取片大小失败,结果为 " & ContentLength & "。")
ElseIf Info.IsFirstThread Then
If Check IsNot Nothing Then
- If ThreadFileSize < Check.MinSize AndAlso Check.MinSize > 0 Then
- Throw New Exception("文件大小不足,获取结果为 " & ThreadFileSize & ",要求至少为 " & Check.MinSize & "。")
+ If ContentLength < Check.MinSize AndAlso Check.MinSize > 0 Then
+ Throw New Exception($"文件大小不足,获取结果为 {ContentLength},要求至少为 {Check.MinSize}。")
End If
- If ThreadFileSize <> Check.ActualSize AndAlso Check.ActualSize > 0 Then
- Throw New Exception("文件大小不一致,获取结果为 " & ThreadFileSize & ",要求必须为 " & Check.ActualSize & "。")
+ If ContentLength <> Check.ActualSize AndAlso Check.ActualSize > 0 Then
+ Throw New Exception($"文件大小不一致,获取结果为 {ContentLength},要求必须为 {Check.ActualSize}。")
End If
End If
- FileSize = ThreadFileSize : IsUnknownSize = False
- Log("[Download] " & LocalName & ":文件大小 " & ThreadFileSize & " B" & "(" & GetString(ThreadFileSize) & ")")
+ FileSize = ContentLength : IsUnknownSize = False
+ Log($"[Download] {LocalName} {Info.Uuid}#:文件大小 {ContentLength}({GetString(ContentLength)})")
'若文件大小大于 50 M,进行剩余磁盘空间校验
- If ThreadFileSize > 50 * 1024 * 1024 Then
+ If ContentLength > 50 * 1024 * 1024 Then
For Each Drive As DriveInfo In DriveInfo.GetDrives
Dim DriveName As String = Drive.Name.First.ToString
- Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ThreadFileSize * 1.1, 0) +
- If(LocalPath.StartsWithF(DriveName), ThreadFileSize + 5 * 1024 * 1024, 0)
+ Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ContentLength * 1.1, 0) +
+ If(LocalPath.StartsWithF(DriveName), ContentLength + 5 * 1024 * 1024, 0)
If Drive.TotalFreeSpace < RequiredSpace Then
Throw New Exception(DriveName & " 盘空间不足,无法进行下载。" & vbCrLf & "需要至少 " & GetString(RequiredSpace) & " 空间,但当前仅剩余 " & GetString(Drive.TotalFreeSpace) & "。" &
If(PathTemp.StartsWithF(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", ""))
@@ -1076,8 +1078,9 @@ StartThread:
Next
End If
ElseIf FileSize < 0 Then
- Throw New Exception("非首线程运行时,尚未获取文件大小。")
- ElseIf Info.DownloadStart > 0 AndAlso ThreadFileSize = FileSize Then
+ Throw New Exception("非首线程运行时,尚未获取文件大小")
+ ElseIf Info.DownloadStart > 0 AndAlso ContentLength = FileSize Then
+NotSupportRange:
SyncLock LockSource
If SourcesOnce.Contains(Info.Source) Then
GoTo SourceBreak
@@ -1085,10 +1088,11 @@ StartThread:
SourcesOnce.Add(Info.Source)
End If
End SyncLock
- Throw New WebException("该下载源不支持断点续传。")
- ElseIf Not FileSize - Info.DownloadStart = ThreadFileSize Then
- Throw New WebException("获取到的片大小不一致:线程结果为 " & ThreadFileSize & " B,任务结果为 " & FileSize & "B,起点为 " & Info.DownloadStart & "B。")
+ Throw New WebException($"该下载源不支持分段下载:Range 起始于 {Info.DownloadStart},预期 ContentLength 为 {FileSize - Info.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}")
+ ElseIf Not FileSize - Info.DownloadStart = ContentLength Then
+ Throw New WebException($"获取到的分段大小不一致:Range 起始于 {Info.DownloadStart},预期 ContentLength 为 {FileSize - Info.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}")
End If
+ 'Log($"[Download] {LocalName} {Info.Uuid}#:通过大小检查,文件大小 {FileSize},起始点 {Info.DownloadStart},ContentLength {ContentLength}")
Info.State = NetState.Get
SyncLock LockState
If State < NetState.Get Then State = NetState.Get
@@ -1108,7 +1112,7 @@ StartThread:
Dim HttpData As Byte() = New Byte(16384) {}
HttpDataCount = HttpStream.Read(HttpData, 0, 16384)
While (IsUnknownSize OrElse Info.DownloadUndone > 0) AndAlso '判断是否下载完成
- HttpDataCount > 0 AndAlso Not IsProgramEnded AndAlso State < NetState.Merge AndAlso (Not Info.Source.IsFailed OrElse Info.Equals(Info.Source.Thread))
+ HttpDataCount > 0 AndAlso Not IsProgramEnded AndAlso State < NetState.Merge AndAlso (Not Info.Source.IsFailed OrElse Info.Equals(Info.Source.Thread))
'限速
While NetTaskSpeedLimitHigh > 0 AndAlso NetTaskSpeedLimitLeft <= 0
Threading.Thread.Sleep(16)
@@ -1170,17 +1174,17 @@ StartThread:
End Using
End Using
SourceBreak:
- If HttpDataCount = 0 AndAlso Info.DownloadUndone > 0 AndAlso Not IsUnknownSize Then
- '服务器无返回数据
- Throw New Exception("服务器无返回数据,但下载尚未完成")
- ElseIf State = NetState.Error OrElse Info.Source.IsFailed OrElse (Info.DownloadUndone > 0 AndAlso Not IsUnknownSize) Then
+ If State = NetState.Error OrElse Info.Source.IsFailed OrElse (Info.DownloadUndone > 0 AndAlso Not IsUnknownSize) Then
'被外部中断
Info.State = NetState.Error
- Log("[Download] " & LocalName & " " & Info.Uuid & "#:中断")
+ Log($"[Download] {LocalName} {Info.Uuid}#:中断")
+ ElseIf HttpDataCount = 0 AndAlso Info.DownloadUndone > 0 AndAlso Not IsUnknownSize Then
+ '服务器无返回数据
+ Throw New Exception($"返回的 ContentLength 过多:ContentLength 为 {ContentLength},但获取到的总数据量仅为 {Info.DownloadDone}(全文件总数据量 {DownloadDone})")
Else
'本线程完成
Info.State = NetState.Finish
- If ModeDebug Then Log("[Download] " & LocalName & " " & Info.Uuid & "#:完成,已下载 " & GetString(Info.DownloadDone))
+ If ModeDebug Then Log($"[Download] {LocalName} {Info.Uuid}#:完成,已下载 {Info.DownloadDone}")
End If
Catch ex As Exception
'状态变更
@@ -1212,11 +1216,11 @@ SourceBreak:
'End SyncLock
Info.Source.Ex = ex
'根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传)
- 'BMCLAPI 的部分源在高频率请求下会返回 403,所以不应因此禁用下载源
If ex.Message.Contains("该下载源不支持") OrElse ex.Message.Contains("未能解析") OrElse ex.Message.Contains("(404)") OrElse
- ex.Message.Contains("(502)") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse ex.Message.Contains("获取到的片大小不一致") OrElse
- (Info.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 40) AndAlso DownloadDone < 1) OrElse
- Info.Source.FailCount > NetTaskThreadLimit Then
+ ex.Message.Contains("(502)") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse ex.Message.Contains("获取到的分段大小不一致") OrElse
+ (ex.Message.Contains("(403)") AndAlso Not Info.Source.Url.ContainsF("bmclapi")) OrElse 'BMCLAPI 的部分源在高频率请求下会返回 403,所以不应因此禁用下载源
+ (Info.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 30) AndAlso DownloadDone < 1) OrElse
+ Info.Source.FailCount > NetTaskThreadLimit + 2 Then
Dim IsThisFail As Boolean = False
SyncLock LockSource
If Info.Source.Thread IsNot Nothing AndAlso Info.Source.Thread.Equals(Info) Then
@@ -1232,8 +1236,8 @@ Wrong:
End SyncLock
'本线程引发下载源被禁用
If IsThisFail Then
- Log("[Download] " & LocalName & " " & Uuid & "#:下载源被禁用(" & Info.Source.Id & "):" & Info.Source.Url)
- Log(ex, "下载源 " & Info.Source.Id & " 已被禁用", If(ex.Message.Contains("不支持断点续传") OrElse ex.Message.Contains("(404)") OrElse ex.Message.Contains("(416)"), LogLevel.Developer, LogLevel.Debug))
+ Log($"[Download] {LocalName} {Info.Uuid}#:下载源被禁用({Info.Source.Id}):{Info.Source.Url}")
+ Log(ex, "下载源 " & Info.Source.Id & " 已被禁用", If(ex.Message.Contains("不支持分段下载") OrElse ex.Message.Contains("(404)") OrElse ex.Message.Contains("(416)"), LogLevel.Developer, LogLevel.Debug))
If IsSourceFailed() Then
'没有可用源
Log("[Download] 文件 " & LocalName & " 已无可用下载源")
@@ -1265,6 +1269,7 @@ Wrong:
SyncLock NetTaskThreadCountLock
NetTaskThreadCount -= 1
End SyncLock
+ '可能在没有下载完的时候开始合并文件了,这造成了大多数合并失败
If ((FileSize >= 0 AndAlso DownloadDone >= FileSize) OrElse (FileSize = -1 AndAlso DownloadDone > 0)) AndAlso State < NetState.Merge Then Merge()
End Try
End Sub
@@ -1287,7 +1292,6 @@ Wrong:
Try
Retry:
SyncLock LockChain
- If ModeDebug Then Log("[Download] " & LocalName & ":正在合并文件")
'创建文件夹
If File.Exists(LocalPath) Then File.Delete(LocalPath)
Dim Info As New FileInfo(LocalPath)
@@ -1295,6 +1299,7 @@ Retry:
'合并文件
If IsNoSplit Then
'仅有一个线程,从缓存中输出
+ If ModeDebug Then Log($"[Download] {LocalName}:下载结束,从缓存输出文件")
MergeFile = New FileStream(LocalPath, FileMode.Create)
AddWriter = New BinaryWriter(MergeFile)
AddWriter.Write(SmailFileCache.ToArray)
@@ -1302,17 +1307,19 @@ Retry:
MergeFile.Dispose() : MergeFile = Nothing
ElseIf Threads.DownloadDone = DownloadDone AndAlso Threads.Temp IsNot Nothing Then
'仅有一个文件,直接复制
+ If ModeDebug Then Log($"[Download] {LocalName}:下载结束,仅有一个文件,无需合并")
CopyFile(Threads.Temp, LocalPath)
Else
'有多个线程,合并
+ If ModeDebug Then Log($"[Download] {LocalName}:下载结束,开始合并文件")
MergeFile = New FileStream(LocalPath, FileMode.Create)
AddWriter = New BinaryWriter(MergeFile)
For Each Thread As NetThread In Threads
If Thread.DownloadDone = 0 OrElse Thread.Temp Is Nothing Then Continue For
Using fs As New FileStream(Thread.Temp, FileMode.Open, FileAccess.Read, FileShare.Read)
- Dim TempReader As New BinaryReader(fs)
- AddWriter.Write(TempReader.ReadBytes(fs.Length))
- TempReader.Close()
+ Using TempReader As New BinaryReader(fs)
+ AddWriter.Write(TempReader.ReadBytes(Thread.DownloadDone))
+ End Using
End Using
Next
AddWriter.Dispose() : AddWriter = Nothing
@@ -1329,9 +1336,9 @@ Retry:
'检查文件
Dim CheckResult As String = Check?.Check(LocalPath)
If CheckResult IsNot Nothing Then
- Log("[Download] " & Uuid & "# 的下载线程细节:")
+ Log($"[Download] {LocalName} 合并文件失败,下载线程细节:")
For Each Th As NetThread In Threads
- Log("[Download] " & Th.Uuid & "#,状态 " & GetStringFromEnum(CType(Th.State, [Enum])) & ",字节范围 " & Th.DownloadStart & "~" & (Th.DownloadStart + Th.DownloadDone) & ",字节剩余 " & Th.DownloadUndone)
+ Log($"[Download] {Th.Uuid}#,状态 {GetStringFromEnum(Th.State)},范围 {Th.DownloadStart}~{Th.DownloadStart + Th.DownloadDone},完成 {Th.DownloadDone},剩余 {Th.DownloadUndone}")
Next
Throw New Exception(CheckResult)
End If
@@ -1379,11 +1386,6 @@ Retry:
SyncLock NetManager.LockRemain
NetManager.FileRemain -= 1
Log("[Download] " & LocalName & ":已失败,剩余文件 " & NetManager.FileRemain)
- 'If NetManage.FileRemainList.Contains(LocalPath) Then
- ' NetManage.FileRemainList.Remove(LocalPath)
- 'Else
- ' Log("ERROR " & LocalPath)
- 'End If
End SyncLock
For Each Task In Tasks
Task.OnFileFail(Me)
@@ -1396,7 +1398,7 @@ Retry:
'确认任务移除
SyncLock LockTasks
Tasks.Remove(CausedByTask)
- If Tasks.Count > 0 Then Exit Sub
+ If Tasks.Any Then Exit Sub
End SyncLock
'确认中断
SyncLock LockState
@@ -1406,11 +1408,6 @@ Retry:
SyncLock NetManager.LockRemain
NetManager.FileRemain -= 1
If ModeDebug Then Log("[Download] " & LocalName & ":已取消,剩余文件 " & NetManager.FileRemain)
- 'If NetManage.FileRemainList.Contains(LocalPath) Then
- ' NetManage.FileRemainList.Remove(LocalPath)
- 'Else
- ' Log("ERROR " & LocalPath)
- 'End If
End SyncLock
End Sub
@@ -1426,11 +1423,6 @@ Retry:
SyncLock NetManager.LockRemain
NetManager.FileRemain -= 1
If PrintLog Then Log("[Download] " & LocalName & ":已完成,剩余文件 " & NetManager.FileRemain)
- 'If NetManage.FileRemainList.Contains(LocalPath) Then
- ' NetManage.FileRemainList.Remove(LocalPath)
- 'Else
- ' Log("ERROR " & LocalPath)
- 'End If
End SyncLock
SyncLock LockTasks
For Each Task In Tasks
@@ -1507,7 +1499,7 @@ FinishExCatch:
#End Region
'''
- ''' 刷新公开属性。由 NetManager 每 0.2 秒调用一次。
+ ''' 刷新公开属性。由 NetManager 每 0.1 秒调用一次。
'''
Public Sub RefreshStat()
'计算进度
@@ -1519,15 +1511,15 @@ FinishExCatch:
NewProgress += File.Progress * 0.2
TotalProgress += 0.2
Else
- NewProgress += File.Progress '* If(File.Progress < 1, 0.9, 1)
+ NewProgress += File.Progress
TotalProgress += 1
End If
Next
End SyncLock
If TotalProgress > 0 Then NewProgress /= TotalProgress
'刷新进度
- If NewProgress < 1 AndAlso NewProgress > 0 Then NewProgress = 1 - (1 - NewProgress) ^ 0.9 'MathBezier(NewProgress, 0, 0.05, 1, 0.8, 0.0001)
- _Progress = NewProgress * 0.99 + 0.01
+ If NewProgress < 1 AndAlso NewProgress > 0 Then NewProgress = 2 * (NewProgress ^ 3) - 3 * (NewProgress ^ 2) + 2 * NewProgress '2x^3-3x^2+2x,模拟开头和结尾更慢的情况
+ _Progress = NewProgress
End Sub
Public Sub New(Name As String, FileTasks As List(Of NetFile))
@@ -1556,71 +1548,72 @@ NextElement:
End SyncLock
State = LoadState.Loading
'开始执行
- RunInNewThread(Sub()
- Try
- '输入检测
- If Not Files.Any() Then
- OnFinish()
- Exit Sub
- End If
- For Each File As NetFile In Files
- If File Is Nothing Then Throw New ArgumentException("存在空文件请求!")
- For Each Source As NetSource In File.Sources
- If Not (Source.Url.StartsWithF("https://", True) OrElse Source.Url.StartsWithF("http://", True)) Then
- Source.Ex = New ArgumentException("输入的下载链接不正确!")
- Source.IsFailed = True
- End If
- Next
- If File.IsSourceFailed() Then Throw New ArgumentException("输入的下载链接不正确!")
- If Not File.LocalPath.ToLower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确!")
- If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径!")
- '文件夹检测
- Dim DirPath As String = New FileInfo(File.LocalPath).Directory.FullName
- If Not Directory.Exists(DirPath) Then Directory.CreateDirectory(DirPath)
- Next
- '接入下载管理器
- NetManager.Start(Me)
- '将文件分配给多个线程以进行已存在查找
- Dim Folders As New List(Of String) '可能会用于已存在查找的文件夹列表
- Dim FoldersFinal As New List(Of String) '最终用于查找的列表
- If Not Setup.Get("SystemDebugSkipCopy") Then '在设置中禁用复制
- Folders.Add(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\") '总是添加官启文件夹,因为 HMCL 会把所有文件存在这里
- For Each Folder In McFolderList
- Folders.Add(Folder.Path)
- Next
- Folders = Folders.Distinct.ToList
- For Each Folder In Folders
- If Folder <> PathMcFolder AndAlso Directory.Exists(Folder) Then FoldersFinal.Add(Folder)
- Next
- End If
- '最多 5 个线程,最少每个线程分配 10 个文件
- 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.Count > 0 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
- End Sub, "NetTask " & Uuid & " Main")
+ RunInNewThread(
+ Sub()
+ Try
+ '输入检测
+ If Not Files.Any() Then
+ OnFinish()
+ Exit Sub
+ End If
+ For Each File As NetFile In Files
+ If File Is Nothing Then Throw New ArgumentException("存在空文件请求!")
+ For Each Source As NetSource In File.Sources
+ If Not (Source.Url.StartsWithF("https://", True) OrElse Source.Url.StartsWithF("http://", True)) Then
+ Source.Ex = New ArgumentException("输入的下载链接不正确!")
+ Source.IsFailed = True
+ End If
+ Next
+ If File.IsSourceFailed() Then Throw New ArgumentException("输入的下载链接不正确!")
+ If Not File.LocalPath.ToLower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确!")
+ If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径!")
+ '文件夹检测
+ Dim DirPath As String = New FileInfo(File.LocalPath).Directory.FullName
+ If Not Directory.Exists(DirPath) Then Directory.CreateDirectory(DirPath)
+ Next
+ '接入下载管理器
+ NetManager.Start(Me)
+ '将文件分配给多个线程以进行已存在查找
+ Dim Folders As New List(Of String) '可能会用于已存在查找的文件夹列表
+ Dim FoldersFinal As New List(Of String) '最终用于查找的列表
+ If Not Setup.Get("SystemDebugSkipCopy") Then '在设置中禁用复制
+ Folders.Add(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\") '总是添加官启文件夹,因为 HMCL 会把所有文件存在这里
+ For Each Folder In McFolderList
+ Folders.Add(Folder.Path)
+ Next
+ Folders = Folders.Distinct.ToList
+ For Each Folder In Folders
+ If Folder <> PathMcFolder AndAlso Directory.Exists(Folder) Then FoldersFinal.Add(Folder)
+ Next
+ End If
+ '最多 5 个线程,最少每个线程分配 10 个文件
+ 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
+ End SyncLock
+ Catch ex As Exception
+ OnFail(New List(Of Exception) From {ex})
+ End Try
+ End Sub, "NetTask " & Uuid & " Main")
End Sub
Private Sub StartCopy(Files As List(Of NetFile), FolderList As List(Of String))
Try
- If ModeDebug Then Log("[Download] 检查线程分配文件数:" & Files.Count)
+ If ModeDebug Then Log("[Download] 检查线程分配文件数:" & Files.Count & ",线程名:" & Thread.CurrentThread.Name)
'试图从已存在的 Minecraft 文件夹中寻找目标文件
Dim ExistFiles As New List(Of KeyValuePair(Of NetFile, String)) '{NetFile, Target As String}
For Each File As NetFile In Files
@@ -1702,14 +1695,13 @@ Retry:
If ExList Is Nothing OrElse Not ExList.Any() Then ExList = New List(Of Exception) From {New Exception("未知错误!")}
'寻找第一个不是 404 的下载源
Dim UsefulExs = ExList.Where(Function(e) Not e.Message.Contains("(404)")).ToList
- [Error] = If(UsefulExs.Count > 0, UsefulExs(0), ExList(0))
+ [Error] = If(UsefulExs.Any, UsefulExs(0), ExList(0))
'获取实际失败的文件
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 & ")")).ToList(),
- vbCrLf), [Error])
+ File.Sources.Select(Function(s) If(s.Ex Is Nothing, s.Url, s.Ex.Message & "(" & s.Url & ")")), vbCrLf), [Error])
Exit For
End If
Next
@@ -1794,9 +1786,9 @@ Retry:
'''
Private SpeedLastDone As Long = 0
'''
- ''' 最近 10 次下载速度的记录,较新的在后面。间隔为 0.2 秒,故记录了 2 秒的速度。
+ ''' 至多最近 30 次下载速度的记录,较新的在前面。
'''
- Public SpeedLast As New List(Of Long) From {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ Private SpeedLast As New List(Of Long)
'这些属性由 RefreshStat 刷新
'''
''' 当前的全局下载速度,单位为 Byte / 秒。
@@ -1808,28 +1800,29 @@ Retry:
#End Region
'''
- ''' 进度与下载速度由下载管理线程每隔约 0.2 秒刷新一次。
+ ''' 进度与下载速度由下载管理线程每隔约 0.1 秒刷新一次。
'''
Private Sub RefreshStat()
Try
Dim DeltaTime As Long = GetTimeTick() - RefreshStatLast
RefreshStatLast += DeltaTime
#Region "刷新整体速度"
- '计算即时速度
+ '计算瞬时速度
Dim ActualSpeed As Double = Math.Max(0, (DownloadDone - SpeedLastDone) / (DeltaTime / 1000))
- SpeedLast.Add(ActualSpeed)
- SpeedLast.RemoveAt(0)
+ SpeedLast.Insert(0, ActualSpeed)
+ If SpeedLast.Count >= 31 Then SpeedLast.RemoveAt(30)
SpeedLastDone = DownloadDone
'计算用于显示的速度
- 'If SpeedLast(9) = 0 Then
- ' Speed = 0
- 'Else
- Speed = (SpeedLast(9) + SpeedLast(8) * 0.9 + SpeedLast(7) * 0.8 + SpeedLast(6) * 0.7 + SpeedLast(5) * 0.6 + SpeedLast(4) * 0.5 + SpeedLast(3) * 0.4 + SpeedLast(2) * 0.3 + SpeedLast(1) * 0.2 + SpeedLast(0) * 0.1) / 5.5
- 'End If
+ Dim SpeedSum As Long = 0, SpeedDiv As Long = 0, Weight = SpeedLast.Count
+ For Each SpeedRecord In SpeedLast
+ SpeedSum += SpeedRecord * Weight
+ SpeedDiv += Weight
+ Weight -= 1
+ Next
+ Speed = If(SpeedDiv > 0, SpeedSum / SpeedDiv, 0)
'计算新的速度下限
- SpeedLast.Add(ActualSpeed)
- SpeedLast.RemoveAt(0)
- Dim Limit As Long = Math.Min(Math.Min(Math.Min(Math.Min(SpeedLast(5), SpeedLast(6)), SpeedLast(7)), SpeedLast(8)), SpeedLast(9)) * 0.9
+ Dim Limit As Long = 0
+ If SpeedLast.Count >= 10 Then Limit = SpeedLast.Take(10).Average * 0.85 '取近 1 秒的平均速度的 85%
If Limit > NetTaskSpeedLimitLow Then
NetTaskSpeedLimitLow = Limit
Log("[Download] " & "速度下限已提升到 " & GetString(Limit))
@@ -1854,128 +1847,65 @@ Retry:
Private Sub StartManager()
If IsManagerStarted Then Exit Sub
IsManagerStarted = True
- RunInNewThread(
- Sub()
+ Dim ThreadStarter =
+ Sub(Id As Integer) '0 或 1
Try
- Dim LastLoopTime As Long
While True
- LastLoopTime = GetTimeTick()
+ Thread.Sleep(20)
'若已完成,则清空
- If FileRemain = 0 AndAlso Files.Count > 0 Then
+ If Id = 0 AndAlso FileRemain = 0 AndAlso Files.Any() Then
SyncLock LockFiles
Files.Clear()
End SyncLock
End If
- '开启新线程
- If Speed < NetTaskSpeedLimitLow OrElse FileRemain > NetTaskThreadLimit Then
- '速度小于下限或剩余文件还贼多,尝试开启线程
- Dim IsSuccess As Boolean = False
- Dim NewThreadCount As Integer
- '确定最大线程追加数
- NewThreadCount = Math.Max(FileRemain, MathClamp(NetTaskThreadCount / 2, 1, 4))
- NewThreadCount = Math.Floor(NewThreadCount / 2) '双线程启用减半
- NewThreadCount = MathClamp(NewThreadCount, 1, NetTaskThreadLimit)
- '循环追加
- Do
- IsSuccess = False
- '启动 Wait 的文件后立即会变成 Connect,导致第二次循环再次调用,所以需要先暂时存储进去……
- '此外为了减少 LockFiles 的占用时间,所以先遍历列表再开始
- Dim FilesWaiting As New List(Of NetFile)
- Dim FilesLoading As New List(Of NetFile)
- SyncLock LockFiles
- For Each File As NetFile In Files.Values
- If File.RandomCode Mod 2 = 0 Then Continue For
- If File.State = NetState.WaitForDownload Then
- FilesWaiting.Add(File)
- ElseIf File.State < NetState.Merge Then
- FilesLoading.Add(File)
- End If
- Next
- End SyncLock
- '为文件列表中的文件开始线程
- For Each File As NetFile In FilesWaiting
- If NewThreadCount = 0 Then Exit For
- If File.TryBeginThread() Then
- IsSuccess = True
- NewThreadCount -= 1
+ '获取文件列表
+ Dim AllFiles As List(Of NetFile)
+ SyncLock LockFiles
+ AllFiles = Files.Values.ToList()
+ End SyncLock
+ Dim WaitingFiles As New List(Of NetFile)
+ Dim OngoingFiles As New List(Of NetFile)
+ For Each File As NetFile In AllFiles
+ If File.Uuid Mod 2 = Id Then Continue For
+ If File.State = NetState.WaitForDownload Then
+ WaitingFiles.Add(File)
+ ElseIf File.State < NetState.Merge Then
+ OngoingFiles.Add(File)
+ End If
+ Next
+ '为等待中的文件开始线程
+ For Each File As NetFile In WaitingFiles
+ If NetTaskThreadCount >= NetTaskThreadLimit Then Continue While '最大线程数检查
+ Dim NewThread = File.TryBeginThread()
+ If NewThread IsNot Nothing AndAlso NewThread.Source.Url.Contains("bmclapi.") Then Thread.Sleep(40) '减少 BMCLAPI 请求频率,避免 Too Many Requests
+ Next
+ '为进行中的文件追加线程
+ If Speed >= NetTaskSpeedLimitLow Then Continue While '下载速度足够,无需新增
+ For Each File As NetFile In OngoingFiles
+ If NetTaskThreadCount >= NetTaskThreadLimit Then Continue While '最大线程数检查
+ '线程种类计数
+ Dim PreparingCount = 0, DownloadingCount = 0
+ If File.Threads IsNot Nothing Then
+ For Each Thread As NetThread In File.Threads.ToList
+ If Thread.State < NetState.Download Then
+ PreparingCount += 1
+ ElseIf Thread.State = NetState.Download Then
+ DownloadingCount += 1
End If
Next
- For Each File As NetFile In FilesLoading
- If NewThreadCount = 0 Then Exit For
- If File.TryBeginThread() Then
- IsSuccess = True
- NewThreadCount -= 1
- End If
- Next
- '等待 40 ms:BMCLAPI 部分时候有 20QPS 的限制
- Thread.Sleep(40)
- Loop While NewThreadCount > 0 AndAlso IsSuccess
- End If
- '等待 40 ms
- Thread.Sleep(40)
+ End If
+ '新增线程
+ If PreparingCount > DownloadingCount Then Continue For '准备中的线程已多于下载中的线程,不再新增
+ Dim NewThread = File.TryBeginThread()
+ If NewThread IsNot Nothing AndAlso NewThread.Source.Url.Contains("bmclapi.") Then Thread.Sleep(40) '减少 BMCLAPI 请求频率,避免 Too Many Requests
+ Next
End While
Catch ex As Exception
- Log(ex, "下载管理启动线程 1 出错", LogLevel.Assert)
+ Log(ex, $"下载管理启动线程 {Id} 出错", LogLevel.Assert)
End Try
- End Sub, "NetManager ThreadStarter Single")
- RunInNewThread(
- Sub()
- Try
- Dim LastLoopTime As Long
- While True
- LastLoopTime = GetTimeTick()
- '开启新线程
- If Speed < NetTaskSpeedLimitLow OrElse FileRemain > NetTaskThreadLimit Then
- '速度小于下限或剩余文件还贼多,尝试开启线程
- Dim IsSuccess As Boolean = False
- Dim NewThreadCount As Integer
- '确定最大线程追加数
- NewThreadCount = Math.Max(FileRemain, MathClamp(NetTaskThreadCount / 2, 1, 4))
- NewThreadCount = Math.Floor(NewThreadCount / 2) '双线程启用减半
- NewThreadCount = MathClamp(NewThreadCount, 1, NetTaskThreadLimit)
- '循环追加
- Do
- IsSuccess = False
- '启动 Wait 的文件后立即会变成 Connect,导致第二次循环再次调用,所以需要先暂时存储进去……
- '此外为了减少 LockFiles 的占用时间,所以先遍历列表再开始
- Dim FilesWaiting As New List(Of NetFile)
- Dim FilesLoading As New List(Of NetFile)
- SyncLock LockFiles
- For Each File As NetFile In Files.Values
- If File.RandomCode Mod 2 = 1 Then Continue For
- If File.State = NetState.WaitForDownload Then
- FilesWaiting.Add(File)
- ElseIf File.State < NetState.Merge Then
- FilesLoading.Add(File)
- End If
- Next
- End SyncLock
- '为文件列表中的文件开始线程
- For Each File As NetFile In FilesWaiting
- If NewThreadCount = 0 Then Exit For
- If File.TryBeginThread() Then
- IsSuccess = True
- NewThreadCount -= 1
- End If
- Next
- For Each File As NetFile In FilesLoading
- If NewThreadCount = 0 Then Exit For
- If File.TryBeginThread() Then
- IsSuccess = True
- NewThreadCount -= 1
- End If
- Next
- '等待 40 ms:BMCLAPI 部分时候有 20QPS 的限制
- Thread.Sleep(40)
- Loop While NewThreadCount > 0 AndAlso IsSuccess
- End If
- '等待 40 ms
- Thread.Sleep(40)
- End While
- Catch ex As Exception
- Log(ex, "下载管理启动线程 2 出错", LogLevel.Assert)
- End Try
- End Sub, "NetManager ThreadStarter Odd")
+ End Sub
+ RunInNewThread(Sub() ThreadStarter(0), "NetManager ThreadStarter 0")
+ RunInNewThread(Sub() ThreadStarter(1), "NetManager ThreadStarter 1")
RunInNewThread(
Sub()
Try
@@ -1989,8 +1919,8 @@ Retry:
NetTaskSpeedLimitLeftLast = TimeNow
'刷新公开属性
RefreshStat()
- '等待直至 170 ms
- Do While GetTimeTick() - LastLoopTime < 170
+ '等待直至 80 ms
+ Do While GetTimeTick() - LastLoopTime < 80
Thread.Sleep(10)
Loop
End While
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
index cc112ad..a993f7b 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
@@ -414,10 +414,10 @@
Json("Website") = Website
If LastUpdate IsNot Nothing Then Json("LastUpdate") = LastUpdate
Json("DownloadCount") = DownloadCount
- If ModLoaders IsNot Nothing AndAlso ModLoaders.Count > 0 Then Json("ModLoaders") = New JArray(ModLoaders.Select(Function(m) CInt(m)))
+ If ModLoaders IsNot Nothing AndAlso ModLoaders.Any Then Json("ModLoaders") = New JArray(ModLoaders.Select(Function(m) CInt(m)))
Json("Tags") = New JArray(Tags)
If LogoUrl IsNot Nothing Then Json("LogoUrl") = LogoUrl
- If GameVersions.Count > 0 Then Json("GameVersions") = New JArray(GameVersions)
+ If GameVersions.Any Then Json("GameVersions") = New JArray(GameVersions)
Json("CacheTime") = Date.Now '用于检查缓存时间
Return Json
End Function
@@ -596,7 +596,7 @@
SubtitleList = SubtitleList.Distinct().ToList()
'设置标题与描述
Dim Subtitle As String = ""
- If SubtitleList.Count > 0 Then
+ If SubtitleList.Any Then
For Each Ex In SubtitleList
Dim IsModLoaderDescription As Boolean =
Ex.ToLower.Contains("forge") OrElse Ex.ToLower.Contains("fabric") OrElse Ex.ToLower.Contains("quilt")
@@ -1356,9 +1356,9 @@ Retry:
Dim Info As String = ""
Select Case Type
Case CompType.Mod
- Info += If(ModLoaders.Count > 0,
+ Info += If(ModLoaders.Any,
"适用于 " & Join(ModLoaders.Select(Function(m) GetStringFromEnum(m)).ToList, "/") & ",", "")
- Info += If(ModeDebug AndAlso Dependencies.Count > 0, Dependencies.Count & " 个前置 Mod,", "")
+ Info += If(ModeDebug AndAlso Dependencies.Any, Dependencies.Count & " 个前置 Mod,", "")
Case CompType.ModPack
If GameVersions.All(Function(v) v.Contains("w")) Then
Info += $"游戏版本 {Join(GameVersions, "、")},"
@@ -1452,7 +1452,7 @@ Retry:
SelectMany(Function(f) f.RawDependencies).Distinct().ToList
Dim UndoneDeps = Deps.Where(Function(f) Not CompProjectCache.ContainsKey(f)).ToList
'获取前置 Mod 工程信息
- If UndoneDeps.Count > 0 Then
+ If UndoneDeps.Any Then
Log($"[Comp] {ProjectId} 文件列表中还需要获取信息的前置 Mod:{Join(UndoneDeps, ",")}")
Dim Projects As JArray
If TargetProject.FromCurseForge Then
@@ -1467,7 +1467,7 @@ Retry:
Next
End If
'更新前置 Mod 信息
- If Deps.Count > 0 Then
+ If Deps.Any Then
For Each DepProject In Deps.Select(Function(id) CompProjectCache(id))
For Each File In CompFilesCache(ProjectId)
If File.RawDependencies.Contains(DepProject.Id) AndAlso DepProject.Id <> ProjectId Then
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
index 01bba12..9ab3bb2 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
@@ -94,7 +94,7 @@
Log(ex, "读取可能的崩溃日志文件失败(" & FilePath & ")")
End Try
Next
- If LatestLog IsNot Nothing AndAlso LatestLog.Count > 0 Then
+ If LatestLog IsNot Nothing AndAlso LatestLog.Any Then
Dim RawOutput As String = Join(LatestLog, vbCrLf)
Log("[Crash] 以下为游戏输出的最后一段内容:" & vbCrLf & RawOutput)
WriteFile(TempFolder & "RawOutput.log", RawOutput)
@@ -110,21 +110,20 @@
Public Sub Import(FilePath As String)
Log("[Crash] 步骤 1:自主导入日志文件")
- '解压压缩包
+ '尝试视作压缩包解压
Try
Dim Info As New FileInfo(FilePath)
- If Not Info.Exists OrElse Info.Length = 0 Then Exit Try
- If Not FilePath.EndsWithF(".jar", True) AndAlso ExtractFile(FilePath, TempFolder & "Temp\") Then
- '解压成功
+ If Info.Exists AndAlso Info.Length > 0 AndAlso Not FilePath.EndsWithF(".jar", True) Then
+ ExtractFile(FilePath, TempFolder & "Temp\")
Log("[Crash] 已解压导入的日志文件:" & FilePath)
- Else
- '解压失败
- CopyFile(FilePath, TempFolder & "Temp\" & GetFileNameFromPath(FilePath))
- Log("[Crash] 已复制导入的日志文件:" & FilePath)
+ GoTo Extracted
End If
- Catch ex As Exception
- Log(ex, "解压导入文件中的压缩包失败")
+ Catch
End Try
+ '并非压缩包
+ CopyFile(FilePath, TempFolder & "Temp\" & GetFileNameFromPath(FilePath))
+ Log("[Crash] 已复制导入的日志文件:" & FilePath)
+Extracted:
'导入其中的日志文件
For Each TargetFile As FileInfo In New DirectoryInfo(TempFolder & "Temp\").EnumerateFiles.ToList()
@@ -389,9 +388,9 @@
'1. 精准日志匹配,中/高优先级
AnalyzeCrit1()
- If CrashReasons.Count > 0 Then GoTo Done
+ If CrashReasons.Any Then GoTo Done
AnalyzeCrit2()
- If CrashReasons.Count > 0 Then GoTo Done
+ If CrashReasons.Any Then GoTo Done
'2. 堆栈分析
If LogAll.Contains("orge") OrElse LogAll.Contains("abric") OrElse LogAll.Contains("uilt") OrElse LogAll.Contains("iteloader") Then
@@ -406,7 +405,7 @@
If LogMc IsNot Nothing Then
Dim Fatals = RegexSearch(LogMc, "/FATAL] [\w\W]+?(?=[\n]+\[)")
Log("[Crash] 开始进行 Minecraft 日志堆栈分析,发现 " & Fatals.Count & " 个报错项")
- If Fatals.Count > 0 Then
+ If Fatals.Any Then
For Each Fatal In Fatals
Keywords.AddRange(AnalyzeStackKeyword(Fatal))
Next
@@ -419,7 +418,7 @@
Keywords.AddRange(AnalyzeStackKeyword(StackLogs))
End If
'Mod 名称分析
- If Keywords.Count > 0 Then
+ If Keywords.Any Then
Dim Names = AnalyzeModName(Keywords)
If Names Is Nothing Then
AppendReason(CrashReason.堆栈分析发现关键字, Keywords)
@@ -442,7 +441,7 @@ Done:
Else
Log("[Crash] 步骤 3:分析崩溃原因完成,找到 " & CrashReasons.Count & " 条可能的原因")
For Each Reason In CrashReasons
- Log("[Crash] - " & GetStringFromEnum(Reason.Key) & If(Reason.Value.Count > 0, "(" & Join(Reason.Value, ";") & ")", ""))
+ Log("[Crash] - " & GetStringFromEnum(Reason.Key) & If(Reason.Value.Any, "(" & Join(Reason.Value, ";") & ")", ""))
Next
End If
End Sub
@@ -458,7 +457,7 @@ Done:
Else
CrashReasons.Add(Reason, New List(Of String)(If(Additional, {})))
End If
- Log("[Crash] 可能的崩溃原因:" & GetStringFromEnum(Reason) & If(Additional IsNot Nothing AndAlso Additional.Count > 0, "(" & Join(Additional, ";") & ")", ""))
+ Log("[Crash] 可能的崩溃原因:" & GetStringFromEnum(Reason) & If(Additional IsNot Nothing AndAlso Additional.Any, "(" & Join(Additional, ";") & ")", ""))
End Sub
Private Sub AppendReason(Reason As CrashReason, Additional As String)
AppendReason(Reason, If(String.IsNullOrEmpty(Additional), Nothing, New List(Of String) From {Additional}))
@@ -567,7 +566,6 @@ Done:
End If
End If
If LogCrash.Contains("Multiple entries with same key: ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=Multiple entries with same key: )[^=]+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
- If LogCrash.Contains("due to errors, provided by ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
If LogCrash.Contains("LoaderExceptionModCrash: Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=LoaderExceptionModCrash: Caught exception from )[^\n]+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
If LogCrash.Contains("Failed loading config file ") Then AppendReason(CrashReason.Mod配置文件导致游戏崩溃, {TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=Failed loading config file .+ for modid )[^\n]+"), "").TrimEnd(vbCrLf)).First, If(RegexSeek(LogCrash, "(?<=Failed loading config file ).+(?= of type)"), "").TrimEnd(vbCrLf)})
End If
@@ -612,6 +610,9 @@ Done:
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
'极短的程序输出
If Not (LogMc.Contains("at net.") OrElse LogMc.Contains("INFO]")) AndAlso LogHs Is Nothing AndAlso LogCrash Is Nothing AndAlso LogMc.Length < 100 Then
@@ -678,7 +679,7 @@ NextStack:
Next
PossibleWords = PossibleWords.Distinct.ToList
Log("[Crash] 从堆栈信息中找到 " & PossibleWords.Count & " 个可能的 Mod ID 关键词")
- If PossibleWords.Count > 0 Then Log("[Crash] - " & Join(PossibleWords, ", "))
+ If PossibleWords.Any Then Log("[Crash] - " & Join(PossibleWords, ", "))
If PossibleWords.Count > 10 Then
Log("[Crash] 关键词过多,考虑匹配出错,不纳入考虑")
Return New List(Of String)
@@ -847,7 +848,7 @@ NextStack:
FileName = "游戏崩溃前的输出.txt"
End Select
If File.Exists(OutputFile) Then
- WriteFile(TempFolder & "Report\" & FileName, SecretFilter(ReadFile(OutputFile)))
+ WriteFile(TempFolder & "Report\" & FileName, SecretFilter(ReadFile(OutputFile), If(FileName = "启动脚本.bat", "F", "*")))
End If
Next
'导出报告
@@ -903,7 +904,7 @@ NextStack:
Results.Add("你正在使用 32 位的操作系统,这会导致 Minecraft 无法使用所需的内存,进而造成崩溃。\n\n你或许只能重装 64 位的操作系统来解决此问题。\n如果你的电脑内存在 2GB 以内,那或许只能换台电脑了……\h")
End If
Case CrashReason.Mod缺少前置或MC版本错误
- If Additional.Count > 0 Then
+ If Additional.Any Then
Results.Add("由于未满足 Mod 的依赖项,导致游戏退出。\n未满足的依赖项:\n - " & Join(Additional, "\n - ") & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else
Results.Add("由于未满足 Mod 的依赖项,导致游戏退出。\n请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
index 9a725c5..237b084 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
@@ -79,7 +79,7 @@
Public Overrides Function ToString() As String
Dim VersionString = Version.ToString
If VersionString.StartsWithF("1.") Then VersionString = Mid(VersionString, 3)
- Return If(IsJre, "JRE ", "JDK ") & VersionCode & " (" & VersionString & ")," & If(Is64Bit, "64", "32") & " 位" & If(IsUserImport, ",手动导入", "") & ":" & PathFolder
+ Return If(IsJre, "JRE ", "JDK ") & VersionCode & " (" & VersionString & ")" & If(Is64Bit, "", ",32 位") & If(IsUserImport, ",手动导入", "") & ":" & PathFolder
End Function
'构造
@@ -220,7 +220,7 @@
Next
'检查特定的 Java
- If TargetJavaList.Count > 0 Then
+ If TargetJavaList.Any Then
TargetJavaList = JavaCheckList(TargetJavaList)
Log("[Java] 检查后找到 " & TargetJavaList.Count & " 个特定路径下的 Java:")
For Each Java In TargetJavaList
@@ -534,7 +534,7 @@ NoUserJava:
Log("[Java] 位于 " & Folder & " 的 Java 不含符号链接")
JavaWithoutReparse.Add(Pair.Key, Pair.Value)
Next
- If JavaWithoutReparse.Count > 0 Then JavaPreList = JavaWithoutReparse
+ If JavaWithoutReparse.Any Then JavaPreList = JavaWithoutReparse
'若不全为特殊引用,则清除特殊引用的地址
Dim JavaWithoutInherit As New Dictionary(Of String, Boolean)
@@ -546,7 +546,7 @@ NoUserJava:
JavaWithoutInherit.Add(Pair.Key, Pair.Value)
End If
Next
- If JavaWithoutInherit.Count > 0 Then JavaPreList = JavaWithoutInherit
+ If JavaWithoutInherit.Any Then JavaPreList = JavaWithoutInherit
#End Region
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
index 383eb9a..ba856b5 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
@@ -62,7 +62,7 @@ Public Module ModLaunch
''' 记录启动日志。
'''
Public Sub McLaunchLog(Text As String)
- Text = SecretFilter(Text)
+ Text = SecretFilter(Text, "*")
RunInUi(Sub() FrmLaunchRight.LabLog.Text += vbCrLf & "[" & GetTimeNow() & "] " & Text)
Log("[Launch] " & Text)
End Sub
@@ -101,10 +101,10 @@ Public Module ModLaunch
'正式加载
Try
'构造主加载器
- Dim LaunchLoader As New LoaderCombo(Of Object)("Minecraft 启动", {
- New LoaderTask(Of Integer, Integer)("获取 Java", AddressOf McLaunchJava) With {.ProgressWeight = 4, .Block = False, .Show = False},
+ Dim Loaders As New List(Of LoaderBase) From {
+ New LoaderTask(Of Integer, Integer)("获取 Java", AddressOf McLaunchJava) With {.ProgressWeight = 4, .Block = False},
McLoginLoader,
- New LoaderCombo(Of String)("补全文件", DlClientFix(McVersionCurrent, False, AssetsIndexExistsBehaviour.DownloadInBackground, True)) With {.ProgressWeight = 15, .Show = False, .Block = True},
+ New LoaderCombo(Of String)("补全文件", DlClientFix(McVersionCurrent, False, AssetsIndexExistsBehaviour.DownloadInBackground, True)) With {.ProgressWeight = 15, .Show = False},
New LoaderTask(Of String, List(Of McLibToken))("获取启动参数", AddressOf McLaunchArgumentMain) With {.ProgressWeight = 2},
New LoaderTask(Of List(Of McLibToken), Integer)("解压文件", AddressOf McLaunchNatives) With {.ProgressWeight = 2},
New LoaderTask(Of Integer, Integer)("预启动处理", AddressOf McLaunchPrerun) With {.ProgressWeight = 1},
@@ -112,7 +112,12 @@ Public Module ModLaunch
New LoaderTask(Of Integer, Process)("启动进程", AddressOf McLaunchRun) With {.ProgressWeight = 2},
New LoaderTask(Of Process, Integer)("等待游戏窗口出现", AddressOf McLaunchWait) With {.ProgressWeight = 1},
New LoaderTask(Of Integer, Integer)("结束处理", AddressOf McLaunchEnd) With {.ProgressWeight = 1}
- }) With {.Show = False}
+ }
+ If Setup.Get("LaunchArgumentRam") Then
+ CType(Loaders(2), LoaderCombo(Of String)).Block = False
+ Loaders.Insert(3, New LoaderTask(Of Integer, Integer)("内存优化", AddressOf McLaunchMemoryOptimize) With {.ProgressWeight = 30})
+ End If
+ Dim LaunchLoader As New LoaderCombo(Of Object)("Minecraft 启动", Loaders) With {.Show = False}
If McLoginLoader.State = LoadState.Finished Then McLoginLoader.State = LoadState.Waiting '要求重启登录主加载器,它会自行决定是否启动副加载器
'等待加载器执行并更新 UI
McLaunchLoaderReal = LaunchLoader
@@ -163,6 +168,28 @@ NextInner:
#End Region
+#Region "内存优化"
+
+ Private Sub McLaunchMemoryOptimize(Loader As LoaderTask(Of Integer, Integer))
+ McLaunchLog("内存优化开始")
+ Dim Finished As Boolean = False
+ RunInNewThread(
+ Sub()
+ PageOtherTest.MemoryOptimize(False)
+ Finished = True
+ End Sub, "Launch Memory Optimize")
+ Do While Not Finished AndAlso Not Loader.IsAborted
+ If Loader.Progress < 0.7 Then
+ Loader.Progress += 0.007 '10s
+ Else
+ Loader.Progress += (0.95 - Loader.Progress) * 0.02 '最快 += 0.005
+ End If
+ Thread.Sleep(100)
+ Loop
+ End Sub
+
+#End Region
+
#Region "预检测"
Private Sub McLaunchPrecheck()
@@ -247,7 +274,7 @@ NextInner:
'''
Public BaseUrl As String
'''
- ''' 登录所使用的标识符,如 “Mojang”、“Nide”,用于存储缓存等。
+ ''' 登录所使用的标识符,目前只可能为 “Auth” 或 “Nide”,用于存储缓存等。
'''
Public Token As String
'''
@@ -526,7 +553,13 @@ SkipLogin:
McLaunchLog("登录方式:" & Input.Description & "(" & LogUsername & ")")
Data.Progress = 0.05
'尝试登录
- If (Not Data.Input.ForceReselectProfile) AndAlso Setup.Get("Cache" & Input.Token & "Username") = Data.Input.UserName AndAlso Setup.Get("Cache" & Input.Token & "Pass") = Data.Input.Password AndAlso Not Setup.Get("Cache" & Input.Token & "Access") = "" AndAlso Not Setup.Get("Cache" & Input.Token & "Client") = "" AndAlso Not Setup.Get("Cache" & Input.Token & "Uuid") = "" AndAlso Not Setup.Get("Cache" & Input.Token & "Name") = "" Then
+ If (Not Data.Input.ForceReselectProfile) AndAlso
+ Setup.Get("Cache" & Input.Token & "Username") = Data.Input.UserName AndAlso
+ Setup.Get("Cache" & Input.Token & "Pass") = Data.Input.Password AndAlso
+ Setup.Get("Cache" & Input.Token & "Access") <> "" AndAlso
+ Setup.Get("Cache" & Input.Token & "Client") <> "" AndAlso
+ Setup.Get("Cache" & Input.Token & "Uuid") <> "" AndAlso
+ Setup.Get("Cache" & Input.Token & "Name") <> "" Then
'尝试验证登录
Try
If Data.IsAborted Then Throw New ThreadInterruptedException
@@ -990,14 +1023,14 @@ SystemBrowser:
Case 1
'Steve
Do Until McSkinSex(Uuid) = "Steve"
- If Uuid.EndsWithF("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
- Uuid = Mid(Uuid, 1, 32 - 5) & (Long.Parse(Right(Uuid, 5), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X")
+ If Uuid.EndsWithF("FFFFF") Then Uuid = Uuid.Substring(0, 27) & "00000"
+ Uuid = Uuid.Substring(0, 27) & (Long.Parse(Uuid.Substring(27), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X").PadLeft(5, "0")
Loop
Case 2
'Alex
Do Until McSkinSex(Uuid) = "Alex"
- If Uuid.EndsWithF("FFFFF") Then Uuid = Mid(Uuid, 1, 32 - 5) & "00000"
- Uuid = Mid(Uuid, 1, 32 - 5) & (Long.Parse(Right(Uuid, 5), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X")
+ If Uuid.EndsWithF("FFFFF") Then Uuid = Uuid.Substring(0, 27) & "00000"
+ Uuid = Uuid.Substring(0, 27) & (Long.Parse(Uuid.Substring(27), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X").PadLeft(5, "0")
Loop
Case 3
'使用正版用户名
@@ -1096,22 +1129,25 @@ SystemBrowser:
If McVersionCurrent.Version.HasForge Then
If McVersionCurrent.Version.McName = "1.7.2" Then
'1.7.2:必须 Java 7
- MinVer = New Version(1, 7, 0, 0) : MaxVer = New Version(1, 7, 999, 999)
+ MinVer = If(New Version(1, 7, 0, 0) > MinVer, New Version(1, 7, 0, 0), MinVer)
+ MaxVer = If(New Version(1, 7, 999, 999) < MaxVer, New Version(1, 7, 999, 999), MaxVer)
ElseIf McVersionCurrent.Version.McCodeMain <= 12 AndAlso McVersionCurrent.Version.McCodeMain > 0 Then
'<=1.12:Java 8
MaxVer = New Version(1, 8, 999, 999)
ElseIf McVersionCurrent.Version.McCodeMain <= 14 AndAlso McVersionCurrent.Version.McCodeMain >= 13 Then
'1.13 - 1.14:Java 8 - 10
- MinVer = New Version(1, 8, 0, 0) : MaxVer = New Version(1, 10, 999, 999)
+ MinVer = If(New Version(1, 8, 0, 0) > MinVer, New Version(1, 8, 0, 0), MinVer)
+ MaxVer = If(New Version(1, 10, 999, 999) < MaxVer, New Version(1, 10, 999, 999), MaxVer)
ElseIf McVersionCurrent.Version.McCodeMain = 15 Then
'1.15:Java 8 - 15
- MinVer = New Version(1, 8, 0, 0) : MaxVer = New Version(1, 15, 999, 999)
+ MinVer = If(New Version(1, 8, 0, 0) > MinVer, New Version(1, 8, 0, 0), MinVer)
+ MaxVer = If(New Version(1, 15, 999, 999) < MaxVer, New Version(1, 15, 999, 999), MaxVer)
ElseIf VersionSortBoolean(McVersionCurrent.Version.ForgeVersion, "34.0.0") AndAlso VersionSortBoolean("36.2.25", McVersionCurrent.Version.ForgeVersion) Then
'1.16,Forge 34.X ~ 36.2.25:最高 Java 8u320
- MaxVer = New Version(1, 8, 0, 320)
+ MaxVer = If(New Version(1, 8, 0, 320) < MaxVer, New Version(1, 8, 0, 320), MaxVer)
ElseIf McVersionCurrent.Version.McCodeMain >= 18 AndAlso McVersionCurrent.Version.McCodeMain < 19 AndAlso McVersionCurrent.Version.HasOptiFine Then '#305
'1.18:若安装了 OptiFine,最高 Java 18
- MaxVer = New Version(1, 18, 999, 999)
+ MaxVer = If(New Version(1, 18, 999, 999) < MaxVer, New Version(1, 18, 999, 999), MaxVer)
End If
End If
@@ -1119,10 +1155,10 @@ SystemBrowser:
If McVersionCurrent.Version.HasFabric Then
If McVersionCurrent.Version.McCodeMain >= 15 AndAlso McVersionCurrent.Version.McCodeMain <= 16 AndAlso McVersionCurrent.Version.McCodeMain <> -1 Then
'1.15 - 1.16:Java 8+
- MinVer = New Version(1, 8, 0, 0)
+ MinVer = If(New Version(1, 8, 0, 0) > MinVer, New Version(1, 8, 0, 0), MinVer)
ElseIf McVersionCurrent.Version.McCodeMain >= 18 AndAlso McVersionCurrent.Version.McCodeMain < 99 Then
'1.18+:Java 17+
- MinVer = New Version(1, 17, 0, 0)
+ MinVer = If(New Version(1, 17, 0, 0) > MinVer, New Version(1, 17, 0, 0), MinVer)
End If
End If
@@ -1202,17 +1238,20 @@ SystemBrowser:
'''
Public Function ExtractJavaWrapper() As String
Dim WrapperPath As String = GetJavaWrapperDir() & "\JavaWrapper.jar"
- WriteFile(WrapperPath, GetResources("JavaWrapper"))
+ SyncLock ExtractJavaWrapperLock '避免 OptiFine 和 Forge 安装时同时释放 Java Wrapper 导致冲突
+ WriteFile(WrapperPath, GetResources("JavaWrapper"))
+ End SyncLock
Log("[Java] 已释放 Java Wrapper:" & WrapperPath)
Return WrapperPath
End Function
+ Private ExtractJavaWrapperLock As New Object
'''
''' 获取 Java Wrapper 所在的文件夹,不以 \ 结尾。
'''
Public Function GetJavaWrapperDir() As String
- If Encoding.UTF8.GetByteCount(PathAppdata) = PathAppdata.Length Then
+ If PathAppdata.IsASCII() Then
Return PathAppdata.TrimEnd("\")
- ElseIf Encoding.UTF8.GetByteCount(PathTemp) = PathTemp.Length Then
+ ElseIf PathTemp.IsASCII() Then
Log("[Java] Wrapper:AppData 路径中包含非 ASCII 字符,换用 Temp 目录")
Return PathTemp.TrimEnd("\")
Else
@@ -1276,9 +1315,7 @@ SystemBrowser:
'不包含端口号
Arguments += " --server " & Server & " --port 25565"
End If
- If McVersionCurrent.Version.HasOptiFine Then 'OptiFine 警告
- Hint("OptiFine 与自动进入服务器可能不兼容,有概率导致材质丢失甚至游戏崩溃!", HintType.Critical)
- End If
+ If McVersionCurrent.Version.HasOptiFine Then Hint("OptiFine 与自动进入服务器可能不兼容,有概率导致材质丢失甚至游戏崩溃!", HintType.Critical)
End If
End If
'自定义
@@ -1300,10 +1337,11 @@ SystemBrowser:
Dim ArgumentJvm As String = Setup.Get("VersionAdvanceJvm", Version:=McVersionCurrent)
If ArgumentJvm = "" Then ArgumentJvm = Setup.Get("LaunchAdvanceJvm")
If Not ArgumentJvm.Contains("-Dlog4j2.formatMsgNoLookups=true") Then ArgumentJvm += " -Dlog4j2.formatMsgNoLookups=true"
+ ArgumentJvm = ArgumentJvm.Replace(" -XX:MaxDirectMemorySize=256M", "") '#3511 的清理
DataList.Insert(0, ArgumentJvm) '可变 JVM 参数
- DataList.Add("-Xmn256m")
+ DataList.Add("-Xmn" & Math.Floor(PageVersionSetup.GetRam(McVersionCurrent, Not McLaunchJavaSelected.Is64Bit) * 1024 * 0.5) & "m")
DataList.Add("-Xmx" & Math.Floor(PageVersionSetup.GetRam(McVersionCurrent, Not McLaunchJavaSelected.Is64Bit) * 1024) & "m")
- DataList.Add("""-Djava.library.path=" & Version.Path & Version.Name & "-natives""")
+ DataList.Add("""-Djava.library.path=" & GetNativesFolder() & """")
DataList.Add("-cp ${classpath}") '把支持库添加进启动参数表
'统一通行证
@@ -1415,6 +1453,9 @@ NextVersion:
DeDuplicateDataList.Add(CurrentEntry.Trim.Replace("McEmu= ", "McEmu="))
Next
+ '#3511 的清理
+ DeDuplicateDataList.Remove("-XX:MaxDirectMemorySize=256M")
+
'去重
Dim Result As String = Join(DeDuplicateDataList.Distinct.ToList, " ")
@@ -1535,7 +1576,7 @@ NextVersion:
'基础参数
GameArguments.Add("${classpath_separator}", ";")
- GameArguments.Add("${natives_directory}", Version.Path & Version.Name & "-natives")
+ GameArguments.Add("${natives_directory}", GetNativesFolder())
GameArguments.Add("${library_directory}", PathMcFolder & "libraries")
GameArguments.Add("${libraries_directory}", PathMcFolder & "libraries")
GameArguments.Add("${launcher_name}", "PCL")
@@ -1552,9 +1593,26 @@ NextVersion:
GameArguments.Add("${access_token}", McLoginLoader.Output.AccessToken)
GameArguments.Add("${auth_session}", McLoginLoader.Output.AccessToken)
GameArguments.Add("${user_type}", "msa") '#1221
- Dim GameSize As Size = Setup.GetLaunchArgumentWindowSize()
- GameArguments.Add("${resolution_width}", GameSize.Width)
- GameArguments.Add("${resolution_height}", GameSize.Height)
+
+ '窗口尺寸参数
+ Dim GameSize As Size
+ Select Case Setup.Get("LaunchArgumentWindowType")
+ Case 2
+ Dim Result As Size
+ RunInUiWait(Sub() Result = New Size(GetPixelSize(FrmMain.PanForm.ActualWidth), GetPixelSize(FrmMain.PanForm.ActualHeight)))
+ GameSize = Result
+ Case 3
+ GameSize = New Size(Math.Max(100, Setup.Get("LaunchArgumentWindowWidth") - 2), Math.Max(100, Setup.Get("LaunchArgumentWindowHeight") - 2))
+ Case Else
+ GameSize = New Size(875 - 2, 540 - 2)
+ End Select
+ GameSize.Height -= 29.5 * DPI / 96 '标题栏高度
+ If McVersionCurrent.Version.McCodeMain <= 12 AndAlso McLaunchJavaSelected.VersionCode <= 8 Then '修复 #3463:1.12.2-,JRE 8 下窗口大小为设置大小的 DPI% 倍
+ GameSize.Width /= DPI / 96
+ GameSize.Height /= DPI / 96
+ End If
+ GameArguments.Add("${resolution_width}", Math.Round(GameSize.Width))
+ GameArguments.Add("${resolution_height}", Math.Round(GameSize.Height))
'Assets 相关参数
GameArguments.Add("${game_assets}", PathMcFolder & "assets\virtual\legacy") '1.5.2 的 pre-1.6 资源索引应与 legacy 合并
@@ -1586,7 +1644,8 @@ NextVersion:
Private Sub McLaunchNatives(Loader As LoaderTask(Of List(Of McLibToken), Integer))
'创建文件夹
- Directory.CreateDirectory(McVersionCurrent.Path & McVersionCurrent.Name & "-natives")
+ Dim Target As String = GetNativesFolder() & "\"
+ Directory.CreateDirectory(Target)
'解压文件
McLaunchLog("正在解压 Natives 文件")
@@ -1605,7 +1664,7 @@ NextVersion:
Dim FileName As String = Entry.FullName
If FileName.EndsWithF(".dll", True) Then
'实际解压文件的步骤
- Dim FilePath As String = McVersionCurrent.Path & McVersionCurrent.Name & "-natives\" & FileName
+ Dim FilePath As String = Target & FileName
ExistFiles.Add(FilePath)
Dim OriginalFile As New FileInfo(FilePath)
If OriginalFile.Exists Then
@@ -1631,7 +1690,7 @@ NextVersion:
Next
'删除多余文件
- For Each FileName As String In Directory.GetFiles(McVersionCurrent.Path & McVersionCurrent.Name & "-natives")
+ For Each FileName As String In Directory.GetFiles(Target)
If ExistFiles.Contains(FileName) Then Continue For
Try
McLaunchLog("删除:" & FileName)
@@ -1644,6 +1703,16 @@ NextVersion:
Next
End Sub
+ '''
+ ''' 获取 Natives 文件夹路径,不以 \ 结尾。
+ '''
+ Private Function GetNativesFolder() As String
+ Dim Result As String = McVersionCurrent.Path & McVersionCurrent.Name & "-natives"
+ If IsGBKEncoding OrElse Result.IsASCII() Then Return Result
+ Result = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\bin\natives"
+ If Result.IsASCII() Then Return Result
+ Return OsDrive & "ProgramData\PCL\natives"
+ End Function
#End Region
@@ -1758,7 +1827,7 @@ NextVersion:
Select Case Setup.Get("LaunchArgumentWindowType")
Case 0 '全屏
WriteIni(SetupFileAddress, "fullscreen", "true")
- Case 5 '保持默认
+ Case 1 '默认
Case Else '其他
WriteIni(SetupFileAddress, "fullscreen", "false")
End Select
@@ -1936,7 +2005,7 @@ IgnoreCustomSkin:
"""" & McLaunchJavaSelected.PathJava & """ " & McLaunchArgument & vbCrLf &
"echo 游戏已退出。" & vbCrLf &
"pause"
- WriteFile(If(McLaunchLoader.Input.SaveBatch, Path & "PCL\LatestLaunch.bat"), SecretFilter(CmdString),
+ WriteFile(If(McLaunchLoader.Input.SaveBatch, Path & "PCL\LatestLaunch.bat"), SecretFilter(CmdString, "F"),
Encoding:=If(Encoding.Default.Equals(Encoding.UTF8), Encoding.UTF8, Encoding.GetEncoding("GB18030")))
If McLaunchLoader.Input.SaveBatch IsNot Nothing Then
McLaunchLog("导出启动脚本完成,强制结束启动过程")
@@ -2058,7 +2127,7 @@ IgnoreCustomSkin:
McLaunchLog("")
McLaunchLog("~ 基础参数 ~")
McLaunchLog("PCL 版本:" & VersionDisplayName & " (" & VersionCode & ")")
- McLaunchLog("游戏版本:" & McVersionCurrent.Version.ToString & "(" & McVersionCurrent.Version.McCodeMain & "." & McVersionCurrent.Version.McCodeSub & ")")
+ McLaunchLog("游戏版本:" & McVersionCurrent.Version.ToString & "(识别为 1." & McVersionCurrent.Version.McCodeMain & "." & McVersionCurrent.Version.McCodeSub & ")")
McLaunchLog("资源版本:" & McAssetsGetIndexName(McVersionCurrent))
McLaunchLog("版本继承:" & If(McVersionCurrent.InheritVersion = "", "无", McVersionCurrent.InheritVersion))
McLaunchLog("分配的内存:" & PageVersionSetup.GetRam(McVersionCurrent, Not McLaunchJavaSelected.Is64Bit) & " GB(" & Math.Round(PageVersionSetup.GetRam(McVersionCurrent, Not McLaunchJavaSelected.Is64Bit) * 1024) & " MB)")
@@ -2068,6 +2137,7 @@ IgnoreCustomSkin:
McLaunchLog("HMCL 格式:" & McVersionCurrent.IsHmclFormatJson)
McLaunchLog("Java 信息:" & If(McLaunchJavaSelected IsNot Nothing, McLaunchJavaSelected.ToString, "无可用 Java"))
McLaunchLog("环境变量:" & If(McLaunchJavaSelected IsNot Nothing, If(McLaunchJavaSelected.HasEnvironment, "已设置", "未设置"), "未设置"))
+ McLaunchLog("Natives 文件夹:" & GetNativesFolder())
McLaunchLog("")
McLaunchLog("~ 登录参数 ~")
McLaunchLog("玩家用户名:" & McLoginLoader.Output.Name)
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
index 1f25858..0014d14 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
@@ -181,7 +181,7 @@
If AniControlEnabled = 0 AndAlso
Setup.Get("VersionServerAuthServer", Version:=value) <> Setup.Get("CacheAuthServerServer") AndAlso
Setup.Get("VersionServerLogin", Version:=value) = 4 Then
- Setup.Set("CacheNideServer", "")
+ Setup.Set("CacheAuthAccess", "")
Log("[Launch] 服务器改变,要求重新登录 Authlib-Injector")
End If
If Setup.Get("VersionServerLogin", Version:=value) = 4 Then
@@ -216,8 +216,8 @@
'尚未判断
Dim ModFolder As New DirectoryInfo(Path & "mods\")
Dim SaveFolder As New DirectoryInfo(Path & "saves\")
- If (ModFolder.Exists AndAlso ModFolder.EnumerateFiles.Count > 0) OrElse
- (SaveFolder.Exists AndAlso SaveFolder.EnumerateFiles.Count > 0) Then
+ If (ModFolder.Exists AndAlso ModFolder.EnumerateFiles.Any) OrElse
+ (SaveFolder.Exists AndAlso SaveFolder.EnumerateFiles.Any) Then
'自动开启
Setup.Set("VersionArgumentIndie", 1, Version:=Me)
Log("[Setup] 已自动开启单版本隔离:" & Name)
@@ -1234,7 +1234,7 @@ OnLoaded:
For Each Version As McVersion In VersionList
If Version.IsStar AndAlso Not Version.DisplayType = McVersionCardType.Hidden Then StaredVersions.Add(Version)
Next
- If StaredVersions.Count > 0 Then VersionListOriginal.Add(McVersionCardType.Star, StaredVersions)
+ If StaredVersions.Any Then VersionListOriginal.Add(McVersionCardType.Star, StaredVersions)
'预先筛选出愚人节的版本
McVersionFilter(VersionList, VersionListOriginal, {McVersionState.Error}, McVersionCardType.Error)
@@ -1308,8 +1308,8 @@ OnLoaded:
'将剩余的东西添加进去
VersionRubbish.AddRange(VersionList)
- If VersionUseful.Count > 0 Then VersionListOriginal.Add(McVersionCardType.OriginalLike, VersionUseful)
- If VersionRubbish.Count > 0 Then VersionListOriginal.Add(McVersionCardType.Rubbish, VersionRubbish)
+ If VersionUseful.Any Then VersionListOriginal.Add(McVersionCardType.OriginalLike, VersionUseful)
+ If VersionRubbish.Any Then VersionListOriginal.Add(McVersionCardType.Rubbish, VersionRubbish)
'按照自定义版本分类重新添加
For Each VersionPair In VersionListOriginal
@@ -1429,7 +1429,7 @@ OnLoaded:
NextVersion:
Next
'加入版本列表,并从剩余中删除
- If KeepList.Count > 0 Then
+ If KeepList.Any Then
Target.Add(CardType, KeepList)
For Each Version As McVersion In KeepList
VersionList.Remove(Version)
@@ -1450,7 +1450,7 @@ NextVersion:
Next
NextVersion:
Next
- If KeepList.Count > 0 Then
+ If KeepList.Any Then
For Each Version As McVersion In KeepList
VersionList.Remove(Version)
Next
@@ -1515,7 +1515,7 @@ NextVersion:
'''
Public Function McSkinGetAddress(Uuid As String, Type As String) As String
If Uuid = "" Then Throw New Exception("Uuid 为空。")
- If Uuid.StartsWithF("000000") Then Throw New Exception("离线 Uuid 无正版皮肤文件。")
+ If Uuid.StartsWithF("00000") Then Throw New Exception("离线 Uuid 无正版皮肤文件。")
'尝试读取缓存
Dim CacheSkinAddress As String = ReadIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", Uuid)
If Not CacheSkinAddress = "" Then Return CacheSkinAddress
@@ -2048,8 +2048,7 @@ NextVersion:
If Version.InheritVersion = "" Then Exit Do
Version = New McVersion(PathMcFolder & "versions\" & Version.InheritVersion)
Loop
- Catch ex As Exception
- Log(ex, "获取资源文件索引下载地址失败")
+ Catch
End Try
'无法获取到下载地址
If ReturnLegacyOnError Then
@@ -2239,10 +2238,11 @@ NextVersion:
'弹窗结果
If MsgResult = 2 Then
'下载
- RunInUi(Sub()
- PageDownloadInstall.McVersionWaitingForSelect = VersionName
- FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
- End Sub)
+ RunInUi(
+ Sub()
+ PageDownloadInstall.McVersionWaitingForSelect = VersionName
+ FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
+ End Sub)
End If
Catch ex As Exception
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
index 1a05fe3..040e9d5 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
@@ -337,7 +337,7 @@ Public Module ModMod
For Each Token In AuthorJson
Author.Add(Token.ToString)
Next
- If Author.Count > 0 Then Authors = Join(Author, ", ")
+ If Author.Any Then Authors = Join(Author, ", ")
End If
Dim Reqs As JArray = InfoObject("requiredMods")
If Reqs IsNot Nothing Then
@@ -393,7 +393,7 @@ GotFabric:
For Each Token In AuthorJson
Author.Add(Token.ToString)
Next
- If Author.Count > 0 Then Authors = Join(Author, ", ")
+ If Author.Any Then Authors = Join(Author, ", ")
End If
'If (Not FabricObject.ContainsKey("serverSideOnly")) OrElse FabricObject("serverSideOnly")("value").ToObject(Of Boolean) = False Then
' '添加 Minecraft 依赖
@@ -438,7 +438,7 @@ GotFabric:
Line = Line.Substring(0, Line.IndexOfF("#"))
End If
Line = Line.Trim(New Char() {" "c, " "c, " "c}) '去除头尾的空格
- If Line.Count > 0 Then Lines.Add(Line) '去除空行
+ If Line.Any Then Lines.Add(Line) '去除空行
Next
'读取文件数据
Dim TomlData As New List(Of KeyValuePair(Of String, Dictionary(Of String, Object))) From {New KeyValuePair(Of String, Dictionary(Of String, Object))("", New Dictionary(Of String, Object))}
@@ -925,7 +925,7 @@ Finished:
End Sub
'联网加载 Mod 详情
- Private Const LocalModCacheVersion As Integer = 2
+ Private Const LocalModCacheVersion As Integer = 3
Public McModDetailLoader As New LoaderTask(Of KeyValuePair(Of List(Of McMod), JObject), Integer)("Mod List Detail Loader", AddressOf McModDetailLoad)
Private Sub McModDetailLoad(Loader As LoaderTask(Of KeyValuePair(Of List(Of McMod), JObject), Integer))
Dim Mods As List(Of McMod) = Loader.Input.Key
@@ -965,6 +965,7 @@ Finished:
Dim ModrinthMapping As New Dictionary(Of String, List(Of McMod))
For Each Entry In Mods
If Not ModrinthVersion.ContainsKey(Entry.ModrinthHash) Then Continue For
+ If ModrinthVersion(Entry.ModrinthHash)("files")(0)("hashes")("sha1") <> Entry.ModrinthHash Then Continue For
Dim ProjectId = ModrinthVersion(Entry.ModrinthHash)("project_id").ToString
If CompProjectCache.ContainsKey(ProjectId) AndAlso Entry.Comp Is Nothing Then Entry.Comp = CompProjectCache(ProjectId) '读取已加载的缓存,加快结果出现速度
If Not ModrinthMapping.ContainsKey(ProjectId) Then ModrinthMapping(ProjectId) = New List(Of McMod)
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
index 9cc2d6f..bcd878c 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
@@ -244,16 +244,17 @@ Retry:
ModList.Add(ModEntry("fileID"))
If ModEntry("required") IsNot Nothing AndAlso Not ModEntry("required").ToObject(Of Boolean) Then ModOptionalList.Add(ModEntry("fileID"))
Next
- If ModList.Count > 0 Then
+ If ModList.Any Then
+ Dim ModDownloadLoaders As New List(Of LoaderBase)
'获取 Mod 下载信息
- InstallLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
+ ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
Sub(Task As LoaderTask(Of Integer, JArray))
Task.Output = GetJson(NetRequestRetry("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 作者删除,因此无法完成整合包安装,请联系整合包作者更新整合包中的 Mod 版本")
End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s
'构造 NetFile
- InstallLoaders.Add(New LoaderTask(Of JArray, List(Of NetFile))("构造 Mod 下载信息",
+ ModDownloadLoaders.Add(New LoaderTask(Of JArray, List(Of NetFile))("构造 Mod 下载信息",
Sub(Task As LoaderTask(Of JArray, List(Of NetFile)))
Dim FileList As New Dictionary(Of Integer, NetFile)
For Each ModJson In Task.Input
@@ -288,7 +289,10 @@ Retry:
Task.Output = FileList.Values.ToList
End Sub) With {.ProgressWeight = ModList.Count / 200, .Show = False}) '每 200 Mod 需要 1s
'下载 Mod 文件
- InstallLoaders.Add(New LoaderDownload("下载 Mod", New List(Of NetFile)) With {.ProgressWeight = ModList.Count * 1.5}) '每个 Mod 需要 1.5s
+ ModDownloadLoaders.Add(New LoaderDownload("下载 Mod", New List(Of NetFile)) With {.ProgressWeight = ModList.Count * 1.5}) '每个 Mod 需要 1.5s
+ '构造加载器
+ InstallLoaders.Add(New LoaderCombo(Of Integer)("下载 Mod(主加载器)", ModDownloadLoaders) With
+ {.Show = False, .ProgressWeight = ModDownloadLoaders.Sum(Function(l) l.ProgressWeight)})
End If
'构造加载器
@@ -299,43 +303,35 @@ Retry:
.ForgeVersion = ForgeVersion,
.FabricVersion = FabricVersion
}
- Dim InstallExpectTime As Double = 0
- For Each InstallLoader In InstallLoaders
- InstallExpectTime += InstallLoader.ProgressWeight
- Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
- Dim MergeExpectTime As Double = 0
- For Each MergeLoader In MergeLoaders
- MergeExpectTime += MergeLoader.ProgressWeight
- Next
- '构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
+ '构造 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})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase)
- Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallExpectTime})
- Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeExpectTime})
+ Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
+ Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
- Sub(Task As LoaderTask(Of String, String))
- '设置图标
- Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
- If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
- File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
- WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
- WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
- Log("[ModPack] 已设置整合包 Logo:" & Logo)
- End If
- '删除原始整合包文件
- For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
- If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
- Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target)
- File.Delete(Target)
- End If
- Next
- End Sub) With {.ProgressWeight = 0.1, .Show = False})
+ Sub(Task As LoaderTask(Of String, String))
+ '设置图标
+ Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
+ If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
+ File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
+ WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
+ WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
+ Log("[ModPack] 已设置整合包 Logo:" & Logo)
+ End If
+ '删除原始整合包文件
+ For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
+ If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
+ Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target)
+ File.Delete(Target)
+ End If
+ Next
+ End Sub) With {.ProgressWeight = 0.1, .Show = False})
'重复任务检查
Dim LoaderName As String = "CurseForge 整合包安装:" & VersionName & " "
@@ -438,10 +434,10 @@ Retry:
End If
'添加下载文件
FileList.Add(New NetFile(File("downloads").Select(Function(t) t.ToString.Replace("://edge.forgecdn", "://media.forgecdn")).ToArray, '修复 #2390
- PathMcFolder & "versions\" & VersionName & "\" & File("path").ToString,
- New FileChecker(ActualSize:=File("fileSize").ToObject(Of Long), Hash:=File("hashes")("sha1").ToString), True))
+ PathMcFolder & "versions\" & VersionName & "\" & File("path").ToString,
+ New FileChecker(ActualSize:=File("fileSize").ToObject(Of Long), Hash:=File("hashes")("sha1").ToString), True))
Next
- If FileList.Count > 0 Then
+ If FileList.Any Then
InstallLoaders.Add(New LoaderDownload("下载额外文件", FileList) With {.ProgressWeight = FileList.Count * 1.5}) '每个 Mod 需要 1.5s
End If
@@ -453,43 +449,35 @@ Retry:
.ForgeVersion = ForgeVersion,
.FabricVersion = FabricVersion
}
- Dim InstallExpectTime As Double = 0
- For Each InstallLoader In InstallLoaders
- InstallExpectTime += InstallLoader.ProgressWeight
- Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
- Dim MergeExpectTime As Double = 0
- For Each MergeLoader In MergeLoaders
- MergeExpectTime += MergeLoader.ProgressWeight
- Next
- '构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
+ '构造 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})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase)
- Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallExpectTime})
- Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeExpectTime})
+ Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .Block = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
+ Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
Loaders.Add(New LoaderTask(Of String, String)("最终整理文件",
- Sub(Task As LoaderTask(Of String, String))
- '设置图标
- Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
- If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
- File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
- WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
- WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
- Log("[ModPack] 已设置整合包 Logo:" & Logo)
- End If
- '删除原始整合包文件
- For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
- If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
- Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target)
- File.Delete(Target)
- End If
- Next
- End Sub) With {.ProgressWeight = 0.1, .Show = False})
+ Sub(Task As LoaderTask(Of String, String))
+ '设置图标
+ Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
+ If Logo IsNot Nothing AndAlso File.Exists(Logo) Then
+ File.Copy(Logo, VersionFolder & "PCL\Logo.png", True)
+ WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png")
+ WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True")
+ Log("[ModPack] 已设置整合包 Logo:" & Logo)
+ End If
+ '删除原始整合包文件
+ For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"}
+ If Not Setup.Get("ToolDownloadKeepModpack") AndAlso File.Exists(Target) Then
+ Log("[ModPack] 根据设置要求删除原始整合包文件:" & Target)
+ File.Delete(Target)
+ End If
+ Next
+ End Sub) With {.ProgressWeight = 0.1, .Show = False})
'重复任务检查
Dim LoaderName As String = "Modrinth 整合包安装:" & VersionName & " "
@@ -554,16 +542,8 @@ Retry:
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
.MinecraftName = Json("gameVersion").ToString
}
- Dim InstallExpectTime As Double = 0
- For Each InstallLoader In InstallLoaders
- InstallExpectTime += InstallLoader.ProgressWeight
- Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
- Dim MergeExpectTime As Double = 0
- For Each MergeLoader In MergeLoaders
- MergeExpectTime += MergeLoader.ProgressWeight
- Next
'构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, String)("重命名版本 Json(副加载器)",
@@ -584,8 +564,8 @@ Retry:
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase) From {
- New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeExpectTime},
- New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallExpectTime},
+ New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)},
+ New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)},
New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8}
}
@@ -704,24 +684,16 @@ Retry:
End Select
Next
'构造加载器
- Dim InstallExpectTime As Double = 0
- For Each InstallLoader In InstallLoaders
- InstallExpectTime += InstallLoader.ProgressWeight
- Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
- Dim MergeExpectTime As Double = 0
- For Each MergeLoader In MergeLoaders
- MergeExpectTime += MergeLoader.ProgressWeight
- Next
- '构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
+ '构造 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})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase)
- Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeExpectTime})
- Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallExpectTime})
+ Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
+ Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
'重复任务检查
@@ -802,24 +774,16 @@ Retry:
.ForgeVersion = If(Addons.ContainsKey("forge"), Addons("forge"), Nothing),
.FabricVersion = If(Addons.ContainsKey("fabric"), Addons("fabric"), Nothing)
}
- Dim InstallExpectTime As Double = 0
- For Each InstallLoader In InstallLoaders
- InstallExpectTime += InstallLoader.ProgressWeight
- Next
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
If MergeLoaders Is Nothing Then Exit Sub
- Dim MergeExpectTime As Double = 0
- For Each MergeLoader In MergeLoaders
- MergeExpectTime += MergeLoader.ProgressWeight
- Next
- '构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
+ '构造 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})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
'构造总加载器
Dim Loaders As New List(Of LoaderBase)
- Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeExpectTime})
- Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallExpectTime})
+ Loaders.Add(New LoaderCombo(Of String)("游戏安装", MergeLoaders) With {.Show = False, .Block = False, .ProgressWeight = MergeLoaders.Sum(Function(l) l.ProgressWeight)})
+ Loaders.Add(New LoaderCombo(Of String)("整合包安装", InstallLoaders) With {.Show = False, .ProgressWeight = InstallLoaders.Sum(Function(l) l.ProgressWeight)})
Loaders.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
'重复任务检查
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb
index 2c63b18..c4e5c55 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb
@@ -276,17 +276,18 @@
IsWindowFinished = True
'最大化
If Setup.Get("LaunchArgumentWindowType") = 4 Then
- RunInNewThread(Sub()
- Try
- '如果最大化导致屏幕渲染大小不对,那是 MC 的 Bug,不是我的 Bug
- '……虽然我很想这样说,但总有人反馈,算了
- Thread.Sleep(2000)
- ShowWindow(WindowHandle, 3)
- WatcherLog($"已最大化 Minecraft 窗口:{MinecraftWindowHandle.ToInt64}")
- Catch ex As Exception
- Log(ex, "最大化 Minecraft 窗口时出现错误")
- End Try
- End Sub, "MinecraftWindowMaximize")
+ RunInNewThread(
+ Sub()
+ Try
+ '如果最大化导致屏幕渲染大小不对,那是 MC 的 Bug,不是我的 Bug
+ '……虽然我很想这样说,但总有人反馈,算了
+ Thread.Sleep(2000)
+ ShowWindow(WindowHandle, 3)
+ WatcherLog($"已最大化 Minecraft 窗口:{MinecraftWindowHandle.ToInt64}")
+ Catch ex As Exception
+ Log(ex, "最大化 Minecraft 窗口时出现错误")
+ End Try
+ End Sub, "MinecraftWindowMaximize")
End If
ElseIf Not IsWindowAppeared Then
'已找到 FML 窗口
diff --git a/Plain Craft Launcher 2/Modules/ModMusic.vb b/Plain Craft Launcher 2/Modules/ModMusic.vb
index aecafd2..860a967 100644
--- a/Plain Craft Launcher 2/Modules/ModMusic.vb
+++ b/Plain Craft Launcher 2/Modules/ModMusic.vb
@@ -266,7 +266,7 @@ Public Module ModMusic
Thread.Sleep(100)
End While
'当前音乐已播放结束,继续下一曲
- If CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped AndAlso MusicAllList.Count > 0 Then MusicStartPlay(DequeueNextMusicAddress)
+ If CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped AndAlso MusicAllList.Any Then MusicStartPlay(DequeueNextMusicAddress)
Catch ex As Exception
Log("[Music] 播放音乐失败的文件完整路径:" & MusicCurrent)
If TypeOf ex Is NAudio.MmException AndAlso (ex.Message.Contains("NoDriver") OrElse ex.Message.Contains("BadDeviceId")) Then
diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb
index 49ea2bc..e657d2d 100644
--- a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb
+++ b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb
@@ -8,11 +8,11 @@ Imports System.Runtime.InteropServices
'查看程序集特性的值
-
+
-
-
+
+
@@ -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 48560e0..5a8f8e9 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
@@ -487,7 +487,7 @@ Public Module ModDownloadLib
outputWaitHandle.WaitOne(10000)
errorWaitHandle.WaitOne(10000)
process.Dispose()
- If TotalLength < 1000 Then Throw New Exception("安装器运行出错,末行为 " & LastResult)
+ If TotalLength < 1000 OrElse LastResult.Contains("at ") Then Throw New Exception("安装器运行出错,末行为 " & LastResult)
End Using
End Using
End SyncLock
@@ -538,7 +538,7 @@ Public Module ModDownloadLib
'OptiFine 中文镜像源
Sources.Add("https://optifine.cn/download/" & DownloadInfo.NameFile)
'构造文件请求
- Task.Output = New List(Of NetFile) From {New NetFile(Sources.ToArray, Target, New FileChecker(MinSize:=64 * 1024))}
+ Task.Output = New List(Of NetFile) From {New NetFile(Sources.ToArray, Target, New FileChecker(MinSize:=300 * 1024))}
End Sub) With {.ProgressWeight = 8})
Loaders.Add(New LoaderDownload("下载 OptiFine 主文件", New List(Of NetFile)) With {.ProgressWeight = 8})
Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("等待原版下载",
@@ -548,8 +548,8 @@ Public Module ModDownloadLib
Dim TargetLoaders As List(Of LoaderBase) =
ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
Where(Function(l) l.State <> LoadState.Finished).ToList
- If TargetLoaders.Count > 0 Then Log("[Download] OptiFine 安装正在等待原版文件下载完成")
- Do While TargetLoaders.Count > 0 AndAlso Not Task.IsAborted
+ If TargetLoaders.Any Then Log("[Download] OptiFine 安装正在等待原版文件下载完成")
+ Do While TargetLoaders.Any AndAlso Not Task.IsAborted
TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
Thread.Sleep(50)
Loop
@@ -560,12 +560,10 @@ Public Module ModDownloadLib
Dim ClientName As String = GetFolderNameFromPath(ClientFolder)
Directory.CreateDirectory(McFolder & "versions\" & DownloadInfo.Inherit)
If Not File.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json") Then
- CopyFile(ClientFolder & ClientName & ".json",
- McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json")
+ CopyFile($"{ClientFolder}{ClientName}.json", $"{McFolder}versions\{DownloadInfo.Inherit}\{DownloadInfo.Inherit}.json")
End If
If Not File.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar") Then
- CopyFile(ClientFolder & ClientName & ".jar",
- McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar")
+ CopyFile($"{ClientFolder}{ClientName}.jar", $"{McFolder}versions\{DownloadInfo.Inherit}\{DownloadInfo.Inherit}.jar")
End If
End SyncLock
End Sub) With {.ProgressWeight = 0.1, .Show = False})
@@ -1283,20 +1281,20 @@ Retry:
'获取下载信息
If DownloadInfo Is Nothing Then
Loaders.Add(New LoaderTask(Of String, String)("获取 Mod 加载器详细信息",
- Sub(Task As LoaderTask(Of String, String))
- '获取 Forge 版本列表
- Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("McDownloadForgeLoader " & Inherit, AddressOf DlForgeVersionMain)
- ForgeLoader.WaitForExit(Inherit)
- Task.Progress = 0.8
- '查找对应版本
- For Each ForgeVersion In ForgeLoader.Output
- If ForgeVersion.Version = Version Then
- DownloadInfo = ForgeVersion
- Exit Sub
- End If
- Next
- Throw New Exception("未能找到 Forge " & Inherit & "-" & Version & " 的详细信息!")
- End Sub) With {.ProgressWeight = 3})
+ Sub(Task As LoaderTask(Of String, String))
+ '获取 Forge 版本列表
+ Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("McDownloadForgeLoader " & Inherit, AddressOf DlForgeVersionMain)
+ ForgeLoader.WaitForExit(Inherit)
+ Task.Progress = 0.8
+ '查找对应版本
+ For Each ForgeVersion In ForgeLoader.Output
+ If ForgeVersion.Version = Version Then
+ DownloadInfo = ForgeVersion
+ Exit Sub
+ End If
+ Next
+ Throw New Exception("未能找到 Forge " & Inherit & "-" & Version & " 的详细信息!")
+ End Sub) With {.ProgressWeight = 3})
End If
'下载 Forge 主文件
Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("准备 Mod 加载器下载",
@@ -1383,8 +1381,8 @@ Retry:
Dim TargetLoaders As List(Of LoaderBase) =
ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
Where(Function(l) l.State <> LoadState.Finished).ToList
- If TargetLoaders.Count > 0 Then Log("[Download] Forge 安装正在等待原版文件下载完成")
- Do While TargetLoaders.Count > 0 AndAlso Not Task.IsAborted
+ If TargetLoaders.Any Then Log("[Download] Forge 安装正在等待原版文件下载完成")
+ Do While TargetLoaders.Any AndAlso Not Task.IsAborted
TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
Thread.Sleep(50)
Loop
@@ -1441,7 +1439,7 @@ Retry:
End Try
'拷贝新增的版本 Json
Dim DeltaList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.
- SkipWhile(Function(i) OldList.Contains(i.FullName)).ToList()
+ SkipWhile(Function(i) OldList.Contains(i.FullName)).ToList()
If DeltaList.Count > 1 Then
'它可能和 OptiFine 安装同时运行,导致增加的文件不止一个(这导致了 #151)
'也可能是因为 Forge 安装器的 Bug,生成了一个名字错误的文件夹,所以需要检查文件夹是否为空
@@ -1537,7 +1535,7 @@ Retry:
Public Sub ForgeDownloadListItemPreload(Stack As StackPanel, Entrys As List(Of DlForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
'获取推荐版本与最新版本
Dim FreshVersion As DlForgeVersionEntry = Nothing
- If Entrys.Count > 0 Then
+ If Entrys.Any Then
FreshVersion = Entrys(0)
Else
Log("[System] 未找到可用的 Forge 版本", LogLevel.Debug)
@@ -2014,7 +2012,7 @@ Retry:
Dim LoaderList As New List(Of LoaderBase)
'添加忽略标识
- LoaderList.Add(New LoaderTask(Of Integer, Integer)("添加忽略标识", Sub() WriteFile(OutputFolder & ".pclignore", "用于临时地 PCL 的版本列表中屏蔽此版本。")) With {.Show = False, .Block = False})
+ 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(New McVersion(OutputFolder).GetPathIndie(True) & "mods\")}) With {.ProgressWeight = 3, .Block = False})
@@ -2164,7 +2162,7 @@ Retry:
For i = 0 To RawArguments.Count - 1
If RawArguments(i).StartsWithF("-") Then
SplitArguments.Add(RawArguments(i))
- ElseIf SplitArguments.Count > 0 AndAlso SplitArguments.Last.StartsWithF("-") AndAlso Not SplitArguments.Last.Contains(" ") Then
+ ElseIf SplitArguments.Any AndAlso SplitArguments.Last.StartsWithF("-") AndAlso Not SplitArguments.Last.Contains(" ") Then
SplitArguments(SplitArguments.Count - 1) = SplitArguments.Last & " " & RawArguments(i)
Else
SplitArguments.Add(RawArguments(i))
@@ -2172,6 +2170,7 @@ Retry:
Next
Dim RealArguments As String = Join(SplitArguments.Distinct.ToList, " ")
'合并
+ '相关讨论见 #2801
OutputJson = MinecraftJson
If HasOptiFine Then
'合并 OptiFine
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb
index 2434192..56959a5 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb
@@ -210,10 +210,10 @@
If Project.Type = CompType.Mod Then
'获取 Mod 所需的加载器种类
Dim AllowForge As Boolean? = Nothing, AllowFabric As Boolean? = Nothing
- If File.ModLoaders.Count > 0 Then '从文件中获取
+ If File.ModLoaders.Any Then '从文件中获取
AllowForge = File.ModLoaders.Contains(CompModLoaderType.Forge)
AllowFabric = File.ModLoaders.Contains(CompModLoaderType.Fabric)
- ElseIf Project.ModLoaders.Count > 0 Then '从工程中获取
+ ElseIf Project.ModLoaders.Any Then '从工程中获取
AllowForge = Project.ModLoaders.Contains(CompModLoaderType.Forge)
AllowFabric = Project.ModLoaders.Contains(CompModLoaderType.Fabric)
End If
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml
index ec68dd9..f7333fe 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml
@@ -20,7 +20,6 @@
-
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
index 1c6f77b..edfd0af 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
@@ -32,7 +32,7 @@
#Region "页面切换"
'页面切换动画
- Private IsInSelectPage As Boolean = False
+ Public IsInSelectPage As Boolean = False
Private IsFirstLoaded As Boolean = False
Private Sub EnterSelectPage()
If IsInSelectPage Then Exit Sub
@@ -273,11 +273,13 @@
End If
End Sub
+ Private IsReloading As Boolean = False '#3742 中,LoadOptiFineGetError 会初始化 LoadOptiFine,触发事件 LoadOptiFine.StateChanged,导致再次调用 SelectReload
'''
''' 重载已选择的项目的显示。
'''
Private Sub SelectReload() Handles CardOptiFine.Swap, LoadOptiFine.StateChanged, CardForge.Swap, LoadForge.StateChanged, CardFabric.Swap, LoadFabric.StateChanged, CardFabricApi.Swap, LoadFabricApi.StateChanged, CardOptiFabric.Swap, LoadOptiFabric.StateChanged, CardLiteLoader.Swap, LoadLiteLoader.StateChanged
- If SelectedMinecraftId Is Nothing Then Exit Sub
+ If SelectedMinecraftId Is Nothing OrElse IsReloading Then Exit Sub
+ IsReloading = True
'主预览
SelectNameUpdate()
ItemSelect.Title = TextSelectName.Text
@@ -385,17 +387,12 @@
'主警告
HintFabricAPI.Visibility = If(SelectedFabric IsNot Nothing AndAlso SelectedFabricApi Is Nothing, Visibility.Visible, Visibility.Collapsed)
If SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso SelectedOptiFabric Is Nothing Then
- If SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15") Then
- HintOptiFabric.Visibility = Visibility.Collapsed
- HintOptiFabricOld.Visibility = Visibility.Visible
- Else
- HintOptiFabric.Visibility = Visibility.Visible
- HintOptiFabricOld.Visibility = Visibility.Collapsed
- End If
+ HintOptiFabric.Visibility = Visibility.Visible
Else
HintOptiFabric.Visibility = Visibility.Collapsed
- HintOptiFabricOld.Visibility = Visibility.Collapsed
End If
+ '结束
+ IsReloading = False
End Sub
'''
''' 清空已选择的项目。
@@ -1037,7 +1034,6 @@
''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
'''
Private Function LoadOptiFabricGetError() As String
- If SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15") Then Return "不兼容老版本 Fabric,请手动下载 OptiFabric Origins"
If LoadOptiFabric Is Nothing OrElse LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFabric.State, Object).Error.Message
If DlOptiFabricLoader.Output Is Nothing Then
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
index 92b0585..814d1c8 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
@@ -35,7 +35,6 @@
-
@@ -44,11 +43,9 @@
-
-
@@ -122,4 +119,4 @@
-
+
\ No newline at end of file
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
index 26bdd3c..a59954f 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
@@ -34,7 +34,6 @@
-
@@ -43,11 +42,9 @@
-
-
@@ -111,4 +108,4 @@
-
+
\ No newline at end of file
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb
index 8ea7421..1cc46fe 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb
@@ -19,51 +19,53 @@
RefreshButtonsUI()
'加载版本
- RunInNewThread(Sub()
- '确认 Minecraft 文件夹存在
- PathMcFolder = Setup.Get("LaunchFolderSelect").ToString.Replace("$", Path)
- If PathMcFolder = "" OrElse Not Directory.Exists(PathMcFolder) Then
- '无效的文件夹
- If PathMcFolder = "" Then
- Log("[Launch] 没有已储存的 Minecraft 文件夹")
- Else
- Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" & PathMcFolder, LogLevel.Debug)
- End If
- McFolderListLoader.WaitForExit(IsForceRestart:=True)
- Setup.Set("LaunchFolderSelect", McFolderList(0).Path.Replace(Path, "$"))
- End If
- Log("[Launch] Minecraft 文件夹:" & PathMcFolder)
- If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
- '确认 Minecraft 版本存在
- Dim Selection As String = Setup.Get("LaunchVersionSelect")
- Dim Version As McVersion
- If Selection = "" Then
- Version = Nothing
- Else
- Version = New McVersion(Selection)
- End If
- If IsNothing(Version) OrElse Not (Version.Path.StartsWith(PathMcFolder) AndAlso Version.Check) Then
- '无效的版本
- Log("[Launch] Minecraft 版本无效" & If(IsNothing(Version), ",没有有效版本", ":" & Version.Path), If(IsNothing(Version), LogLevel.Normal, LogLevel.Debug))
- If Not McVersionListLoader.State = LoadState.Finished Then LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
- If Not McVersionList.Any() OrElse McVersionList.First.Value(0).Logo.Contains("RedstoneBlock") Then
- Version = Nothing
- Setup.Set("LaunchVersionSelect", "")
- Log("[Launch] 无可用 Minecraft 版本")
- Else
- Version = McVersionList.First.Value(0)
- Setup.Set("LaunchVersionSelect", Version.Name)
- Log("[Launch] 自动选择 Minecraft 版本:" & Version.Path)
- End If
- End If
- RunInUi(Sub()
- McVersionCurrent = Version '绕这一圈是为了避免 McVersionCheck 触发第二次版本改变
- IsLoadFinished = True
- RefreshButtonsUI()
- RefreshPage(False, False) '有可能选择的版本变化了,需要重新刷新
- If McLoginAble() = "" Then McLoginLoader.Start() '自动登录
- End Sub)
- End Sub, "Version Check", ThreadPriority.AboveNormal)
+ RunInNewThread(
+ Sub()
+ '确认 Minecraft 文件夹存在
+ PathMcFolder = Setup.Get("LaunchFolderSelect").ToString.Replace("$", Path)
+ If PathMcFolder = "" OrElse Not Directory.Exists(PathMcFolder) Then
+ '无效的文件夹
+ If PathMcFolder = "" Then
+ Log("[Launch] 没有已储存的 Minecraft 文件夹")
+ Else
+ Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" & PathMcFolder, LogLevel.Debug)
+ End If
+ McFolderListLoader.WaitForExit(IsForceRestart:=True)
+ Setup.Set("LaunchFolderSelect", McFolderList(0).Path.Replace(Path, "$"))
+ End If
+ Log("[Launch] Minecraft 文件夹:" & PathMcFolder)
+ If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
+ '确认 Minecraft 版本存在
+ Dim Selection As String = Setup.Get("LaunchVersionSelect")
+ Dim Version As McVersion
+ If Selection = "" Then
+ Version = Nothing
+ Else
+ Version = New McVersion(Selection)
+ End If
+ If IsNothing(Version) OrElse Not (Version.Path.StartsWith(PathMcFolder) AndAlso Version.Check) Then
+ '无效的版本
+ Log("[Launch] Minecraft 版本无效" & If(IsNothing(Version), ",没有有效版本", ":" & Version.Path), If(IsNothing(Version), LogLevel.Normal, LogLevel.Debug))
+ If Not McVersionListLoader.State = LoadState.Finished Then LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
+ If Not McVersionList.Any() OrElse McVersionList.First.Value(0).Logo.Contains("RedstoneBlock") Then
+ Version = Nothing
+ Setup.Set("LaunchVersionSelect", "")
+ Log("[Launch] 无可用 Minecraft 版本")
+ Else
+ Version = McVersionList.First.Value(0)
+ Setup.Set("LaunchVersionSelect", Version.Name)
+ Log("[Launch] 自动选择 Minecraft 版本:" & Version.Path)
+ End If
+ End If
+ RunInUi(
+ Sub()
+ McVersionCurrent = Version '绕这一圈是为了避免 McVersionCheck 触发第二次版本改变
+ IsLoadFinished = True
+ RefreshButtonsUI()
+ RefreshPage(False, False) '有可能选择的版本变化了,需要重新刷新
+ If McLoginAble() = "" Then McLoginLoader.Start() '自动登录
+ End Sub)
+ End Sub, "Version Check", ThreadPriority.AboveNormal)
'改变页面
Dim LoginType As McLoginType = Setup.Get("LoginType")
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
index bae5e07..64d755f 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
@@ -67,7 +67,7 @@ Download:
End If
Case 3
Select Case Setup.Get("UiCustomPreset")
- Case 0 '你知道吗
+ Case 0
Log("[Page] 主页预设:你知道吗")
Content = "
@@ -76,7 +76,7 @@ Download:
EventType=""刷新主页"" EventData=""/""
Logo=""M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z"" />
"
- Case 1 '回声洞
+ Case 1
Log("[Page] 主页预设:回声洞")
Content = "
@@ -85,17 +85,17 @@ Download:
EventType=""刷新主页"" EventData=""/""
Logo=""M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z"" />
"
- Case 2 '新闻
+ Case 2
Log("[Page] 主页预设:Minecraft 新闻")
Url = "http://pcl.mcnews.thestack.top"
GoTo Download
- Case 3 '简单主页
+ Case 3
Log("[Page] 主页预设:简单主页")
Url = "https://gitee.com/mfn233/PCL-Mainpage/raw/main/Custom.xaml"
GoTo Download
- Case 4 '历史上的今天
- Log("[Page] 主页预设:历史上的今天")
- Url = "https://pclnews.52chye.cn/custom.xaml"
+ Case 4
+ Log("[Page] 主页预设:每日整合包推荐")
+ Url = "https://pclsub.sodamc.com/"
GoTo Download
End Select
End Select
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb
index 6d3ee42..15a3581 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb
@@ -85,50 +85,51 @@
Hint("正在更改皮肤……")
IsChanging = True
'开始实际获取
- RunInNewThread(Async Sub()
- Try
+ RunInNewThread(
+ Async Sub()
+ Try
Retry:
- If McLoginMsLoader.State = LoadState.Loading Then McLoginMsLoader.WaitForExit() '等待登录结束
- Dim AccessToken As String = Setup.Get("CacheMsAccess")
- Dim Uuid As String = Setup.Get("CacheMsUuid")
+ If McLoginMsLoader.State = LoadState.Loading Then McLoginMsLoader.WaitForExit() '等待登录结束
+ 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)
- Client.DefaultRequestHeaders.Accept.Add(New Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*"))
- Client.DefaultRequestHeaders.UserAgent.Add(New Net.Http.Headers.ProductInfoHeaderValue("MojangSharp", "0.1"))
- Dim Contents As New Net.Http.MultipartFormDataContent From {
- {New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"},
- {New Net.Http.ByteArrayContent(File.ReadAllBytes(SkinInfo.LocalFile)), "file", GetFileNameFromPath(SkinInfo.LocalFile)}
- }
- Dim Result As String = Await (Await Client.PostAsync(New Uri("https://api.minecraftservices.com/minecraft/profile/skins"), Contents)).Content.ReadAsStringAsync
- If Result.Contains("request requires user authentication") Then
- Hint("正在登录,将在登录完成后继续更改皮肤……")
- McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
- GoTo Retry
- ElseIf Result.Contains("""error""") Then
- Hint("更改皮肤失败:" & GetJson(Result)("error"), HintType.Critical)
- Exit Sub
- End If
- '获取新皮肤地址
- Log("[Skin] 皮肤修改返回值:" & vbCrLf & Result)
- Dim ResultJson As JObject = GetJson(Result)
- For Each Skin As JObject In ResultJson("skins")
- If Skin("state").ToString = "ACTIVE" Then
- MySkin.ReloadCache(Skin("url"))
- Exit Sub
- End If
- Next
- Throw New Exception("未知错误(" & Result & ")")
- Catch ex As Exception
- If ex.GetType.Equals(GetType(Tasks.TaskCanceledException)) Then
- Hint("更改皮肤失败:与 Mojang 皮肤服务器的连接超时,请检查你的网络是否通畅!", HintType.Critical)
- Else
- Log(ex, "更改皮肤失败", LogLevel.Hint)
- End If
- Finally
- IsChanging = False
- End Try
- End Sub, "Ms Skin Upload")
+ Dim Client As New Net.Http.HttpClient With {.Timeout = New TimeSpan(0, 0, 30)}
+ Client.DefaultRequestHeaders.Authorization = New Net.Http.Headers.AuthenticationHeaderValue("Bearer", AccessToken)
+ Client.DefaultRequestHeaders.Accept.Add(New Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*"))
+ Client.DefaultRequestHeaders.UserAgent.Add(New Net.Http.Headers.ProductInfoHeaderValue("MojangSharp", "0.1"))
+ Dim Contents As New Net.Http.MultipartFormDataContent From {
+ {New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"},
+ {New Net.Http.ByteArrayContent(File.ReadAllBytes(SkinInfo.LocalFile)), "file", GetFileNameFromPath(SkinInfo.LocalFile)}
+ }
+ Dim Result As String = Await (Await Client.PostAsync(New Uri("https://api.minecraftservices.com/minecraft/profile/skins"), Contents)).Content.ReadAsStringAsync
+ If Result.Contains("request requires user authentication") Then
+ Hint("正在登录,将在登录完成后继续更改皮肤……")
+ McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
+ GoTo Retry
+ ElseIf Result.Contains("""error""") Then
+ Hint("更改皮肤失败:" & GetJson(Result)("error"), HintType.Critical)
+ Exit Sub
+ End If
+ '获取新皮肤地址
+ Log("[Skin] 皮肤修改返回值:" & vbCrLf & Result)
+ Dim ResultJson As JObject = GetJson(Result)
+ For Each Skin As JObject In ResultJson("skins")
+ If Skin("state").ToString = "ACTIVE" Then
+ MySkin.ReloadCache(Skin("url"))
+ Exit Sub
+ End If
+ Next
+ Throw New Exception("未知错误(" & Result & ")")
+ Catch ex As Exception
+ If ex.GetType.Equals(GetType(Tasks.TaskCanceledException)) Then
+ Hint("更改皮肤失败:与 Mojang 皮肤服务器的连接超时,请检查你的网络是否通畅!", HintType.Critical)
+ Else
+ Log(ex, "更改皮肤失败", LogLevel.Hint)
+ End If
+ Finally
+ IsChanging = False
+ End Try
+ End Sub, "Ms Skin Upload")
End Sub
'保存皮肤
diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb
index 9848581..ac127bf 100644
--- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb
@@ -237,7 +237,7 @@
If Not Version.Modable Then Continue For
'4. 该版本的隔离文件夹下不存在 mods
Dim ModIndieFolder As New DirectoryInfo(Version.Path & "mods\")
- If ModIndieFolder.Exists AndAlso ModIndieFolder.EnumerateFiles.Count > 0 Then Exit Sub
+ If ModIndieFolder.Exists AndAlso ModIndieFolder.EnumerateFiles.Any Then Exit Sub
'满足以上全部条件则视为根目录整合包
Setup.Set("VersionArgumentIndie", 2, Version:=Version)
Log("[Setup] 已自动关闭单版本隔离:" & Version.Name, LogLevel.Debug)
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml
index 8e9be7c..f4ff7e8 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml
+++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml
@@ -115,7 +115,7 @@
-
+
@@ -125,11 +125,10 @@
-
-
-
+
+
+
-
@@ -138,7 +137,7 @@
+ ToolTip="Forge 1.12.2 等个别版本存在 Bug,会导致高度设定无效" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5">
@@ -175,11 +174,16 @@
+
+
+
@@ -229,7 +233,7 @@
-
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb
index 20e888e..99b962a 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb
@@ -38,6 +38,7 @@
ComboArgumentWindowType.SelectedIndex = Setup.Get("LaunchArgumentWindowType")
TextArgumentWindowWidth.Text = Setup.Get("LaunchArgumentWindowWidth")
TextArgumentWindowHeight.Text = Setup.Get("LaunchArgumentWindowHeight")
+ CheckArgumentRam.Checked = Setup.Get("LaunchArgumentRam")
RefreshJavaComboBox()
'游戏内存
@@ -71,6 +72,7 @@
Setup.Reset("LaunchArgumentWindowWidth")
Setup.Reset("LaunchArgumentWindowHeight")
Setup.Reset("LaunchArgumentPriority")
+ Setup.Reset("LaunchArgumentRam")
Setup.Reset("LaunchRamType")
Setup.Reset("LaunchRamCustom")
Setup.Reset("LaunchSkinType")
@@ -108,7 +110,7 @@
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndie.SelectionChanged, ComboArgumentVisibie.SelectionChanged, ComboArgumentWindowType.SelectionChanged, ComboArgumentPriority.SelectionChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex)
End Sub
- Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckAdvanceAssets.Change, CheckAdvanceJava.Change, CheckAdvanceRunWait.Change
+ Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckAdvanceAssets.Change, CheckAdvanceJava.Change, CheckAdvanceRunWait.Change, CheckArgumentRam.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
End Sub
@@ -352,19 +354,19 @@
'可安装 Mod 的版本
Dim ModDir As New DirectoryInfo(Version.PathIndie & "mods\")
Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Length, 0)
- RamMininum = 0.4 + ModCount / 150
- RamTarget1 = 1.5 + ModCount / 100
- RamTarget2 = 3 + ModCount / 60
- RamTarget3 = 6 + ModCount / 30
+ RamMininum = 0.5 + ModCount / 150
+ RamTarget1 = 1.5 + ModCount / 90
+ RamTarget2 = 2.7 + ModCount / 50
+ RamTarget3 = 4.5 + ModCount / 25
ElseIf Version IsNot Nothing AndAlso Version.Version.HasOptiFine Then
'OptiFine 版本
- RamMininum = 0.3
+ RamMininum = 0.5
RamTarget1 = 1.5
RamTarget2 = 3
- RamTarget3 = 6
+ RamTarget3 = 5
Else
'普通版本
- RamMininum = 0.3
+ RamMininum = 0.5
RamTarget1 = 1.5
RamTarget2 = 2.5
RamTarget3 = 4
@@ -372,27 +374,23 @@
Dim RamDelta As Double
'预分配内存,阶段一,0 ~ T1,100%
RamDelta = RamTarget1
- RamAvailable = Math.Max(0, RamAvailable - 0.1)
- RamGive += Math.Min(RamAvailable * 1, RamDelta)
- RamAvailable -= RamDelta / 1 + 0.1
+ RamGive += Math.Min(RamAvailable, RamDelta)
+ RamAvailable -= RamDelta
If RamAvailable < 0.1 Then GoTo PreFin
- '预分配内存,阶段二,T1 ~ T2,80%
+ '预分配内存,阶段二,T1 ~ T2,70%
RamDelta = RamTarget2 - RamTarget1
- RamAvailable = Math.Max(0, RamAvailable - 0.1)
- RamGive += Math.Min(RamAvailable * 0.8, RamDelta)
- RamAvailable -= RamDelta / 0.8 + 0.1
+ RamGive += Math.Min(RamAvailable * 0.7, RamDelta)
+ RamAvailable -= RamDelta / 0.7
If RamAvailable < 0.1 Then GoTo PreFin
- '预分配内存,阶段三,T2 ~ T3,60%
+ '预分配内存,阶段三,T2 ~ T3,40%
RamDelta = RamTarget3 - RamTarget2
- RamAvailable = Math.Max(0, RamAvailable - 0.2)
- RamGive += Math.Min(RamAvailable * 0.6, RamDelta)
- RamAvailable -= RamDelta / 0.6 + 0.2
- If RamAvailable < 0.1 Then GoTo PreFin
- '预分配内存,阶段四,T3 ~ T3 * 2,40%
- RamDelta = RamTarget3
- RamAvailable = Math.Max(0, RamAvailable - 0.3)
RamGive += Math.Min(RamAvailable * 0.4, RamDelta)
- RamAvailable -= RamDelta / 0.4 + 0.3
+ RamAvailable -= RamDelta / 0.4
+ If RamAvailable < 0.1 Then GoTo PreFin
+ '预分配内存,阶段四,T3 ~ T3 * 2,15%
+ RamDelta = RamTarget3
+ RamGive += Math.Min(RamAvailable * 0.15, RamDelta)
+ RamAvailable -= RamDelta / 0.15
If RamAvailable < 0.1 Then GoTo PreFin
PreFin:
'不低于最低值
@@ -444,7 +442,7 @@ PreFin:
Log(ex, "更新设置 Java 下拉框失败", LogLevel.Feedback)
End Try
'更新选择项
- If SelectedItem Is Nothing AndAlso JavaList.Count > 0 Then SelectedItem = ComboArgumentJava.Items(0) '选中 “自动选择”
+ If SelectedItem Is Nothing AndAlso JavaList.Any Then SelectedItem = ComboArgumentJava.Items(0) '选中 “自动选择”
ComboArgumentJava.SelectedItem = SelectedItem
'结束处理
If SelectedItem Is Nothing Then
@@ -515,15 +513,16 @@ PreFin:
Hint("正在搜索 Java,请稍候!", HintType.Critical)
Exit Sub
End If
- RunInThread(Sub()
- Hint("正在搜索 Java!")
- JavaSearchLoader.WaitForExit(IsForceRestart:=True)
- If Not JavaList.Any() Then
- Hint("未找到可用的 Java!", HintType.Critical)
- Else
- Hint("已找到 " & JavaList.Count & " 个 Java,请检查下拉框查看列表!", HintType.Finish)
- End If
- End Sub)
+ RunInThread(
+ Sub()
+ Hint("正在搜索 Java!")
+ JavaSearchLoader.WaitForExit(IsForceRestart:=True)
+ If Not JavaList.Any() Then
+ Hint("未找到可用的 Java!", HintType.Critical)
+ Else
+ Hint("已找到 " & JavaList.Count & " 个 Java,请检查下拉框查看列表!", HintType.Finish)
+ End If
+ End Sub)
End Sub
#End Region
@@ -548,12 +547,24 @@ PreFin:
If AniControlEnabled <> 0 Then Exit Sub
If ComboArgumentVisibie.SelectedIndex = 0 Then
If MyMsgBox("若在游戏启动后立即关闭启动器,崩溃检测、更改游戏标题等功能将失效。" & vbCrLf &
- "如果想保留这些功能,可以选择让启动器在游戏启动后隐藏,游戏退出后自动关闭。", "提示", "继续", "取消") = 2 Then
+ "如果想保留这些功能,可以选择让启动器在游戏启动后隐藏,游戏退出后自动关闭。", "提醒", "继续", "取消") = 2 Then
ComboArgumentVisibie.SelectedItem = e.RemovedItems(0)
End If
End If
End Sub
+ '开启自动内存优化的警告
+ Private Sub CheckArgumentRam_Change() Handles CheckArgumentRam.Change
+ If AniControlEnabled <> 0 Then Exit Sub
+ If Not CheckArgumentRam.Checked Then Return
+ If MyMsgBox("内存优化耗时较长,这会拖慢游戏的启动过程,建议仅在电脑内存不充裕时开启此选项。" & vbCrLf &
+ "如果你在使用机械硬盘,这还可能会导致一小段时间的严重卡顿。" &
+ If(IsAdmin(), "", $"{vbCrLf}{vbCrLf}每次启动游戏,PCL 都需要申请管理员权限以进行内存优化。{vbCrLf}若想自动授予权限,可以右键 PCL,打开 属性 → 兼容性 → 以管理员身份运行此程序。"),
+ "提醒", "确定", "取消") = 2 Then
+ CheckArgumentRam.Checked = False
+ End If
+ End Sub
+
#End Region
#Region "高级设置"
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb
index 14dbfef..9ec4061 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb
@@ -126,23 +126,21 @@
'滑动条
Private Sub SliderLoad()
- SliderDownloadThread.GetHintText = Function(Value As Integer)
- Return Value + 1
- End Function
- SliderDownloadSpeed.GetHintText = Function(Value As Integer)
- If Value <= 14 Then
- Return (Value + 1) * 0.1 & " M/s"
- ElseIf Value <= 31 Then
- Return (Value - 11) * 0.5 & " M/s"
- ElseIf Value <= 41 Then
- Return (Value - 21) & " M/s"
- Else
- Return "无限制"
- End If
- End Function
- SliderDebugAnim.GetHintText = Function(Value As Integer)
- Return If(Value > 29, "关闭", (Value / 10 + 0.1) & "x")
- End Function
+ SliderDownloadThread.GetHintText = Function(v) v + 1
+ SliderDownloadSpeed.GetHintText =
+ Function(v)
+ Select Case v
+ Case Is <= 14
+ Return (v + 1) * 0.1 & " M/s"
+ Case Is <= 31
+ Return (v - 11) * 0.5 & " M/s"
+ Case Is <= 41
+ Return (v - 21) & " M/s"
+ Case Else
+ Return "无限制"
+ End Select
+ End Function
+ SliderDebugAnim.GetHintText = Function(v) If(v > 29, "关闭", (v / 10 + 0.1) & "x")
End Sub
Private Sub SliderDownloadThread_PreviewChange(sender As Object, e As RouteEventArgs) Handles SliderDownloadThread.PreviewChange
If SliderDownloadThread.Value < 100 Then Exit Sub
diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
index ce03d0d..9af7c14 100644
--- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
@@ -177,7 +177,7 @@
Private Sub BtnManageCheck_Click(sender As Object, e As EventArgs) Handles BtnManageCheck.Click
Try
Dim Result = McModCheck(PageVersionLeft.Version, McModLoader.Output)
- If Result.Count > 0 Then
+ If Result.Any Then
MyMsgBox(Join(Result, vbCrLf & vbCrLf), "Mod 检查结果")
Else
Hint("Mod 检查完成,未发现任何问题!", HintType.Finish)
@@ -620,13 +620,13 @@
If ModEntry.ModId IsNot Nothing Then
DebugInfo.Add("Mod ID:" & ModEntry.ModId)
End If
- If ModEntry.Dependencies.Count > 0 Then
+ If ModEntry.Dependencies.Any Then
DebugInfo.Add("依赖于:")
For Each Dep In ModEntry.Dependencies
DebugInfo.Add(" - " & Dep.Key & If(Dep.Value Is Nothing, "", ",版本:" & Dep.Value))
Next
End If
- If DebugInfo.Count > 0 Then
+ If DebugInfo.Any Then
ContentLines.Add("")
ContentLines.AddRange(DebugInfo)
End If
diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb
index b54cc26..ad72125 100644
--- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb
@@ -33,7 +33,7 @@
If Indie = -1 Then
Dim ModFolder As New DirectoryInfo(PageVersionLeft.Version.Path & "mods\")
Dim SaveFolder As New DirectoryInfo(PageVersionLeft.Version.Path & "saves\")
- If (ModFolder.Exists AndAlso ModFolder.EnumerateFiles.Count > 0) OrElse (SaveFolder.Exists AndAlso SaveFolder.EnumerateFiles.Count > 0) Then
+ If (ModFolder.Exists AndAlso ModFolder.EnumerateFiles.Any) OrElse (SaveFolder.Exists AndAlso SaveFolder.EnumerateFiles.Any) Then
'自动开启
Setup.Set("VersionArgumentIndie", 1, Version:=PageVersionLeft.Version)
Log("[Setup] 已自动开启单版本隔离:" & PageVersionLeft.Version.Name)
@@ -438,7 +438,7 @@ PreFin:
Log(ex, "更新版本设置 Java 下拉框失败", LogLevel.Feedback)
End Try
'更新选择项
- If SelectedItem Is Nothing AndAlso JavaList.Count > 0 Then
+ If SelectedItem Is Nothing AndAlso JavaList.Any Then
If SelectedBySetup = "" Then
SelectedItem = ComboArgumentJava.Items(1) '选中 “自动选择”
Else
diff --git a/Plain Craft Launcher 2/Resources/Help.zip b/Plain Craft Launcher 2/Resources/Help.zip
index d00647e..c55c8d3 100644
Binary files a/Plain Craft Launcher 2/Resources/Help.zip and b/Plain Craft Launcher 2/Resources/Help.zip differ
diff --git a/Plain Craft Launcher 2/app.manifest b/Plain Craft Launcher 2/app.manifest
index bb8082f..2d4820f 100644
--- a/Plain Craft Launcher 2/app.manifest
+++ b/Plain Craft Launcher 2/app.manifest
@@ -29,8 +29,8 @@
-
-
+
@@ -38,7 +38,7 @@
-
+