From 52b4c87fbc16dfa8ea9462c1f549a91e69f15221 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BE=99=E8=85=BE=E7=8C=AB=E8=B7=83?= <1043137532@qq.com>
Date: Thu, 15 Jan 2026 03:20:43 +0800
Subject: [PATCH] 2.12.2
---
Plain Craft Launcher 2/Application.xaml.vb | 10 +-
Plain Craft Launcher 2/FormMain.xaml.vb | 25 +-
.../Modules/Base/ModAnimation.vb | 10 +-
.../Modules/Base/ModBase.vb | 69 +-
.../Modules/Base/ModLoader.vb | 4 +-
Plain Craft Launcher 2/Modules/Base/ModNet.vb | 64 +-
.../Modules/Base/MyBitmap.vb | 2 +-
.../Modules/Minecraft/ModComp.vb | 14 +-
.../Modules/Minecraft/ModCrash.vb | 12 +-
.../Modules/Minecraft/ModDownload.vb | 6 +-
.../Modules/Minecraft/ModJava.vb | 7 +-
.../Modules/Minecraft/ModLaunch.vb | 6 +-
.../Modules/Minecraft/ModMinecraft.vb | 2 +-
.../Modules/Minecraft/ModMod.vb | 13 +-
.../Modules/Minecraft/ModModpack.vb | 7 +-
Plain Craft Launcher 2/Modules/ModMain.vb | 2 +-
.../My Project/AssemblyInfo.vb | 4 +-
.../Pages/PageDownload/ModDownloadLib.vb | 8 +-
.../PageInstance/PageInstanceExport.xaml | 10 +-
.../PageInstance/PageInstanceExport.xaml.vb | 2 +-
.../PageInstance/PageInstanceMod.xaml.vb | 27 +-
.../Pages/PageLaunch/MySkin.xaml.vb | 28 +-
.../Pages/PageLink/PageLinkMain.xaml.vb | 2 +-
.../Pages/PageOther/PageOtherAbout.xaml | 2408 +++--------------
24 files changed, 530 insertions(+), 2212 deletions(-)
diff --git a/Plain Craft Launcher 2/Application.xaml.vb b/Plain Craft Launcher 2/Application.xaml.vb
index e595d11..e2540b0 100644
--- a/Plain Craft Launcher 2/Application.xaml.vb
+++ b/Plain Craft Launcher 2/Application.xaml.vb
@@ -145,8 +145,8 @@ WaitRetry:
Setup.Load("ToolDownloadCert")
Setup.Load("ToolDownloadSpeed")
'计时
- Log("[Start] 第一阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
- ApplicationStartTick = GetTimeTick()
+ Log("[Start] 第一阶段加载用时:" & GetTimeMs() - ApplicationStartTick & " ms")
+ ApplicationStartTick = GetTimeMs()
'执行测试
#If DEBUG Then
Test()
@@ -213,7 +213,11 @@ WaitRetry:
'WebP 特判
If Prefix = "Imazen.WebP" Then
SetDllDirectory(PathPure.TrimEnd("\"c))
- WriteFile(PathPure & "libwebp.dll", GetResources("libwebp64"))
+ Try
+ WriteFile(PathPure & "libwebp.dll", GetResources("libwebp64"))
+ Catch ex As Exception
+ Log(ex, "写入 libwebp.dll 失败") '防止同时加载多个图片时,同时写入文件导致文件占用,进而导致崩溃
+ End Try
End If
End If
Return LoadedAssembly(Prefix)
diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb
index 69ff16e..05cd5fc 100644
--- a/Plain Craft Launcher 2/FormMain.xaml.vb
+++ b/Plain Craft Launcher 2/FormMain.xaml.vb
@@ -11,8 +11,18 @@ Public Class FormMain
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
'统计更新日志条目
#If BETA Then
+ If LastVersion < 379 Then 'Release 2.12.1
+ If LastVersion >= 376 Then
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "删除:暂时隐藏联机入口……不过只是暂时关闭,它还会回来的!"))
+ End If
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:适配新的 Minecraft 版本号系统与 Unobfuscated 版本"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:巨幅优化各个下载页面和 Mod 管理页面的性能"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:更换披风时会显示当前使用的披风"))
+ FeatureCount += 33
+ BugCount += 29
+ End If
If LastVersion < 376 Then 'Release 2.11.2
- FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:联机功能!"))
+ 'FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:联机功能!"))
FeatureCount += 32
BugCount += 21
End If
@@ -118,6 +128,11 @@ Public Class FormMain
'3:BUG+ IMP* FEAT-
'2:BUG* IMP-
'1:BUG-
+ If LastVersion < 380 Then 'Snapshot 2.12.2
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法搜索 CurseForge 上的社区资源"))
+ FeatureCount += 3
+ BugCount += 13
+ End If
If LastVersion < 378 Then 'Snapshot 2.12.1
If LastVersion >= 377 Then
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:在版本列表中存在 OptiFine 时可能无法加载版本列表"))
@@ -323,7 +338,7 @@ Public Class FormMain
'窗口加载
Private IsWindowLoadFinished As Boolean = False
Public Sub New()
- ApplicationStartTick = GetTimeTick()
+ ApplicationStartTick = GetTimeMs()
'窗体参数初始化
FrmMain = Me
FrmLaunchLeft = New PageLaunchLeft
@@ -387,10 +402,10 @@ Public Class FormMain
'尽早执行的加载池
McFolderListLoader.Start(0) '为了让下载已存在文件检测可以正常运行,必须跑一次;为了让启动按钮尽快可用,需要尽早执行;为了与 PageLaunchLeft 联动,需要为 0 而不是 GetUuid
- Log("[Start] 第二阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
+ Log("[Start] 第二阶段加载用时:" & GetTimeMs() - ApplicationStartTick & " ms")
End Sub
Private Sub FormMain_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
- ApplicationStartTick = GetTimeTick()
+ ApplicationStartTick = GetTimeMs()
Handle = New Interop.WindowInteropHelper(Me).Handle
'读取设置
Setup.Load("UiBackgroundOpacity")
@@ -496,7 +511,7 @@ Public Class FormMain
Telemetry("启动")
End Sub, "初始化", ThreadPriority.Lowest)
- Log("[Start] 第三阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
+ Log("[Start] 第三阶段加载用时:" & GetTimeMs() - ApplicationStartTick & " ms")
End Sub
'根据打开次数触发的事件
Private Sub RunCountSub()
diff --git a/Plain Craft Launcher 2/Modules/Base/ModAnimation.vb b/Plain Craft Launcher 2/Modules/Base/ModAnimation.vb
index 4761708..a1fb5cd 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModAnimation.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModAnimation.vb
@@ -743,9 +743,9 @@ Public Module ModAnimation
''' 由 Aa 开头的函数初始化的 AniData 对象集合。
''' 动画组的名称。如果重复会直接停止同名动画组。
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
'''
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
diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb
index c01d6ac..1e8106d 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModBase.vb
@@ -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
'''
''' 程序的打开计时。
'''
- Public ApplicationStartTick As Long = GetTimeTick()
+ Public ApplicationStartTick As Long = GetTimeMs()
'''
''' 程序打开时的时间。
'''
@@ -1284,27 +1284,31 @@ Re:
'''
''' 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 jar 以 zip 方式解压。
''' 会尝试创建,但不会清空目标文件夹。
+ ''' 会先使用 UTF-8 解压,失败后换用 GB18030 解压。
'''
- 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
'''
@@ -1609,6 +1623,7 @@ RetryDir:
End Function
'''
''' 分割字符串。
+ ''' 若原始字符串为空,则返回 {""}。
'''
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
'''
- ''' 获取系统运行时间(毫秒),保证为正 Long 且大于 1,但可能突变减小。
+ ''' 获取一个单调递增时间值(毫秒)。
'''
- Public Function GetTimeTick() As Long
- Return My.Computer.Clock.TickCount + 2147483651L
+ Public Function GetTimeMs() As Long
+ Return Stopwatch.GetTimestamp() \ (Stopwatch.Frequency \ 1000L)
End Function
'''
''' 将时间间隔转换为类似“5 分 10 秒前”的易于阅读的形式。
diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
index 75b8b4f..0071a62 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
@@ -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
diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb
index b371126..dbfac3a 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModNet.vb
@@ -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:
'''
''' 上次记速时的时间。
'''
- Private SpeedLastTime As Long = GetTimeTick()
+ Private SpeedLastTime As Long = GetTimeMs()
'''
''' 上次记速时的已下载大小。
'''
@@ -596,8 +596,8 @@ RequestFinished:
'''
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:
'''
''' 线程初始化时的时间。
'''
- Public InitTime As Long = GetTimeTick()
+ Public InitTime As Long = GetTimeMs()
'''
''' 上次接受到有效数据的时间,-1 表示尚未有有效数据。
'''
@@ -773,7 +773,7 @@ RequestFinished:
'''
''' 上次记速时的时间。
'''
- Private SpeedLastTime As Long = GetTimeTick()
+ Private SpeedLastTime As Long = GetTimeMs()
'''
''' 上次记速时的已下载大小。
'''
@@ -783,8 +783,8 @@ RequestFinished:
'''
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:
'''
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
diff --git a/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb b/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb
index bc36a53..dce0cce 100644
--- a/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb
+++ b/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb
@@ -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)
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
index de9d868..42a29d2 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
@@ -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:
'''
Public ReadOnly Hash As String = Nothing
'''
+ ''' 文件大小。不可用时为 -1。
+ '''
+ Public ReadOnly Size As Integer = -1
+ '''
''' 该文件的所有依赖工程的原始 ID。
''' 这些 ID 可能没有加载,在加载后会添加到 Dependencies 中(主要是因为 Modrinth 返回的是字符串 ID 而非 Slug,导致 Project.Id 查询不到)。
'''
@@ -1368,7 +1372,7 @@ Retry:
'''
''' 目标本地文件夹,或完整的文件路径。会自动判断类型。
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
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
index 69e3d8d..45f9fdd 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
@@ -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
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
index 283a731..30c7569 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
@@ -222,14 +222,14 @@
'''
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)
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
index 48ad2e1..3a49edc 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
@@ -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)
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
index 58654a4..5b7b43f 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
@@ -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)
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
index 6169c57..a0ea8b1 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
@@ -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(
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
index e308dd0..c96a843 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
@@ -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:
'''
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
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
index d391786..1cc3e3b 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
@@ -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)
diff --git a/Plain Craft Launcher 2/Modules/ModMain.vb b/Plain Craft Launcher 2/Modules/ModMain.vb
index 4ef49d2..b966537 100644
--- a/Plain Craft Launcher 2/Modules/ModMain.vb
+++ b/Plain Craft Launcher 2/Modules/ModMain.vb
@@ -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
diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb
index 1bb4bd3..0392544 100644
--- a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb
+++ b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*”
-
-
+
+
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
index c9820c9..89d4a62 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
@@ -1329,7 +1329,7 @@ Retry:
Dim Installer As ZipArchive = Nothing
Try
'解压并获取、合并两个 Json 的信息
- Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
+ Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open, FileAccess.Read, FileShare.Read))
Task.Progress = 0.2
Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
Dim Json2 As JObject = GetJson(ReadFile(Installer.GetEntry("version.json").Open))
@@ -1417,7 +1417,7 @@ Retry:
'记录当前文件夹列表(在新建目标文件夹之前)
Dim OldList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.Select(Function(i) i.FullName).ToList()
'解压并获取信息
- Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
+ Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open, FileAccess.Read, FileShare.Read))
Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
'新建目标版本文件夹
Directory.CreateDirectory(VersionFolder)
@@ -1484,7 +1484,7 @@ Retry:
Dim Installer As ZipArchive = Nothing
Try
'解压并获取信息
- Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
+ Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open, FileAccess.Read, FileShare.Read))
Task.Progress = 0.2
Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
Task.Progress = 0.4
@@ -1501,7 +1501,7 @@ Retry:
Task.Progress = 0.6
'解压支持库文件
Installer.Dispose()
- ExtractFile(InstallerAddress, InstallerAddress & "_unrar\")
+ ExtractCompressedFile(InstallerAddress, InstallerAddress & "_unrar\")
CopyDirectory(InstallerAddress & "_unrar\maven\", McFolder & "libraries\")
DeleteDirectory(InstallerAddress & "_unrar\")
Else
diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml
index ae32c51..badc9c3 100644
--- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml
+++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml
@@ -94,7 +94,7 @@
@@ -114,6 +114,14 @@
DefaultChecked="True" />
+
+
+
+
+
''' 已加载的 Mod UI 缓存,不确保按显示顺序排列。Key 为 Mod 的 RawFileName。
'''
- Public ModItems As New Dictionary(Of String, MyLocalModItem)
+ Public ModItems As New SafeDictionary(Of String, MyLocalModItem)
'''
''' 将加载器结果的 Mod 列表加载为 UI。
'''
@@ -87,10 +87,12 @@
Return
End If
'修改缓存
- ModItems.Clear()
- For Each ModEntity As McMod In McModLoader.Output
- ModItems(ModEntity.RawFileName) = McModListItem(ModEntity)
- Next
+ SyncLock ModItems.SyncRoot
+ ModItems.Clear()
+ For Each ModEntity As McMod In McModLoader.Output
+ ModItems(ModEntity.RawFileName) = McModListItem(ModEntity)
+ Next
+ End SyncLock
'显示结果
Filter = FilterType.All
SearchBox.Text = "" '这会触发结果刷新,所以需要在 ModItems 更新之后,详见 #3124 的视频
@@ -151,11 +153,13 @@
If ShowingMods.Any() Then
PanList.Visibility = Visibility.Visible
PanList.Children.Clear()
- For Each TargetMod In ShowingMods
- Dim Item As MyLocalModItem = ModItems(TargetMod.RawFileName)
- Item.Checked = SelectedMods.Contains(TargetMod.RawFileName) '更新选中状态
- PanList.Children.Add(Item)
- Next
+ SyncLock ModItems.SyncRoot
+ For Each TargetMod In ShowingMods
+ Dim Item As MyLocalModItem = ModItems(TargetMod.RawFileName)
+ Item.Checked = SelectedMods.Contains(TargetMod.RawFileName) '更新选中状态
+ PanList.Children.Add(Item)
+ Next
+ End SyncLock
Else
PanList.Visibility = Visibility.Collapsed
End If
@@ -528,6 +532,7 @@ Install:
If IndexOfUi = -1 Then Continue For '因为未知原因 Mod 的状态已经切换完了
PanList.Children.RemoveAt(IndexOfUi)
PanList.Children.Insert(IndexOfUi, NewItem)
+ NewItem.UpdateLayout() '#7861
Next
If IsSuccessful Then
RefreshBars()
@@ -591,7 +596,7 @@ Install:
NewestReplaceName = Join(NewestSegs, "-")
End If
'添加到下载列表
- Dim TempAddress As String = PathTemp & "DownloadedMods\" & Entry.FileName.Replace(CurrentReplaceName, NewestReplaceName)
+ Dim TempAddress As String = PathTemp & "mods\" & Entry.FileName.Replace(CurrentReplaceName, NewestReplaceName) '需要下载到 mods 文件夹,以便重复文件检查时识别
Dim RealAddress As String = GetPathFromFullPath(Entry.Path) & Entry.FileName.Replace(CurrentReplaceName, NewestReplaceName)
FileList.Add(File.ToNetFile(TempAddress))
FileCopyList(TempAddress) = RealAddress
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
index 4c4b4bc..e72c29f 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
@@ -232,9 +232,7 @@ Retry:
Dim Uuid As String = McLoginMsLoader.Output.Uuid
Dim SkinData As JObject = GetJson(McLoginMsLoader.Output.ProfileJson)
'获取玩家的所有披风
- Dim SelId As Integer? = Nothing
- '获取玩家当前的披风
- Dim CurId As Integer? = Nothing
+ Dim SelectedIndex As Integer? = Nothing
RunInUiWait(
Sub()
Try
@@ -248,25 +246,23 @@ Retry:
{"Mojang Office", "Mojang 办公室披风"}, {"Home", "家园披风"}, {"Menace", "入侵披风"}, {"Yearn", "渴望披风"},
{"Common", "普通披风"}, {"Pan", "薄煎饼披风"}, {"Founder's", "创始人披风"}, {"Copper", "铜披风"}, {"Zombie Horse", "僵尸马披风"}
}
- Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}}
- Dim Id As Integer = 0
+ Dim SelectionControl As New List(Of IMyRadio) From {
+ New MyRadioBox With {.Text = "无披风", .Checked = Not SkinData("capes").Any(Function(c) c("state")?.ToString = "ACTIVE")}}
For Each Cape In SkinData("capes")
- Id += 1
Dim CapeName As String = Cape("alias").ToString
If CapeNames.ContainsKey(CapeName) Then CapeName = CapeNames(CapeName)
- If Cape("state")?.ToString = "ACTIVE" Then CurId = Id
SelectionControl.Add(New MyRadioBox With {.Text = CapeName, .Checked = Cape("state")?.ToString = "ACTIVE"})
Next
- SelId = MyMsgBoxSelect(SelectionControl, "选择披风", "确定", "取消")
+ SelectedIndex = MyMsgBoxSelect(SelectionControl, "选择披风", "确定", "取消")
Catch ex As Exception
Log(ex, "获取玩家皮肤列表失败", LogLevel.Feedback)
End Try
End Sub)
- If SelId Is Nothing Then Return
+ If SelectedIndex Is Nothing Then Return
'发送请求
Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/capes/active",
- If(SelId = 0, HttpMethod.Delete, HttpMethod.Put),
- Content:=If(SelId = 0, "", New JObject(New JProperty("capeId", SkinData("capes")(SelId - 1)("id"))).ToString(0)),
+ If(SelectedIndex = 0, HttpMethod.Delete, HttpMethod.Put),
+ Content:=If(SelectedIndex = 0, "", New JObject(New JProperty("capeId", SkinData("capes")(SelectedIndex - 1)("id"))).ToString(0)),
ContentType:="application/json",
Headers:={{"Authorization", "Bearer " & AccessToken}})
If Result.Contains("""errorMessage""") Then
@@ -274,11 +270,11 @@ Retry:
Return
Else
Hint("更改披风成功!", HintType.Green)
- '#7894,更换披风后需更新当前选择的披风
- SkinData("capes")(SelId - 1)("state") = "ACTIVE"
- If CurId IsNot Nothing Then
- SkinData("capes")(CurId - 1)("state") = "INACTIVE"
- End If
+ '更新当前选择的披风
+ For Each Cape In SkinData("capes")
+ Cape("state") = "INACTIVE"
+ Next
+ If SelectedIndex > 0 Then SkinData("capes")(SelectedIndex - 1)("state") = "ACTIVE"
McLoginMsLoader.Output.ProfileJson = SkinData.ToString()
End If
Catch ex As Exception
diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb b/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb
index 8a7b1e4..4a3dcff 100644
--- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb
@@ -484,7 +484,7 @@ Public Class PageLinkMain
If File.Exists(PathEasyTier & "EasyTier.zip") Then
'解压
Dim ExtractPath As String = RequestTaskTempFolder()
- ExtractFile(PathEasyTier & "EasyTier.zip", ExtractPath,
+ ExtractCompressedFile(PathEasyTier & "EasyTier.zip", ExtractPath,
ProgressIncrementHandler:=Sub(Progress) Task.Progress += Progress * 0.05)
Dim ExtractedPath As String = New DirectoryInfo(ExtractPath).EnumerateDirectories.FirstOrDefault?.FullName
Log("[Link] 联机模块解压时的临时路径:" & ExtractedPath)
diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
index 2d7edce..fabadba 100644
--- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
+++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
@@ -118,124 +118,24 @@
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -249,584 +149,87 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -843,6 +246,7 @@
+
@@ -876,6 +280,7 @@
+
@@ -889,450 +294,129 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -1351,6 +435,7 @@
+
@@ -1378,528 +463,149 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
@@ -1923,6 +629,7 @@
+
@@ -1940,296 +647,111 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -2252,279 +774,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -2534,101 +866,43 @@
-
+
+
+
+
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+