2.12.2
This commit is contained in:
@@ -743,9 +743,9 @@ Public Module ModAnimation
|
||||
''' <param name="AniGroup">由 Aa 开头的函数初始化的 AniData 对象集合。</param>
|
||||
''' <param name="Name">动画组的名称。如果重复会直接停止同名动画组。</param>
|
||||
Public Sub AniStart(AniGroup As IList, Optional Name As String = "", Optional RefreshTime As Boolean = False)
|
||||
If RefreshTime Then AniLastTick = GetTimeTick() '避免处理动画时已经造成了极大的延迟,导致动画突然结束
|
||||
If RefreshTime Then AniLastTick = GetTimeMs() '避免处理动画时已经造成了极大的延迟,导致动画突然结束
|
||||
'添加到正在执行的动画组
|
||||
Dim NewEntry As New AniGroupEntry With {.Data = GetFullList(Of AniData)(AniGroup), .StartTick = GetTimeTick()}
|
||||
Dim NewEntry As New AniGroupEntry With {.Data = GetFullList(Of AniData)(AniGroup), .StartTick = GetTimeMs()}
|
||||
If Name = "" Then
|
||||
Name = NewEntry.Uuid
|
||||
Else
|
||||
@@ -788,7 +788,7 @@ Public Module ModAnimation
|
||||
''' </summary>
|
||||
Public Sub AniStart()
|
||||
'初始化计时器
|
||||
AniLastTick = GetTimeTick()
|
||||
AniLastTick = GetTimeMs()
|
||||
AniFPSTimer = AniLastTick
|
||||
AniRunning = True '标记动画执行开始
|
||||
|
||||
@@ -798,9 +798,9 @@ Public Module ModAnimation
|
||||
Log("[Animation] 动画线程开始")
|
||||
Do While True
|
||||
'两帧之间的间隔时间
|
||||
Dim DeltaTime As Long = MathClamp(GetTimeTick() - AniLastTick, 0, 100000)
|
||||
Dim DeltaTime As Long = MathClamp(GetTimeMs() - AniLastTick, 0, 100000)
|
||||
If DeltaTime < 3 Then GoTo Sleeper
|
||||
AniLastTick = GetTimeTick()
|
||||
AniLastTick = GetTimeMs()
|
||||
'记录 FPS
|
||||
If ModeDebug Then
|
||||
If MathClamp(AniLastTick - AniFPSTimer, 0, 100000) >= 500 Then
|
||||
|
||||
@@ -14,13 +14,13 @@ Public Module ModBase
|
||||
#Region "声明"
|
||||
|
||||
'下列版本信息由更新器自动修改
|
||||
Public Const VersionBaseName As String = "2.12.1" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.12.1." & VersionBranchCode '标准格式的四段式版本号
|
||||
Public Const VersionBaseName As String = "2.12.2" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.12.2." & VersionBranchCode '标准格式的四段式版本号
|
||||
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
|
||||
#If BETA Then
|
||||
Public Const VersionCode As Integer = 372 'Release
|
||||
Public Const VersionCode As Integer = 379 'Release
|
||||
#Else
|
||||
Public Const VersionCode As Integer = 378 'Snapshot
|
||||
Public Const VersionCode As Integer = 380 'Snapshot
|
||||
#End If
|
||||
'自动生成的版本信息
|
||||
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
||||
@@ -62,7 +62,7 @@ Public Module ModBase
|
||||
''' <summary>
|
||||
''' 程序的打开计时。
|
||||
''' </summary>
|
||||
Public ApplicationStartTick As Long = GetTimeTick()
|
||||
Public ApplicationStartTick As Long = GetTimeMs()
|
||||
''' <summary>
|
||||
''' 程序打开时的时间。
|
||||
''' </summary>
|
||||
@@ -1284,27 +1284,31 @@ Re:
|
||||
''' <summary>
|
||||
''' 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 jar 以 zip 方式解压。
|
||||
''' 会尝试创建,但不会清空目标文件夹。
|
||||
''' 会先使用 UTF-8 解压,失败后换用 GB18030 解压。
|
||||
''' </summary>
|
||||
Public Sub ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing,
|
||||
Optional ProgressIncrementHandler As Action(Of Double) = Nothing)
|
||||
Public Sub ExtractCompressedFile(CompressFilePath As String, DestDirectory As String, Optional ProgressIncrementHandler As Action(Of Double) = Nothing)
|
||||
Directory.CreateDirectory(DestDirectory)
|
||||
'解压 gz(gz 不需要考虑编码)
|
||||
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")))
|
||||
Dim TotalCount As Long = Archive.Entries.Count
|
||||
For Each Entry As ZipArchiveEntry In Archive.Entries
|
||||
If ProgressIncrementHandler IsNot Nothing AndAlso TotalCount > 0 Then ProgressIncrementHandler(1 / TotalCount)
|
||||
Using stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.Read, FileShare.Read), CompressionMode.Decompress)
|
||||
Using 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
|
||||
End Using
|
||||
End Using
|
||||
Return
|
||||
End If
|
||||
'解压 zip
|
||||
Dim TryExtractZip =
|
||||
Sub(Encoding As Encoding)
|
||||
Using Archive = ZipFile.Open(CompressFilePath, ZipArchiveMode.Read, Encoding)
|
||||
Dim EntryCount = Archive.Entries.Count
|
||||
For Each Entry In Archive.Entries
|
||||
If ProgressIncrementHandler IsNot Nothing AndAlso EntryCount > 0 Then ProgressIncrementHandler(1 / EntryCount)
|
||||
Dim DestinationFullPath As String = IO.Path.Combine(DestDirectory, Entry.FullName)
|
||||
If Not IO.Path.GetFullPath(DestinationFullPath).StartsWithF(IO.Path.GetFullPath(DestDirectory), True) Then Continue For 'ZipSlip 漏洞修复
|
||||
If DestinationFullPath.EndsWithF("\") OrElse DestinationFullPath.EndsWithF("/") Then Continue For '不创建空文件夹
|
||||
@@ -1313,7 +1317,17 @@ Re:
|
||||
Entry.ExtractToFile(DestinationFullPath.Replace(DestinationDirectory, ShortenPath(DestinationDirectory)), True) '#7329
|
||||
Next
|
||||
End Using
|
||||
End If
|
||||
End Sub
|
||||
Try
|
||||
TryExtractZip(Encoding.UTF8)
|
||||
Catch ex As Exception
|
||||
Log(ex, $"首次解压尝试失败,将更换编码并重试({CompressFilePath} → {DestDirectory})")
|
||||
Try
|
||||
TryExtractZip(Encoding.GetEncoding("GB18030"))
|
||||
Catch
|
||||
Throw
|
||||
End Try
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
@@ -1609,6 +1623,7 @@ RetryDir:
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 分割字符串。
|
||||
''' 若原始字符串为空,则返回 {""}。
|
||||
''' </summary>
|
||||
<Extension> Public Function Split(FullStr As String, SplitStr As String) As String()
|
||||
If SplitStr.Length = 1 Then
|
||||
@@ -2297,10 +2312,10 @@ NextElement:
|
||||
Return Date.Now.ToString("HH':'mm':'ss'.'fff")
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 获取系统运行时间(毫秒),保证为正 Long 且大于 1,但可能突变减小。
|
||||
''' 获取一个单调递增时间值(毫秒)。
|
||||
''' </summary>
|
||||
Public Function GetTimeTick() As Long
|
||||
Return My.Computer.Clock.TickCount + 2147483651L
|
||||
Public Function GetTimeMs() As Long
|
||||
Return Stopwatch.GetTimestamp() \ (Stopwatch.Frequency \ 1000L)
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 将时间间隔转换为类似“5 分 10 秒前”的易于阅读的形式。
|
||||
|
||||
@@ -295,7 +295,7 @@
|
||||
|
||||
If (State = LoadState.Loading OrElse State = LoadState.Finished) AndAlso '正在加载或已结束…
|
||||
(IgnoreReloadTimeout OrElse ReloadTimeout = -1 OrElse
|
||||
LastFinishedTime = 0 OrElse GetTimeTick() - LastFinishedTime < ReloadTimeout) Then '…且没有超时…
|
||||
LastFinishedTime = 0 OrElse GetTimeMs() - LastFinishedTime < ReloadTimeout) Then '…且没有超时…
|
||||
Return False '…则不重试
|
||||
Else
|
||||
Return True '否则需要重启
|
||||
@@ -328,7 +328,7 @@
|
||||
If ModeDebug AndAlso Not LogBlackList.Contains(Name) Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已完成")
|
||||
RaisePreviewFinish()
|
||||
State = LoadState.Finished
|
||||
LastFinishedTime = GetTimeTick() '未中断,本次输出有效
|
||||
LastFinishedTime = GetTimeMs() '未中断,本次输出有效
|
||||
Catch ex As CancelledException
|
||||
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发取消中断,已完成 {Math.Round(Progress * 100)}%")
|
||||
If Not IsAborted Then State = LoadState.Aborted
|
||||
|
||||
@@ -52,7 +52,7 @@ Public Module ModNet
|
||||
Optional Encoding As Encoding = Nothing, Optional SimulateBrowserHeaders As Boolean = False) As String
|
||||
Dim RetryCount As Integer = 0
|
||||
Dim RetryException As Exception = Nothing
|
||||
Dim StartTime As Long = GetTimeTick()
|
||||
Dim StartTime As Long = GetTimeMs()
|
||||
Try
|
||||
Retry:
|
||||
Select Case RetryCount
|
||||
@@ -62,7 +62,7 @@ Retry:
|
||||
Thread.Sleep(500)
|
||||
Return NetRequestByClient(Url, Method, Content, ContentType, Accept, 30000, Headers, RequireJson, Encoding, SimulateBrowserHeaders)
|
||||
Case Else '快速重试
|
||||
If GetTimeTick() - StartTime > 5500 Then
|
||||
If GetTimeMs() - StartTime > 5500 Then
|
||||
'若前两次加载耗费 5 秒以上,才进行重试
|
||||
Thread.Sleep(500)
|
||||
Return NetRequestByClient(Url, Method, Content, ContentType, Accept, 4000, Headers, RequireJson, Encoding, SimulateBrowserHeaders)
|
||||
@@ -586,7 +586,7 @@ RequestFinished:
|
||||
''' <summary>
|
||||
''' 上次记速时的时间。
|
||||
''' </summary>
|
||||
Private SpeedLastTime As Long = GetTimeTick()
|
||||
Private SpeedLastTime As Long = GetTimeMs()
|
||||
''' <summary>
|
||||
''' 上次记速时的已下载大小。
|
||||
''' </summary>
|
||||
@@ -596,8 +596,8 @@ RequestFinished:
|
||||
''' </summary>
|
||||
Public ReadOnly Property Speed As Long
|
||||
Get
|
||||
If GetTimeTick() - SpeedLastTime > 200 Then
|
||||
Dim DeltaTime As Long = GetTimeTick() - SpeedLastTime
|
||||
If GetTimeMs() - SpeedLastTime > 200 Then
|
||||
Dim DeltaTime As Long = GetTimeMs() - SpeedLastTime
|
||||
_Speed = (DownloadDone - SpeedLastDone) / (DeltaTime / 1000)
|
||||
SpeedLastDone = DownloadDone
|
||||
SpeedLastTime += DeltaTime
|
||||
@@ -610,7 +610,7 @@ RequestFinished:
|
||||
''' <summary>
|
||||
''' 线程初始化时的时间。
|
||||
''' </summary>
|
||||
Public InitTime As Long = GetTimeTick()
|
||||
Public InitTime As Long = GetTimeMs()
|
||||
''' <summary>
|
||||
''' 上次接受到有效数据的时间,-1 表示尚未有有效数据。
|
||||
''' </summary>
|
||||
@@ -773,7 +773,7 @@ RequestFinished:
|
||||
''' <summary>
|
||||
''' 上次记速时的时间。
|
||||
''' </summary>
|
||||
Private SpeedLastTime As Long = GetTimeTick()
|
||||
Private SpeedLastTime As Long = GetTimeMs()
|
||||
''' <summary>
|
||||
''' 上次记速时的已下载大小。
|
||||
''' </summary>
|
||||
@@ -783,8 +783,8 @@ RequestFinished:
|
||||
''' </summary>
|
||||
Public ReadOnly Property Speed As Long
|
||||
Get
|
||||
If GetTimeTick() - SpeedLastTime > 200 Then
|
||||
Dim DeltaTime As Long = GetTimeTick() - SpeedLastTime
|
||||
If GetTimeMs() - SpeedLastTime > 200 Then
|
||||
Dim DeltaTime As Long = GetTimeMs() - SpeedLastTime
|
||||
_Speed = (DownloadDone - SpeedLastDone) / (DeltaTime / 1000)
|
||||
SpeedLastDone = DownloadDone
|
||||
SpeedLastTime += DeltaTime
|
||||
@@ -1079,7 +1079,7 @@ NotSupportRange:
|
||||
SyncLock NetTaskSpeedLimitLeftLock
|
||||
If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft -= RealDataCount
|
||||
End SyncLock
|
||||
Dim DeltaTime = GetTimeTick() - Th.LastReceiveTime
|
||||
Dim DeltaTime = GetTimeMs() - Th.LastReceiveTime
|
||||
If DeltaTime > 1000000 Then DeltaTime = 1 '避免时间刻反转导致出现极大值
|
||||
If RealDataCount > 0 Then
|
||||
'有数据
|
||||
@@ -1091,7 +1091,7 @@ NotSupportRange:
|
||||
End SyncLock
|
||||
SyncLock LockCount
|
||||
ConnectCount += 1
|
||||
ConnectTime += GetTimeTick() - Th.InitTime
|
||||
ConnectTime += GetTimeMs() - Th.InitTime
|
||||
End SyncLock
|
||||
End If
|
||||
SyncLock LockCount
|
||||
@@ -1113,7 +1113,7 @@ NotSupportRange:
|
||||
Th.Source.SingleThread Is Nothing Then '且并非单线程下载
|
||||
Throw New TimeoutException("由于速度过慢断开链接,下载 " & RealDataCount & " B,消耗 " & DeltaTime & " ms。")
|
||||
End If
|
||||
Th.LastReceiveTime = GetTimeTick()
|
||||
Th.LastReceiveTime = GetTimeMs()
|
||||
ElseIf Th.LastReceiveTime > 0 AndAlso DeltaTime > Timeout Then
|
||||
'无数据,且已超时
|
||||
Throw New TimeoutException("操作超时,无数据。")
|
||||
@@ -1346,6 +1346,7 @@ Retry:
|
||||
If State >= NetState.Finished Then Return
|
||||
If RaiseEx IsNot Nothing Then Ex.Add(RaiseEx)
|
||||
'凉凉
|
||||
Log($"[Download] {LocalName}:已失败,当前状态 {State}")
|
||||
State = NetState.Interrupted
|
||||
End SyncLock
|
||||
AbortInternal()
|
||||
@@ -1363,6 +1364,7 @@ Retry:
|
||||
'确认中断
|
||||
SyncLock LockState
|
||||
If State >= NetState.Finished Then Return
|
||||
Log($"[Download] {LocalName}:已中断,当前状态 {State}")
|
||||
State = NetState.Interrupted
|
||||
End SyncLock
|
||||
AbortInternal()
|
||||
@@ -1373,7 +1375,6 @@ Retry:
|
||||
SyncLock NetManager.LockRemain
|
||||
NetManager.FileRemain -= 1
|
||||
End SyncLock
|
||||
Log($"[Download] {LocalName}:已终止,当前状态 {State}")
|
||||
End Sub
|
||||
|
||||
'状态改变接口
|
||||
@@ -1584,14 +1585,8 @@ FinishExCatch:
|
||||
For Each File As NetFile In Files
|
||||
Dim Target As String = CheckExistingFile(FolderList, VersionFolders, File)
|
||||
If File.State >= NetState.WaitingToDownload Then Return '中断
|
||||
If Target Is Nothing Then
|
||||
'未找到相同文件
|
||||
SyncLock LockState
|
||||
File.State = NetState.WaitingToDownload
|
||||
File.IsCopy = False
|
||||
End SyncLock
|
||||
Else
|
||||
'已找到相同文件
|
||||
'已找到相同文件
|
||||
If Target IsNot Nothing Then
|
||||
File.IsCopy = True
|
||||
Dim RetryCount As Integer = 0
|
||||
Retry:
|
||||
@@ -1601,20 +1596,21 @@ Retry:
|
||||
CopyFile(Target, File.LocalPath)
|
||||
End If
|
||||
File.Finish(False)
|
||||
Continue For
|
||||
Catch ex As Exception
|
||||
RetryCount += 1
|
||||
Log(ex, $"复制已存在的文件失败,第 {RetryCount} 次重试({Target} → {File.LocalPath})")
|
||||
If RetryCount < 3 Then
|
||||
Thread.Sleep(200)
|
||||
Thread.Sleep(2000)
|
||||
GoTo Retry
|
||||
End If
|
||||
'失败,回退到下载
|
||||
SyncLock LockState
|
||||
File.State = NetState.WaitingToDownload
|
||||
File.IsCopy = False
|
||||
End SyncLock
|
||||
End Try
|
||||
End If
|
||||
'回退到下载
|
||||
SyncLock LockState
|
||||
File.State = NetState.WaitingToDownload
|
||||
File.IsCopy = False
|
||||
End SyncLock
|
||||
Next
|
||||
Catch ex As Exception
|
||||
OnFail(New List(Of Exception) From {New Exception("下载已存在文件查找失败", ex)})
|
||||
@@ -1639,6 +1635,7 @@ Retry:
|
||||
End If
|
||||
Dim Type = TypeIndexes.MaxOf(Function(kv) kv.Item2).FolderName.TrimStart("\"c)
|
||||
'根据类别进行查找
|
||||
Static Sizes As New SafeDictionary(Of String, Long)
|
||||
Select Case Type
|
||||
Case "assets\", "libraries\"
|
||||
'assets/libraries:查找 MC 文件夹下的相同路径
|
||||
@@ -1651,6 +1648,10 @@ Retry:
|
||||
For Each VersionFolder In VersionFolders
|
||||
For Each Candidate In Directory.GetFiles(VersionFolder,
|
||||
"*." & GetFileNameFromPath(File.LocalPath).AfterLast(".").ToLower, SearchOption.TopDirectoryOnly)
|
||||
'快速进行大小校验
|
||||
If Not Sizes.ContainsKey(Candidate) Then Sizes(Candidate) = New FileInfo(Candidate).Length
|
||||
If File.Check.ActualSize <> Sizes(Candidate) Then Continue For
|
||||
'Hash 校验
|
||||
If File.Check.Check(Candidate) Is Nothing Then Return Candidate
|
||||
Next
|
||||
Next
|
||||
@@ -1662,7 +1663,6 @@ Retry:
|
||||
If Not Directory.Exists(TargetFolder) Then Continue For
|
||||
For Each Candidate In Directory.GetFiles(TargetFolder)
|
||||
'快速进行大小校验
|
||||
Static Sizes As New SafeDictionary(Of String, Long)
|
||||
If Not Sizes.ContainsKey(Candidate) Then Sizes(Candidate) = New FileInfo(Candidate).Length
|
||||
If File.Check.ActualSize <> Sizes(Candidate) Then Continue For
|
||||
'Hash 校验
|
||||
@@ -1803,7 +1803,7 @@ Retry:
|
||||
''' </summary>
|
||||
Private Sub RefreshStat()
|
||||
Try
|
||||
Dim DeltaTime As Long = GetTimeTick() - RefreshStatLast
|
||||
Dim DeltaTime As Long = GetTimeMs() - RefreshStatLast
|
||||
If DeltaTime = 0 Then Return
|
||||
RefreshStatLast += DeltaTime
|
||||
#Region "刷新整体速度"
|
||||
@@ -1905,7 +1905,7 @@ Retry:
|
||||
RunInNewThread(
|
||||
Sub()
|
||||
Try
|
||||
Dim NextTick As Long = GetTimeTick()
|
||||
Dim NextTick As Long = GetTimeMs()
|
||||
While True
|
||||
'增加限速余量
|
||||
If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft = NetTaskSpeedLimitHigh / 10
|
||||
@@ -1913,11 +1913,11 @@ Retry:
|
||||
RefreshStat()
|
||||
'等待 100 ms
|
||||
NextTick += 100
|
||||
Dim SleepTime = NextTick - GetTimeTick()
|
||||
Dim SleepTime = NextTick - GetTimeMs()
|
||||
If SleepTime > 0 Then
|
||||
Thread.Sleep(SleepTime)
|
||||
Else
|
||||
NextTick = GetTimeTick() '超时,直接追帧,不等待
|
||||
NextTick = GetTimeMs() '超时,直接追帧,不等待
|
||||
End If
|
||||
End While
|
||||
Catch ex As Exception
|
||||
|
||||
@@ -72,7 +72,7 @@ Public Class MyBitmap
|
||||
End If
|
||||
Else
|
||||
'使用这种自己接管 FileStream 的方法加载才能解除文件占用
|
||||
Using InputStream As New FileStream(FilePathOrResourceName, FileMode.Open)
|
||||
Using InputStream As New FileStream(FilePathOrResourceName, FileMode.Open, FileAccess.Read, FileShare.Read)
|
||||
'判断是否为 WebP 文件头
|
||||
Dim Header(1) As Byte
|
||||
InputStream.Read(Header, 0, 2)
|
||||
|
||||
@@ -48,9 +48,9 @@
|
||||
|
||||
#Region "CompDatabase | Mod 数据库"
|
||||
|
||||
Private _CompDatabase As List(Of CompDatabaseEntry) = Nothing
|
||||
Private ReadOnly Property CompDatabase As List(Of CompDatabaseEntry)
|
||||
Get
|
||||
Static _CompDatabase As List(Of CompDatabaseEntry) = Nothing
|
||||
If _CompDatabase IsNot Nothing Then Return _CompDatabase
|
||||
'初始化数据库
|
||||
_CompDatabase = New List(Of CompDatabaseEntry)
|
||||
@@ -881,7 +881,7 @@ NoSubtitle:
|
||||
Case CompType.ResourcePack
|
||||
Address += "&classId=12"
|
||||
End Select
|
||||
Address += "&categoryId=" & If(Tag = "", "0", Tag.BeforeFirst("/"))
|
||||
If Tag <> "" Then Address += "&categoryId=" & Tag.BeforeFirst("/")
|
||||
If ModLoader <> CompModLoaderType.Any Then Address += "&modLoaderType=" & CType(ModLoader, Integer)
|
||||
If Not String.IsNullOrEmpty(GameVersion) Then Address += "&gameVersion=" & GameVersion
|
||||
If Not String.IsNullOrEmpty(SearchText) Then Address += "&searchFilter=" & Net.WebUtility.UrlEncode(SearchText)
|
||||
@@ -1355,6 +1355,10 @@ Retry:
|
||||
''' </summary>
|
||||
Public ReadOnly Hash As String = Nothing
|
||||
''' <summary>
|
||||
''' 文件大小。不可用时为 -1。
|
||||
''' </summary>
|
||||
Public ReadOnly Size As Integer = -1
|
||||
''' <summary>
|
||||
''' 该文件的所有依赖工程的原始 ID。
|
||||
''' 这些 ID 可能没有加载,在加载后会添加到 Dependencies 中(主要是因为 Modrinth 返回的是字符串 ID 而非 Slug,导致 Project.Id 查询不到)。
|
||||
''' </summary>
|
||||
@@ -1368,7 +1372,7 @@ Retry:
|
||||
''' </summary>
|
||||
''' <param name="LocalAddress">目标本地文件夹,或完整的文件路径。会自动判断类型。</param>
|
||||
Public Function ToNetFile(LocalAddress As String) As NetFile
|
||||
Return New NetFile(DownloadUrls, LocalAddress & If(LocalAddress.EndsWithF("\"), FileName, ""), New FileChecker(Hash:=Hash), SimulateBrowserHeaders:=True)
|
||||
Return New NetFile(DownloadUrls, LocalAddress & If(LocalAddress.EndsWithF("\"), FileName, ""), New FileChecker(Hash:=Hash, ActualSize:=Size), SimulateBrowserHeaders:=True)
|
||||
End Function
|
||||
|
||||
'实例化
|
||||
@@ -1390,6 +1394,7 @@ Retry:
|
||||
If Data.ContainsKey("FileName") Then FileName = Data("FileName").ToString
|
||||
If Data.ContainsKey("DownloadUrls") Then DownloadUrls = Data("DownloadUrls").ToObject(Of List(Of String))
|
||||
If Data.ContainsKey("ModLoaders") Then ModLoaders = Data("ModLoaders").ToObject(Of List(Of CompModLoaderType))
|
||||
If Data.ContainsKey("Size") Then Size = Data("Size").ToObject(Of Integer)
|
||||
If Data.ContainsKey("Hash") Then Hash = Data("Hash").ToString
|
||||
If Data.ContainsKey("GameVersions") Then GameVersions = Data("GameVersions").ToObject(Of List(Of String))
|
||||
If Data.ContainsKey("RawDependencies") Then RawDependencies = Data("RawDependencies").ToObject(Of List(Of String))
|
||||
@@ -1407,6 +1412,7 @@ Retry:
|
||||
Status = CType(Data("releaseType").ToObject(Of Integer), CompFileStatus)
|
||||
DownloadCount = Data("downloadCount")
|
||||
FileName = Data("fileName")
|
||||
Size = Data("fileLength")
|
||||
Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 1)?("value")
|
||||
If Hash Is Nothing Then Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 2)?("value")
|
||||
'DownloadAddress
|
||||
@@ -1453,6 +1459,7 @@ Retry:
|
||||
Dim File As JToken = Data("files")(0)
|
||||
FileName = File("filename")
|
||||
DownloadUrls = New List(Of String) From {File("url"), DlSourceModGet(File("url"))}.Distinct.ToList '同时添加了镜像源
|
||||
Size = File("size")
|
||||
Hash = File("hashes")("sha1")
|
||||
End If
|
||||
'ModLoaders
|
||||
@@ -1531,6 +1538,7 @@ Retry:
|
||||
If FileName IsNot Nothing Then Json.Add("FileName", FileName)
|
||||
If DownloadUrls IsNot Nothing Then Json.Add("DownloadUrls", New JArray(DownloadUrls))
|
||||
If Hash IsNot Nothing Then Json.Add("Hash", Hash)
|
||||
If Size >= 0 Then Json.Add("Size", Size)
|
||||
Json.Add("RawDependencies", New JArray(RawDependencies))
|
||||
Json.Add("Dependencies", New JArray(Dependencies))
|
||||
Return Json
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
Try
|
||||
Dim Info As New FileInfo(FilePath)
|
||||
If Info.Exists AndAlso Info.Length > 0 AndAlso Not FilePath.EndsWithF(".jar", True) Then
|
||||
ExtractFile(FilePath, TempFolder & "Temp\")
|
||||
ExtractCompressedFile(FilePath, TempFolder & "Temp\")
|
||||
Log("[Crash] 已解压导入的日志文件:" & FilePath)
|
||||
GoTo Extracted
|
||||
End If
|
||||
@@ -712,11 +712,11 @@ NextStack:
|
||||
Dim Word As String = Splited(i)
|
||||
If Word.Length <= 2 OrElse Word.StartsWithF("func_") Then Continue For
|
||||
If {"com", "org", "net", "asm", "fml", "mod", "jar", "sun", "lib", "map", "gui", "dev", "nio", "api", "dsi", "top", "mcp",
|
||||
"core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base", "oshi", "impl", "data", "pool", "task",
|
||||
"forge", "setup", "block", "model", "mixin", "event", "unimi", "netty", "world", "lwjgl",
|
||||
"gitlab", "common", "server", "config", "mixins", "compat", "loader", "launch", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events",
|
||||
"preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content", "systems", "modules", "service",
|
||||
"fastutil", "optifine", "internal", "platform", "override", "fabricmc", "neoforge",
|
||||
"core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base", "fake", "oshi", "impl", "data", "pool", "task",
|
||||
"forge", "setup", "block", "model", "mixin", "event", "unimi", "netty", "world", "lwjgl", "fakes",
|
||||
"gitlab", "common", "server", "config", "mixins", "compat", "loader", "launch", "script", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events",
|
||||
"preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content", "systems", "modules", "service", "scripts", "network",
|
||||
"fastutil", "optifine", "internal", "platform", "override", "fabricmc", "neoforge", "external",
|
||||
"injection", "listeners", "scheduler", "minecraft", "universal", "multipart", "neoforged", "microsoft",
|
||||
"transformer", "transformers", "minecraftforge", "blockentity", "spongepowered", "electronwill", "concurrent"
|
||||
}.Contains(Word.ToLower) Then Continue For
|
||||
|
||||
@@ -222,14 +222,14 @@
|
||||
''' </summary>
|
||||
Public DlClientListMojangLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Mojang", AddressOf DlClientListMojangMain)
|
||||
Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult))
|
||||
Dim StartTime As Long = GetTimeTick()
|
||||
Dim StartTime As Long = GetTimeMs()
|
||||
Dim Json As JObject = GetJson(NetRequestByClientRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json", RequireJson:=True))
|
||||
Try
|
||||
Dim Versions As JArray = Json("versions")
|
||||
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
|
||||
'确定官方源是否可用
|
||||
If Not DlPreferMojang Then
|
||||
Dim DeltaTime = GetTimeTick() - StartTime
|
||||
Dim DeltaTime = GetTimeMs() - StartTime
|
||||
DlPreferMojang = DeltaTime < 4000
|
||||
Log($"[Download] Mojang 官方源加载耗时:{DeltaTime}ms,{If(DlPreferMojang, "可优先使用官方源", "不优先使用官方源")}")
|
||||
End If
|
||||
@@ -844,7 +844,7 @@
|
||||
Public Sub New(ApiName As String)
|
||||
IsNeoForge = True
|
||||
Me.ApiName = ApiName
|
||||
IsBeta = ApiName.Contains("beta") OrElse ApiName.Contains("alpha")
|
||||
IsBeta = ApiName.ContainsF("beta", True) OrElse ApiName.ContainsF("alpha", True)
|
||||
If ApiName.Contains("1.20.1") Then '1.20.1-47.1.99
|
||||
VersionName = ApiName.Replace("1.20.1-", "")
|
||||
Version = New Version("19." & VersionName)
|
||||
|
||||
@@ -465,9 +465,10 @@ NoUserJava:
|
||||
If Not Left.IsJre AndAlso Right.IsJre Then Return False
|
||||
'4. Java 大版本
|
||||
If Left.MajorVersion <> Right.MajorVersion Then
|
||||
' Java 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23...
|
||||
Dim Weight = {0, 1, 2, 3, 4, 5, 6, 14, 30, 10, 12, 15, 13, 9, 8, 7, 11, 31, 29, 16, 17, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18}
|
||||
Return Weight.ElementAtOrDefault(Left.MajorVersion) >= Weight.ElementAtOrDefault(Right.MajorVersion)
|
||||
' Java 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
||||
Dim Weight = {0, 1, 2, 3, 4, 5, 6, 14, 30, 10, 12, 15, 13, 9, 8, 7, 11, 31, 29, 16, 17} '更高的版本指定为 20,且越低越好
|
||||
Return If(Left.MajorVersion > 20, 20 - Left.MajorVersion * 0.0001, Weight.ElementAtOrDefault(Left.MajorVersion)) >=
|
||||
If(Right.MajorVersion > 20, 20 - Right.MajorVersion * 0.0001, Weight.ElementAtOrDefault(Right.MajorVersion))
|
||||
End If
|
||||
'5. 最次级版本号更接近 51
|
||||
Return Math.Abs(Left.Version.Revision - 51) <= Math.Abs(Right.Version.Revision - 51)
|
||||
|
||||
@@ -544,7 +544,7 @@ NextInner:
|
||||
'检查是否已经登录完成
|
||||
If Not Data.IsForceRestarting AndAlso '不要求强行重启
|
||||
Input.AccessToken <> "" AndAlso '已经登录过了
|
||||
(McLoginMsRefreshTime > 0 AndAlso GetTimeTick() - McLoginMsRefreshTime < 1000 * 60 * 10) Then '完成时间在 10 分钟内
|
||||
(McLoginMsRefreshTime > 0 AndAlso GetTimeMs() - McLoginMsRefreshTime < 1000 * 60 * 10) Then '完成时间在 10 分钟内
|
||||
Data.Output = New McLoginResult With
|
||||
{.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid, .ProfileJson = Input.ProfileJson}
|
||||
GoTo SkipLogin
|
||||
@@ -591,7 +591,7 @@ Relogin:
|
||||
Setup.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None))
|
||||
Data.Output = New McLoginResult With {.AccessToken = AccessToken, .Name = Result(1), .Uuid = Result(0), .Type = "Microsoft", .ClientToken = Result(0), .ProfileJson = Result(2)}
|
||||
'结束
|
||||
McLoginMsRefreshTime = GetTimeTick()
|
||||
McLoginMsRefreshTime = GetTimeMs()
|
||||
McLaunchLog("微软登录完成")
|
||||
SkipLogin:
|
||||
Setup.Set("HintBuy", True) '关闭正版购买提示
|
||||
@@ -1771,7 +1771,7 @@ NextInstance:
|
||||
If Not Native.IsNatives Then Continue For
|
||||
Dim Zip As ZipArchive
|
||||
Try
|
||||
Zip = New ZipArchive(New FileStream(Native.LocalPath, FileMode.Open))
|
||||
Zip = New ZipArchive(New FileStream(Native.LocalPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
Catch ex As InvalidDataException
|
||||
Log(ex, "打开 Natives 文件失败(" & Native.LocalPath & ")")
|
||||
File.Delete(Native.LocalPath)
|
||||
|
||||
@@ -426,8 +426,8 @@ Public Module ModMinecraft
|
||||
End Try
|
||||
#End Region
|
||||
VersionSearchFinish:
|
||||
_Version.VanillaName = _Version.VanillaName.Replace("_unobfuscated", "").Replace(" Unobfuscated", "")
|
||||
'获取版本号
|
||||
_Version.VanillaName = _Version.VanillaName.Replace("_unobfuscated", "").Replace(" Unobfuscated", "")
|
||||
If _Version.VanillaName.StartsWithF("1.") Then
|
||||
Dim Segments = _Version.VanillaName.Split(" _-.".ToCharArray)
|
||||
_Version.Vanilla = New Version(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Imports System.IO.Compression
|
||||
|
||||
Public Module ModMod
|
||||
Private Const LocalModCacheVersion As Integer = 10
|
||||
Private Const LocalModCacheVersion As Integer = 11
|
||||
|
||||
Public Class McMod
|
||||
|
||||
@@ -137,7 +137,7 @@ Public Module ModMod
|
||||
'基础可用性检查、打开 Jar 文件
|
||||
If Path.Length < 2 Then Throw New FileNotFoundException("错误的 Mod 文件路径(" & If(Path, "null") & ")")
|
||||
If Not File.Exists(Path) Then Throw New FileNotFoundException("未找到 Mod 文件(" & Path & ")")
|
||||
Jar = New ZipArchive(New FileStream(Path, FileMode.Open))
|
||||
Jar = New ZipArchive(New FileStream(Path, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
'信息获取
|
||||
LoadMetadataFromJar(Jar)
|
||||
Catch ex As UnauthorizedAccessException
|
||||
@@ -424,7 +424,7 @@ Finished:
|
||||
''' </summary>
|
||||
Public ReadOnly Property CanUpdate As Boolean
|
||||
Get
|
||||
Return Not Setup.Get("UiHiddenFunctionModUpdate") AndAlso Not Setup.Get("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance) AndAlso ChangelogUrls.Any()
|
||||
Return Not Setup.Get("UiHiddenFunctionModUpdate") AndAlso Not Setup.Get("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance) AndAlso UpdateFile IsNot Nothing
|
||||
End Get
|
||||
End Property
|
||||
|
||||
@@ -604,7 +604,7 @@ Finished:
|
||||
For Each ModFile As FileInfo In ModFileList
|
||||
If Loader.IsAborted Then Return
|
||||
Dim ModEntry As New McMod(ModFile.FullName)
|
||||
Dim DumpMod As McMod = ModList.FirstOrDefault(Function(m) m.RawFileName = ModEntry.RawFileName)
|
||||
Dim DumpMod As McMod = ModList.FirstOrDefault(Function(m) m.RawFileName = ModEntry.RawFileName) '存在两个文件,名称相同,但一个启用一个禁用
|
||||
If DumpMod IsNot Nothing Then
|
||||
Dim DisabledMod As McMod = If(DumpMod.State = McMod.McModState.Disabled, DumpMod, ModEntry)
|
||||
Log($"[Mod] 重复的 Mod 文件:{DumpMod.FileName} 与 {ModEntry.FileName},已忽略 {DisabledMod.FileName}", LogLevel.Debug)
|
||||
@@ -619,10 +619,7 @@ Finished:
|
||||
Log($"[Mod] 共发现 {ModList.Count} 个 Mod")
|
||||
|
||||
'排序
|
||||
ModList = ModList.SortByComparison(
|
||||
Function(Left, Right) As Boolean
|
||||
Return Not Right.FileName.CompareTo(Left.FileName)
|
||||
End Function)
|
||||
ModList = ModList.OrderBy(Function(m) m.FileName).ToList
|
||||
|
||||
'回设
|
||||
If Loader.IsAborted Then Return
|
||||
|
||||
@@ -112,19 +112,14 @@ Public Module ModModpack
|
||||
Private Sub ExtractModpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase, ProgressIncrement As Double)
|
||||
'解压文件
|
||||
Dim RetryCount As Integer = 1
|
||||
Dim Encode = Encoding.GetEncoding("GB18030")
|
||||
Dim InitialProgress = Loader.Progress
|
||||
Try
|
||||
Retry:
|
||||
Loader.Progress = InitialProgress
|
||||
DeleteDirectory(InstallTemp)
|
||||
ExtractFile(FileAddress, InstallTemp, Encode, ProgressIncrementHandler:=Sub(Delta) Loader.Progress += Delta * ProgressIncrement)
|
||||
ExtractCompressedFile(FileAddress, InstallTemp, ProgressIncrementHandler:=Sub(Delta) Loader.Progress += Delta * ProgressIncrement)
|
||||
Catch ex As Exception
|
||||
Log(ex, "第 " & RetryCount & " 次解压尝试失败")
|
||||
If TypeOf ex Is ArgumentException Then
|
||||
Encode = Encoding.UTF8
|
||||
Log("[ModPack] 已切换压缩包解压编码为 UTF8")
|
||||
End If
|
||||
'完全不知道为啥会出现文件正在被另一进程使用的问题,总之加个重试
|
||||
If RetryCount < 5 Then
|
||||
Thread.Sleep(RetryCount * 2000)
|
||||
|
||||
@@ -647,7 +647,7 @@ NextFile:
|
||||
DeleteDirectory(PathTemp & "Help")
|
||||
Directory.CreateDirectory(PathTemp & "Help")
|
||||
WriteFile(PathTemp & "Cache\Help.zip", GetResources("Help"))
|
||||
ExtractFile(PathTemp & "Cache\Help.zip", PathTemp & "Help", Encoding.UTF8)
|
||||
ExtractCompressedFile(PathTemp & "Cache\Help.zip", PathTemp & "Help")
|
||||
Setup.Set("SystemHelpVersion", VersionCode)
|
||||
Log("[Help] 已解压内置帮助文件,目前状态:" & File.Exists(PathTemp & "Help\启动器\备份设置.xaml"), LogLevel.Debug)
|
||||
End If
|
||||
|
||||
Reference in New Issue
Block a user