2.10.1
This commit is contained in:
@@ -624,6 +624,26 @@ Public Module ModAnimation
|
||||
Return Ease.GetValue(t)
|
||||
End Function
|
||||
End Class
|
||||
''' <summary>
|
||||
''' 以特定速度开始的平滑结束。
|
||||
''' </summary>
|
||||
Public Class AniEaseOutFluentWithInitial
|
||||
Inherits AniEase
|
||||
Private ReadOnly alpha As Double '(初速度 / 平均速度) – 1
|
||||
''' <param name="InitialPixelPerSecond">初速度,px/s</param>
|
||||
''' <param name="TotalSecond">总时长,s</param>
|
||||
''' <param name="TotalDistance">总路程,px</param>
|
||||
Public Sub New(InitialPixelPerSecond As Double, TotalSecond As Double, TotalDistance As Double)
|
||||
Dim v0_norm As Double = InitialPixelPerSecond * TotalSecond / TotalDistance '归一化初速度
|
||||
alpha = v0_norm - 1.0
|
||||
If alpha < 0 Then alpha = 0 '初速度小于平均速度时,退化为线性
|
||||
End Sub
|
||||
Public Overrides Function GetValue(percent As Double) As Double
|
||||
Dim p As Double = MathClamp(percent, 0, 1)
|
||||
If alpha = 0 Then Return p '退化到线性
|
||||
Return (alpha + 1) * p / (1 + alpha * p)
|
||||
End Function
|
||||
End Class
|
||||
|
||||
'Back / 回弹
|
||||
''' <summary>
|
||||
@@ -807,7 +827,7 @@ Sleeper:
|
||||
Thread.Sleep(1)
|
||||
Loop
|
||||
Catch ex As Exception
|
||||
Log(ex, "动画帧执行失败", LogLevel.Assert)
|
||||
Log(ex, "动画帧执行失败", LogLevel.Critical)
|
||||
End Try
|
||||
End Sub, "Animation", ThreadPriority.AboveNormal)
|
||||
End Sub
|
||||
|
||||
@@ -13,13 +13,13 @@ Public Module ModBase
|
||||
#Region "声明"
|
||||
|
||||
'下列版本信息由更新器自动修改
|
||||
Public Const VersionBaseName As String = "2.10.0" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.10.0." & VersionBranchCode '标准格式的四段式版本号
|
||||
Public Const VersionBaseName As String = "2.10.1" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.10.1." & VersionBranchCode '标准格式的四段式版本号
|
||||
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
|
||||
#If BETA Then
|
||||
Public Const VersionCode As Integer = 357 'Release
|
||||
#Else
|
||||
Public Const VersionCode As Integer = 356 'Snapshot
|
||||
Public Const VersionCode As Integer = 358 'Snapshot
|
||||
#End If
|
||||
'自动生成的版本信息
|
||||
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
||||
@@ -785,13 +785,16 @@ Public Module ModBase
|
||||
End Function
|
||||
|
||||
'读取、写入、复制文件
|
||||
''' <summary>
|
||||
''' 复制文件。会自动创建文件夹、会覆盖已有的文件。
|
||||
''' </summary>
|
||||
Public Sub CopyFile(FromPath As String, ToPath As String)
|
||||
Try
|
||||
'还原文件路径
|
||||
If Not FromPath.Contains(":\") Then FromPath = Path & FromPath
|
||||
If Not ToPath.Contains(":\") Then ToPath = Path & ToPath
|
||||
'如果复制同一个文件则跳过
|
||||
If FromPath = ToPath Then Exit Sub
|
||||
If FromPath = ToPath Then Return
|
||||
'确保目录存在
|
||||
Directory.CreateDirectory(GetPathFromFullPath(ToPath))
|
||||
'复制文件
|
||||
@@ -803,7 +806,6 @@ Public Module ModBase
|
||||
''' <summary>
|
||||
''' 读取文件,如果失败则返回空数组。
|
||||
''' </summary>
|
||||
''' <param name="FilePath">文件完整或相对路径。</param>
|
||||
Public Function ReadFileBytes(FilePath As String, Optional Encoding As Encoding = Nothing) As Byte()
|
||||
Try
|
||||
'还原文件路径
|
||||
@@ -1363,7 +1365,7 @@ RetryDir:
|
||||
Try
|
||||
Directory.Delete(Path, True)
|
||||
Catch ex As Exception
|
||||
If Not RetriedDir Then
|
||||
If Not RetriedDir AndAlso Not RunInUi() Then
|
||||
RetriedDir = True
|
||||
Log(ex, $"删除文件夹失败,将在 0.3s 后重试({Path})")
|
||||
Thread.Sleep(300)
|
||||
@@ -1459,7 +1461,7 @@ RetryDir:
|
||||
CommonReason = "由于操作系统或显卡存在问题,导致出现错误。请尝试重启 PCL。"
|
||||
ElseIf {"远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝",
|
||||
"操作已超时", "操作超时", "服务器超时", "连接超时"}.Any(Function(s) DescList.Any(Function(l) l.Contains(s))) Then
|
||||
CommonReason = "你的网络环境不佳,导致难以连接到服务器。请检查网络,多重试几次,或尝试使用 VPN。"
|
||||
CommonReason = "你的网络环境不佳,导致难以连接到服务器。请稍后重试,或使用 VPN 以改善网络环境。"
|
||||
End If
|
||||
|
||||
'构造输出信息
|
||||
@@ -1502,7 +1504,7 @@ RetryDir:
|
||||
CommonReason = "由于操作系统或显卡存在问题,导致出现错误。请尝试重启 PCL。"
|
||||
ElseIf {"远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝",
|
||||
"操作已超时", "操作超时", "服务器超时", "连接超时"}.Any(Function(s) Desc.Contains(s)) Then
|
||||
CommonReason = "你的网络环境不佳,导致难以连接到服务器。请检查网络,多重试几次,或尝试使用 VPN。"
|
||||
CommonReason = "你的网络环境不佳,导致难以连接到服务器。请稍后重试,或使用 VPN 以改善网络环境。"
|
||||
End If
|
||||
|
||||
'构造输出信息
|
||||
@@ -1981,8 +1983,8 @@ RetryDir:
|
||||
#Region "系统"
|
||||
|
||||
''' <summary>
|
||||
''' 线程安全的,可以直接使用 For Each 的 List。
|
||||
''' 在使用 For Each 循环时,列表的结果可能并非最新,但不会抛出异常。
|
||||
''' 线程安全的 List。
|
||||
''' 通过在 For Each 循环中使用一个浅表副本规避多线程操作或移除自身导致的异常。
|
||||
''' </summary>
|
||||
Public Class SafeList(Of T)
|
||||
Inherits SynchronizedCollection(Of T)
|
||||
@@ -2014,8 +2016,8 @@ RetryDir:
|
||||
End Class
|
||||
|
||||
''' <summary>
|
||||
''' 线程安全的,可以直接使用 For Each 的字典。
|
||||
''' 在使用 For Each 循环时,字典的结果可能并非最新,但不会抛出异常。
|
||||
''' 线程安全的字典。
|
||||
''' 通过在 For Each 循环中使用一个浅表副本规避多线程操作或移除自身导致的异常。
|
||||
''' </summary>
|
||||
Public Class SafeDictionary(Of TKey, TValue)
|
||||
Implements IDictionary(Of TKey, TValue)
|
||||
@@ -2674,7 +2676,7 @@ Retry:
|
||||
End Select
|
||||
End If
|
||||
|
||||
'If Double.IsNaN(newValue) OrElse Double.IsInfinity(newValue) Then Exit Sub '安全性检查
|
||||
'If Double.IsNaN(newValue) OrElse Double.IsInfinity(newValue) Then Return '安全性检查
|
||||
'Select Case control.VerticalAlignment
|
||||
' Case VerticalAlignment.Top, VerticalAlignment.Stretch, VerticalAlignment.Center
|
||||
' control.Margin = New Thickness(control.Margin.Left, newValue, control.Margin.Right, control.Margin.Bottom)
|
||||
@@ -2847,9 +2849,10 @@ Retry:
|
||||
''' </summary>
|
||||
Feedback = 5
|
||||
''' <summary>
|
||||
''' 弹窗,结束程序。
|
||||
''' 弹出 Windows 原生弹窗,要求反馈。在无法保证 WPF 窗口能正常运行时使用此级别。
|
||||
''' 在第二次触发后会直接结束程序。
|
||||
''' </summary>
|
||||
Assert = 6
|
||||
Critical = 6
|
||||
End Enum
|
||||
Private LogList As New StringBuilder
|
||||
Private LogWritter As StreamWriter
|
||||
@@ -2892,7 +2895,7 @@ Retry:
|
||||
Private ReadOnly LogFlushLock As New Object '防止外部调用 LogFlush 时同时输出多次日志
|
||||
Public Sub LogFlush()
|
||||
On Error Resume Next
|
||||
If LogWritter Is Nothing Then Exit Sub
|
||||
If LogWritter Is Nothing Then Return
|
||||
Dim Log As String = Nothing
|
||||
SyncLock LogFlushLock
|
||||
If LogList.Length > 0 Then
|
||||
@@ -2908,6 +2911,7 @@ Retry:
|
||||
End Sub
|
||||
|
||||
Private ReadOnly LogListLock As New Object '防止日志乱码,只在调试模式下启用
|
||||
Private IsCriticalErrorTriggered As Boolean = False
|
||||
''' <summary>
|
||||
''' 输出 Log。
|
||||
''' </summary>
|
||||
@@ -2929,7 +2933,7 @@ Retry:
|
||||
#If DEBUG Then
|
||||
Console.Write(AppendText)
|
||||
#End If
|
||||
If IsProgramEnded OrElse Level = LogLevel.Normal Then Exit Sub
|
||||
If IsProgramEnded OrElse Level = LogLevel.Normal Then Return
|
||||
|
||||
'去除前缀
|
||||
Text = Text.RegexReplace("\[[^\]]+?\] ", "")
|
||||
@@ -2956,20 +2960,17 @@ Retry:
|
||||
Else
|
||||
MyMsgBox(Text & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", Title, IsWarn:=True)
|
||||
End If
|
||||
Case LogLevel.Assert
|
||||
Dim Time As Long = GetTimeTick()
|
||||
Case LogLevel.Critical
|
||||
If IsCriticalErrorTriggered Then
|
||||
FormMain.EndProgramForce(ProcessReturnValues.Exception)
|
||||
Return
|
||||
End If
|
||||
IsCriticalErrorTriggered = True
|
||||
If CanFeedback(False) Then
|
||||
If MsgBox(Text & vbCrLf & vbCrLf & "是否反馈此问题?如果不反馈,这个问题可能永远无法得到解决!", MsgBoxStyle.Critical + MsgBoxStyle.YesNo, Title) = MsgBoxResult.Yes Then Feedback(False, True)
|
||||
Else
|
||||
MsgBox(Text & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", MsgBoxStyle.Critical, Title)
|
||||
End If
|
||||
If GetTimeTick() - Time < 1500 Then
|
||||
'弹窗无法保留
|
||||
Log("[System] PCL 已崩溃:" & vbCrLf & Text)
|
||||
FormMain.EndProgramForce(ProcessReturnValues.Exception)
|
||||
Else
|
||||
FormMain.EndProgramForce(ProcessReturnValues.Fail)
|
||||
End If
|
||||
End Select
|
||||
|
||||
End Sub
|
||||
@@ -2979,7 +2980,7 @@ Retry:
|
||||
''' <param name="Desc">错误描述。会在处理时在末尾加入冒号。</param>
|
||||
Public Sub Log(Ex As Exception, Desc As String, Optional Level As LogLevel = LogLevel.Debug, Optional Title As String = "出现错误")
|
||||
On Error Resume Next
|
||||
If TypeOf Ex Is ThreadInterruptedException Then Exit Sub
|
||||
If TypeOf Ex Is ThreadInterruptedException Then Return
|
||||
|
||||
'获取错误信息
|
||||
Dim ExFull As String = Desc & ":" & GetExceptionDetail(Ex)
|
||||
@@ -2996,7 +2997,7 @@ Retry:
|
||||
#If DEBUG Then
|
||||
Console.Write(AppendText)
|
||||
#End If
|
||||
If IsProgramEnded Then Exit Sub
|
||||
If IsProgramEnded Then Return
|
||||
|
||||
'输出提示
|
||||
Select Case Level
|
||||
@@ -3025,20 +3026,17 @@ Retry:
|
||||
Else
|
||||
MyMsgBox(ExFull & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", Title, IsWarn:=True)
|
||||
End If
|
||||
Case LogLevel.Assert
|
||||
Dim Time As Long = GetTimeTick()
|
||||
Case LogLevel.Critical
|
||||
If IsCriticalErrorTriggered Then
|
||||
FormMain.EndProgramForce(ProcessReturnValues.Exception)
|
||||
Return
|
||||
End If
|
||||
IsCriticalErrorTriggered = True
|
||||
If CanFeedback(False) Then
|
||||
If MsgBox(ExFull & vbCrLf & vbCrLf & "是否反馈此问题?如果不反馈,这个问题可能永远无法得到解决!", MsgBoxStyle.Critical + MsgBoxStyle.YesNo, Title) = MsgBoxResult.Yes Then Feedback(False, True)
|
||||
Else
|
||||
MsgBox(ExFull & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", MsgBoxStyle.Critical, Title)
|
||||
End If
|
||||
If GetTimeTick() - Time < 1500 Then
|
||||
'弹窗无法保留
|
||||
Log("[System] PCL 已崩溃:" & vbCrLf & ExFull)
|
||||
FormMain.EndProgramForce(ProcessReturnValues.Exception)
|
||||
Else
|
||||
FormMain.EndProgramForce(ProcessReturnValues.Fail)
|
||||
End If
|
||||
End Select
|
||||
|
||||
End Sub
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
Return _State
|
||||
End Get
|
||||
Set(value As LoadState)
|
||||
If _State = value Then Exit Property
|
||||
If _State = value Then Return
|
||||
Dim OldState = _State
|
||||
If value = LoadState.Finished AndAlso Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000))
|
||||
_State = value
|
||||
@@ -112,7 +112,7 @@
|
||||
Return _LoadingState
|
||||
End Get
|
||||
Set(value As MyLoading.MyLoadingState)
|
||||
If _LoadingState = value Then Exit Property
|
||||
If _LoadingState = value Then Return
|
||||
Dim OldState = _LoadingState
|
||||
_LoadingState = value
|
||||
RaiseEvent LoadingStateChanged(value, OldState)
|
||||
@@ -154,7 +154,7 @@
|
||||
End Select
|
||||
End Get
|
||||
Set(value As Double)
|
||||
If _Progress = value Then Exit Property
|
||||
If _Progress = value Then Return
|
||||
Dim OldValue = _Progress
|
||||
_Progress = value
|
||||
RaiseEvent ProgressChanged(value, OldValue)
|
||||
@@ -184,7 +184,7 @@
|
||||
Thread.Sleep(10)
|
||||
Loop
|
||||
If State = LoadState.Finished Then
|
||||
Exit Sub
|
||||
Return
|
||||
ElseIf State = LoadState.Aborted Then
|
||||
Throw New ThreadInterruptedException("加载器执行已中断。")
|
||||
ElseIf IsNothing([Error]) Then
|
||||
@@ -207,7 +207,7 @@
|
||||
If Timeout < 0 Then Throw New TimeoutException(TimeoutMessage)
|
||||
Loop
|
||||
If State = LoadState.Finished Then
|
||||
Exit Sub
|
||||
Return
|
||||
ElseIf State = LoadState.Aborted Then
|
||||
Throw New ThreadInterruptedException("加载器执行已中断。")
|
||||
ElseIf IsNothing([Error]) Then
|
||||
@@ -308,48 +308,49 @@
|
||||
Progress = -1
|
||||
End SyncLock
|
||||
Else
|
||||
Exit Sub
|
||||
Return
|
||||
End If
|
||||
|
||||
LastRunningThread = New Thread(
|
||||
Sub()
|
||||
Try
|
||||
IsForceRestarting = IsForceRestart
|
||||
If ModeDebug Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动")
|
||||
LoadDelegate(Me)
|
||||
If IsAborted Then
|
||||
Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId)})", LogLevel.Developer)
|
||||
Else
|
||||
RaisePreviewFinish()
|
||||
State = LoadState.Finished
|
||||
LastFinishedTime = GetTimeTick() '未中断,本次输出有效
|
||||
End If
|
||||
Catch ex As CancelledException
|
||||
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发取消中断,已完成 {Math.Round(Progress * 100)}%")
|
||||
If Not IsAborted Then State = LoadState.Aborted
|
||||
Catch ex As ThreadInterruptedException
|
||||
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发线程中断,已完成 {Math.Round(Progress * 100)}%")
|
||||
'如果线程是因为判断到 IsAborted 而提前中止,则代表已有新线程被重启,此时不应当改为 Aborted
|
||||
'如果线程是在没有 IsAborted 时手动引发了 ThreadInterruptedException,则代表没有重启线程,这通常代表用户手动取消,应当改为 Aborted
|
||||
If Not IsAborted Then State = LoadState.Aborted
|
||||
Catch ex As Exception
|
||||
If IsAborted Then Exit Sub
|
||||
Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%", LogLevel.Developer)
|
||||
[Error] = ex
|
||||
State = LoadState.Failed
|
||||
End Try
|
||||
End Sub) With {.Name = Name, .Priority = ThreadPriority}
|
||||
Sub()
|
||||
Try
|
||||
IsForceRestarting = IsForceRestart
|
||||
If ModeDebug Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动")
|
||||
LoadDelegate(Me)
|
||||
If IsAborted Then
|
||||
Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId)})", LogLevel.Developer)
|
||||
Return
|
||||
End If
|
||||
If ModeDebug Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已完成")
|
||||
RaisePreviewFinish()
|
||||
State = LoadState.Finished
|
||||
LastFinishedTime = GetTimeTick() '未中断,本次输出有效
|
||||
Catch ex As CancelledException
|
||||
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发取消中断,已完成 {Math.Round(Progress * 100)}%")
|
||||
If Not IsAborted Then State = LoadState.Aborted
|
||||
Catch ex As ThreadInterruptedException
|
||||
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发线程中断,已完成 {Math.Round(Progress * 100)}%")
|
||||
'如果线程是因为判断到 IsAborted 而提前中止,则代表已有新线程被重启,此时不应当改为 Aborted
|
||||
'如果线程是在没有 IsAborted 时手动引发了 ThreadInterruptedException,则代表没有重启线程,这通常代表用户手动取消,应当改为 Aborted
|
||||
If Not IsAborted Then State = LoadState.Aborted
|
||||
Catch ex As Exception
|
||||
If IsAborted Then Return
|
||||
Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%", LogLevel.Developer)
|
||||
[Error] = ex
|
||||
State = LoadState.Failed
|
||||
End Try
|
||||
End Sub) With {.Name = Name, .Priority = ThreadPriority}
|
||||
LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted
|
||||
End Sub
|
||||
Public Overrides Sub Abort()
|
||||
If State <> LoadState.Loading Then Exit Sub
|
||||
If State <> LoadState.Loading Then Return
|
||||
SyncLock LockState
|
||||
State = LoadState.Aborted
|
||||
End SyncLock
|
||||
TriggerThreadAbort()
|
||||
End Sub
|
||||
Private Sub TriggerThreadAbort()
|
||||
If LastRunningThread Is Nothing Then Exit Sub
|
||||
If LastRunningThread Is Nothing Then Return
|
||||
If ModeDebug Then Log($"[Loader] 加载线程 {Name} ({LastRunningThread.ManagedThreadId}) 已中断")
|
||||
If LastRunningThread.IsAlive Then LastRunningThread.Interrupt()
|
||||
LastRunningThread = Nothing
|
||||
@@ -419,7 +420,7 @@
|
||||
'改变状态
|
||||
SyncLock LockState
|
||||
If State = LoadState.Loading Then
|
||||
Exit Sub
|
||||
Return
|
||||
Else
|
||||
State = LoadState.Loading
|
||||
End If
|
||||
@@ -439,7 +440,7 @@
|
||||
If State = LoadState.Loading OrElse State = LoadState.Waiting Then
|
||||
State = LoadState.Aborted
|
||||
Else
|
||||
Exit Sub
|
||||
Return
|
||||
End If
|
||||
End SyncLock
|
||||
RunInThread(
|
||||
@@ -470,7 +471,7 @@
|
||||
Case Else
|
||||
'完蛋,出错了
|
||||
SyncLock LockState
|
||||
If State >= LoadState.Finished Then Exit Sub
|
||||
If State >= LoadState.Finished Then Return
|
||||
[Error] = New Exception(Loader.Name & "失败", Loader.Error)
|
||||
State = Loader.State
|
||||
End SyncLock
|
||||
@@ -478,14 +479,14 @@
|
||||
Loader.Abort()
|
||||
Next
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
Exit Sub
|
||||
Return
|
||||
End Select
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 触发一次更新,以启动新加载器或完成。
|
||||
''' </summary>
|
||||
Private Sub Update()
|
||||
If State = LoadState.Finished OrElse State = LoadState.Failed OrElse State = LoadState.Aborted Then Exit Sub
|
||||
If State = LoadState.Finished OrElse State = LoadState.Failed OrElse State = LoadState.Aborted Then Return
|
||||
Dim IsFinished As Boolean = True
|
||||
Dim Blocked As Boolean = False
|
||||
Dim Input As Object = Me.Input
|
||||
@@ -584,16 +585,11 @@ Restart:
|
||||
Try
|
||||
Dim NewState As Shell.TaskbarItemProgressState
|
||||
Dim NewProgress As Double = LoaderTaskbarProgressGet()
|
||||
'检查任务是否完成,若完成则移除
|
||||
'外显任务是否已经全部完成
|
||||
Dim IsAllDownloadTaskCompleted As Boolean = True
|
||||
For Each Loader In LoaderTaskbar.ToList()
|
||||
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 Then
|
||||
If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRefresh(Task)
|
||||
'若单个任务已中止,或全部任务已完成,则刷新并移除
|
||||
For Each Task In LoaderTaskbar
|
||||
If LoaderTaskbar.All(Function(l) l.State <> LoadState.Loading) OrElse
|
||||
(Task.State = LoadState.Waiting OrElse Task.State = LoadState.Aborted) Then
|
||||
FrmSpeedLeft?.TaskRefresh(Task)
|
||||
LoaderTaskbar.Remove(Task)
|
||||
Log($"[Taskbar] {Task.Name} 已移出任务列表")
|
||||
End If
|
||||
@@ -625,8 +621,8 @@ Restart:
|
||||
End Sub
|
||||
Public Function LoaderTaskbarProgressGet() As Double
|
||||
Try
|
||||
If Not LoaderTaskbar.Where(Function(l) l.Show).Any Then Return 1
|
||||
Return MathClamp(LoaderTaskbar.Where(Function(l) l.Show).Select(Function(l) l.Progress).Average(), 0, 1)
|
||||
If Not LoaderTaskbar.Any Then Return 1
|
||||
Return MathClamp(LoaderTaskbar.Select(Function(l) l.Progress).Average(), 0, 1)
|
||||
Catch ex As Exception
|
||||
Log(ex, "获取任务栏进度出错", LogLevel.Feedback)
|
||||
Return 0.5
|
||||
|
||||
@@ -1345,7 +1345,7 @@ Wrong:
|
||||
If State < NetState.Merge Then
|
||||
State = NetState.Merge
|
||||
Else
|
||||
Exit Sub
|
||||
Return
|
||||
End If
|
||||
End SyncLock
|
||||
Dim RetryCount As Integer = 0
|
||||
@@ -1355,8 +1355,7 @@ Retry:
|
||||
SyncLock LockChain
|
||||
'创建文件夹
|
||||
If File.Exists(LocalPath) Then File.Delete(LocalPath)
|
||||
Dim Info As New FileInfo(LocalPath)
|
||||
Info.Directory.Create()
|
||||
Directory.CreateDirectory(GetPathFromFullPath(LocalPath))
|
||||
'合并文件
|
||||
If IsNoSplit Then
|
||||
'仅有一个线程,从缓存中输出
|
||||
@@ -1435,7 +1434,7 @@ Retry:
|
||||
''' </summary>
|
||||
Private Sub Fail(Optional RaiseEx As Exception = Nothing)
|
||||
SyncLock LockState
|
||||
If State >= NetState.Finish Then Exit Sub
|
||||
If State >= NetState.Finish Then Return
|
||||
If RaiseEx IsNot Nothing Then Ex.Add(RaiseEx)
|
||||
'凉凉
|
||||
State = NetState.Error
|
||||
@@ -1451,10 +1450,10 @@ Retry:
|
||||
Public Sub Abort(CausedByTask As LoaderDownload)
|
||||
'从特定任务中移除,如果它还属于其他任务,则继续下载
|
||||
Tasks.Remove(CausedByTask)
|
||||
If Tasks.Any Then Exit Sub
|
||||
If Tasks.Any Then Return
|
||||
'确认中断
|
||||
SyncLock LockState
|
||||
If State >= NetState.Finish Then Exit Sub
|
||||
If State >= NetState.Finish Then Return
|
||||
State = NetState.Error
|
||||
End SyncLock
|
||||
InterruptAndDelete()
|
||||
@@ -1474,7 +1473,7 @@ Retry:
|
||||
''' </summary>
|
||||
Public Sub Finish(Optional PrintLog As Boolean = True)
|
||||
SyncLock LockState
|
||||
If State >= NetState.Finish Then Exit Sub
|
||||
If State >= NetState.Finish Then Return
|
||||
State = NetState.Finish
|
||||
End SyncLock
|
||||
SyncLock NetManager.LockRemain
|
||||
@@ -1601,7 +1600,7 @@ NextElement:
|
||||
'输入检测
|
||||
If Not Files.Any() Then
|
||||
OnFinish()
|
||||
Exit Sub
|
||||
Return
|
||||
End If
|
||||
For Each File As NetFile In Files
|
||||
If File Is Nothing Then Throw New ArgumentException("存在空文件请求!")
|
||||
@@ -1658,13 +1657,14 @@ NextElement:
|
||||
End Sub
|
||||
Private Sub StartCopy(Files As List(Of NetFile), FolderList As List(Of String))
|
||||
Try
|
||||
If ModeDebug Then Log("[Download] 检查线程分配文件数:" & Files.Count & ",线程名:" & Thread.CurrentThread.Name)
|
||||
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
|
||||
Dim ExistFilePath As String = Nothing
|
||||
'判断是否有已存在的文件
|
||||
If File.Check IsNot Nothing AndAlso McFolderList IsNot Nothing AndAlso PathMcFolder IsNot Nothing AndAlso File.Check.CanUseExistsFile AndAlso File.LocalPath.StartsWithF(PathMcFolder) Then
|
||||
If File.Check IsNot Nothing AndAlso McFolderList IsNot Nothing AndAlso PathMcFolder IsNot Nothing AndAlso
|
||||
File.Check.CanUseExistsFile AndAlso File.LocalPath.StartsWithF(PathMcFolder) Then
|
||||
Dim Relative = File.LocalPath.Replace(PathMcFolder, "")
|
||||
For Each Folder In FolderList
|
||||
Dim Target = Folder & Relative
|
||||
@@ -1690,7 +1690,7 @@ NextElement:
|
||||
For Each FileToken In ExistFiles
|
||||
Dim File As NetFile = FileToken.Key
|
||||
SyncLock LockState
|
||||
If File.State > NetState.WaitForCopy Then Exit Sub
|
||||
If File.State > NetState.WaitForCopy Then Return
|
||||
End SyncLock
|
||||
Dim LocalPath As String = FileToken.Value
|
||||
Dim RetryCount As Integer = 0
|
||||
@@ -1701,7 +1701,7 @@ Retry:
|
||||
File.Finish(False)
|
||||
Catch ex As Exception
|
||||
RetryCount += 1
|
||||
Log(ex, String.Format("复制已存在的文件失败,重试第 {2} 次({0} -> {1})", LocalPath, File.LocalPath, RetryCount))
|
||||
Log(ex, $"复制已存在的文件失败,重试第 {RetryCount} 次({LocalPath} -> {File.LocalPath})")
|
||||
If RetryCount < 3 Then
|
||||
Thread.Sleep(200)
|
||||
GoTo Retry
|
||||
@@ -1719,14 +1719,14 @@ Retry:
|
||||
'要求全部文件完成
|
||||
SyncLock FileRemainLock
|
||||
FileRemain -= 1
|
||||
If FileRemain > 0 Then Exit Sub
|
||||
If FileRemain > 0 Then Return
|
||||
End SyncLock
|
||||
OnFinish()
|
||||
End Sub
|
||||
Public Sub OnFinish()
|
||||
RaisePreviewFinish()
|
||||
SyncLock LockState
|
||||
If State > LoadState.Loading Then Exit Sub
|
||||
If State > LoadState.Loading Then Return
|
||||
State = LoadState.Finished
|
||||
End SyncLock
|
||||
End Sub
|
||||
@@ -1739,7 +1739,7 @@ Retry:
|
||||
End Sub
|
||||
Public Sub OnFail(ExList As List(Of Exception))
|
||||
SyncLock LockState
|
||||
If State > LoadState.Loading Then Exit Sub
|
||||
If State > LoadState.Loading Then Return
|
||||
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
|
||||
@@ -1768,7 +1768,7 @@ Retry:
|
||||
End Sub
|
||||
Public Overrides Sub Abort()
|
||||
SyncLock LockState
|
||||
If State >= LoadState.Finished Then Exit Sub
|
||||
If State >= LoadState.Finished Then Return
|
||||
State = LoadState.Aborted
|
||||
End SyncLock
|
||||
Log("[Download] " & Name & " 已取消!")
|
||||
@@ -1885,7 +1885,7 @@ Retry:
|
||||
''' 启动监控线程,用于新增下载线程。
|
||||
''' </summary>
|
||||
Private Sub StartManager()
|
||||
If IsManagerStarted Then Exit Sub
|
||||
If IsManagerStarted Then Return
|
||||
IsManagerStarted = True
|
||||
Dim ThreadStarter =
|
||||
Sub(Id As Integer) '0 或 1
|
||||
@@ -1936,7 +1936,7 @@ Retry:
|
||||
Next
|
||||
End While
|
||||
Catch ex As Exception
|
||||
Log(ex, $"下载管理启动线程 {Id} 出错", LogLevel.Assert)
|
||||
Log(ex, $"下载管理启动线程 {Id} 出错", LogLevel.Critical)
|
||||
End Try
|
||||
End Sub
|
||||
RunInNewThread(Sub() ThreadStarter(0), "NetManager ThreadStarter 0")
|
||||
@@ -1960,7 +1960,7 @@ Retry:
|
||||
Loop
|
||||
End While
|
||||
Catch ex As Exception
|
||||
Log(ex, "下载管理刷新线程出错", LogLevel.Assert)
|
||||
Log(ex, "下载管理刷新线程出错", LogLevel.Critical)
|
||||
End Try
|
||||
End Sub, "NetManager StatRefresher")
|
||||
End Sub
|
||||
|
||||
Reference in New Issue
Block a user