diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index fa9c3a7..bf88c42 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -36,6 +36,13 @@ jobs:
(gc "Plain Craft Launcher 2\Modules\ModSecret.vb") -replace 'Public Const OAuthClientId As String = ""', 'Public Const OAuthClientId As String = "${{ secrets.CLIENT_ID }}"' | Out-File "Plain Craft Launcher 2\Modules\ModSecret.vb"
(gc "Plain Craft Launcher 2\Modules\ModSecret.vb") -replace 'Public Const CurseForgeAPIKey As String = ""', 'Public Const CurseForgeAPIKey As String = "${{ secrets.CURSEFORGE_API_KEY }}"' | Out-File "Plain Craft Launcher 2\Modules\ModSecret.vb"
(gc "Plain Craft Launcher 2\Modules\Base\ModBase.vb") -replace 'Public Const CommitHash As String = ""', 'Public Const CommitHash As String = "${{ github.sha }}"' | Out-File "Plain Craft Launcher 2\Modules\Base\ModBase.vb"
+ rm "Plain Craft Launcher 2\Resources\Help.zip"
+ aria2c "--out=Plain Craft Launcher 2\Resources\Help.zip" "https://codeload.github.com/LTCatt/PCL2Help/zip/refs/heads/master"
+ 7z x "Plain Craft Launcher 2\Resources\Help.zip" -o"Plain Craft Launcher 2\Resources"
+ rm "Plain Craft Launcher 2\Resources\Help.zip"
+ rm "Plain Craft Launcher 2\Resources\PCL2Help-master\*.*"
+ 7z a "Plain Craft Launcher 2\Resources\Help.zip" ".\Plain Craft Launcher 2\Resources\PCL2Help-master\*"
+ rm "Plain Craft Launcher 2\Resources\PCL2Help-master\" -Recurse
- name: Build
run: msbuild "Plain Craft Launcher 2\Plain Craft Launcher 2.vbproj" -p:Configuration=${{ matrix.configuration }}
- name: Upload a Build Artifact
diff --git a/.github/workflows/issue_similarity.yml b/.github/workflows/issue_similarity.yml
deleted file mode 100644
index 49735c5..0000000
--- a/.github/workflows/issue_similarity.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-name: Issues Similarity Analysis
-
-on:
- issues:
- types: [opened, edited]
-
-jobs:
- similarity-analysis:
- runs-on: ubuntu-latest
- steps:
- - name: Issues Similarity Analysis
- uses: actions-cool/issues-similarity-analysis@v1.3.2
- with:
- filter-threshold: 0.75
- comment-title: '### 反馈重复性检测 | Issues Similarity Analysis'
- comment-body: '${index}. ${similarity} #${number}'
- show-footer: false
- show-mentioned: true
- since-days: 730
diff --git a/LICENCE b/LICENCE
index 47848b2..2336a98 100644
--- a/LICENCE
+++ b/LICENCE
@@ -2,24 +2,25 @@
一、承诺与声明。
- 开发者承诺,在您遵守本指南的情况下,不会追究您的责任,但最终裁量权仍由开发者保留。
+ 开发者承诺,在您遵守本指南且善意使用的情况下,不会追究您的责任,但最终裁量权仍由开发者保留。
法律上,开发者仍保留所有权利(All Rights Reserved),且可能随时修改本指南,本指南并不是永久性保证。
二、少量使用情形。
如果您仅合理使用本存储库中的少量内容,或是参考实现思路,您必须:
- 1、给出适当的署名,且提供指向本存储库的链接。
+ 1、给出适当的署名,且提供指向本存储库的链接。GitHub 上的 Fork 可视为满足此条。
2、不得以任何方式暗示开发者为您或您的使用作担保。
三、大量使用情形。
如果您基于该存储库创作衍生作品,或合理使用了本存储库中的较大量内容,您必须:
1、给出适当的署名,且提供指向本存储库的链接。GitHub 上的 Fork 可视为满足此条。
- 2、不得以任何方式暗示开发者为您或您的使用作担保,且需要给出适当的说明,表示这是非官方内容。
- 3、使用本指南文件作为协议,不得附加额外条款。
- 4、该衍生作品不能被允许用于再次分发。包括但不限于用于制作整合包。
- 5、该衍生作品的名称必须以 “PCL” 或 “Plain Craft Launcher” 开头,并在其后添加后缀,例如 “PCL 启动修复版”、“PCL PR Collection”。
- 6、该衍生作品不得包含 PCL 的赞助功能,或是其他作用相似的功能。包括但不限于主题功能、回声洞投稿功能等。
+ 2、不得以任何方式暗示开发者为您或您的使用作担保。
+ 3、给出适当的说明,以明确表示该衍生作品是非官方内容。
+ 4、使用本指南文件作为协议,不得附加额外条款。
+ 5、该衍生作品的名称必须以 “PCL” 或 “Plain Craft Launcher” 开头,并在其后添加后缀。例如 “PCL 整合包优化版”、“PCL PR Collection”。
+ 6、该衍生作品不得包含 PCL 的赞助解锁功能,或与其用途相近的功能。包括但不限于:主题切换(自定义软件颜色/皮肤)、回声洞投稿等。
+ 7、以善意目的进行合理使用,不要用 PCL 来干坏事、恰烂钱、整烂活。开发者可能会将撤销所有授权作为最终手段。
————————————
diff --git a/Plain Craft Launcher 2/Application.xaml.vb b/Plain Craft Launcher 2/Application.xaml.vb
index 14f28ea..4233f8f 100644
--- a/Plain Craft Launcher 2/Application.xaml.vb
+++ b/Plain Craft Launcher 2/Application.xaml.vb
@@ -31,7 +31,7 @@ Public Class Application
'内存优化
Dim Ram = My.Computer.Info.AvailablePhysicalMemory
Try
- PageOtherTest.MemoryOptimizeInternal()
+ PageOtherTest.MemoryOptimizeInternal(False)
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "内存优化失败")
Environment.Exit(-1)
@@ -72,9 +72,17 @@ Public Class Application
Directory.CreateDirectory(PathAppdata)
'检测单例
#If Not DEBUG Then
+ Dim ShouldWaitForExit As Boolean = e.Args.Length > 0 AndAlso e.Args(0) = "--wait" '要求等待已有的 PCL 退出
+ Dim WaitRetryCount As Integer = 0
+WaitRetry:
Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher ")
If WindowHwnd = IntPtr.Zero Then FindWindow(Nothing, "Plain Craft Launcher 2 ")
If WindowHwnd <> IntPtr.Zero Then
+ If ShouldWaitForExit AndAlso WaitRetryCount < 20 Then '至多等待 10 秒
+ WaitRetryCount += 1
+ Thread.Sleep(500)
+ GoTo WaitRetry
+ End If
'将已有的 PCL 窗口拖出来
ShowWindowToTop(WindowHwnd)
'播放提示音并退出
@@ -106,7 +114,7 @@ Public Class Application
Log($"[Start] 管理员权限:{IsAdmin()}")
'检测异常环境
If Path.Contains(IO.Path.GetTempPath()) OrElse Path.Contains("AppData\Local\Temp\") Then
- MyMsgBox("请将 PCL 从压缩文件中解压,或是更换文件夹后再继续使用!" & vbCrLf & "程序目前在临时文件夹中运行,设置、游戏存档等可能无法保存,且部分功能将无法使用。", "环境警告", "我知道了", IsWarn:=True)
+ MyMsgBox("请将 PCL 从压缩包中解压之后再使用!" & vbCrLf & "在当前环境下运行可能会导致丢失游戏存档或设置,部分功能也可能无法使用!", "环境警告", "我知道了", IsWarn:=True)
End If
If Is32BitSystem Then
MyMsgBox("PCL 和新版 Minecraft 均不再支持 32 位系统,部分功能将无法使用。" & vbCrLf & "非常建议重装为 64 位系统后再进行游戏!", "环境警告", "我知道了", IsWarn:=True)
@@ -162,7 +170,7 @@ Public Class Application
ExceptionString.Contains(".NET Framework") OrElse ' “自动错误判断” 的结果分析
ExceptionString.Contains("未能加载文件或程序集") Then
OpenWebsite("https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-offline-installer")
- MsgBox("你的 .NET Framework 版本过低或损坏,请在打开的网页中重新下载并安装 .NET Framework 4.6.2 后重试!", MsgBoxStyle.Information, "运行环境错误")
+ MsgBox("你的 .NET Framework 版本过低或损坏,请下载并重新安装 .NET Framework 4.6.2!", MsgBoxStyle.Information, "运行环境错误")
FormMain.EndProgramForce(Result.Cancel)
Else
FeedbackInfo()
diff --git a/Plain Craft Launcher 2/Controls/MyCard.vb b/Plain Craft Launcher 2/Controls/MyCard.vb
index 8ae95ef..30c6588 100644
--- a/Plain Craft Launcher 2/Controls/MyCard.vb
+++ b/Plain Craft Launcher 2/Controls/MyCard.vb
@@ -293,26 +293,28 @@
Public Const SwapedHeight As Integer = 40
Private Sub MyCard_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
Dim Pos As Double = Mouse.GetPosition(Me).Y
- If Not IsSwaped AndAlso (IsNothing(SwapControl) OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判
+ If Not IsSwaped AndAlso
+ (SwapControl Is Nothing OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判
IsMouseDown = True
End Sub
Private Sub MyCard_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
- If IsMouseDown Then
+ If Not IsMouseDown Then Return
+ IsMouseDown = False
+
+ Dim Pos As Double = Mouse.GetPosition(Me).Y
+ If Not IsSwaped AndAlso
+ (SwapControl Is Nothing OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判
+
+ Dim ee = New RouteEventArgs(True)
+ RaiseEvent PreviewSwap(Me, ee)
+ If ee.Handled Then
IsMouseDown = False
- Dim Pos As Double = Mouse.GetPosition(Me).Y
- If Not IsSwaped AndAlso (IsNothing(SwapControl) OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判
-
- Dim ee = New RouteEventArgs(True)
- RaiseEvent PreviewSwap(Me, ee)
- If ee.Handled Then
- IsMouseDown = False
- Exit Sub
- End If
-
- IsSwaped = Not IsSwaped
- Log("[Control] " & If(IsSwaped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title))
- RaiseEvent Swap(Me, ee)
+ Return
End If
+
+ IsSwaped = Not IsSwaped
+ Log("[Control] " & If(IsSwaped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title))
+ RaiseEvent Swap(Me, ee)
End Sub
Private Sub MyCard_MouseLeave_Swap(sender As Object, e As MouseEventArgs) Handles Me.MouseLeave
IsMouseDown = False
diff --git a/Plain Craft Launcher 2/Controls/MyImage.vb b/Plain Craft Launcher 2/Controls/MyImage.vb
index 29cc916..92ba1c0 100644
--- a/Plain Craft Launcher 2/Controls/MyImage.vb
+++ b/Plain Craft Launcher 2/Controls/MyImage.vb
@@ -14,13 +14,14 @@
'''
Public Property EnableCache As Boolean
Get
- Return _EnableCache
+ Return GetValue(EnableCacheProperty)
End Get
Set(value As Boolean)
- _EnableCache = value
+ SetValue(EnableCacheProperty, value)
End Set
End Property
- Private _EnableCache As Boolean = True
+ Public Shared Shadows ReadOnly EnableCacheProperty As DependencyProperty = DependencyProperty.Register(
+ "EnableCache", GetType(Boolean), GetType(MyImage), New PropertyMetadata(True))
'''
''' 与 Image 的 Source 类似。
@@ -114,9 +115,10 @@
Dim Retried As Boolean = False
Dim TempPath As String = GetTempPath(Url)
Dim TempFile As New FileInfo(TempPath)
+ Dim EnableCache As Boolean = Me.EnableCache
If EnableCache AndAlso TempFile.Exists Then
ActualSource = TempPath
- If (Date.Now - TempFile.CreationTime) < FileCacheExpiredTime Then Exit Sub '无需刷新缓存
+ If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Exit Sub '无需刷新缓存
End If
RunInNewThread(
Sub()
@@ -126,7 +128,10 @@ RetryStart:
'下载
ActualSource = LoadingSource '显示加载中图片
TempDownloadingPath = TempPath & RandomInteger(0, 10000000)
- NetDownload(Url, TempDownloadingPath, True)
+ Directory.CreateDirectory(GetPathFromFullPath(TempPath)) '重新实现下载,以避免携带 Header(#5072)
+ Using Client As New Net.WebClient
+ Client.DownloadFile(Url, TempDownloadingPath)
+ End Using
If Url <> Source AndAlso Url <> FallbackSource Then
'已经更换了地址
File.Delete(TempDownloadingPath)
diff --git a/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb b/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb
index 85bb421..02594cf 100644
--- a/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb
+++ b/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb
@@ -654,6 +654,8 @@
Dim Unused = New HelpEntry(GetEventAbsoluteUrls(EventData, EventType)(0)).SetToListItem(Me)
Catch ex As Exception
Log(ex, "设置帮助 MyListItem 失败", LogLevel.Msgbox)
+ EventType = Nothing
+ EventData = Nothing
End Try
End If
End Sub
diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml
index bf23281..282ecb2 100644
--- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml
+++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml
@@ -25,7 +25,7 @@
+ VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMult="0.7">
diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml
index 5c21822..b4f75ba 100644
--- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml
+++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml
@@ -24,7 +24,7 @@
+ VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMult="0.7">
diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml
index 10f2a92..0bbf157 100644
--- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml
+++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml
@@ -24,7 +24,7 @@
+ VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMult="0.7">
diff --git a/Plain Craft Launcher 2/Controls/MyPageLeft.vb b/Plain Craft Launcher 2/Controls/MyPageLeft.vb
index b09897b..9c368a6 100644
--- a/Plain Craft Launcher 2/Controls/MyPageLeft.vb
+++ b/Plain Craft Launcher 2/Controls/MyPageLeft.vb
@@ -104,3 +104,7 @@
End Sub
End Class
+
+Public Interface IRefreshable
+ Sub Refresh()
+End Interface
\ No newline at end of file
diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml
index e5753e0..aa42f53 100644
--- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml
+++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml
@@ -4,6 +4,6 @@
HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27">
-
+
diff --git a/Plain Craft Launcher 2/Controls/MyScrollViewer.vb b/Plain Craft Launcher 2/Controls/MyScrollViewer.vb
index beaeb1c..42da890 100644
--- a/Plain Craft Launcher 2/Controls/MyScrollViewer.vb
+++ b/Plain Craft Launcher 2/Controls/MyScrollViewer.vb
@@ -1,7 +1,7 @@
Public Class MyScrollViewer
Inherits ScrollViewer
- Public Property DeltaMuity As Double = 1
+ Public Property DeltaMult As Double = 1
Private RealOffset As Double
@@ -25,10 +25,12 @@
Next
End Sub
Public Sub PerformVerticalOffsetDelta(Delta As Double)
- AniStart(AaDouble(Sub(AnimDelta As Double)
- RealOffset = MathClamp(RealOffset + AnimDelta, 0, ExtentHeight - ActualHeight)
- ScrollToVerticalOffset(RealOffset)
- End Sub, Delta * DeltaMuity, 300,, New AniEaseOutFluent(6)))
+ AniStart(
+ AaDouble(
+ Sub(AnimDelta As Double)
+ RealOffset = MathClamp(RealOffset + AnimDelta, 0, ExtentHeight - ActualHeight)
+ ScrollToVerticalOffset(RealOffset)
+ End Sub, Delta * DeltaMult, 300,, New AniEaseOutFluent(6)))
End Sub
Private Sub MyScrollViewer_ScrollChanged(sender As Object, e As ScrollChangedEventArgs) Handles Me.ScrollChanged
RealOffset = VerticalOffset
@@ -43,4 +45,7 @@
ScrollBar = GetTemplateChild("PART_VerticalScrollBar")
End Sub
+ Private Sub MyScrollViewer_PreviewGotKeyboardFocus(sender As Object, e As KeyboardFocusChangedEventArgs) Handles Me.PreviewGotKeyboardFocus
+ If e.NewFocus IsNot Nothing AndAlso TypeOf e.NewFocus Is MySlider Then e.Handled = True '#3854,阻止获得焦点时自动滚动
+ End Sub
End Class
diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb
index c520c42..9f6b2f2 100644
--- a/Plain Craft Launcher 2/FormMain.xaml.vb
+++ b/Plain Craft Launcher 2/FormMain.xaml.vb
@@ -10,6 +10,21 @@ Public Class FormMain
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
'统计更新日志条目
#If BETA Then
+ If LastVersion < 347 Then 'Release 2.8.12
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面添加下载 Mod、安装 Mod 选项"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 详情页面支持按加载器、游戏版本进行分类和筛选"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持安装同时包含 modpack 文件和启动器的懒人包"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化整合包导入流程"))
+ FeatureCount += 43
+ BugCount += 37
+ End If
+ If LastVersion < 342 Then 'Release 2.8.9
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持下载原版服务端"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "本地 Mod 的标题支持选择显示 Mod 原始文件名"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复搜索后启用/禁用 Mod 时出错的 Bug"))
+ FeatureCount += 17
+ BugCount += 13
+ End If
If LastVersion < 340 Then 'Release 2.8.8
If LastVersion = 338 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复数个与新正版登录相关的严重 Bug"))
FeatureCount += 3
@@ -75,6 +90,21 @@ Public Class FormMain
'3:BUG+ IMP* FEAT-
'2:BUG* IMP-
'1:BUG-
+ If LastVersion < 346 Then 'Snapshot 2.8.12
+ If LastVersion = 345 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复帮助页面报错的 Bug"))
+ End If
+ If LastVersion < 345 Then 'Snapshot 2.8.11
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面添加下载 Mod、安装 Mod 选项"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 详情页面支持按加载器、游戏版本进行分类和筛选"))
+ FeatureCount += 23
+ BugCount += 21
+ End If
+ If LastVersion < 343 Then 'Snapshot 2.8.10
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "支持安装同时包含 modpack 文件和启动器的懒人包"))
+ FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化整合包导入流程"))
+ FeatureCount += 20
+ BugCount += 16
+ End If
If LastVersion < 341 Then 'Snapshot 2.8.9
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "支持下载原版服务端"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "本地 Mod 的标题支持选择显示 Mod 原始文件名"))
@@ -227,7 +257,9 @@ Public Class FormMain
If Not IsNothing(FrmLaunchLeft.Parent) Then FrmLaunchLeft.SetValue(ContentPresenter.ContentProperty, Nothing)
If Not IsNothing(FrmLaunchRight.Parent) Then FrmLaunchRight.SetValue(ContentPresenter.ContentProperty, Nothing)
PanMainLeft.Child = FrmLaunchLeft
+ PageLeft = FrmLaunchLeft
PanMainRight.Child = FrmLaunchRight
+ PageRight = FrmLaunchRight
FrmLaunchRight.PageState = MyPageRight.PageStates.ContentStay
'模式提醒
#If DEBUG Then
@@ -279,10 +311,10 @@ Public Class FormMain
Height = MinHeight + 100
Width = MinWidth + 100
End Try
-#If DEBUG Then
- MinHeight = 50
- MinWidth = 50
-#End If
+ '#If DEBUG Then
+ ' MinHeight = 50
+ ' MinWidth = 50
+ '#End If
Topmost = False
If FrmStart IsNot Nothing Then FrmStart.Close(New TimeSpan(0, 0, 0, 0, 400 / AniSpeed))
'更改窗口
@@ -313,7 +345,7 @@ Public Class FormMain
'EULA 提示
If Not Setup.Get("SystemEula") Then
Select Case MyMsgBox("在使用 PCL 前,请同意 PCL 的用户协议与免责声明。", "协议授权", "同意", "拒绝", "查看用户协议与免责声明",
- Button3Action:=Sub() OpenWebsite("https://shimo.im/docs/rGrd8pY8xWkt6ryW"))
+ Button3Action:=Sub() OpenWebsite("https://shimo.im/docs/rGrd8pY8xWkt6ryW"))
Case 1
Setup.Set("SystemEula", True)
Case 2
@@ -599,6 +631,12 @@ Public Class FormMain
PageSetupUI.HiddenRefresh()
Exit Sub
End If
+ '按 F5 刷新页面
+ If e.Key = Key.F5 Then
+ If TypeOf PageLeft Is IRefreshable Then CType(PageLeft, IRefreshable).Refresh()
+ If TypeOf PageRight Is IRefreshable Then CType(PageRight, IRefreshable).Refresh()
+ Exit Sub
+ End If
'调用启动游戏
If e.Key = Key.Enter AndAlso PageCurrent = FormMain.PageType.Launch Then
If IsAprilEnabled AndAlso Not IsAprilGiveup Then
@@ -736,14 +774,14 @@ Public Class FormMain
If FilePathList.Count > 1 Then
'必须要求全部为 jar 文件
For Each File In FilePathList
- If Not {"jar", "litemod", "disabled", "old"}.Contains(File.After(".").ToLower) Then
+ If Not {"jar", "litemod", "disabled", "old"}.Contains(File.AfterLast(".").ToLower) Then
Hint("一次请只拖入一个文件!", HintType.Critical)
Exit Sub
End If
Next
End If
'自定义主页
- Dim Extension As String = FilePath.After(".").ToLower
+ Dim Extension As String = FilePath.AfterLast(".").ToLower
If Extension = "xaml" Then
Log("[System] 文件后缀为 XAML,作为自定义主页加载")
If File.Exists(Path & "PCL\Custom.xaml") Then
@@ -760,46 +798,19 @@ Public Class FormMain
End Sub)
Exit Sub
End If
- 'Mod 安装
- If {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then
- Log("[System] 文件为 jar/litemod 格式,尝试作为 Mod 安装")
- '获取并检查目标版本
- Dim TargetVersion As McVersion = McVersionCurrent
- If PageCurrent = PageType.VersionSetup Then TargetVersion = PageVersionLeft.Version
- If PageCurrent = PageType.VersionSelect OrElse TargetVersion Is Nothing OrElse Not TargetVersion.Modable Then
- '正在选择版本,或当前版本不能安装 Mod
- Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!")
- ElseIf Not (PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionMod) Then
- '未处于 Mod 管理页面
- If MyMsgBox($"是否要将这{If(FilePathList.Count = 1, "个", "些")}文件作为 Mod 安装到 {TargetVersion.Name}?", "Mod 安装确认", "确定", "取消") = 1 Then GoTo Install
- Else
- '处于 Mod 管理页面
-Install:
- Try
- For Each ModFile In FilePathList
- Dim NewFileName = GetFileNameFromPath(ModFile).Replace(".disabled", "")
- If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227
- CopyFile(ModFile, TargetVersion.PathIndie & "mods\" & NewFileName)
- Next
- If FilePathList.Count = 1 Then
- Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "")}!", HintType.Finish)
- Else
- Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Finish)
- End If
- '刷新列表
- If PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionMod Then
- LoaderFolderRun(McModLoader, TargetVersion.PathIndie & "mods\", LoaderFolderRunType.ForceRun)
- End If
- Catch ex As Exception
- Log(ex, "复制 Mod 文件失败", LogLevel.Msgbox)
- End Try
- End If
- Exit Sub
- End If
+ '安装 Mod
+ If PageVersionMod.InstallMods(FilePathList) Then Exit Sub
'安装整合包
If {"zip", "rar", "mrpack"}.Any(Function(t) t = Extension) Then '部分压缩包是 zip 格式但后缀为 rar,总之试一试
Log("[System] 文件为压缩包,尝试作为整合包安装")
- If ModpackInstall(FilePath, ShowHint:=False) IsNot Nothing Then Exit Sub
+ Try
+ ModpackInstall(FilePath)
+ Exit Sub
+ Catch ex As CancelledException
+ Exit Sub '用户主动取消
+ Catch ex As Exception
+ '安装失败,继续往后尝试
+ End Try
End If
'RAR 处理
If Extension = "rar" Then
@@ -1029,9 +1040,6 @@ Install:
Case PageType.Download
If FrmDownloadLeft Is Nothing Then FrmDownloadLeft = New PageDownloadLeft
Return FrmDownloadLeft.PageID
- Case PageType.Link
- If FrmLinkLeft Is Nothing Then FrmLinkLeft = New PageLinkLeft
- Return FrmLinkLeft.PageID
Case PageType.Setup
If FrmSetupLeft Is Nothing Then FrmSetupLeft = New PageSetupLeft
Return FrmSetupLeft.PageID
@@ -1100,9 +1108,6 @@ Install:
CType(PanTitleSelect.Children(Stack), MyRadioButton).SetChecked(True, True, PageNameGet(PageCurrent) = "")
IsChangingPage = False
Select Case Stack.Page
- Case PageType.Link
- If FrmLinkLeft Is Nothing Then FrmLinkLeft = New PageLinkLeft
- CType(FrmLinkLeft.PanItem.Children(SubType), MyListItem).SetChecked(True, True, Stack = PageCurrent)
Case PageType.Download
If FrmDownloadLeft Is Nothing Then FrmDownloadLeft = New PageDownloadLeft
CType(FrmDownloadLeft.PanItem.Children(SubType), MyListItem).SetChecked(True, True, Stack = PageCurrent)
@@ -1131,14 +1136,6 @@ Install:
If IsChangingPage Then Exit Sub
PageChangeActual(Val(sender.Tag))
End Sub
- Private Sub CancelLink(sender As Object, e As RouteEventArgs) Handles BtnTitleSelect2.PreviewClick
- If MyMsgBox("由于联机提供商要求新联机强制付费,且高度商业化,PCL 将暂时关闭联机功能,不再使用该联机模块。" & vbCrLf &
- "PCL、HMCL、BakaXL 将合作开发新的跨启动器联机功能,在开发结束后将同步开放,请各位多多理解。",
- "联机功能已暂时关闭", "查看详情", "确定") = 1 Then
- OpenWebsite("https://www.bilibili.com/read/cv19845645")
- End If
- e.Handled = True
- End Sub
'''
''' 通过点击返回按钮或手动触发返回来改变页面。
'''
@@ -1169,9 +1166,9 @@ Install:
If PageStack.Any Then
'子页面 → 另一个子页面,更新
AniStart({
- AaOpacity(LabTitleInner, -LabTitleInner.Opacity, 130),
- AaCode(Sub() LabTitleInner.Text = PageName,, True),
- AaOpacity(LabTitleInner, 1, 150, 30)
+ AaOpacity(LabTitleInner, -LabTitleInner.Opacity, 130),
+ AaCode(Sub() LabTitleInner.Text = PageName,, True),
+ AaOpacity(LabTitleInner, 1, 150, 30)
}, "FrmMain Titlebar SubLayer")
If PageStack.Contains(Stack) Then
'返回到更上层的子页面
@@ -1265,37 +1262,41 @@ Install:
AniControlEnabled -= 1
'执行动画
AniStart({
- AaCode(Sub()
- AniControlEnabled += 1
- '把新页面添加进容器
- PanMainLeft.Child = PageLeft
- PageLeft.Opacity = 0
- PanMainLeft.Background = Nothing
- AniControlEnabled -= 1
- RunInUi(Sub() PanMainLeft_Resize(PanMainLeft.ActualWidth), True)
- End Sub, 130),
- AaCode(Sub()
- '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
- PageLeft.Opacity = 1
- PageLeft.TriggerShowAnimation()
- End Sub, 30, True)
+ AaCode(
+ Sub()
+ AniControlEnabled += 1
+ '把新页面添加进容器
+ PanMainLeft.Child = PageLeft
+ PageLeft.Opacity = 0
+ PanMainLeft.Background = Nothing
+ AniControlEnabled -= 1
+ RunInUi(Sub() PanMainLeft_Resize(PanMainLeft.ActualWidth), True)
+ End Sub, 130),
+ AaCode(
+ Sub()
+ '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
+ PageLeft.Opacity = 1
+ PageLeft.TriggerShowAnimation()
+ End Sub, 30, True)
}, "FrmMain PageChangeLeft")
AniStart({
- AaCode(Sub()
- AniControlEnabled += 1
- CType(PanMainRight.Child, MyPageRight).PageOnForceExit()
- '把新页面添加进容器
- PanMainRight.Child = PageRight
- PageRight.Opacity = 0
- PanMainRight.Background = Nothing
- AniControlEnabled -= 1
- RunInUi(Sub() BtnExtraBack.ShowRefresh(), True)
- End Sub, 130),
- AaCode(Sub()
- '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
- PageRight.Opacity = 1
- PageRight.PageOnEnter()
- End Sub, 30, True)
+ AaCode(
+ Sub()
+ AniControlEnabled += 1
+ CType(PanMainRight.Child, MyPageRight).PageOnForceExit()
+ '把新页面添加进容器
+ PanMainRight.Child = PageRight
+ PageRight.Opacity = 0
+ PanMainRight.Background = Nothing
+ AniControlEnabled -= 1
+ RunInUi(Sub() BtnExtraBack.ShowRefresh(), True)
+ End Sub, 130),
+ AaCode(
+ Sub()
+ '延迟触发页面通用动画,以使得在 Loaded 事件中加载的控件得以处理
+ PageRight.Opacity = 1
+ PageRight.PageOnEnter()
+ End Sub, 30, True)
}, "FrmMain PageChangeRight")
End Sub
'''
@@ -1308,12 +1309,12 @@ Install:
PanTitleMain.IsHitTestVisible = True
PanTitleInner.IsHitTestVisible = False
AniStart({
- AaOpacity(PanTitleInner, -PanTitleInner.Opacity, 150),
- AaX(PanTitleInner, -18 - PanTitleInner.Margin.Left, 150,, New AniEaseInFluent),
- AaOpacity(PanTitleMain, 1 - PanTitleMain.Opacity, 150, 200),
- AaX(PanTitleMain, -PanTitleMain.Margin.Left, 350, 200, New AniEaseOutBack(AniEasePower.Weak)),
- AaCode(Sub() PanTitleInner.Visibility = Visibility.Collapsed,, True)
- }, "FrmMain Titlebar FirstLayer")
+ AaOpacity(PanTitleInner, -PanTitleInner.Opacity, 150),
+ AaX(PanTitleInner, -18 - PanTitleInner.Margin.Left, 150,, New AniEaseInFluent),
+ AaOpacity(PanTitleMain, 1 - PanTitleMain.Opacity, 150, 200),
+ AaX(PanTitleMain, -PanTitleMain.Margin.Left, 350, 200, New AniEaseOutBack(AniEasePower.Weak)),
+ AaCode(Sub() PanTitleInner.Visibility = Visibility.Collapsed,, True)
+ }, "FrmMain Titlebar FirstLayer")
PageStack.Clear()
Else
'主页面 → 主页面,无事发生
@@ -1332,16 +1333,16 @@ Install:
If NewWidth > 0 Then
'宽度足够,显示
AniStart({
- AaWidth(RectLeftBackground, NewWidth - RectLeftBackground.Width, 400,, New AniEaseOutFluent(AniEasePower.ExtraStrong)),
- AaOpacity(RectLeftShadow, 1 - RectLeftShadow.Opacity, 200),
- AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 250)
+ AaWidth(RectLeftBackground, NewWidth - RectLeftBackground.Width, 400,, New AniEaseOutFluent(AniEasePower.ExtraStrong)),
+ AaOpacity(RectLeftShadow, 1 - RectLeftShadow.Opacity, 200),
+ AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 250)
}, "FrmMain LeftChange", True)
Else
'宽度不足,隐藏
AniStart({
- AaWidth(RectLeftBackground, -RectLeftBackground.Width, 200,, New AniEaseOutFluent),
- AaOpacity(RectLeftShadow, -RectLeftShadow.Opacity, 200),
- AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 170)
+ AaWidth(RectLeftBackground, -RectLeftBackground.Width, 200,, New AniEaseOutFluent),
+ AaOpacity(RectLeftShadow, -RectLeftShadow.Opacity, 200),
+ AaCode(Sub() PanMainLeft.IsHitTestVisible = True, 170)
}, "FrmMain LeftChange", True)
End If
Else
diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb
index 2f13ab0..b2bf023 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModBase.vb
@@ -12,13 +12,13 @@ Public Module ModBase
#Region "声明"
'下列版本信息由更新器自动修改
- Public Const VersionBaseName As String = "2.8.9" '不含分支前缀的显示用版本名
- Public Const VersionStandardCode As String = "2.8.9." & VersionBranchCode '标准格式的四段式版本号
+ Public Const VersionBaseName As String = "2.8.12" '不含分支前缀的显示用版本名
+ Public Const VersionStandardCode As String = "2.8.12." & VersionBranchCode '标准格式的四段式版本号
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
#If BETA Then
- Public Const VersionCode As Integer = 340 'Release
+ Public Const VersionCode As Integer = 347 'Release
#Else
- Public Const VersionCode As Integer = 341 'Snapshot
+ Public Const VersionCode As Integer = 346 'Snapshot
#End If
'自动生成的版本信息
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -971,7 +971,7 @@ Public Module ModBase
End Using
End Function
'''
- ''' 弹出选取文件对话框并且要求选取文件。
+ ''' 弹出选取文件对话框,要求选择一个文件。
'''
''' 要求的格式。如:“常用图片文件(*.png;*.jpg)|*.png;*.jpg”。
''' 弹窗的标题。
@@ -985,12 +985,32 @@ Public Module ModBase
fileDialog.Title = Title
fileDialog.ValidateNames = True
fileDialog.ShowDialog()
- SelectFile = fileDialog.FileName
- Log("[UI] 选择文件返回:" & SelectFile)
+ Log("[UI] 选择单个文件返回:" & fileDialog.FileName)
+ Return fileDialog.FileName
End Using
End Function
'''
- ''' 弹出选取文件夹对话框并且要求选取文件夹。如果没有选择就返回空字符串。
+ ''' 弹出选取文件对话框,要求选择多个文件。
+ '''
+ ''' 要求的格式。如:“常用图片文件(*.png;*.jpg)|*.png;*.jpg”。
+ ''' 弹窗的标题。
+ Public Function SelectFiles(FileFilter As String, Title As String) As String()
+ Using fileDialog As New Forms.OpenFileDialog
+ fileDialog.AddExtension = True
+ fileDialog.AutoUpgradeEnabled = True
+ fileDialog.CheckFileExists = True
+ fileDialog.Filter = FileFilter
+ fileDialog.Multiselect = True
+ fileDialog.Title = Title
+ fileDialog.ValidateNames = True
+ fileDialog.ShowDialog()
+ Log("[UI] 选择多个文件返回:" & fileDialog.FileNames.Join(","))
+ Return fileDialog.FileNames
+ End Using
+ End Function
+ '''
+ ''' 弹出选取文件夹对话框,要求选取文件夹。
+ ''' 返回以 \ 结尾的完整路径,如果没有选择则返回空字符串。
'''
Public Function SelectFolder(Optional Title As String = "选择文件夹") As String
Dim folderDialog As New Ookii.Dialogs.Wpf.VistaFolderBrowserDialog With {.ShowNewFolderButton = True, .RootFolder = Environment.SpecialFolder.Desktop, .Description = Title, .UseDescriptionForTitle = True}
@@ -1207,7 +1227,8 @@ Re:
''' 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 jar 以 zip 方式解压。
''' 会尝试创建,但不会清空目标文件夹。
'''
- Public Sub ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing)
+ Public Sub ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing,
+ Optional ProgressIncrementHandler As Action(Of Double) = Nothing)
Directory.CreateDirectory(DestDirectory)
If CompressFilePath.EndsWithF(".gz", True) Then
'以 gz 方式解压
@@ -1223,7 +1244,9 @@ Re:
Else
'以 zip 方式解压
Using Archive = ZipFile.Open(CompressFilePath, ZipArchiveMode.Read, If(Encode, Encoding.GetEncoding("GB18030")))
+ Dim TotalCount As Integer = Archive.Entries.Count
For Each Entry As ZipArchiveEntry In Archive.Entries
+ If ProgressIncrementHandler IsNot Nothing Then ProgressIncrementHandler(1 / TotalCount)
Dim DestinationPath As String = IO.Path.Combine(DestDirectory, Entry.FullName)
If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then
Continue For '不创建空文件夹
@@ -1293,13 +1316,16 @@ RetryDir:
'''
''' 复制文件夹,失败会抛出异常。
'''
- Public Sub CopyDirectory(FromPath As String, ToPath As String)
+ Public Sub CopyDirectory(FromPath As String, ToPath As String, Optional ProgressIncrementHandler As Action(Of Double) = Nothing)
FromPath = FromPath.Replace("/", "\")
If Not FromPath.EndsWithF("\") Then FromPath &= "\"
ToPath = ToPath.Replace("/", "\")
If Not ToPath.EndsWithF("\") Then ToPath &= "\"
- For Each File In EnumerateFiles(FromPath)
+ Dim AllFiles = EnumerateFiles(FromPath).ToList
+ Dim FileCount As Integer = AllFiles.Count
+ For Each File In AllFiles
CopyFile(File.FullName, File.FullName.Replace(FromPath, ToPath))
+ If ProgressIncrementHandler IsNot Nothing Then ProgressIncrementHandler(1 / FileCount)
Next
End Sub
'''
@@ -1552,10 +1578,10 @@ RetryDir:
End Function
'''
- ''' 获取在子字符串之前的部分。
- ''' 会裁切尽可能多的内容,但如果未找到子字符串则不裁切。
+ ''' 获取在子字符串第一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024。
+ ''' 如果未找到子字符串则不裁切。
'''
- Public Function Before(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String
+ Public Function BeforeFirst(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String
Dim Pos As Integer = If(String.IsNullOrEmpty(Text), -1, Str.IndexOfF(Text, IgnoreCase))
If Pos >= 0 Then
Return Str.Substring(0, Pos)
@@ -1564,10 +1590,34 @@ RetryDir:
End If
End Function
'''
- ''' 获取在子字符串之后的部分。
- ''' 会裁切尽可能多的内容,但如果未找到子字符串则不裁切。
+ ''' 获取在子字符串最后一次出现之前的部分,例如对 2024/11/08 拆切 / 会得到 2024/11。
+ ''' 如果未找到子字符串则不裁切。
'''
- Public Function After(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String
+ Public Function BeforeLast(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String
+ Dim Pos As Integer = If(String.IsNullOrEmpty(Text), -1, Str.LastIndexOfF(Text, IgnoreCase))
+ If Pos >= 0 Then
+ Return Str.Substring(0, Pos)
+ Else
+ Return Str
+ End If
+ End Function
+ '''
+ ''' 获取在子字符串第一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 11/08。
+ ''' 如果未找到子字符串则不裁切。
+ '''
+ Public Function AfterFirst(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String
+ Dim Pos As Integer = If(String.IsNullOrEmpty(Text), -1, Str.IndexOfF(Text, IgnoreCase))
+ If Pos >= 0 Then
+ Return Str.Substring(Pos + Text.Length)
+ Else
+ Return Str
+ End If
+ End Function
+ '''
+ ''' 获取在子字符串最后一次出现之后的部分,例如对 2024/11/08 拆切 / 会得到 08。
+ ''' 如果未找到子字符串则不裁切。
+ '''
+ Public Function AfterLast(Str As String, Text As String, Optional IgnoreCase As Boolean = False) As String
Dim Pos As Integer = If(String.IsNullOrEmpty(Text), -1, Str.LastIndexOfF(Text, IgnoreCase))
If Pos >= 0 Then
Return Str.Substring(Pos + Text.Length)
@@ -1576,8 +1626,8 @@ RetryDir:
End If
End Function
'''
- ''' 获取处于两个子字符串之间的部分。
- ''' 会裁切尽可能多的内容:匹配开始使用 LastIndexOf,匹配结束使用 IndexOf,但如果未找到子字符串则不裁切。
+ ''' 获取处于两个子字符串之间的部分,裁切尽可能多的内容。
+ ''' 如果未找到子字符串则不裁切。
'''
Public Function Between(Str As String, After As String, Before As String, Optional IgnoreCase As Boolean = False) As String
Dim StartPos As Integer = If(String.IsNullOrEmpty(After), -1, Str.LastIndexOfF(After, IgnoreCase))
@@ -1844,6 +1894,39 @@ RetryDir:
#Region "系统"
+ '''
+ ''' 线程安全的,可以直接使用 For Each 的 List。
+ ''' 在使用 For Each 循环时,列表的结果可能并非最新,但不会抛出异常。
+ '''
+ Public Class SafeList(Of T)
+ Inherits SynchronizedCollection(Of T)
+ Implements IEnumerable, IEnumerable(Of T)
+ '构造函数
+ Public Sub New()
+ MyBase.New()
+ End Sub
+ Public Sub New(Data As IEnumerable(Of T))
+ MyBase.New(New Object, Data)
+ End Sub
+ Public Shared Widening Operator CType(Data As List(Of T)) As SafeList(Of T)
+ Return New SafeList(Of T)(Data)
+ End Operator
+ Public Shared Widening Operator CType(Data As SafeList(Of T)) As List(Of T)
+ Return New List(Of T)(Data)
+ End Operator
+ '基于 SyncLock 覆写
+ Public Overloads Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
+ SyncLock SyncRoot
+ Return Items.ToList.GetEnumerator()
+ End SyncLock
+ End Function
+ Private Overloads Function GetEnumeratorGeneral() As IEnumerator Implements IEnumerable.GetEnumerator
+ SyncLock SyncRoot
+ Return Items.ToList.GetEnumerator()
+ End SyncLock
+ End Function
+ End Class
+
'''
''' 可用于临时存放文件的,不含任何特殊字符的文件夹路径,以“\”结尾。
'''
@@ -1866,6 +1949,12 @@ RetryDir:
Public Class RestartException
Inherits Exception
End Class
+ '''
+ ''' 指示用户手动取消了操作,或用户已知晓操作被取消的原因。
+ '''
+ Public Class CancelledException
+ Inherits Exception
+ End Class
'''
''' 当前程序是否拥有管理员权限。
@@ -1983,10 +2072,10 @@ NextElement:
'12~60 月,“1 年 2 个月”
GetTimeSpanString = Math.Floor(TotalMonthes / 12) & " 年" & If((TotalMonthes Mod 12) > 0, " " & (TotalMonthes Mod 12) & " 个月", "")
ElseIf TotalMonthes >= 4 Then
- '4~11 月,“5 月”
- GetTimeSpanString = TotalMonthes & " 月"
+ '4~11 月,“5 个月”
+ GetTimeSpanString = TotalMonthes & " 个月"
ElseIf TotalMonthes >= 1 Then
- '1~4 月,“2 月 13 天”
+ '1~4 月,“2 个月 13 天”
GetTimeSpanString = TotalMonthes & " 月" & If((Span.Days Mod 30) > 0, " " & (Span.Days Mod 30) & " 天", "")
ElseIf Span.TotalDays >= 4 Then
'4~30 天,“23 天”
@@ -2108,7 +2197,7 @@ NextElement:
'''
''' 在新的工作线程中执行代码。
'''
- Public Function RunInNewThread(Action As Action, Name As String, Optional Priority As ThreadPriority = ThreadPriority.Normal) As Thread
+ Public Function RunInNewThread(Action As Action, Optional Name As String = Nothing, Optional Priority As ThreadPriority = ThreadPriority.Normal) As Thread
Dim th As New Thread(
Sub()
Try
@@ -2118,7 +2207,7 @@ NextElement:
Catch ex As Exception
Log(ex, Name & ":线程执行失败", LogLevel.Feedback)
End Try
- End Sub) With {.Name = Name, .Priority = Priority}
+ End Sub) With {.Name = If(Name, "Runtime New Invoke " & GetUuid() & "#"), .Priority = Priority}
th.Start()
Return th
End Function
diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
index e824443..f069882 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb
@@ -568,7 +568,7 @@ Restart:
End Class
'任务栏进度条
- Public LoaderTaskbar As New SynchronizedCollection(Of LoaderBase)
+ Public LoaderTaskbar As New SafeList(Of LoaderBase)
Public LoaderTaskbarProgress As Double = 0 '平滑后的进度
Private LoaderTaskbarProgressLast As Shell.TaskbarItemProgressState = Shell.TaskbarItemProgressState.None
diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb
index db4b308..f046d34 100644
--- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb
+++ b/Plain Craft Launcher 2/Modules/Base/ModNet.vb
@@ -701,7 +701,7 @@ RequestFinished:
'''
''' 所属的文件列表任务。
'''
- Public Tasks As New SynchronizedCollection(Of LoaderDownload)
+ Public Tasks As New SafeList(Of LoaderDownload)
'''
''' 所有下载源。
'''
@@ -930,7 +930,7 @@ RequestFinished:
'条件检测
If NetTaskThreadCount >= NetTaskThreadLimit OrElse IsSourceFailed() OrElse
- (IsNoSplit AndAlso Threads IsNot Nothing AndAlso Threads.State <> NetState.Error) Then Return Nothing
+ (IsNoSplit AndAlso Threads IsNot Nothing AndAlso Threads.State <> NetState.Error) Then Return Nothing
If State >= NetState.Merge OrElse State = NetState.WaitForCheck Then Return Nothing
SyncLock LockState
If State < NetState.Connect Then State = NetState.Connect
@@ -974,7 +974,8 @@ Capture:
Next
'是否禁用多线程,以及规定碎片大小
Dim TargetUrl As String = GetSource().Url
- If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("gitcode.net") OrElse TargetUrl.Contains("github.com") OrElse TargetUrl.Contains("modrinth") Then Return Nothing
+ If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("mcimirror") OrElse TargetUrl.Contains("github.com") OrElse
+ TargetUrl.Contains("optifine.net") OrElse TargetUrl.Contains("modrinth") Then Return Nothing
'寻找最大碎片
'FUTURE: 下载引擎重做,计算下载源平均链接时间和线程下载速度,按最高时间节省来开启多线程
Dim FilePieceMax As NetThread = Threads
@@ -1303,7 +1304,7 @@ Wrong:
If String.IsNullOrEmpty(header) Then Return Nothing
'attachment; filename="filename.ext"
If Not header.Contains("filename=") Then Return Nothing
- Return header.After("filename=").Trim(""""c, " "c).Before(";")
+ Return header.AfterLast("filename=").Trim(""""c, " "c).BeforeFirst(";")
End Function
'下载文件的最终收束事件
@@ -1469,8 +1470,7 @@ Retry:
'''
''' 需要下载的文件。
'''
- Public Files As List(Of NetFile)
- Private ReadOnly FilesLock As New Object
+ Public Files As SafeList(Of NetFile)
'''
''' 剩余未完成的文件数。(用于减轻 FilesLock 的占用)
'''
@@ -1483,9 +1483,7 @@ Retry:
Public Overrides Property Progress As Double
Get
If State >= LoadState.Finished Then Return 1
- SyncLock FilesLock
- If Not Files.Any() Then Return 0 '必须返回 0,否则在获取列表的时候会错觉已经下载完了
- End SyncLock
+ If Not Files.Any() Then Return 0 '必须返回 0,否则在获取列表的时候会错觉已经下载完了
Return _Progress
End Get
Set(value As Double)
@@ -1507,16 +1505,14 @@ Retry:
Log("[Download] 由于同加载器中失败次数过多引发强制失败:连续失败了 " & value & " 次", LogLevel.Debug)
On Error Resume Next
Dim ExList As New List(Of Exception)
- SyncLock FilesLock
- For Each File In Files
- For Each Source In File.Sources
- If Source.Ex IsNot Nothing Then
- ExList.Add(Source.Ex)
- If ExList.Count > 10 Then GoTo FinishExCatch
- End If
- Next
+ For Each File In Files
+ For Each Source In File.Sources
+ If Source.Ex IsNot Nothing Then
+ ExList.Add(Source.Ex)
+ If ExList.Count > 10 Then GoTo FinishExCatch
+ End If
Next
- End SyncLock
+ Next
FinishExCatch:
OnFail(ExList)
End If
@@ -1533,17 +1529,15 @@ FinishExCatch:
'计算进度
Dim NewProgress As Double = 0
Dim TotalProgress As Double = 0
- SyncLock FilesLock
- For Each File In Files
- If File.IsCopy Then
- NewProgress += File.Progress * 0.2
- TotalProgress += 0.2
- Else
- NewProgress += File.Progress
- TotalProgress += 1
- End If
- Next
- End SyncLock
+ For Each File In Files
+ If File.IsCopy Then
+ NewProgress += File.Progress * 0.2
+ TotalProgress += 0.2
+ Else
+ NewProgress += File.Progress
+ TotalProgress += 1
+ End If
+ Next
If TotalProgress > 0 Then NewProgress /= TotalProgress
'刷新进度
If NewProgress < 1 AndAlso NewProgress > 0 Then NewProgress = 2 * (NewProgress ^ 3) - 3 * (NewProgress ^ 2) + 2 * NewProgress '2x^3-3x^2+2x,模拟开头和结尾更慢的情况
@@ -1552,27 +1546,25 @@ FinishExCatch:
Public Sub New(Name As String, FileTasks As List(Of NetFile))
Me.Name = Name
- Files = FileTasks
+ Files = New SafeList(Of NetFile)(FileTasks)
End Sub
Public Overrides Sub Start(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = False)
- SyncLock FilesLock
- If Input IsNot Nothing Then Files = Input
- '去重
- Dim ResultArray As New List(Of NetFile)
- For i = 0 To Files.Count - 1
- For ii = i + 1 To Files.Count - 1
- If Files(i).LocalPath = Files(ii).LocalPath Then GoTo NextElement
- Next
- ResultArray.Add(Files(i))
+ If Input IsNot Nothing Then Files = New SafeList(Of NetFile)(Input)
+ '去重
+ Dim ResultArray As New SafeList(Of NetFile)
+ For i = 0 To Files.Count - 1
+ For ii = i + 1 To Files.Count - 1
+ If Files(i).LocalPath = Files(ii).LocalPath Then GoTo NextElement
+ Next
+ ResultArray.Add(Files(i))
NextElement:
- Next i
- Files = ResultArray
- '设置剩余文件数
- SyncLock FileRemainLock
- For Each File In Files
- If File.State <> NetState.Finish Then FileRemain += 1
- Next
- End SyncLock
+ Next
+ Files = ResultArray
+ '设置剩余文件数
+ SyncLock FileRemainLock
+ For Each File In Files
+ If File.State <> NetState.Finish Then FileRemain += 1
+ Next
End SyncLock
State = LoadState.Loading
'开始执行
@@ -1615,25 +1607,23 @@ NextElement:
Next
End If
'最多 5 个线程,最少每个线程分配 10 个文件
- SyncLock FilesLock
- Dim FilesPerThread As Integer = Math.Max(5, Files.Count / 10 + 1)
- Dim FilesInThread As New List(Of NetFile)
- For Each File In Files
- FilesInThread.Add(File)
- If FilesInThread.Count = FilesPerThread Then
- Dim FilesToRun As New List(Of NetFile)
- FilesToRun.AddRange(FilesInThread)
- RunInNewThread(Sub() StartCopy(FilesToRun, FoldersFinal), "NetTask FileCopy " & Uuid)
- FilesInThread.Clear()
- End If
- Next
- If FilesInThread.Any Then
+ Dim FilesPerThread As Integer = Math.Max(5, Files.Count / 10 + 1)
+ Dim FilesInThread As New List(Of NetFile)
+ For Each File In Files
+ FilesInThread.Add(File)
+ If FilesInThread.Count = FilesPerThread Then
Dim FilesToRun As New List(Of NetFile)
FilesToRun.AddRange(FilesInThread)
RunInNewThread(Sub() StartCopy(FilesToRun, FoldersFinal), "NetTask FileCopy " & Uuid)
FilesInThread.Clear()
End If
- End SyncLock
+ Next
+ If FilesInThread.Any Then
+ Dim FilesToRun As New List(Of NetFile)
+ FilesToRun.AddRange(FilesInThread)
+ RunInNewThread(Sub() StartCopy(FilesToRun, FoldersFinal), "NetTask FileCopy " & Uuid)
+ FilesInThread.Clear()
+ End If
Catch ex As Exception
OnFail(New List(Of Exception) From {ex})
End Try
@@ -1728,24 +1718,20 @@ Retry:
Dim UsefulExs = ExList.Where(Function(e) Not e.Message.Contains("(404)")).ToList
[Error] = If(UsefulExs.Any, UsefulExs(0), ExList(0))
'获取实际失败的文件
- SyncLock FilesLock
- For Each File In Files
- If File.State = NetState.Error Then
- [Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf & Join(
- File.Sources.Select(Function(s) If(s.Ex Is Nothing, s.Url, s.Ex.Message & "(" & s.Url & ")")), vbCrLf), [Error])
- Exit For
- End If
- Next
- End SyncLock
+ For Each File In Files
+ If File.State = NetState.Error Then
+ [Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf & Join(
+ File.Sources.Select(Function(s) If(s.Ex Is Nothing, s.Url, s.Ex.Message & "(" & s.Url & ")")), vbCrLf), [Error])
+ Exit For
+ End If
+ Next
'在设置 Error 对象后再更改为失败,避免 WaitForExit 无法捕获错误
State = LoadState.Failed
End SyncLock
'中断所有文件
- SyncLock FilesLock
- For Each TaskFile In Files
- If TaskFile.State < NetState.Merge Then TaskFile.State = NetState.Error
- Next
- End SyncLock
+ For Each TaskFile In Files
+ If TaskFile.State < NetState.Merge Then TaskFile.State = NetState.Error
+ Next
'在退出同步锁后再进行日志输出
Dim ErrOutput As New List(Of String)
For Each Ex As Exception In ExList
@@ -1760,11 +1746,9 @@ Retry:
End SyncLock
Log("[Download] " & Name & " 已取消!")
'中断所有文件
- SyncLock FilesLock
- For Each TaskFile In Files
- TaskFile.Abort(Me)
- Next
- End SyncLock
+ For Each TaskFile In Files
+ TaskFile.Abort(Me)
+ Next
End Sub
End Class
@@ -1786,8 +1770,7 @@ Retry:
'''
''' 当前的所有下载任务。
'''
- Public Tasks As New List(Of LoaderDownload)
- Private ReadOnly LockTasks As New Object
+ Public Tasks As New SafeList(Of LoaderDownload)
'''
''' 已下载完成的大小。
@@ -1860,11 +1843,9 @@ Retry:
End If
#End Region
#Region "刷新下载任务属性"
- SyncLock LockTasks
- For Each Task In Tasks
- Task.RefreshStat()
- Next
- End SyncLock
+ For Each Task In Tasks
+ Task.RefreshStat()
+ Next
#End Region
Catch ex As Exception
Log(ex, "刷新下载公开属性失败")
@@ -2010,9 +1991,7 @@ Retry:
Task.Files(i) = File '回设
Next
End SyncLock
- SyncLock LockTasks
- Tasks.Add(Task)
- End SyncLock
+ Tasks.Add(Task)
End Sub
End Class
diff --git a/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb b/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb
index e126d61..c5303d6 100644
--- a/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb
+++ b/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb
@@ -17,15 +17,19 @@ Public Class MyBitmap
'自动类型转换
'支持的类:Image,ImageSource,Bitmap,ImageBrush,BitmapSource
Public Shared Widening Operator CType(Image As System.Drawing.Image) As MyBitmap
+ If Image Is Nothing Then Return Nothing
Return New MyBitmap(Image)
End Operator
Public Shared Widening Operator CType(Image As MyBitmap) As System.Drawing.Image
+ If Image Is Nothing Then Return Nothing
Return Image.Pic
End Operator
Public Shared Widening Operator CType(Image As ImageSource) As MyBitmap
+ If Image Is Nothing Then Return Nothing
Return New MyBitmap(Image)
End Operator
Public Shared Widening Operator CType(Image As MyBitmap) As ImageSource
+ If Image Is Nothing Then Return Nothing
Dim Bitmap = Image.Pic
Dim rect = New System.Drawing.Rectangle(0, 0, Bitmap.Width, Bitmap.Height)
Dim bitmapData = Bitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
@@ -37,15 +41,19 @@ Public Class MyBitmap
End Try
End Operator
Public Shared Widening Operator CType(Image As System.Drawing.Bitmap) As MyBitmap
+ If Image Is Nothing Then Return Nothing
Return New MyBitmap(Image)
End Operator
Public Shared Widening Operator CType(Image As MyBitmap) As System.Drawing.Bitmap
+ If Image Is Nothing Then Return Nothing
Return Image.Pic
End Operator
Public Shared Widening Operator CType(Image As ImageBrush) As MyBitmap
+ If Image Is Nothing Then Return Nothing
Return New MyBitmap(Image)
End Operator
Public Shared Widening Operator CType(Image As MyBitmap) As ImageBrush
+ If Image Is Nothing Then Return Nothing
Return New ImageBrush(New MyBitmap(Image.Pic))
End Operator
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
index 73614ed..36cc7ee 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
@@ -271,7 +271,7 @@
Next
CurseForgeFileIds = Files.Select(Function(f) f.Key).Distinct.ToList
GameVersions = Files.SelectMany(Function(f) f.Value).Where(Function(v) v.StartsWithF("1.")).
- Select(Function(v) CInt(Val(v.Split(".")(1).Before("-")))).Where(Function(v) v > 0).
+ Select(Function(v) CInt(Val(v.Split(".")(1).BeforeFirst("-")))).Where(Function(v) v > 0).
Distinct.OrderByDescending(Function(v) v).ToList
ModLoaders = ModLoaders.Distinct.OrderBy(Of Integer)(Function(t) t).ToList
'Type
@@ -349,7 +349,7 @@
'搜索结果的键为 versions,获取特定工程的键为 game_versions
GameVersions = If(CType(If(Data("game_versions"), Data("versions")), JArray), New JArray).
Select(Function(v) v.ToString).Where(Function(v) v.StartsWithF("1.")).
- Select(Of Integer)(Function(v) Val(v.Split(".")(1).Before("-"))).Where(Function(v) v > 0).
+ Select(Of Integer)(Function(v) Val(v.Split(".")(1).BeforeFirst("-"))).Where(Function(v) v > 0).
Distinct.OrderByDescending(Function(v) v).ToList
'Type
Select Case Data("project_type").ToString
@@ -458,14 +458,14 @@
If StartVersion = EndVersion Then
SpaVersions.Add("1." & StartVersion)
ElseIf McVersionHighest > -1 AndAlso StartVersion >= McVersionHighest Then
- If EndVersion <= 10 Then
+ If EndVersion < 10 Then
SpaVersions.Clear()
SpaVersions.Add("全版本")
Exit For
Else
SpaVersions.Add("1." & EndVersion & "+")
End If
- ElseIf EndVersion <= 10 Then
+ ElseIf EndVersion < 10 Then
SpaVersions.Add("1." & StartVersion & "-")
Exit For
ElseIf StartVersion - EndVersion = 1 Then
@@ -478,25 +478,31 @@
End If
'获取 Mod 加载器描述
Dim ModLoaderDescriptionFull As String, ModLoaderDescriptionPart As String
- Select Case ModLoaders.Count
+ Dim ModLoadersForDesc As New List(Of CompModLoaderType)(ModLoaders)
+ If Setup.Get("ToolDownloadIgnoreQuilt") Then ModLoadersForDesc.Remove(CompModLoaderType.Quilt)
+ Select Case ModLoadersForDesc.Count
Case 0
- ModLoaderDescriptionFull = "未知"
- ModLoaderDescriptionPart = ""
+ If ModLoaders.Count = 1 Then
+ ModLoaderDescriptionFull = "仅 " & ModLoaders.Single.ToString
+ ModLoaderDescriptionPart = ModLoaders.Single.ToString
+ Else
+ ModLoaderDescriptionFull = "未知"
+ ModLoaderDescriptionPart = ""
+ End If
Case 1
- ModLoaderDescriptionFull = "仅 " & ModLoaders.Single.ToString
- ModLoaderDescriptionPart = ModLoaders.Single.ToString
- Case 2, 3
- If Setup.Get("ToolDownloadIgnoreQuilt") AndAlso
- ModLoaders.Contains(CompModLoaderType.Forge) AndAlso ModLoaders.Contains(CompModLoaderType.Fabric) Then
+ ModLoaderDescriptionFull = "仅 " & ModLoadersForDesc.Single.ToString
+ ModLoaderDescriptionPart = ModLoadersForDesc.Single.ToString
+ Case Else
+ If ModLoaders.Contains(CompModLoaderType.Forge) AndAlso
+ (GameVersions.Max < 14 OrElse ModLoaders.Contains(CompModLoaderType.Fabric)) AndAlso
+ (GameVersions.Max < 20 OrElse ModLoaders.Contains(CompModLoaderType.NeoForge)) AndAlso
+ (GameVersions.Max < 14 OrElse ModLoaders.Contains(CompModLoaderType.Quilt) OrElse Setup.Get("ToolDownloadIgnoreQuilt")) Then
ModLoaderDescriptionFull = "任意"
ModLoaderDescriptionPart = ""
Else
- ModLoaderDescriptionFull = ModLoaders.Join(" / ")
- ModLoaderDescriptionPart = ModLoaders.Join(" / ")
+ ModLoaderDescriptionFull = ModLoadersForDesc.Join(" / ")
+ ModLoaderDescriptionPart = ModLoadersForDesc.Join(" / ")
End If
- Case Else
- ModLoaderDescriptionFull = "任意"
- ModLoaderDescriptionPart = ""
End Select
'实例化 UI
Dim NewItem As New MyCompItem With {.Tag = Me, .Logo = GetControlLogo()}
@@ -583,9 +589,9 @@
'有中文翻译
'尝试将文本分为三段:Title (EnglishName) - Suffix
'检查时注意 Carpet:它没有中文译名,但有 Suffix
- Title = TranslatedName.Before(" (").Before(" - ")
+ Title = TranslatedName.BeforeFirst(" (").BeforeFirst(" - ")
Dim Suffix As String = ""
- If TranslatedName.After(")").Contains(" - ") Then Suffix = TranslatedName.After(")").After(" - ")
+ If TranslatedName.AfterLast(")").Contains(" - ") Then Suffix = TranslatedName.AfterLast(")").AfterLast(" - ")
Dim EnglishName As String = TranslatedName
If Suffix <> "" Then EnglishName = EnglishName.Replace(" - " & Suffix, "")
EnglishName = EnglishName.Replace(Title, "").Trim("("c, ")"c, " "c)
@@ -758,7 +764,7 @@ NoSubtitle:
Case CompType.ResourcePack
'FUTURE: Res
End Select
- Address += "&categoryId=" & If(Tag = "", "0", Tag.Before("/"))
+ Address += "&categoryId=" & If(Tag = "", "0", 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)
@@ -779,7 +785,7 @@ NoSubtitle:
'facets=[["categories:'game-mechanics'"],["categories:'forge'"],["versions:1.19.3"],["project_type:mod"]]
Dim Facets As New List(Of String)
Facets.Add($"[""project_type:{GetStringFromEnum(Type).ToLower}""]")
- If Not String.IsNullOrEmpty(Tag) Then Facets.Add($"[""categories:'{Tag.After("/")}'""]")
+ If Not String.IsNullOrEmpty(Tag) Then Facets.Add($"[""categories:'{Tag.AfterLast("/")}'""]")
If ModLoader <> CompModLoaderType.Any Then Facets.Add($"[""categories:'{GetStringFromEnum(ModLoader).ToLower}'""]")
If Not String.IsNullOrEmpty(GameVersion) Then Facets.Add($"[""versions:'{GameVersion}'""]")
Address += "&facets=[" & String.Join(",", Facets) & "]"
@@ -887,7 +893,7 @@ NoSubtitle:
If Not SearchResults(i).AbsoluteRight AndAlso i >= Math.Min(2, SearchResults.Count - 1) Then Exit For '把 3 个结果拼合以提高准确度
If SearchResults(i).Item.CurseForgeSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.CurseForgeSlug.Replace("-", " ").Replace("/", " ") & " "
If SearchResults(i).Item.ModrinthSlug IsNot Nothing Then SearchResult += SearchResults(i).Item.ModrinthSlug.Replace("-", " ").Replace("/", " ") & " "
- SearchResult += SearchResults(i).Item.ChineseName.After(" (").TrimEnd(") ").Before(" - ").
+ SearchResult += SearchResults(i).Item.ChineseName.AfterLast(" (").TrimEnd(") ").BeforeFirst(" - ").
Replace(":", "").Replace("(", "").Replace(")", "").ToLower.Replace("/", " ") & " "
Next
Log("[Comp] 中文搜索原始关键词:" & SearchResult, LogLevel.Developer)
@@ -1156,7 +1162,7 @@ Retry:
'''
Public ReadOnly ModLoaders As List(Of CompModLoaderType)
'''
- ''' 支持的游戏版本列表。类型包括:"1.18.5","1.18","1.18 快照","21w15a","未知版本"。
+ ''' 支持的游戏版本列表。类型包括:"1.18.5","1.18","1.18 预览版","21w15a","未知版本"。
'''
Public ReadOnly GameVersions As List(Of String)
'''
@@ -1272,7 +1278,7 @@ Retry:
End If
'GameVersions
Dim RawVersions As List(Of String) = Data("gameVersions").Select(Function(t) t.ToString.Trim.ToLower).ToList
- GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.")).Select(Function(v) v.Replace("-snapshot", " 快照")).ToList
+ GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.")).Select(Function(v) v.Replace("-snapshot", " 预览版")).ToList
If GameVersions.Count > 1 Then
GameVersions = Sort(GameVersions, AddressOf VersionSortBoolean).ToList
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)}
@@ -1313,7 +1319,7 @@ Retry:
'GameVersions
Dim RawVersions As List(Of String) = Data("game_versions").Select(Function(t) t.ToString.Trim.ToLower).ToList
GameVersions = RawVersions.Where(Function(v) v.StartsWithF("1.") OrElse v.StartsWithF("b1.")).
- Select(Function(v) If(v.Contains("-"), v.Before("-") & " 快照", If(v.StartsWithF("b1."), "远古版本", v))).ToList
+ Select(Function(v) If(v.Contains("-"), v.BeforeFirst("-") & " 预览版", If(v.StartsWithF("b1."), "远古版本", v))).ToList
If GameVersions.Count > 1 Then
GameVersions = Sort(GameVersions, AddressOf VersionSortBoolean).ToList
If Type = CompType.ModPack Then GameVersions = New List(Of String) From {GameVersions(0)}
@@ -1362,28 +1368,26 @@ Retry:
Optional BadDisplayName As Boolean = False) As MyListItem
'获取描述信息
- Dim Info As String = ""
+ Dim Title As String = If(BadDisplayName, FileName, DisplayName)
+ Dim Info As New List(Of String)
+ If Title <> FileName.BeforeLast(".") Then Info.Add(FileName.BeforeLast("."))
Select Case Type
Case CompType.Mod
- Info += If(ModLoaders.Any,
- "适用于 " & Join(ModLoaders.Select(Function(m) GetStringFromEnum(m)).ToList, "/") & ",", "")
- Info += If(ModeDebug AndAlso Dependencies.Any, Dependencies.Count & " 个前置 Mod,", "")
+ If Dependencies.Any Then Info.Add(Dependencies.Count & " 个前置 Mod")
Case CompType.ModPack
- If GameVersions.All(Function(v) v.Contains("w")) Then
- Info += $"游戏版本 {Join(GameVersions, "、")},"
- End If
+ If GameVersions.All(Function(v) v.Contains("w")) Then Info.Add($"游戏版本 {Join(GameVersions, "、")}")
End Select
If DownloadCount > 0 Then 'CurseForge 的下载次数经常错误地返回 0
- Info += If(DownloadCount > 100000, Math.Round(DownloadCount / 10000) & " 万次下载,", DownloadCount & " 次下载,")
+ Info.Add("下载 " & If(DownloadCount > 100000, Math.Round(DownloadCount / 10000) & " 万次", DownloadCount & " 次"))
End If
- Info += GetTimeSpanString(ReleaseDate - Date.Now, False) & "更新"
- Info += If(Status = CompFileStatus.Release, "", "," & StatusDescription)
+ Info.Add("更新于 " & GetTimeSpanString(ReleaseDate - Date.Now, False))
+ If Status <> CompFileStatus.Release Then Info.Add(StatusDescription)
'建立控件
Dim NewItem As New MyListItem With {
- .Title = If(BadDisplayName, FileName, DisplayName),
+ .Title = Title,
.SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Me,
- .Info = Info
+ .Info = Info.Join(",")
}
Select Case Status
Case CompFileStatus.Release
@@ -1422,14 +1426,12 @@ Retry:
'''
''' 已知文件信息的缓存。
'''
- Private CompFilesCache As New Dictionary(Of String, List(Of CompFile))
+ Public CompFilesCache As New Dictionary(Of String, List(Of CompFile))
'''
''' 获取某个工程下的全部文件列表。
''' 必须在工作线程执行,失败会抛出异常。
'''
Public Function CompFilesGet(ProjectId As String, FromCurseForge As Boolean) As List(Of CompFile)
- '使用缓存
- If CompFilesCache.ContainsKey(ProjectId) Then Return CompFilesCache(ProjectId)
'获取工程对象
Dim TargetProject As CompProject
If CompProjectCache.ContainsKey(ProjectId) Then '存在缓存
@@ -1440,25 +1442,26 @@ Retry:
TargetProject = New CompProject(DlModRequest("https://api.modrinth.com/v2/project/" & ProjectId, IsJson:=True))
End If
'获取工程对象的文件列表
- Log("[Comp] 开始获取文件列表:" & ProjectId)
- Dim ResultJsonArray As JArray
- If FromCurseForge Then
- 'CurseForge
- If TargetProject.Type = CompType.Mod Then 'Mod 使用每个版本最新的文件
- ResultJsonArray = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(TargetProject.CurseForgeFileIds, ",") & "]}", "application/json"))("data")
- Else '否则使用全部文件
- ResultJsonArray = DlModRequest($"https://api.curseforge.com/v1/mods/{ProjectId}/files?pageSize=999", IsJson:=True)("data")
+ If Not CompFilesCache.ContainsKey(ProjectId) Then '有缓存也不能直接返回,这时候前置 Mod 可能没获取(#5173)
+ Log("[Comp] 开始获取文件列表:" & ProjectId)
+ Dim ResultJsonArray As JArray
+ If FromCurseForge Then
+ 'CurseForge
+ If TargetProject.Type = CompType.Mod Then 'Mod 使用每个版本最新的文件
+ ResultJsonArray = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(TargetProject.CurseForgeFileIds, ",") & "]}", "application/json"))("data")
+ Else '否则使用全部文件
+ ResultJsonArray = DlModRequest($"https://api.curseforge.com/v1/mods/{ProjectId}/files?pageSize=999", IsJson:=True)("data")
+ End If
+ Else
+ 'Modrinth
+ ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version", IsJson:=True)
End If
- Else
- 'Modrinth
- ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version", IsJson:=True)
+ CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)).
+ Where(Function(a) a.Available).ToList.Distinct(Function(a, b) a.Id = b.Id) 'CurseForge 可能会重复返回相同项(#1330)
End If
- CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)).
- Where(Function(a) a.Available).ToList.Distinct(Function(a, b) a.Id = b.Id) 'CurseForge 可能会重复返回相同项(#1330)
'获取前置 Mod 列表
If TargetProject.Type <> CompType.Mod Then Return CompFilesCache(ProjectId)
- Dim Deps As List(Of String) = CompFilesCache(ProjectId).
- SelectMany(Function(f) f.RawDependencies).Distinct().ToList
+ Dim Deps As List(Of String) = CompFilesCache(ProjectId).SelectMany(Function(f) f.RawDependencies).Distinct().ToList
Dim UndoneDeps = Deps.Where(Function(f) Not CompProjectCache.ContainsKey(f)).ToList
'获取前置 Mod 工程信息
If UndoneDeps.Any Then
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
index c88ce9f..a3b3c61 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb
@@ -381,6 +381,7 @@ Extracted:
没有可用的分析文件
使用32位Java导致JVM无法分配足够多的内存
Mod重复安装
+ Mod互不兼容
OptiFine与Forge不兼容
Fabric报错
Fabric报错并给出解决方案
@@ -413,7 +414,7 @@ Extracted:
'崩溃日志
If LogCrash IsNot Nothing Then
Log("[Crash] 开始进行崩溃日志堆栈分析")
- Keywords.AddRange(AnalyzeStackKeyword(LogCrash.Before("System Details")))
+ Keywords.AddRange(AnalyzeStackKeyword(LogCrash.BeforeFirst("System Details")))
End If
'Minecraft 日志
If LogMc IsNot Nothing Then
@@ -541,12 +542,14 @@ Done:
End If
'确定的 Mod 导致崩溃
If LogMc.Contains("Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(RegexSeek(LogMc, "(?<=Caught exception from )[^\n]+?")?.TrimEnd((vbCrLf & " ").ToCharArray)))
- 'Mod 重复安装
+ 'Mod 重复 / 前置问题
If LogMc.Contains("DuplicateModsFoundException") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(LogMc, "(?<=\n\t[\w]+ : [A-Z]{1}:[^\n]+(/|\\))[^/\\\n]+?.jar", RegularExpressions.RegexOptions.IgnoreCase))
If LogMc.Contains("Found a duplicate mod") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(If(RegexSeek(LogMc, "Found a duplicate mod[^\n]+"), ""), "[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase))
If LogMc.Contains("Found duplicate mods") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(LogMc, "(?<=Mod ID: ')\w+?(?=' from mod files:)").Distinct.ToList)
If LogMc.Contains("ModResolutionException: Duplicate") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(If(RegexSeek(LogMc, "ModResolutionException: Duplicate[^\n]+"), ""), "[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase))
- 'Mod 缺少前置
+ If LogMc.Contains("Incompatible mods found!") Then '#5006
+ AppendReason(CrashReason.Mod互不兼容, If(RegexSeek(LogMc, "(?<=Incompatible mods found![\s\S]+: )[\s\S]+?(?=\tat )"), ""))
+ End If
If LogMc.Contains("Missing or unsupported mandatory dependencies:") Then
AppendReason(CrashReason.Mod缺少前置或MC版本错误,
RegexSearch(LogMc, "(?<=Missing or unsupported mandatory dependencies:)([\n\r]+\t(.*))+", RegularExpressions.RegexOptions.IgnoreCase).
@@ -592,37 +595,51 @@ Done:
'''
Private Sub AnalyzeCrit2()
+ 'Mixin 分析
+ Dim MixinAnalyze =
+ Function(LogText As String) As Boolean
+ Dim IsMixin As Boolean =
+ LogText.Contains("Mixin prepare failed ") OrElse LogText.Contains("Mixin apply failed ") OrElse
+ LogText.Contains("MixinApplyError") OrElse LogText.Contains("MixinTransformerError") OrElse
+ LogText.Contains("mixin.injection.throwables.") OrElse LogText.Contains(".json] FAILED during )")
+ If Not IsMixin Then Return False
+ 'Mod 名称匹配
+ Dim ModName As String = RegexSeek(LogText, "(?<=from mod )[^.\/ ]+(?=\] from)")
+ If ModName Is Nothing Then ModName = RegexSeek(LogText, "(?<=for mod )[^.\/ ]+(?= failed)")
+ If ModName IsNot Nothing Then
+ AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(ModName.TrimEnd((vbCrLf & " ").ToCharArray)))
+ Return True
+ End If
+ 'JSON 名称匹配
+ For Each JsonName In RegexSearch(LogText, "(?<=^[^\t]+[ \[{(]{1})[^ \[{(]+\.[^ ]+(?=\.json)", RegularExpressions.RegexOptions.Multiline)
+ AppendReason(CrashReason.ModMixin失败,
+ TryAnalyzeModName(JsonName.Replace("mixins", "mixin").Replace(".mixin", "").Replace("mixin.", "")))
+ Return True
+ Next
+ '没有明确匹配
+ AppendReason(CrashReason.ModMixin失败)
+ Return True
+ End Function
+
'游戏日志分析
If LogMc IsNot Nothing Then
+ 'Mixin 崩溃
+ Dim IsMixin As Boolean = MixinAnalyze(LogMc)
'常规信息
If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf))
If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf))
If LogMc.Contains("A potential solution has been determined, this may resolve your problem:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined, this may resolve your problem:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf))
If LogMc.Contains("确定了一种可能的解决方法,这样做可能会解决你的问题:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=确定了一种可能的解决方法,这样做可能会解决你的问题:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf))
- 'Mixin 崩溃
- If LogMc.Contains("Mixin prepare failed ") OrElse LogMc.Contains("Mixin apply failed ") OrElse LogMc.Contains("MixinApplyError") OrElse
- LogMc.Contains("mixin.injection.throwables.") OrElse LogMc.Contains(".json] FAILED during )") Then
- Dim ModId As String = RegexSeek(LogMc, "(?<=in )[^./ ]+(?=.mixins.json.+failed injection check)")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=in mixins.)[^./ ]+(?=.json.+failed injection check)")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in )[^./ ]+(?=.mixins.json)")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in mixins.)[^./ ]+(?=.json)")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed mixins.)[^./ ]+(?=.json:)")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[)[^./ ]+(?=.mixins.json\] FAILED during )")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[mixins.)[^./ ]+(?=.json\] FAILED during )")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=from mod )[^./ ]+(?=\] from)")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=for mod )[^./ ]+(?= failed)")
- '兜底名称判断
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "[^./ \]]+(?=.mixins.json)")
- If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=mixins.)[^./ \]]+(?=.json)")
- AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(If(ModId, "").TrimEnd((vbCrLf & " ").ToCharArray)))
- Else
- '在 #3104 的情况下,这一句导致 OptiFabric 的 Mixin 失败错判为 Fabric Loader 加载失败
- If LogMc.Contains("due to errors, provided by ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
+ If Not IsMixin AndAlso LogMc.Contains("due to errors, provided by ") Then '在 #3104 的情况下,这一句导致 OptiFabric 的 Mixin 失败错判为 Fabric Loader 加载失败
+ AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
End If
End If
'崩溃报告分析
If LogCrash IsNot Nothing Then
+ 'Mixin 崩溃
+ MixinAnalyze(LogCrash)
+ '常规信息
If LogCrash.Contains("Suspected Mod") Then
Dim SuspectsRaw As String = LogCrash.Between("Suspected Mod", "Stacktrace")
If Not SuspectsRaw.StartsWithF("s: None") Then 'Suspected Mods: None
@@ -644,6 +661,8 @@ Done:
If Not (LogMc.Contains("at net.") OrElse LogMc.Contains("INFO]")) AndAlso LogHs Is Nothing AndAlso LogCrash Is Nothing AndAlso LogMc.Length < 100 Then
AppendReason(CrashReason.极短的程序输出, LogMc)
End If
+ 'Mod 解析错误(常见于 Fabric 前置校验失败)
+ If LogMc.Contains("Mod resolution failed") Then AppendReason(CrashReason.Mod加载器报错)
'Mixin 失败可以导致大量 Mod 实例创建失败
If LogMc.Contains("Failed to create mod instance.") Then AppendReason(CrashReason.Mod初始化失败, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModID: )[^,]+"), If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModId )[^\n]+(?= for )"), "")).TrimEnd(vbCrLf)))
'注意:Fabric 的 Warnings were found! 不一定是崩溃原因,它可能是单纯的警报
@@ -699,7 +718,7 @@ NextStack:
If {"com", "org", "net", "asm", "fml", "mod", "jar", "sun", "lib", "map", "gui", "dev", "nio", "api", "dsi", "top", "mcp",
"core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base", "oshi", "impl", "data", "pool", "task",
"forge", "setup", "block", "model", "mixin", "event", "unimi", "netty", "world",
- "gitlab", "common", "server", "config", "loader", "launch", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events",
+ "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",
"injection", "listeners", "scheduler", "minecraft", "transformer", "transformers", "neoforged", "universal", "multipart", "minecraftforge", "blockentity", "spongepowered", "electronwill"
@@ -742,7 +761,7 @@ NextStack:
Details = Details.Replace("Fabric Mods", "¨")
Log("[Crash] 崩溃报告中检测到 Fabric Mod 信息格式")
End If
- Details = Details.After("¨")
+ Details = Details.AfterLast("¨")
'[Forge] 获取所有包含 .jar 的行
'[Fabric] 获取所有包含 Mod 信息的行
@@ -877,16 +896,19 @@ NextStack:
If ExtraFiles IsNot Nothing Then OutputFiles.AddRange(ExtraFiles)
For Each OutputFile In OutputFiles
Dim FileName As String = GetFileNameFromPath(OutputFile)
+ Dim FileEncoding As Encoding = Nothing
Select Case FileName
Case "LatestLaunch.bat"
FileName = "启动脚本.bat"
Case "Log1.txt"
FileName = "PCL 启动器日志.txt"
+ FileEncoding = Encoding.UTF8
Case "RawOutput.log"
FileName = "游戏崩溃前的输出.txt"
+ FileEncoding = Encoding.UTF8
End Select
If File.Exists(OutputFile) Then
- Dim FileEncoding As Encoding = GetEncoding(ReadFileBytes(OutputFile))
+ If FileEncoding Is Nothing Then FileEncoding = GetEncoding(ReadFileBytes(OutputFile))
WriteFile(TempFolder & "Report\" & FileName,
SecretFilter(ReadFile(OutputFile, FileEncoding), If(FileName = "启动脚本.bat", "F", "*")),
Encoding:=FileEncoding)
@@ -914,7 +936,7 @@ NextStack:
If IsHandAnalyze Then
Return "很抱歉,PCL 无法确定错误原因。"
Else
- Return $"很抱歉,你的游戏出现了一些问题……{vbCrLf}如果要寻求帮助,请导出错误报告并发给他人,而不是发送这个窗口的截图。"
+ Return $"很抱歉,你的游戏出现了一些问题……{vbCrLf}如果要寻求帮助,请把错误报告文件发给对方,而不是发送这个窗口的照片或者截图。"
End If
End If
@@ -970,7 +992,9 @@ NextStack:
Results.Add("以下 Mod 导致了游戏出错:\n - " & Join(Additional, "\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h")
End If
Case CrashReason.ModMixin失败
- If Additional.Count = 1 Then
+ If Additional.Count = 0 Then
+ Results.Add("部分 Mod 注入失败,导致游戏出错。\n这一般代表着部分 Mod 与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试逐步禁用 Mod,然后观察游戏是否还会崩溃,以此定位导致崩溃的 Mod。\n\e\h")
+ ElseIf Additional.Count = 1 Then
Results.Add("名为 " & Additional.First & " 的 Mod 注入失败,导致游戏出错。\n这一般代表着它与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h")
Else
Results.Add("以下 Mod 导致了游戏出错:\n - " & Join(Additional, "\n - ") & "\n这一般代表着它们与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h")
@@ -1043,25 +1067,31 @@ NextStack:
If Additional.Count = 1 Then
Results.Add("Fabric 提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else
- Results.Add("Fabric 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h")
+ Results.Add("Fabric 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
+ End If
+ Case CrashReason.Mod互不兼容
+ If Additional.Count = 1 Then
+ Results.Add("你所安装的 Mod 不兼容:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
+ Else
+ Results.Add("你所安装的 Mod 不兼容,Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If
Case CrashReason.Mod加载器报错
If Additional.Count = 1 Then
Results.Add("Mod 加载器提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else
- Results.Add("Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h")
+ Results.Add("Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If
Case CrashReason.Fabric报错并给出解决方案
If Additional.Count = 1 Then
Results.Add("Fabric 提供了以下解决方案:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else
- Results.Add("Fabric 可能已经提供了解决方案,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h")
+ Results.Add("Fabric 可能已经提供了解决方案,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If
Case CrashReason.Forge报错
If Additional.Count = 1 Then
Results.Add("Forge 提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else
- Results.Add("Forge 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h")
+ Results.Add("Forge 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If
Case CrashReason.没有可用的分析文件
Results.Add("你的游戏出现了一些问题,但 PCL 未能找到相关记录文件,因此无法进行分析。\h")
@@ -1077,7 +1107,7 @@ NextStack:
Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, vbCrLf).
Trim(vbCrLf.ToCharArray) &
If(Not Results.Any(Function(r) r.EndsWithF("\h")) OrElse IsHandAnalyze, "",
- vbCrLf & "如果要寻求帮助,请向他人发送错误报告文件,而不是发送这个窗口的截图。" &
+ vbCrLf & "如果要寻求帮助,请把错误报告文件发给对方,而不是发送这个窗口的照片或者截图。" &
If(If(PageSetupSystem.IsLauncherNewest(), True), "",
vbCrLf & vbCrLf & "此外,你正在使用老版本 PCL,更新 PCL 或许也能解决这个问题。" & vbCrLf & "你可以点击 设置 → 启动器 → 检查更新 来更新 PCL。"))
End Function
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
index 5cbf8e2..81c1a66 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb
@@ -167,24 +167,25 @@
End Structure
'''
''' Minecraft 客户端 版本列表,主加载器。
+ ''' 若要求镜像源必须包含某个版本,则将该版本 ID 作为输入(#5195)。
'''
- Public DlClientListLoader As New LoaderTask(Of Integer, DlClientListResult)("DlClientList Main", AddressOf DlClientListMain)
- Private Sub DlClientListMain(Loader As LoaderTask(Of Integer, DlClientListResult))
+ Public DlClientListLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Main", AddressOf DlClientListMain)
+ Private Sub DlClientListMain(Loader As LoaderTask(Of String, DlClientListResult))
Select Case Setup.Get("ToolDownloadVersion")
Case 0
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListMojangLoader, 60)
+ DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From {
+ New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 30),
+ New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 30 + 60)
}, Loader.IsForceRestarting)
Case 1
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListMojangLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListBmclapiLoader, 35)
+ DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From {
+ New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 5),
+ New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 5 + 30)
}, Loader.IsForceRestarting)
Case Else
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListMojangLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlClientListResult), Integer)(DlClientListBmclapiLoader, 60)
+ DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From {
+ New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 60),
+ New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 60 + 60)
}, Loader.IsForceRestarting)
End Select
End Sub
@@ -193,9 +194,9 @@
'''
''' Minecraft 客户端 版本列表,Mojang 官方源加载器。
'''
- Public DlClientListMojangLoader As New LoaderTask(Of Integer, DlClientListResult)("DlClientList Mojang", AddressOf DlClientListMojangMain)
+ Public DlClientListMojangLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Mojang", AddressOf DlClientListMojangMain)
Private IsNewClientVersionHinted As Boolean = False
- Private Sub DlClientListMojangMain(Loader As LoaderTask(Of Integer, DlClientListResult))
+ Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult))
Dim Json As JObject = NetGetCodeByRequestRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json", IsJson:=True)
Try
Dim Versions As JArray = Json("versions")
@@ -225,14 +226,21 @@
'''
''' Minecraft 客户端 版本列表,BMCLAPI 源加载器。
'''
- Public DlClientListBmclapiLoader As New LoaderTask(Of Integer, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain)
- Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of Integer, DlClientListResult))
+ Public DlClientListBmclapiLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain)
+ Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of String, DlClientListResult))
Dim Json As JObject = NetGetCodeByRequestRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json", IsJson:=True)
Try
Dim Versions As JArray = Json("versions")
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
'添加 PCL 特供项
If File.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(ReadFile(PathTemp & "Cache\download.json")))
+ '检查是否有要求的版本(#5195)
+ If Not String.IsNullOrEmpty(Loader.Input) Then
+ Dim Id = Loader.Input
+ If Not DlClientListLoader.Output.Value("versions").Any(Function(v) v("id") = Id) Then
+ Throw New Exception("BMCLAPI 源未包含目标版本 " & Id)
+ End If
+ End If
'返回
Loader.Output = New DlClientListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Json}
Catch ex As Exception
@@ -245,26 +253,31 @@
'''
Public Function DlClientListGet(Id As String)
Try
- '确认 Minecraft 版本列表已完成获取
- Select Case DlClientListLoader.State
- Case LoadState.Loading
- DlClientListLoader.WaitForExit()
- Case LoadState.Failed, LoadState.Aborted, LoadState.Waiting
- DlClientListLoader.WaitForExit(IsForceRestart:=True)
- End Select
'确认版本格式标准
Id = Id.Replace("_", "-") '1.7.10_pre4 在版本列表中显示为 1.7.10-pre4
If Id <> "1.0" AndAlso Id.EndsWithF(".0") Then Id = Left(Id, Id.Length - 2) 'OptiFine 1.8 的下载会触发此问题,显示版本为 1.8.0
- '查找版本并开始
+ '获取 Minecraft 版本列表
+ Select Case DlClientListLoader.State
+ Case LoadState.Finished
+ '从当前的结果获取目标版本…
+ For Each Version As JObject In DlClientListLoader.Output.Value("versions")
+ If Version("id") = Id Then Return Version("url").ToString
+ Next
+ '…如果没有,则重新尝试获取(在版本刚更新时可能出现这种情况,#5195)
+ DlClientListLoader.WaitForExit(Id, IsForceRestart:=True)
+ Case LoadState.Loading
+ DlClientListLoader.WaitForExit(Id)
+ Case LoadState.Failed, LoadState.Aborted, LoadState.Waiting
+ DlClientListLoader.WaitForExit(Id, IsForceRestart:=True)
+ End Select
+ '重新查找版本
For Each Version As JObject In DlClientListLoader.Output.Value("versions")
- If Version("id") = Id Then
- Return Version("url").ToString
- End If
+ If Version("id") = Id Then Return Version("url").ToString
Next
- Log("未发现版本 " & Id & " 的 json 下载地址,版本列表返回为:" & vbCrLf & DlClientListLoader.Output.Value.ToString, LogLevel.Debug)
+ Log($"未发现版本 {Id} 的 json 下载地址,版本列表返回为:{vbCrLf}{DlClientListLoader.Output.Value.ToString}", LogLevel.Debug)
Return Nothing
Catch ex As Exception
- Log(ex, "获取版本 " & Id & " 的 json 下载地址失败")
+ Log(ex, $"获取版本 {Id} 的 json 下载地址失败")
Return Nothing
End Try
End Function
@@ -337,17 +350,17 @@
Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 30 + 60)
}, Loader.IsForceRestarting)
Case 1
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 35)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 5 + 30)
}, Loader.IsForceRestarting)
Case Else
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 60 + 60)
}, Loader.IsForceRestarting)
End Select
End Sub
@@ -443,17 +456,17 @@
Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 30 + 60)
}, Loader.IsForceRestarting)
Case 1
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 35)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 5 + 30)
}, Loader.IsForceRestarting)
Case Else
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 60 + 60)
}, Loader.IsForceRestarting)
End Select
End Sub
@@ -588,17 +601,17 @@
Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From {
New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 30 + 60)
}, Loader.IsForceRestarting)
Case 1
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From {
New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 35)
+ New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 5 + 30)
}, Loader.IsForceRestarting)
Case Else
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From {
New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 60 + 60)
}, Loader.IsForceRestarting)
End Select
End Sub
@@ -780,7 +793,7 @@
Inherit = "1.20.1"
Else '20.4.30-beta
VersionName = ApiName
- Version = New Version(ApiName.Before("-"))
+ Version = New Version(ApiName.BeforeFirst("-"))
Inherit = $"1.{Version.Major}" & If(Version.Minor = 0, "", "." & Version.Minor)
End If
End Sub
@@ -795,17 +808,17 @@
Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 30 + 60)
}, Loader.IsForceRestarting)
Case 1
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 35)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 5 + 30)
}, Loader.IsForceRestarting)
Case Else
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 60 + 60)
}, Loader.IsForceRestarting)
End Select
End Sub
@@ -920,17 +933,17 @@
Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 30 + 60)
}, Loader.IsForceRestarting)
Case 1
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 35)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 5 + 30)
}, Loader.IsForceRestarting)
Case Else
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 60 + 60)
}, Loader.IsForceRestarting)
End Select
End Sub
@@ -1019,17 +1032,17 @@
Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 30 + 60)
}, Loader.IsForceRestarting)
Case 1
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 35)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 5 + 30)
}, Loader.IsForceRestarting)
Case Else
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 60)
+ New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 60 + 60)
}, Loader.IsForceRestarting)
End Select
End Sub
@@ -1089,7 +1102,7 @@
Dim Urls As New List(Of KeyValuePair(Of String, Integer))
If McimUrl <> Url Then
Select Case Setup.Get("ToolDownloadMod")
- 'UNDONE: 在 MCIM 源稳定后回调
+ 'TODO: 在 MCIM 源稳定后回调
Case 0
If ModeDebug Then
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
@@ -1138,7 +1151,7 @@
Dim Urls As New List(Of KeyValuePair(Of String, Integer))
If McimUrl <> Url Then
Select Case Setup.Get("ToolDownloadMod")
- 'UNDONE: 在 MCIM 源稳定后回调
+ 'TODO: 在 MCIM 源稳定后回调
Case 0
If ModeDebug Then
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
@@ -1235,71 +1248,63 @@
Optional IsForceRestart As Boolean = False)
Dim WaitCycle As Integer = 0
Do While True
- '检查加载结束
- Dim IsAllFailed As Boolean = True
+ '检查状态
+ Dim BeforeLoadersAllFailed As Boolean = True
For Each SubLoader In LoaderList
- If WaitCycle = 0 Then
- '如果要强制刷新,就不使用已经加载好的值
- If IsForceRestart Then Exit For
- '如果输入不一样,就不使用已经加载好的值
+ If WaitCycle = 0 Then '判断是否可以不加载,直接使用已经加载好的结果
+ If IsForceRestart Then Continue For '强制刷新,不行
If (SubLoader.Key.Input Is Nothing Xor MainLoader.Input Is Nothing) OrElse
- (SubLoader.Key.Input IsNot Nothing AndAlso Not SubLoader.Key.Input.Equals(MainLoader.Input)) Then Continue For
+ (SubLoader.Key.Input IsNot Nothing AndAlso Not SubLoader.Key.Input.Equals(MainLoader.Input)) Then Continue For '父子加载器的输入不一样,也不行
End If
- If SubLoader.Key.State <> LoadState.Failed Then IsAllFailed = False
+ If SubLoader.Key.State <> LoadState.Failed Then BeforeLoadersAllFailed = False
If SubLoader.Key.State = LoadState.Finished Then
+ '检查加载器成功
MainLoader.Output = SubLoader.Key.Output
DlSourceLoaderAbort(LoaderList)
Exit Sub
- ElseIf IsAllFailed Then
+ ElseIf BeforeLoadersAllFailed Then
+ '此前的加载器全部失败,直接启动后续加载器
If WaitCycle < SubLoader.Value * 100 Then WaitCycle = SubLoader.Value * 100
End If
- '由于 Forge BMCLAPI 没有可用版本导致强制失败
- '在没有可用版本时,官方源会一直卡住,直接使用 BMCLAPI 判定失败即可
- If SubLoader.Key.Error IsNot Nothing AndAlso SubLoader.Key.Error.Message.Contains("没有可用版本") Then
- For Each SubLoader2 In LoaderList
- If WaitCycle < SubLoader2.Value * 100 Then WaitCycle = SubLoader2.Value * 100
- Next
- End If
Next
- '启动加载源
+ '第一轮时:既然不直接使用已经加载好的结果,那就启动第一个加载器
If WaitCycle = 0 Then
- '启动第一个源
- LoaderList(0).Key.Start(MainLoader.Input, IsForceRestart)
- '将其他源标记为未启动,以确保可以切换下载源(#184)
- For i = 1 To LoaderList.Count - 1
- LoaderList(i).Key.State = LoadState.Waiting
+ LoaderList.First.Key.Start(MainLoader.Input, IsForceRestart)
+ For Each Loader In LoaderList.Skip(1)
+ Loader.Key.State = LoadState.Waiting '将其他源标记为未启动,以确保可以切换下载源(#184)
Next
End If
+ '检查加载器失败或超时
For i = 0 To LoaderList.Count - 1
- If WaitCycle = LoaderList(i).Value * 100 Then
- If i < LoaderList.Count - 1 Then
- '启动下一个源
- LoaderList(i + 1).Key.Start(MainLoader.Input, IsForceRestart)
- Else
- '失败
- Dim ErrorInfo As Exception = Nothing
- For ii = 0 To LoaderList.Count - 1
- LoaderList(ii).Key.Input = Nothing '重置输入,以免以同样的输入“重试加载”时直接失败
- If LoaderList(ii).Key.Error IsNot Nothing Then
- If ErrorInfo Is Nothing OrElse LoaderList(ii).Key.Error.Message.Contains("没有可用版本") Then
- ErrorInfo = LoaderList(ii).Key.Error
- End If
+ If WaitCycle <> LoaderList(i).Value * 100 Then Continue For
+ If i < LoaderList.Count - 1 AndAlso Not LoaderList.All(Function(l) l.Key.State = LoadState.Failed) Then
+ '若还有下一个源,则启动下一个源
+ LoaderList(i + 1).Key.Start(MainLoader.Input, IsForceRestart)
+ Else
+ '若没有,则失败
+ Dim ErrorInfo As Exception = Nothing
+ For ii = 0 To LoaderList.Count - 1
+ LoaderList(ii).Key.Input = Nothing '重置输入,以免以同样的输入“重试加载”时直接失败
+ If LoaderList(ii).Key.Error IsNot Nothing Then
+ If ErrorInfo Is Nothing OrElse LoaderList(ii).Key.Error.Message.Contains("没有可用版本") Then
+ ErrorInfo = LoaderList(ii).Key.Error
End If
- Next
- If ErrorInfo Is Nothing Then ErrorInfo = New TimeoutException("下载源连接超时")
- DlSourceLoaderAbort(LoaderList)
- Throw ErrorInfo
- End If
- Exit For
+ End If
+ Next
+ If ErrorInfo Is Nothing Then ErrorInfo = New TimeoutException("下载源连接超时")
+ DlSourceLoaderAbort(LoaderList)
+ Throw ErrorInfo
End If
+ Exit For
Next
'计时
+ Thread.Sleep(10)
+ WaitCycle += 1
+ '检查父加载器中断
If MainLoader.IsAborted Then
DlSourceLoaderAbort(LoaderList)
Exit Sub
End If
- Thread.Sleep(10)
- WaitCycle += 1
Loop
End Sub
Private Sub DlSourceLoaderAbort(Of InputType, OutputType)(LoaderList As List(Of KeyValuePair(Of LoaderTask(Of InputType, OutputType), Integer)))
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
index af527ef..d11075e 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb
@@ -489,16 +489,18 @@ NoUserJava:
Public JavaSearchLoader As New LoaderTask(Of Integer, Integer)("查找 Java", AddressOf JavaSearchLoaderSub) With {.ProgressWeight = 2}
Private Sub JavaSearchLoaderSub(Loader As LoaderTask(Of Integer, Integer))
If FrmSetupLaunch IsNot Nothing Then
- RunInUiWait(Sub()
- FrmSetupLaunch.ComboArgumentJava.Items.Clear()
- FrmSetupLaunch.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True})
- End Sub)
+ RunInUiWait(
+ Sub()
+ FrmSetupLaunch.ComboArgumentJava.Items.Clear()
+ FrmSetupLaunch.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True})
+ End Sub)
End If
If FrmVersionSetup IsNot Nothing Then
- RunInUiWait(Sub()
- FrmVersionSetup.ComboArgumentJava.Items.Clear()
- FrmVersionSetup.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True})
- End Sub)
+ RunInUiWait(
+ Sub()
+ FrmVersionSetup.ComboArgumentJava.Items.Clear()
+ FrmVersionSetup.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True})
+ End Sub)
End If
Try
@@ -520,6 +522,7 @@ NoUserJava:
Next
'查找磁盘中的 Java
For Each Disk As DriveInfo In DriveInfo.GetDrives()
+ If Disk.DriveType = DriveType.Network Then Continue For '跳过网络驱动器(#3705)
JavaSearchFolder(Disk.Name, JavaPreList, False)
Next
'查找 APPDATA 文件夹中的 Java
@@ -681,8 +684,8 @@ Wait:
For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories
If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接
Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).ToLower '用于搜索的字符串
- If IsFullSearch OrElse FolderInfo.Parent.Name.ToLower = "users" OrElse
- Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then
+ If IsFullSearch OrElse
+ FolderInfo.Parent.Name.ToLower = "users" OrElse Val(SearchEntry) > 0 OrElse Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then
JavaSearchFolder(FolderInfo, Results, Source)
End If
Next
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
index 1be022c..62e457f 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
@@ -225,9 +225,9 @@ NextInner:
Select Case Setup.Get("SystemLaunchCount")
Case 10, 20, 40, 60, 80, 100, 120, 150, 200, 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000
If MyMsgBox("PCL 已经为你启动了 " & Setup.Get("SystemLaunchCount") & " 次游戏啦!" & vbCrLf &
- "如果觉得 PCL 还算好用的话,也可以考虑赞助一下作者……一点心意也行……" & vbCrLf &
- "毕竟一个人开发也不容易(悲)……",
- "求赞助啦……", "这就赞助!", "但是我拒绝") = 1 Then
+ "如果 PCL 还算好用的话,能不能考虑赞助一下 PCL……" & vbCrLf &
+ "如果没有大家的支持,PCL 很难在免费、无任何广告的情况下维持数年的更新(磕头)……!",
+ Setup.Get("SystemLaunchCount") & " 次启动!", "支持 PCL!", "但是我拒绝") = 1 Then
OpenWebsite("https://afdian.com/a/LTCat")
End If
End Select
@@ -237,10 +237,10 @@ NextInner:
If Not Setup.Get("HintBuy") AndAlso Setup.Get("LoginType") <> McLoginType.Ms Then
If IsSystemLanguageChinese() Then
Select Case Setup.Get("SystemLaunchCount")
- Case 2, 5, 10, 15, 20, 40, 60, 80, 100, 125, 150, 175, 200, 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000
+ Case 3, 8, 15, 30, 50, 70, 90, 110, 130, 180, 220, 280, 330, 380, 450, 550, 660, 750, 880, 950, 1100, 1300, 1500, 1700, 1900
If MyMsgBox("你已经启动了 " & Setup.Get("SystemLaunchCount") & " 次 Minecraft 啦!" & vbCrLf &
- "如果觉得 Minecraft 还不错,可以购买正版支持一下,毕竟开发游戏也真的很不容易……" & vbCrLf & vbCrLf &
- "在你登录一次正版账号后,就不会再出现这个提示了!",
+ "如果觉得 Minecraft 还不错,可以购买正版支持一下,毕竟开发游戏也真的很不容易……不要一直白嫖啦。" & vbCrLf & vbCrLf &
+ "在登录一次正版账号后,就不会再出现这个提示了!",
"考虑一下正版?", "支持正版游戏!", "下次一定") = 1 Then
OpenWebsite("https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj")
End If
@@ -380,7 +380,7 @@ NextInner:
Case McLoginType.Ms
If Setup.Get("CacheMsV2Name") <> "" Then Return Setup.Get("CacheMsV2Name")
Case McLoginType.Legacy
- If Setup.Get("LoginLegacyName") <> "" Then Return Setup.Get("LoginLegacyName").ToString.Before("¨")
+ If Setup.Get("LoginLegacyName") <> "" Then Return Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨")
Case McLoginType.Nide
If Setup.Get("CacheNideName") <> "" Then Return Setup.Get("CacheNideName")
Case McLoginType.Auth
@@ -390,7 +390,7 @@ NextInner:
If Setup.Get("CacheMsV2Name") <> "" Then Return Setup.Get("CacheMsV2Name")
If Setup.Get("CacheNideName") <> "" Then Return Setup.Get("CacheNideName")
If Setup.Get("CacheAuthName") <> "" Then Return Setup.Get("CacheAuthName")
- If Setup.Get("LoginLegacyName") <> "" Then Return Setup.Get("LoginLegacyName").ToString.Before("¨")
+ If Setup.Get("LoginLegacyName") <> "" Then Return Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨")
Return Nothing
End Function
'''
@@ -501,7 +501,7 @@ NextInner:
#Region "分方式登录模块"
'各个登录方式的主对象与输入构造
- Public McLoginMsLoader As New LoaderTask(Of McLoginMs, McLoginResult)("Loader Login Ms", AddressOf McLoginMsStart)
+ Public McLoginMsLoader As New LoaderTask(Of McLoginMs, McLoginResult)("Loader Login Ms", AddressOf McLoginMsStart) With {.ReloadTimeout = 1}
Public McLoginLegacyLoader As New LoaderTask(Of McLoginLegacy, McLoginResult)("Loader Login Legacy", AddressOf McLoginLegacyStart)
Public McLoginNideLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Nide", AddressOf McLoginServerStart) With {.ReloadTimeout = 1000 * 60 * 10}
Public McLoginAuthLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Auth", AddressOf McLoginServerStart) With {.ReloadTimeout = 1000 * 60 * 10}
@@ -805,7 +805,19 @@ LoginFinish:
ErrorMessage = GetJson(DirectCast(ex, ResponsedWebException).Response)("errorMessage")
Catch
End Try
- If Not String.IsNullOrWhiteSpace(ErrorMessage) Then Throw New Exception("$登录失败:" & ErrorMessage)
+ If Not String.IsNullOrWhiteSpace(ErrorMessage) Then
+ If ErrorMessage.Contains("密码错误") OrElse ErrorMessage.ContainsF("Incorrect username or password", True) Then
+ '密码错误,退出登录 (#5090)
+ McLaunchLog("密码错误,退出登录")
+ Select Case Data.Input.Type
+ Case McLoginType.Auth
+ RunInUi(AddressOf PageLoginAuthSkin.ExitLogin)
+ Case McLoginType.Nide
+ RunInUi(AddressOf PageLoginNideSkin.ExitLogin)
+ End Select
+ End If
+ Throw New Exception("$登录失败:" & ErrorMessage)
+ End If
End If
'通用关键字检测
If AllMessage.Contains("403") Then
@@ -1643,8 +1655,11 @@ NextVersion:
GameSize = New Size(875 - 2, 540 - 2)
End Select
GameSize.Height -= 29.5 * DPI / 96 '标题栏高度
- If McVersionCurrent.Version.McCodeMain <= 12 AndAlso McLaunchJavaSelected.VersionCode <= 8 AndAlso
- Not McVersionCurrent.Version.HasOptiFine AndAlso Not McVersionCurrent.Version.HasForge Then '修复 #3463:1.12.2-,JRE 8 下窗口大小为设置大小的 DPI% 倍
+ If McVersionCurrent.Version.McCodeMain <= 12 AndAlso
+ McLaunchJavaSelected.VersionCode <= 8 AndAlso McLaunchJavaSelected.Version.Revision >= 200 AndAlso McLaunchJavaSelected.Version.Revision <= 321 AndAlso
+ Not McVersionCurrent.Version.HasOptiFine AndAlso Not McVersionCurrent.Version.HasForge Then
+ '修复 #3463:1.12.2-,JRE 8u200~321 下窗口大小为设置大小的 DPI% 倍
+ McLaunchLog($"已应用窗口大小过大修复({McLaunchJavaSelected.Version.Revision})")
GameSize.Width /= DPI / 96
GameSize.Height /= DPI / 96
End If
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
index 213a82c..2d87c22 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb
@@ -85,7 +85,7 @@ Public Module ModMinecraft
Next
If Not Renamed Then CacheMcFolderList.Add(New McFolder With {.Name = Name, .Path = Path, .Type = McFolderType.Custom})
Else
- Hint("无效的 Minecraft 文件夹:" & Path, HintType.Critical)
+ Hint("无法访问 Minecraft 文件夹:" & Path, HintType.Critical)
End If
Next
@@ -1291,8 +1291,11 @@ OnLoaded:
'单独列出收藏的版本
Dim StaredVersions As New List(Of McVersion)
- For Each Version As McVersion In VersionList
- If Version.IsStar AndAlso Not Version.DisplayType = McVersionCardType.Hidden Then StaredVersions.Add(Version)
+ For Each Version As McVersion In VersionList.ToList
+ If Version.IsStar AndAlso Not Version.DisplayType = McVersionCardType.Hidden Then
+ StaredVersions.Add(Version)
+ VersionList.Remove(Version)
+ End If
Next
If StaredVersions.Any Then VersionListOriginal.Add(McVersionCardType.Star, StaredVersions)
@@ -2305,8 +2308,8 @@ OnLoaded:
End If
Left = Left.ToLowerInvariant
Right = Right.ToLowerInvariant
- Dim Lefts = RegexSearch(Left.Replace("快照", "snapshot"), "[a-z]+|[0-9]+")
- Dim Rights = RegexSearch(Right.Replace("快照", "snapshot"), "[a-z]+|[0-9]+")
+ Dim Lefts = RegexSearch(Left.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+")
+ Dim Rights = RegexSearch(Right.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+")
Dim i As Integer = 0
While True
'两边均缺失,感觉是一个东西
@@ -2355,15 +2358,11 @@ NextEntry:
'''
''' 比较两个版本名的排序器。
'''
- Public Class VersionSorter
+ Public Class VersionComparer
Implements IComparer(Of String)
- Public IsDecreased As Boolean = True
Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
- Return VersionSortInteger(x, y) * If(IsDecreased, -1, 1)
+ Return VersionSortInteger(x, y)
End Function
- Public Sub New(Optional IsDecreased As Boolean = True)
- Me.IsDecreased = IsDecreased
- End Sub
End Class
'''
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
index a6662ad..f1cb169 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb
@@ -688,7 +688,7 @@ Finished:
'''
Public ReadOnly Property CanUpdate As Boolean
Get
- Return ChangelogUrls.Any()
+ Return Not Setup.Get("UiHiddenFunctionModUpdate") AndAlso ChangelogUrls.Any()
End Get
End Property
@@ -702,7 +702,7 @@ Finished:
Dim Info As New FileInfo(Path)
Dim CacheKey As String = GetHash($"{RawPath}-{Info.LastWriteTime.ToLongTimeString}-{Info.Length}-C")
Dim Cached As String = ReadIni(PathTemp & "Cache\ModHash.ini", CacheKey)
- If Cached <> "" Then
+ If Cached <> "" AndAlso RegexCheck(Cached, "^\d+$") Then '#5062
_CurseForgeHash = Cached
Return _CurseForgeHash
End If
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
index d7285bd..487e0e6 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
@@ -1,4 +1,5 @@
Imports System.IO.Compression
+Imports System.Linq.Expressions
Public Module ModModpack
@@ -9,13 +10,22 @@ Public Module ModModpack
Public Sub ModpackInstall()
Dim File As String = SelectFile("整合包文件(*.rar;*.zip;*.mrpack)|*.rar;*.zip;*.mrpack", "选择整合包压缩文件") '选择整合包文件
If String.IsNullOrEmpty(File) Then Exit Sub
- RunInThread(Sub() ModpackInstall(File))
+ RunInThread(
+ Sub()
+ Try
+ ModpackInstall(File)
+ Catch ex As CancelledException
+ Catch ex As Exception
+ Log(ex, "手动安装整合包失败", LogLevel.Msgbox)
+ End Try
+ End Sub)
End Sub
'''
- ''' 安装一个给定的整合包文件,返回启动的安装加载器,如果未成功启动则返回 Nothing。
+ ''' 构建并启动安装给定的整合包文件的加载器,并返回该加载器。若失败则抛出异常。
''' 必须在工作线程执行。
'''
- Public Function ModpackInstall(File As String, Optional VersionName As String = Nothing, Optional ShowHint As Boolean = True, Optional Logo As String = Nothing) As LoaderCombo(Of String)
+ '''
+ Public Function ModpackInstall(File As String, Optional VersionName As String = Nothing, Optional Logo As String = Nothing) As LoaderCombo(Of String)
Log("[ModPack] 整合包安装请求:" & If(File, "null"))
Dim Archive As ZipArchive = Nothing
Dim ArchiveBaseFolder As String = ""
@@ -23,7 +33,7 @@ Public Module ModModpack
'获取整合包种类与关键 Json
Dim PackType As Integer = -1
Try
- Archive = New ZipArchive(New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ Archive = New ZipArchive(New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.Read))
'从根目录判断整合包类型
If Archive.GetEntry("mcbbs.packmeta") IsNot Nothing Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断)
If Archive.GetEntry("mmc-pack.json") IsNot Nothing Then PackType = 2 : Exit Try 'MMC 整合包(优先于 manifest.json 判断,#4194)
@@ -37,11 +47,11 @@ Public Module ModModpack
End If
End If
If Archive.GetEntry("modpack.json") IsNot Nothing Then PackType = 1 : Exit Try 'HMCL 整合包
+ If Archive.GetEntry("modpack.zip") IsNot Nothing OrElse Archive.GetEntry("modpack.mrpack") IsNot Nothing Then PackType = 9 : Exit Try '带启动器的压缩包
'从一级目录判断整合包类型
For Each Entry In Archive.Entries
Dim FullNames As String() = Entry.FullName.Split("/")
ArchiveBaseFolder = FullNames(0) & "/"
- If Entry.FullName.EndsWithF("/versions/") AndAlso FullNames.Count = 3 Then PackType = 9 : Exit Try '压缩包
'确定为一级目录下
If FullNames.Count <> 2 Then Continue For
'判断是否为关键文件
@@ -57,17 +67,15 @@ Public Module ModModpack
End If
End If
If FullNames(1) = "modpack.json" Then PackType = 1 : Exit Try 'HMCL 整合包
+ If FullNames(1) = "modpack.zip" OrElse FullNames(1) = "modpack.mrpack" Then PackType = 9 : Exit Try '带启动器的压缩包
Next
Catch ex As Exception
If GetExceptionDetail(ex, True).Contains("Error.WinIOError") Then
- Log(ex, "打开整合包文件失败", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
- Return Nothing
+ Throw New Exception("打开整合包文件失败", ex)
ElseIf File.EndsWithF(".rar", True) Then
- Log(ex, "PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
- Return Nothing
+ Throw New Exception("PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", ex)
Else
- Log(ex, "打开整合包文件失败,文件可能损坏或为不支持的压缩包格式", If(ShowHint, LogLevel.Hint, LogLevel.Normal))
- Return Nothing
+ Throw New Exception("打开整合包文件失败,文件可能损坏或为不支持的压缩包格式", ex)
End If
End Try
'执行对应的安装方法
@@ -88,21 +96,12 @@ Public Module ModModpack
Log("[ModPack] 整合包种类:Modrinth")
Return InstallPackModrinth(File, Archive, ArchiveBaseFolder, VersionName, Logo)
Case 9
- Log("[ModPack] 整合包种类:压缩包")
- Archive.Dispose()
- Archive = Nothing
- Return InstallPackCompress(File, ArchiveBaseFolder)
+ Log("[ModPack] 整合包种类:带启动器的压缩包")
+ Return InstallPackLauncherPack(File, Archive, ArchiveBaseFolder)
Case Else
- If ShowHint Then
- Hint("未能识别该整合包的种类,无法安装!", HintType.Critical)
- Else
- Log("[ModPack] 未能识别该整合包的种类,无法安装!")
- End If
- Return Nothing
+ Log("[ModPack] 整合包种类:未能识别,假定为压缩包")
+ Return InstallPackCompress(File, Archive)
End Select
- Catch ex As Exception
- Log(ex, "准备安装整合包失败", LogLevel.Feedback)
- Return Nothing
Finally
If Archive IsNot Nothing Then Archive.Dispose()
End Try
@@ -111,7 +110,7 @@ Public Module ModModpack
'整合包缓存清理
Private IsInstallCacheCleared As Boolean = False
Private IsInstallCacheClearing As Boolean = False
- Private Sub UnpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase)
+ Private Sub ExtractModpackFiles(InstallTemp As String, FileAddress As String, Loader As LoaderBase, LoaderProgressDelta As Double)
'清理缓存文件夹
If Not IsInstallCacheCleared Then
IsInstallCacheCleared = True
@@ -138,7 +137,7 @@ Public Module ModModpack
Retry:
'完全不知道为啥会出现文件正在被另一进程使用的问题,总之多试试
DeleteDirectory(InstallTemp)
- ExtractFile(FileAddress, InstallTemp, Encode)
+ ExtractFile(FileAddress, InstallTemp, Encode, ProgressIncrementHandler:=Sub(Delta) Loader.Progress += Delta * LoaderProgressDelta)
Catch ex As Exception
Log(ex, "第 " & RetryCount & " 次解压尝试失败")
If TypeOf ex Is ArgumentException Then
@@ -151,7 +150,7 @@ Retry:
RetryCount += 1
GoTo Retry
Else
- Throw
+ Throw New Exception("解压整合包文件失败", ex)
End If
End Try
End Sub
@@ -166,20 +165,18 @@ Retry:
Dim Json As JObject
Try
Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "manifest.json").Open))
- If Json("minecraft") Is Nothing OrElse Json("minecraft")("version") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息")
Catch ex As Exception
- Log(ex, "CurseForge 整合包安装信息存在问题", LogLevel.Hint)
- Return Nothing
+ Throw New Exception("CurseForge 整合包安装信息存在问题", ex)
End Try
+ If Json("minecraft") Is Nothing OrElse Json("minecraft")("version") Is Nothing Then Throw New Exception("CurseForge 整合包未提供 Minecraft 版本信息")
'获取版本名
- Dim ShowRibble As Boolean = VersionName Is Nothing
If VersionName Is Nothing Then
VersionName = If(Json("name"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(VersionName) <> "" Then VersionName = ""
If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
- If String.IsNullOrEmpty(VersionName) Then Return Nothing
+ If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
End If
'获取 Mod API 版本信息
@@ -190,35 +187,19 @@ Retry:
Dim Id As String = If(Entry("id"), "").ToString.ToLower
If Id.StartsWithF("forge-") Then
'Forge 指定
- If Id.Contains("recommended") Then
- Log("[ModPack] 该整合包版本过老,已不支持进行安装!", LogLevel.Hint)
- Return Nothing
- End If
- Try
- Log("[ModPack] 整合包 Forge 版本:" & Id)
- ForgeVersion = Id.Replace("forge-", "")
- Exit For
- Catch ex As Exception
- Log(ex, "读取整合包 Forge 版本失败:" & Id)
- End Try
+ If Id.Contains("recommended") Then Throw New Exception("该整合包版本过老,已不支持进行安装!")
+ Log("[ModPack] 整合包 Forge 版本:" & Id)
+ ForgeVersion = Id.Replace("forge-", "")
ElseIf Id.StartsWithF("neoforge-") Then
'NeoForge 指定
- Try
- Log("[ModPack] 整合包 NeoForge 版本:" & Id)
- NeoForgeVersion = Id.Replace("neoforge-", "")
- Exit For
- Catch ex As Exception
- Log(ex, "读取整合包 NeoForge 版本失败:" & Id)
- End Try
+ Log("[ModPack] 整合包 NeoForge 版本:" & Id)
+ NeoForgeVersion = Id.Replace("neoforge-", "")
ElseIf Id.StartsWithF("fabric-") Then
'Fabric 指定
- Try
- Log("[ModPack] 整合包 Fabric 版本:" & Id)
- FabricVersion = Id.Replace("fabric-", "")
- Exit For
- Catch ex As Exception
- Log(ex, "读取整合包 Fabric 版本失败:" & Id)
- End Try
+ Log("[ModPack] 整合包 Fabric 版本:" & Id)
+ FabricVersion = Id.Replace("fabric-", "")
+ Else
+ Log("[ModPack] 未知 Mod 加载器:" & Id)
End If
Next
'解压与配置文件
@@ -228,17 +209,17 @@ Retry:
If OverrideHome <> "" Then
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
- UnpackFiles(InstallTemp, FileAddress, Task)
- Task.Progress = 0.5
+ ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
+ Task.Progress = 0.6
Dim OverridePath As String = InstallTemp & ArchiveBaseFolder & OverrideHome
'复制结果
If Directory.Exists(OverridePath) Then
- CopyDirectory(OverridePath, PathMcFolder & "versions\" & VersionName)
+ CopyDirectory(OverridePath, PathMcFolder & "versions\" & VersionName, Sub(Delta) Task.Progress += Delta * 0.35)
Log($"[ModPack] 整合包 override 复制:{OverridePath} -> {PathMcFolder & "versions\" & VersionName}")
Else
Log($"[ModPack] 整合包中未找到 override 文件夹:{OverridePath}")
End If
- Task.Progress = 0.9
+ Task.Progress = 0.95
'开启版本隔离
WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
End Sub) With {
@@ -260,9 +241,11 @@ Retry:
'获取 Mod 下载信息
ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
Sub(Task As LoaderTask(Of Integer, JArray))
- Task.Output = GetJson(DlModRequest("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json"))("data")
+ '由于 MCIM 缺少下载信息,只使用官方源获取列表
+ 'TODO: 在 MCIM 源稳定后回调回 DlModRequest
+ Task.Output = GetJson(NetRequestRetry("https://api.curseforge.com/v1/mods/files", "POST", "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json"))("data")
'如果文件已被删除,则 API 会跳过那一项
- If ModList.Count > Task.Output.Count Then Throw New Exception("整合包所需要的部分 Mod 版本已被 Mod 作者删除,因此无法完成整合包安装,请联系整合包作者更新整合包中的 Mod 版本")
+ If ModList.Count > Task.Output.Count Then Throw New Exception("整合包中的部分 Mod 版本已被 Mod 作者删除,所以没法继续安装了,请向整合包作者反馈该问题")
End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s
'构造 NetFile
ModDownloadLoaders.Add(New LoaderTask(Of JArray, List(Of NetFile))("构造 Mod 下载信息",
@@ -320,7 +303,6 @@ Retry:
.FabricVersion = FabricVersion
}
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
- If MergeLoaders Is Nothing Then Return Nothing
'构造 Libraries 加载器
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
@@ -353,7 +335,7 @@ Retry:
Dim LoaderName As String = "CurseForge 整合包安装:" & VersionName & " "
If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
Hint("该整合包正在安装中!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End If
'启动
@@ -361,7 +343,7 @@ Retry:
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
- If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
+ RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
Return Loader
End Function
@@ -372,11 +354,10 @@ Retry:
Dim Json As JObject
Try
Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modrinth.index.json").Open))
- If Json("dependencies") Is Nothing OrElse Json("dependencies")("minecraft") Is Nothing Then Throw New Exception("整合包未提供 Minecraft 版本信息")
Catch ex As Exception
- Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
- Return Nothing
+ Throw New Exception("Modrinth 整合包安装信息存在问题", ex)
End Try
+ If Json("dependencies") Is Nothing OrElse Json("dependencies")("minecraft") Is Nothing Then Throw New Exception("Modrinth 整合包未提供 Minecraft 版本信息")
'获取 Mod API 版本信息
Dim MinecraftVersion As String = Nothing
Dim ForgeVersion As String = Nothing
@@ -397,39 +378,40 @@ Retry:
Log("[ModPack] 整合包 Fabric 版本:" & FabricVersion)
Case "quilt-loader" 'eg. 1.0.0
Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
Case Else
Hint($"无法安装整合包,其中出现了未知的 Mod 加载器 {Entry.Value}!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End Select
Next
'获取版本名
- Dim ShowRibble As Boolean = VersionName Is Nothing
If VersionName Is Nothing Then
VersionName = If(Json("name"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(VersionName) <> "" Then VersionName = ""
If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
- If String.IsNullOrEmpty(VersionName) Then Return Nothing
+ If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
End If
'解压和配置文件
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
Dim InstallLoaders As New List(Of LoaderBase)
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
- UnpackFiles(InstallTemp, FileAddress, Task)
- Task.Progress = 0.5
+ ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
+ Task.Progress = 0.6
'复制 overrides 文件夹和 client-overrides 文件夹
If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then
- CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName)
+ CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName,
+ Sub(Delta) Task.Progress += Delta * 0.25)
Else
Log("[ModPack] 整合包中未找到 override 目录,已跳过")
End If
- Task.Progress = 0.8
+ Task.Progress = 0.85
If Directory.Exists(InstallTemp & ArchiveBaseFolder & "client-overrides") Then
- CopyDirectory(InstallTemp & ArchiveBaseFolder & "client-overrides", PathMcFolder & "versions\" & VersionName)
+ CopyDirectory(InstallTemp & ArchiveBaseFolder & "client-overrides", PathMcFolder & "versions\" & VersionName,
+ Sub(Delta) Task.Progress += Delta * 0.1)
End If
- Task.Progress = 0.9
+ Task.Progress = 0.95
'开启版本隔离
WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
@@ -469,7 +451,6 @@ Retry:
.FabricVersion = FabricVersion
}
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
- If MergeLoaders Is Nothing Then Return Nothing
'构造 Libraries 加载器
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
@@ -502,7 +483,7 @@ Retry:
Dim LoaderName As String = "Modrinth 整合包安装:" & VersionName & " "
If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
Hint("该整合包正在安装中!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End If
'启动
@@ -510,9 +491,8 @@ Retry:
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
- If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
+ RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
Return Loader
-
End Function
'HMCL
@@ -522,44 +502,39 @@ Retry:
Try
Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modpack.json").Open, Encoding.UTF8))
Catch ex As Exception
- Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
- Return Nothing
+ Throw New Exception("HMCL 整合包安装信息存在问题", ex)
End Try
'获取版本名
Dim VersionName As String = If(Json("name"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(VersionName) <> "" Then VersionName = ""
If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
- If String.IsNullOrEmpty(VersionName) Then Return Nothing
+ If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
'解压与配置文件
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
Dim InstallLoaders As New List(Of LoaderBase)
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
- UnpackFiles(InstallTemp, FileAddress, Task)
- Task.Progress = 0.5
+ ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
+ Task.Progress = 0.6
'复制结果
If Directory.Exists(InstallTemp & ArchiveBaseFolder & "minecraft") Then
- CopyDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", PathMcFolder & "versions\" & VersionName)
+ CopyDirectory(InstallTemp & ArchiveBaseFolder & "minecraft", PathMcFolder & "versions\" & VersionName, Sub(Delta) Task.Progress += Delta * 0.35)
Else
Log("[ModPack] 整合包中未找到 minecraft override 目录,已跳过")
End If
- Task.Progress = 0.9
+ Task.Progress = 0.95
'开启版本隔离
WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
'构造加载器
- If Json("gameVersion") Is Nothing Then
- Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
- Return Nothing
- End If
+ If Json("gameVersion") Is Nothing Then Throw New Exception("该 HMCL 整合包未提供游戏版本信息,无法安装!")
Dim Request As New McInstallRequest With {
.TargetVersionName = VersionName,
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
.MinecraftName = Json("gameVersion").ToString
}
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
- If MergeLoaders Is Nothing Then Return Nothing
'构造 Libraries 加载器(为了使得 Mods 下载结束后再构造,这样才会下载 JumpLoader 文件)
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, String)("重命名版本 Json(副加载器)",
@@ -589,7 +564,7 @@ Retry:
Dim LoaderName As String = "HMCL 整合包安装:" & VersionName & " "
If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
Hint("该整合包正在安装中!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End If
'启动
@@ -598,7 +573,7 @@ Retry:
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
- FrmMain.BtnExtraDownload.Ribble()
+ RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
Return Loader
End Function
@@ -610,30 +585,29 @@ Retry:
PackJson = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "mmc-pack.json").Open, Encoding.UTF8))
PackInstance = ReadFile(Archive.GetEntry(ArchiveBaseFolder & "instance.cfg").Open, Encoding.UTF8)
Catch ex As Exception
- Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
- Return Nothing
+ Throw New Exception("MMC 整合包安装信息存在问题", ex)
End Try
'获取版本名
Dim VersionName As String = If(RegexSeek(PackInstance, "(?<=\nname\=)[^\n]+"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(VersionName) <> "" Then VersionName = ""
If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
- If String.IsNullOrEmpty(VersionName) Then Return Nothing
+ If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
'解压、配置设置文件
Dim InstallTemp As String = $"{PathTemp}PackInstall\{RandomInteger(0, 100000)}\"
Dim SetupFile As String = $"{PathMcFolder}versions\{VersionName}\PCL\Setup.ini"
Dim InstallLoaders As New List(Of LoaderBase)
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
- UnpackFiles(InstallTemp, FileAddress, Task)
- Task.Progress = 0.5
+ ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
+ Task.Progress = 0.6
'复制结果
If Directory.Exists(InstallTemp & ArchiveBaseFolder & ".minecraft") Then
- CopyDirectory(InstallTemp & ArchiveBaseFolder & ".minecraft", PathMcFolder & "versions\" & VersionName)
+ CopyDirectory(InstallTemp & ArchiveBaseFolder & ".minecraft", PathMcFolder & "versions\" & VersionName, Sub(Delta) Task.Progress += Delta * 0.35)
Else
Log("[ModPack] 整合包中未找到 override .minecraft 目录,已跳过")
End If
- Task.Progress = 0.9
+ Task.Progress = 0.95
'开启版本隔离
WriteIni(SetupFile, "VersionArgumentIndie", 1)
'读取 MMC 设置文件(#2655)
@@ -676,10 +650,7 @@ Retry:
End Try
End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
'构造版本安装请求
- If PackJson("components") Is Nothing Then
- Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
- Return Nothing
- End If
+ If PackJson("components") Is Nothing Then Throw New Exception("该 MMC 整合包未提供游戏版本信息,无法安装!")
Dim Request As New McInstallRequest With {.TargetVersionName = VersionName, .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\"}
For Each Component In PackJson("components")
Select Case If(Component("uid"), "").ToString
@@ -695,12 +666,11 @@ Retry:
Request.FabricVersion = Component("version")
Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End Select
Next
'构造加载器
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
- If MergeLoaders Is Nothing Then Return Nothing
'构造 Libraries 加载器
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
@@ -715,7 +685,7 @@ Retry:
Dim LoaderName As String = "MMC 整合包安装:" & VersionName & " "
If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
Hint("该整合包正在安装中!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End If
'启动
@@ -723,7 +693,7 @@ Retry:
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
- FrmMain.BtnExtraDownload.Ribble()
+ RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
Return Loader
End Function
@@ -736,51 +706,44 @@ Retry:
Dim Entry = If(Archive.GetEntry(ArchiveBaseFolder & "mcbbs.packmeta"), Archive.GetEntry(ArchiveBaseFolder & "manifest.json"))
Json = GetJson(ReadFile(Entry.Open, Encoding.UTF8))
Catch ex As Exception
- Log(ex, "整合包安装信息存在问题", LogLevel.Hint)
- Return Nothing
+ Throw New Exception("MCBBS 整合包安装信息存在问题", ex)
End Try
'获取版本名
- Dim ShowRibble As Boolean = VersionName Is Nothing
If VersionName Is Nothing Then
VersionName = If(Json("name"), "")
Dim Validate As New ValidateFolderName(PathMcFolder & "versions")
If Validate.Validate(VersionName) <> "" Then VersionName = ""
If VersionName = "" Then VersionName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate})
- If String.IsNullOrEmpty(VersionName) Then Return Nothing
+ If String.IsNullOrEmpty(VersionName) Then Throw New CancelledException
End If
'解压与配置文件
Dim InstallTemp As String = PathTemp & "PackInstall\" & RandomInteger(0, 100000) & "\"
Dim InstallLoaders As New List(Of LoaderBase)
InstallLoaders.Add(New LoaderTask(Of String, Integer)("解压整合包文件",
Sub(Task As LoaderTask(Of String, Integer))
- UnpackFiles(InstallTemp, FileAddress, Task)
- Task.Progress = 0.5
+ ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6)
+ Task.Progress = 0.6
'复制结果
If Directory.Exists(InstallTemp & ArchiveBaseFolder & "overrides") Then
- CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName)
+ CopyDirectory(InstallTemp & ArchiveBaseFolder & "overrides", PathMcFolder & "versions\" & VersionName,
+ Sub(Delta) Task.Progress += 0.35 * Delta)
Else
Log("[ModPack] 整合包中未找到 overrides 目录,已跳过")
End If
- Task.Progress = 0.9
+ Task.Progress = 0.95
'开启版本隔离
WriteIni(PathMcFolder & "versions\" & VersionName & "\PCL\Setup.ini", "VersionArgumentIndie", 1)
End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s
'构造加载器
- If Json("addons") Is Nothing Then
- Hint("该整合包未提供游戏版本附加信息,无法安装!", HintType.Critical)
- Return Nothing
- End If
+ If Json("addons") Is Nothing Then Throw New Exception("该 MCBBS 整合包未提供游戏版本附加信息,无法安装!")
Dim Addons As New Dictionary(Of String, String)
For Each Entry In Json("addons")
Addons.Add(Entry("id"), Entry("version"))
Next
- If Not Addons.ContainsKey("game") Then
- Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
- Return Nothing
- End If
+ If Not Addons.ContainsKey("game") Then Throw New Exception("该 MCBBS 整合包未提供游戏版本信息,无法安装!")
If Addons.ContainsKey("quilt") Then
Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End If
Dim Request As New McInstallRequest With {
.TargetVersionName = VersionName,
@@ -792,7 +755,6 @@ Retry:
.FabricVersion = If(Addons.ContainsKey("fabric"), Addons("fabric"), Nothing)
}
Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request, True)
- If MergeLoaders Is Nothing Then Return Nothing
'构造 Libraries 加载器
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionName))) With {.ProgressWeight = 1, .Show = False})
@@ -807,7 +769,7 @@ Retry:
Dim LoaderName As String = "MCBBS 整合包安装:" & VersionName & " "
If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then
Hint("该整合包正在安装中!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End If
'启动
@@ -816,31 +778,101 @@ Retry:
Loader.Start(Request.TargetVersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
- If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
+ RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
+ Return Loader
+ End Function
+
+ '带启动器的压缩包
+ Private Function InstallPackLauncherPack(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String) As LoaderCombo(Of String)
+ '获取解压路径
+ MyMsgBox("接下来请选择一个空文件夹,它会被安装到这个文件夹里。", "安装", "继续", ForceWait:=True)
+ Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)")
+ If String.IsNullOrEmpty(TargetFolder) Then Throw New CancelledException
+ If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Throw New CancelledException
+ If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Throw New CancelledException
+ '解压
+ Dim Loader As New LoaderCombo(Of String)("解压压缩包", {
+ New LoaderTask(Of String, Integer)("解压压缩包",
+ Sub(Task As LoaderTask(Of String, Integer))
+ ExtractModpackFiles(TargetFolder, FileAddress, Task, 0.9)
+ Thread.Sleep(400) '避免文件争用
+ '查找解压后的 exe 文件
+ Dim Launcher As String = Nothing
+ For Each ExeFile In Directory.GetFiles(TargetFolder, "*.exe", SearchOption.AllDirectories)
+ Dim Info = FileVersionInfo.GetVersionInfo(ExeFile)
+ Log($"[Modpack] 文件 {ExeFile} 的产品名标识为 {Info.ProductName}")
+ If Info.ProductName = "Plain Craft Launcher" Then
+ Launcher = ExeFile
+ ElseIf (Info.ProductName.ContainsF("Launcher", True) OrElse Info.ProductName.ContainsF("启动器", True)) AndAlso
+ Not Info.ProductName = "Plain Craft Launcher Admin Manager" Then
+ If Launcher Is Nothing Then Launcher = ExeFile
+ End If
+ Next
+ Task.Progress = 0.95
+ '尝试使用附带的启动器打开
+ If Launcher IsNot Nothing Then
+ Log("[Modpack] 找到压缩包中附带的启动器:" & Launcher)
+ If MyMsgBox($"整合包中似乎自带了启动器,是否换用它继续安装?{vbCrLf}通常推荐这样做,以获得最佳体验。{vbCrLf}即将打开:{Launcher}", "换用整合包启动器?", "继续", "取消") = 1 Then
+ ShellOnly(Launcher, "--wait")
+ Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序")
+ FrmMain.EndProgram(False)
+ Return
+ End If
+ Else
+ Log("[Modpack] 未找到压缩包中附带的启动器")
+ End If
+ '加入文件夹列表
+ Dim VersionName As String = GetFolderNameFromPath(TargetFolder)
+ PageSelectLeft.AddFolder(
+ TargetFolder & ArchiveBaseFolder.Replace("/", "\").TrimStart("\"), '格式例如:包裹文件夹\.minecraft\(最短为空字符串)
+ VersionName, False)
+ '调用 modpack 文件进行安装
+ Dim ModpackFile = Directory.GetFiles(TargetFolder, "modpack.*", SearchOption.AllDirectories).First
+ Log("[Modpack] 调用 modpack 文件继续安装:" & ModpackFile)
+ ModpackInstall(ModpackFile, VersionName)
+ End Sub)
+ })
+ Loader.Start(TargetFolder)
+ LoaderTaskbarAdd(Loader)
+ FrmMain.BtnExtraDownload.ShowRefresh()
+ FrmMain.BtnExtraDownload.Ribble()
Return Loader
End Function
'普通压缩包
- Private Function InstallPackCompress(FileAddress As String, ArchiveBaseFolder As String) As LoaderCombo(Of String)
- MyMsgBox("请在接下来打开的窗口中选择安装目标文件夹,它必须是一个空文件夹。", "安装提示", "继续", ForceWait:=True)
+ Private Function InstallPackCompress(FileAddress As String, Archive As Compression.ZipArchive) As LoaderCombo(Of String)
+ '尝试定位 .minecraft 文件夹:寻找形如 “/versions/XXX/XXX.json” 的路径
+ Dim Match As RegularExpressions.Match = Nothing
+ Dim Regex As New RegularExpressions.Regex("^.*\/(?=versions\/(?[^\/]+)\/(\k)\.json$)", RegularExpressions.RegexOptions.IgnoreCase)
+ For Each Entry In Archive.Entries
+ Dim EntryMatch = Regex.Match("/" & Entry.FullName)
+ If EntryMatch.Success Then
+ Match = EntryMatch
+ Exit For
+ End If
+ Next
+ If Match Is Nothing Then Throw New Exception("未能找到适合的文件结构,这可能不是一个 MC 压缩包") '没有匹配
+ Dim ArchiveBaseFolder As String = Match.Value.Replace("/", "\").TrimStart("\") '格式例如:包裹文件夹\.minecraft\(最短为空字符串)
+ Dim VersionName As String = Match.Groups(1).Value
+ Log("[ModPack] 检测到压缩包的 .minecraft 根目录:" & ArchiveBaseFolder & ",命中的版本名:" & VersionName)
'获取解压路径
+ MyMsgBox("接下来请选择一个空文件夹,它会被安装到这个文件夹里。", "安装", "继续", ForceWait:=True)
Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)")
- If String.IsNullOrEmpty(TargetFolder) Then Return Nothing
- If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Return Nothing
- If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Return Nothing
- '要求显示名称
- Dim NewName As String = MyMsgBoxInput("输入显示名称", "输入该文件夹在左边栏列表中显示的名称。", GetFolderNameFromPath(TargetFolder),
- New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})})
- If String.IsNullOrWhiteSpace(NewName) Then Return Nothing
+ If String.IsNullOrEmpty(TargetFolder) Then Throw New CancelledException
+ If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Throw New CancelledException
+ If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Throw New CancelledException
'解压
- Dim Loader As New LoaderCombo(Of String)("安装压缩包", {
- New LoaderTask(Of String, Integer)("安装压缩包",
- Sub()
- UnpackFiles(TargetFolder, FileAddress, Nothing)
- PageSelectLeft.AddFolder(TargetFolder, NewName, False) '加入文件夹列表
- End Sub)
- })
- Loader.Start()
+ Dim Loader As New LoaderCombo(Of String)("解压压缩包", {
+ New LoaderTask(Of String, Integer)("解压压缩包",
+ Sub(Task As LoaderTask(Of String, Integer))
+ ExtractModpackFiles(TargetFolder, FileAddress, Task, 0.95)
+ '加入文件夹列表
+ PageSelectLeft.AddFolder(TargetFolder & ArchiveBaseFolder, GetFolderNameFromPath(TargetFolder), False)
+ Thread.Sleep(400) '避免文件争用
+ RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.VersionSelect))
+ End Sub)
+ }) With {.OnStateChanged = AddressOf McInstallState}
+ Loader.Start(TargetFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml.vb b/Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml.vb
index 5b03a13..d3bcaf4 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/MyCompItem.xaml.vb
@@ -96,7 +96,7 @@
'记录当前展开的卡片标题(#2712)
Dim Titles As New List(Of String)
If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
- For Each Card As MyCard In FrmDownloadCompDetail.PanMain.Children
+ For Each Card As MyCard In FrmDownloadCompDetail.PanResults.Children
If Card.Title <> "" AndAlso Not Card.IsSwaped Then Titles.Add(Card.Title)
Next
Log("[Comp] 记录当前已展开的卡片:" & String.Join("、", Titles))
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml
index d626409..445f44b 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml
+++ b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml
@@ -30,12 +30,12 @@
-
+
-
+
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb
index df794e6..f826928 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb
+++ b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb
@@ -303,30 +303,33 @@ Public Class MyLocalModItem
#End Region
+ Private Function GetUpdateCompareDescription() As String
+ Dim CurrentName = Entry.CompFile.FileName.Replace(".jar", "")
+ Dim NewestName = Entry.UpdateFile.FileName.Replace(".jar", "")
+ '简化名称对比
+ Dim CurrentSegs = CurrentName.Split("-"c).ToList()
+ Dim NewestSegs = NewestName.Split("-"c).ToList()
+ Dim Shortened As Boolean = False
+ For Each Seg In CurrentSegs.ToList()
+ If Not NewestSegs.Contains(Seg) Then Continue For
+ CurrentSegs.Remove(Seg)
+ NewestSegs.Remove(Seg)
+ Shortened = True
+ Next
+ If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then
+ CurrentName = Join(CurrentSegs, "-")
+ NewestName = Join(NewestSegs, "-")
+ Entry._Version = CurrentName '使用网络信息作为显示的版本号
+ End If
+ Return $"当前版本:{CurrentName}({GetTimeSpanString(Entry.CompFile.ReleaseDate - Date.Now, False)}){vbCrLf}最新版本:{NewestName}({GetTimeSpanString(Entry.UpdateFile.ReleaseDate - Date.Now, False)})"
+ End Function
Public Sub Refresh() Handles Me.Loaded
RunInUi(
Sub()
'更新
If Entry.CanUpdate Then
BtnUpdate.Visibility = Visibility.Visible
- Dim CurrentName = Entry.CompFile.FileName.Replace(".jar", "")
- Dim NewestName = Entry.UpdateFile.FileName.Replace(".jar", "")
- '简化名称对比
- Dim CurrentSegs = CurrentName.Split("-"c).ToList()
- Dim NewestSegs = NewestName.Split("-"c).ToList()
- Dim Shortened As Boolean = False
- For Each Seg In CurrentSegs.ToList()
- If Not NewestSegs.Contains(Seg) Then Continue For
- CurrentSegs.Remove(Seg)
- NewestSegs.Remove(Seg)
- Shortened = True
- Next
- If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then
- CurrentName = Join(CurrentSegs, "-")
- NewestName = Join(NewestSegs, "-")
- Entry._Version = CurrentName '使用网络信息作为显示的版本号
- End If
- BtnUpdate.ToolTip = $"当前版本:{CurrentName} ({Entry.CompFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}最新版本:{NewestName} ({Entry.UpdateFile.ReleaseDate:yyyy/MM/dd HH:mm:ss}){vbCrLf}点击以更新,右键查看更新日志。"
+ BtnUpdate.ToolTip = $"{GetUpdateCompareDescription()}{vbCrLf}点击以更新,右键查看更新日志。"
Else
BtnUpdate.Visibility = Visibility.Collapsed
End If
@@ -476,20 +479,57 @@ Public Class MyLocalModItem
'触发更新
Private Sub BtnUpdate_Click(sender As Object, e As EventArgs) Handles BtnUpdate.Click
+ If MyMsgBox($"是否要更新 {Entry.Name}?{vbCrLf}{vbCrLf}{GetUpdateCompareDescription()}", "Mod 更新确认", "更新", "取消") = 2 Then Return
FrmVersionMod.UpdateMods({Entry})
End Sub
'自适应(#4465)
- Private Sub PanTitle_SizeChanged(sender As Object, e As SizeChangedEventArgs) Handles PanTitle.SizeChanged
- If ColumnExtend.Width.IsStar AndAlso ColumnExtend.ActualWidth < 0.5 Then
- '压缩 Subtitle
- ColumnSubtitle.Width = New GridLength(1, GridUnitType.Star)
- ColumnExtend.Width = New GridLength(0, GridUnitType.Pixel)
- ElseIf Not ColumnExtend.Width.IsStar AndAlso Not LabSubtitle.IsTextTrimmed Then
- '向右展开 Subtitle
- ColumnSubtitle.Width = GridLength.Auto
- ColumnExtend.Width = New GridLength(1, GridUnitType.Star)
- End If
+ Private Sub PanTitle_SizeChanged() Handles PanTitle.SizeChanged
+ '0:全部舒展:Auto - Auto - (Auto) - 1*
+ '1:压缩 Subtitle:Auto - 1* - (Auto) - 0
+ '2:继续压缩 Title:1* - 0 - (Auto) - 0
+ Dim CurrentCompressLevel As Integer =
+ If(ColumnExtend.Width.IsStar, 0, If(ColumnTitle.Width.IsStar, 2, 1)) 'Subtitle 可能是 Collapsed
+ Dim NewCompressLevel As Integer
+ Select Case CurrentCompressLevel
+ Case 0
+ If ColumnExtend.ActualWidth < 0.5 Then
+ NewCompressLevel = If(LabSubtitle.Visibility = Visibility.Collapsed, 2, 1)
+ Else
+ Return
+ End If
+ Case 1
+ If ColumnSubtitle.ActualWidth < 0.5 Then
+ NewCompressLevel = 2
+ ElseIf Not LabSubtitle.IsTextTrimmed Then
+ NewCompressLevel = 0
+ Else
+ Return
+ End If
+ Case 2
+ If Not LabTitle.IsTextTrimmed Then
+ NewCompressLevel = If(LabSubtitle.Visibility = Visibility.Collapsed, 0, 1)
+ Else
+ Return
+ End If
+ End Select
+ Select Case NewCompressLevel
+ Case 0
+ '全部舒展:Auto - Auto - (Auto) - 1*
+ ColumnTitle.Width = GridLength.Auto
+ ColumnSubtitle.Width = GridLength.Auto
+ ColumnExtend.Width = New GridLength(1, GridUnitType.Star)
+ Case 1
+ '压缩 Subtitle:Auto - 1* - (Auto) - 0
+ ColumnTitle.Width = GridLength.Auto
+ ColumnSubtitle.Width = New GridLength(1, GridUnitType.Star)
+ ColumnExtend.Width = New GridLength(0, GridUnitType.Pixel)
+ Case 2
+ '继续压缩 Title:1* - 0 - (Auto) - 0
+ ColumnTitle.Width = New GridLength(1, GridUnitType.Star)
+ ColumnSubtitle.Width = New GridLength(0, GridUnitType.Pixel)
+ ColumnExtend.Width = New GridLength(0, GridUnitType.Pixel)
+ End Select
End Sub
End Class
diff --git a/Plain Craft Launcher 2/Modules/ModEvent.vb b/Plain Craft Launcher 2/Modules/ModEvent.vb
index 9c29699..be69955 100644
--- a/Plain Craft Launcher 2/Modules/ModEvent.vb
+++ b/Plain Craft Launcher 2/Modules/ModEvent.vb
@@ -139,7 +139,6 @@
Dim LocalTemp1 As String = PathTemp & "CustomEvent\" & RawFileName
Dim LocalTemp2 As String = PathTemp & "CustomEvent\" & RawFileName.Replace(".json", ".xaml")
Log("[Event] 转换网络资源:" & RelativeUrl & " -> " & LocalTemp1)
- Hint("正在获取资源,请稍候……")
Try
NetDownload(RelativeUrl, LocalTemp1)
NetDownload(RelativeUrl.Replace(".json", ".xaml"), LocalTemp1.Replace(".json", ".xaml"))
diff --git a/Plain Craft Launcher 2/Modules/ModMain.vb b/Plain Craft Launcher 2/Modules/ModMain.vb
index e629d76..e93cb74 100644
--- a/Plain Craft Launcher 2/Modules/ModMain.vb
+++ b/Plain Craft Launcher 2/Modules/ModMain.vb
@@ -443,6 +443,10 @@ EndHint:
#Region "帮助"
Public Class HelpEntry
+ '''
+ ''' 原始信息路径。用于刷新。
+ '''
+ Public RawPath As String
'基础
@@ -501,6 +505,7 @@ EndHint:
''' 从文件初始化 HelpEntry 对象,失败会抛出异常。
'''
Public Sub New(FilePath As String)
+ RawPath = FilePath
Dim JsonData As JObject = GetJson(HelpArgumentReplace(ReadFile(FilePath)))
If JsonData Is Nothing Then Throw New FileNotFoundException("未找到帮助文件:" & FilePath, FilePath)
'加载常规信息
@@ -598,7 +603,7 @@ EndHint:
'加载忽略列表
Log("[Help] 发现 .helpignore 文件:" & File.FullName)
For Each Line In ReadFile(File.FullName).Split(vbCrLf.ToCharArray)
- Dim RealString As String = Line.Before("#").Trim
+ Dim RealString As String = Line.BeforeFirst("#").Trim
If String.IsNullOrWhiteSpace(RealString) Then Continue For
IgnoreList.Add(RealString)
If ModeDebug Then Log("[Help] > " & RealString)
diff --git a/Plain Craft Launcher 2/Modules/ModMusic.vb b/Plain Craft Launcher 2/Modules/ModMusic.vb
index da27e44..12de669 100644
--- a/Plain Craft Launcher 2/Modules/ModMusic.vb
+++ b/Plain Craft Launcher 2/Modules/ModMusic.vb
@@ -17,8 +17,8 @@ Public Module ModMusic
''' 初始化音乐播放列表。
'''
''' 强制全部重新载入列表。
- ''' 在重载列表时避免让某项成为第一项。
- Private Sub MusicListInit(ForceReload As Boolean, Optional IgnoreFirst As String = "")
+ ''' 在重载列表时避免让某项成为第一项。
+ Private Sub MusicListInit(ForceReload As Boolean, Optional PreventFirst As String = Nothing)
If ForceReload Then MusicAllList = Nothing
Try
'初始化全部可用音乐列表
@@ -34,10 +34,10 @@ Public Module ModMusic
End If
'打乱顺序播放
MusicWaitingList = If(Setup.Get("UiMusicRandom"), Shuffle(New List(Of String)(MusicAllList)), New List(Of String)(MusicAllList))
- If Not IgnoreFirst = "" AndAlso Not Not MusicWaitingList.Any() AndAlso MusicWaitingList(0) = IgnoreFirst Then
+ If PreventFirst IsNot Nothing AndAlso MusicWaitingList.FirstOrDefault = PreventFirst Then
'若需要避免成为第一项的为第一项,则将它放在最后
MusicWaitingList.RemoveAt(0)
- MusicWaitingList.Add(IgnoreFirst)
+ MusicWaitingList.Add(PreventFirst)
End If
Catch ex As Exception
Log(ex, "初始化音乐列表失败", LogLevel.Feedback)
@@ -45,13 +45,18 @@ Public Module ModMusic
End Sub
'''
''' 获取下一首播放的音乐路径并将其从列表中移除。
+ ''' 如果没有,可能会返回 Nothing。
'''
Private Function DequeueNextMusicAddress() As String
'初始化,确保存在音乐
If MusicAllList Is Nothing OrElse Not MusicAllList.Any() OrElse Not MusicWaitingList.Any() Then MusicListInit(False)
'出列下一个音乐,如果出列结束则生成新列表
- DequeueNextMusicAddress = MusicWaitingList(0)
- MusicWaitingList.RemoveAt(0)
+ If MusicWaitingList.Any() Then
+ DequeueNextMusicAddress = MusicWaitingList(0)
+ MusicWaitingList.RemoveAt(0)
+ Else
+ DequeueNextMusicAddress = Nothing
+ End If
If Not MusicWaitingList.Any() Then MusicListInit(False, DequeueNextMusicAddress)
End Function
@@ -63,44 +68,45 @@ Public Module ModMusic
''' 刷新背景音乐按钮 UI 与设置页 UI。
'''
Private Sub MusicRefreshUI()
- RunInUi(Sub()
- Try
+ RunInUi(
+ Sub()
+ Try
- If Not MusicAllList.Any() Then
- '无背景音乐
- FrmMain.BtnExtraMusic.Show = False
+ If Not MusicAllList.Any() Then
+ '无背景音乐
+ FrmMain.BtnExtraMusic.Show = False
+ Else
+ '有背景音乐
+ FrmMain.BtnExtraMusic.Show = True
+ Dim ToolTipText As String
+ If MusicState = MusicStates.Pause Then
+ FrmMain.BtnExtraMusic.Logo = Logo.IconPlay
+ FrmMain.BtnExtraMusic.LogoScale = 0.8
+ ToolTipText = "已暂停:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
+ If MusicAllList.Count > 1 Then
+ ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。"
Else
- '有背景音乐
- FrmMain.BtnExtraMusic.Show = True
- Dim ToolTipText As String
- If MusicState = MusicStates.Pause Then
- FrmMain.BtnExtraMusic.Logo = Logo.IconPlay
- FrmMain.BtnExtraMusic.LogoScale = 0.8
- ToolTipText = "已暂停:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
- If MusicAllList.Count > 1 Then
- ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。"
- Else
- ToolTipText += vbCrLf & "左键恢复播放,右键重新从头播放。"
- End If
- Else
- FrmMain.BtnExtraMusic.Logo = Logo.IconMusic
- FrmMain.BtnExtraMusic.LogoScale = 1
- ToolTipText = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
- If MusicAllList.Count > 1 Then
- ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。"
- Else
- ToolTipText += vbCrLf & "左键暂停,右键重新从头播放。"
- End If
- End If
- FrmMain.BtnExtraMusic.ToolTip = ToolTipText
- ToolTipService.SetVerticalOffset(FrmMain.BtnExtraMusic, If(ToolTipText.Contains(vbLf), 10, 16))
+ ToolTipText += vbCrLf & "左键恢复播放,右键重新从头播放。"
End If
- If FrmSetupUI IsNot Nothing Then FrmSetupUI.MusicRefreshUI()
+ Else
+ FrmMain.BtnExtraMusic.Logo = Logo.IconMusic
+ FrmMain.BtnExtraMusic.LogoScale = 1
+ ToolTipText = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
+ If MusicAllList.Count > 1 Then
+ ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。"
+ Else
+ ToolTipText += vbCrLf & "左键暂停,右键重新从头播放。"
+ End If
+ End If
+ FrmMain.BtnExtraMusic.ToolTip = ToolTipText
+ ToolTipService.SetVerticalOffset(FrmMain.BtnExtraMusic, If(ToolTipText.Contains(vbLf), 10, 16))
+ End If
+ If FrmSetupUI IsNot Nothing Then FrmSetupUI.MusicRefreshUI()
- Catch ex As Exception
- Log(ex, "刷新背景音乐 UI 失败", LogLevel.Feedback)
- End Try
- End Sub)
+ Catch ex As Exception
+ Log(ex, "刷新背景音乐 UI 失败", LogLevel.Feedback)
+ End Try
+ End Sub)
End Sub
'''
@@ -131,8 +137,12 @@ Public Module ModMusic
Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Finish)
Else
Dim Address As String = DequeueNextMusicAddress()
- MusicStartPlay(Address)
- Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish)
+ If Address Is Nothing Then
+ Hint("没有可以播放的音乐!", HintType.Critical)
+ Else
+ MusicStartPlay(Address)
+ Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish)
+ End If
End If
MusicRefreshUI()
End Sub
@@ -182,11 +192,15 @@ Public Module ModMusic
End If
Else
Dim Address As String = DequeueNextMusicAddress()
- Try
- MusicStartPlay(Address, IsFirstLoad)
- If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Finish, False)
- Catch
- End Try
+ If Address Is Nothing Then
+ If ShowHint Then Hint("没有可以播放的音乐!", HintType.Critical)
+ Else
+ Try
+ MusicStartPlay(Address, IsFirstLoad)
+ If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Finish, False)
+ Catch
+ End Try
+ End If
End If
MusicRefreshUI()
@@ -198,6 +212,7 @@ Public Module ModMusic
''' 开始播放音乐。
'''
Private Sub MusicStartPlay(Address As String, Optional IsFirstLoad As Boolean = False)
+ If Address Is Nothing Then Return
Log("[Music] 播放开始:" & Address)
MusicCurrent = Address
RunInNewThread(Sub() MusicLoop(IsFirstLoad), "Music", ThreadPriority.BelowNormal)
@@ -292,15 +307,21 @@ Public Module ModMusic
End If
If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 不支持播放音频属性在中途发生变化的音乐", HintType.Critical)
- ElseIf Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) Then
+ ElseIf Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse
+ ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4)
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Critical)
Else
Log(ex, "播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & ")", LogLevel.Hint)
End If
- Thread.Sleep(1000)
+ '将播放错误的音乐从列表中移除
+ MusicAllList.Remove(MusicCurrent)
+ MusicWaitingList.Remove(MusicCurrent)
+ MusicRefreshUI()
+ '等待 2 秒后继续播放
+ Thread.Sleep(2000)
If TypeOf ex Is FileNotFoundException Then
MusicRefreshPlay(True, IsFirstLoad)
- ElseIf MusicAllList.Count > 1 Then
+ Else
MusicStartPlay(DequeueNextMusicAddress(), IsFirstLoad)
End If
Finally
diff --git a/Plain Craft Launcher 2/Modules/ModSecret.vb b/Plain Craft Launcher 2/Modules/ModSecret.vb
index fb7644c..52fd4d2 100644
--- a/Plain Craft Launcher 2/Modules/ModSecret.vb
+++ b/Plain Craft Launcher 2/Modules/ModSecret.vb
@@ -109,7 +109,7 @@ Friend Module ModSecret
Client.Headers("User-Agent") = "PCL2/" & VersionStandardCode
End If
Client.Headers("Referer") = "http://" & VersionCode & ".pcl2.open.server/"
- Client.Headers("x-api-key") = CurseForgeAPIKey
+ If Url.Contains("api.curseforge.com") Then Client.Headers("x-api-key") = CurseForgeAPIKey
End Sub
'''
''' 设置 Headers 的 UA、Referer。
@@ -123,7 +123,7 @@ Friend Module ModSecret
Request.UserAgent = "PCL2/" & VersionStandardCode
End If
Request.Referer = "http://" & VersionCode & ".pcl2.open.server/"
- Request.Headers("x-api-key") = CurseForgeAPIKey
+ If Url.Contains("api.curseforge.com") Then Request.Headers("x-api-key") = CurseForgeAPIKey
End Sub
#End Region
diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb
index 400835c..5f7dcd9 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 8a62135..ff7ec51 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb
@@ -236,7 +236,15 @@ Public Module ModDownloadLib
Sub(Task As LoaderTask(Of String, List(Of NetFile)))
'分析服务端 JAR 文件下载地址
Dim McVersion As New McVersion(VersionFolder)
- If McVersion.JsonObject("downloads") Is Nothing OrElse McVersion.JsonObject("downloads")("server") Is Nothing OrElse McVersion.JsonObject("downloads")("server")("url") Is Nothing Then Throw New Exception($"{Id} 版本没有提供服务端文件")
+ If McVersion.JsonObject("downloads") Is Nothing OrElse McVersion.JsonObject("downloads")("server") Is Nothing OrElse McVersion.JsonObject("downloads")("server")("url") Is Nothing Then
+ File.Delete(VersionFolder & Id & ".json")
+ If Not New DirectoryInfo(VersionFolder).GetFileSystemInfos.Any() Then Directory.Delete(VersionFolder)
+ Task.Output = New List(Of NetFile)
+ Hint($"Mojang 没有给 Minecraft {Id} 提供官方服务端下载,没法下,撤退!", HintType.Critical)
+ Thread.Sleep(2000) '等玩家把上一个提示看完
+ Task.Abort()
+ Exit Sub
+ End If
Dim JarUrl As String = McVersion.JsonObject("downloads")("server")("url")
Dim Checker As New FileChecker(MinSize:=1024, ActualSize:=If(McVersion.JsonObject("downloads")("server")("size"), -1), Hash:=McVersion.JsonObject("downloads")("server")("sha1"))
Task.Output = New List(Of NetFile) From {New NetFile(DlSourceLauncherOrMetaGet(JarUrl), VersionFolder & Id & "-server.jar", Checker)}
@@ -551,10 +559,12 @@ pause"
Task.Progress = 0.1
Dim Sources As New List(Of String)
'BMCLAPI 源
+ Dim BmclapiInherit As String = DownloadInfo.Inherit
+ If BmclapiInherit = "1.8" OrElse BmclapiInherit = "1.9" Then BmclapiInherit &= ".0" '#4281
If DownloadInfo.IsPreview Then
- Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
+ Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & BmclapiInherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
Else
- Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
+ Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & BmclapiInherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
End If
'官方源
Dim PageData As String
@@ -562,12 +572,10 @@ pause"
PageData = NetGetCodeByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile, New UTF8Encoding(False), 15000, "text/html", True)
Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
- Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources(0))
+ Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last)
Catch ex As Exception
Log(ex, "获取 OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址失败")
End Try
- 'OptiFine 中文镜像源
- Sources.Add("https://optifine.cn/download/" & DownloadInfo.NameFile)
'构造文件请求
Task.Output = New List(Of NetFile) From {New NetFile(Sources.ToArray, Target, New FileChecker(MinSize:=300 * 1024))}
End Sub) With {.ProgressWeight = 8})
@@ -714,10 +722,12 @@ Retry:
Sub(Task As LoaderTask(Of DlOptiFineListEntry, List(Of NetFile)))
Dim Sources As New List(Of String)
'BMCLAPI 源
+ Dim BmclapiInherit As String = DownloadInfo.Inherit
+ If BmclapiInherit = "1.8" OrElse BmclapiInherit = "1.9" Then BmclapiInherit &= ".0" '#4281
If DownloadInfo.IsPreview Then
- Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
+ Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & BmclapiInherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
Else
- Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
+ Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & BmclapiInherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
End If
'官方源
Dim PageData As String
@@ -725,7 +735,7 @@ Retry:
PageData = NetGetCodeByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile, New UTF8Encoding(False), 15000, "text/html", True)
Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
- Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources(0))
+ Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last)
Catch ex As Exception
Log(ex, "获取 OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址失败")
End Try
@@ -1248,8 +1258,8 @@ Retry:
End If
If Not IsNeoForge AndAlso LoaderVersion.StartsWithF("1.") AndAlso LoaderVersion.Contains("-") Then
'类似 1.19.3-41.2.8 格式,优先使用 Version 中要求的版本而非 Inherit(例如 1.19.3 却使用了 1.19 的 Forge)
- Inherit = LoaderVersion.Before("-")
- LoaderVersion = LoaderVersion.After("-")
+ Inherit = LoaderVersion.BeforeFirst("-")
+ LoaderVersion = LoaderVersion.AfterLast("-")
End If
Dim LoaderName As String = If(IsNeoForge, "NeoForge", "Forge")
Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
@@ -1309,7 +1319,7 @@ Retry:
Loaders.Add(New LoaderDownload($"下载 {LoaderName} 主文件", New List(Of NetFile)) With {.ProgressWeight = 9})
'安装(仅在新版安装时需要原版 Jar)
- If IsNeoForge OrElse LoaderVersion.Before(".") >= 20 Then
+ If IsNeoForge OrElse LoaderVersion.BeforeFirst(".") >= 20 Then
Log($"[Download] 检测为{If(IsNeoForge, " Neo", "新版 ")}Forge:" & LoaderVersion)
Dim Libs As List(Of McLibToken) = Nothing
Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"分析 {LoaderName} 支持库文件",
@@ -1331,7 +1341,7 @@ Retry:
Task.Progress = 0.4
Dim RawJson As JObject = GetJson(NetGetCodeByDownload(DlSourceLauncherOrMetaGet(DlClientListGet(Inherit)), IsJson:=True))
'[net.minecraft:client:1.17.1-20210706.113038:mappings@txt] 或 @tsrg]
- Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Before("@")
+ Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).BeforeFirst("@")
Dim Address = McLibGet(OriginalName).Replace(".jar", "-mappings." & Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(1))
Dim ClientMappings As JToken = RawJson("downloads")("client_mappings")
Libs.Add(New McLibToken With {
@@ -1865,7 +1875,7 @@ Retry:
Public Function FabricApiDownloadListItem(Entry As CompFile, OnClick As MyListItem.ClickEventHandler) As MyListItem
'建立控件
Dim NewItem As New MyListItem With {
- .Title = Entry.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").Before("+").Trim, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
+ .Title = Entry.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").BeforeFirst("+").Trim, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
.Info = Entry.StatusDescription & ",发布于 " & Entry.ReleaseDate.ToString("yyyy'/'MM'/'dd HH':'mm"),
.Logo = PathImage & "Blocks/Fabric.png"
}
@@ -2030,6 +2040,8 @@ Retry:
FrmMain.BtnExtraDownload.Ribble()
Return True
+ Catch ex As CancelledException
+ Return False
Catch ex As Exception
Log(ex, "开始合并安装失败", LogLevel.Feedback)
Return False
@@ -2037,8 +2049,8 @@ Retry:
End Function
'''
''' 获取合并安装加载器列表,并进行前期的缓存清理与 Java 检查工作。
- ''' 如果出现已知问题且已提示用户,则返回 Nothing。出现异常则直接抛出。
'''
+ '''
Public Function McInstallLoader(Request As McInstallRequest, Optional DontFixLibraries As Boolean = False) As List(Of LoaderBase)
'获取缓存目录
Dim PathInstallTemp As String
@@ -2050,11 +2062,10 @@ Retry:
'清理缓存
Try
- If Not IsInstallTempCleared Then
- IsInstallTempCleared = True
- DeleteDirectory(PathInstallTemp, True)
- Log("[Download] 已清理合并安装缓存")
- End If
+ If IsInstallTempCleared Then Exit Try
+ IsInstallTempCleared = True
+ DeleteDirectory(PathInstallTemp, True)
+ Log("[Download] 已清理合并安装缓存")
Catch ex As Exception
Log(ex, "清理合并安装缓存失败")
End Try
@@ -2065,7 +2076,7 @@ Retry:
If Directory.Exists(TempMcFolder) Then DeleteDirectory(TempMcFolder)
Dim OptiFineFolder As String = Nothing
If Request.OptiFineVersion IsNot Nothing Then
- If Request.OptiFineVersion.Contains("_HD_U_") Then Request.OptiFineVersion = "HD_U_" & Request.OptiFineVersion.After("_HD_U_") '#735
+ If Request.OptiFineVersion.Contains("_HD_U_") Then Request.OptiFineVersion = "HD_U_" & Request.OptiFineVersion.AfterLast("_HD_U_") '#735
Request.OptiFineEntry = New DlOptiFineListEntry With {
.NameDisplay = Request.MinecraftName & " " & Request.OptiFineVersion.Replace("HD_U_", "").Replace("_", "").Replace("pre", " pre"),
.Inherit = Request.MinecraftName,
@@ -2110,7 +2121,7 @@ Retry:
'重复版本检查
If File.Exists(OutputFolder & Request.TargetVersionName & ".json") Then
Hint("版本 " & Request.TargetVersionName & " 已经存在!", HintType.Critical)
- Return Nothing
+ Throw New CancelledException
End If
Dim LoaderList As New List(Of LoaderBase)
@@ -2166,7 +2177,7 @@ Retry:
End Sub) With {.ProgressWeight = 2, .Block = True})
'补全文件
If Not DontFixLibraries AndAlso
- (Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.Before(".") >= 20) OrElse Request.NeoForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing) Then
+ (Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.BeforeFirst(".") >= 20) OrElse Request.NeoForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing) Then
Dim LoadersLib As New List(Of LoaderBase)
LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(OutputFolder))) With {.ProgressWeight = 1, .Show = False})
LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml
index 7333268..28f238f 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml
@@ -20,8 +20,13 @@
-
-
+
+
+
+
+
+
+
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb
index 892375d..c988751 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadCompDetail.xaml.vb
@@ -34,41 +34,121 @@
End Select
End Sub
'结果 UI 化
- Private Class VersionSorterWithSelect
+ Private Class CardSorter
Implements IComparer(Of String)
- Public Top As String = ""
+ Public Topmost As String = ""
Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
+ '相同
If x = y Then Return 0
- If x = Top Then Return -1
- If y = Top Then Return 1
+ '置顶
+ If x = Topmost Then Return -1
+ If y = Topmost Then Return 1
+ '特殊版本
+ Dim IsXSpecial As Boolean = x.EndsWithF("版本")
+ Dim IsYSpecial As Boolean = y.EndsWithF("版本")
+ If IsXSpecial AndAlso IsYSpecial Then Return x.CompareTo(y)
+ If IsXSpecial Then Return 1
+ If IsYSpecial Then Return -1
+ '比较版本号
+ Dim VersionCodeSort = -VersionSortInteger(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", ""))
+ If VersionCodeSort <> 0 Then Return VersionCodeSort
+ '比较全部
Return -VersionSortInteger(x, y)
End Function
- Public Sub New(Optional Top As String = "")
- Me.Top = If(Top, "")
+ Public Sub New(Optional Topmost As String = "")
+ Me.Topmost = If(Topmost, "")
End Sub
End Class
+
+ Private VersionFilter As String
+ Private IsMajorVersionFilter As Boolean '是否按大版本号筛选(1.21 / 1.20 / 1.19 / ...)而非小版本号(1.21.1 / 1.21 / 1.20.4 / ...)
Private Sub Load_OnFinish()
+ '初始化筛选器
+ Dim VersionFilters As List(Of String)
+
+ '按小版本号筛选?
+ IsMajorVersionFilter = False
+ VersionFilters = CompFileLoader.Output.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True)).
+ Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
+ '按大版本号筛选?
+ If VersionFilters.Count >= 9 Then
+ IsMajorVersionFilter = True
+ VersionFilters = CompFileLoader.Output.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True)).
+ Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
+ End If
+
+ 'UI 化筛选器
+ PanFilter.Children.Clear()
+ If VersionFilters.Count <= 2 Then
+ CardFilter.Visibility = Visibility.Collapsed
+ VersionFilter = Nothing
+ Else
+ CardFilter.Visibility = Visibility.Visible
+ VersionFilters.Insert(0, "全部")
+ '转化为按钮
+ For Each Version As String In VersionFilters
+ Dim NewButton As New MyRadioButton With {
+ .Text = Version, .Margin = New Thickness(2, 0, 2, 0), .ColorType = MyRadioButton.ColorState.Highlight}
+ NewButton.LabText.Margin = New Thickness(-2, 0, 8, 0)
+ AddHandler NewButton.Check,
+ Sub(sender As MyRadioButton, raiseByMouse As Boolean)
+ PanScroll.ScrollToHome()
+ VersionFilter = If(sender.Text = "全部", Nothing, sender.Text)
+ UpdateFilterResult()
+ End Sub
+ PanFilter.Children.Add(NewButton)
+ Next
+ '自动选择
+ Dim ToCheck As MyRadioButton = Nothing
+ If TargetVersion <> "" Then
+ Dim TargetFile = CompFileLoader.Output.FirstOrDefault(Function(v) v.GameVersions.Contains(TargetVersion))
+ If TargetFile IsNot Nothing Then
+ Dim TargetGroup = GetGroupedVersionName(TargetVersion, IsMajorVersionFilter, True)
+ For Each Button As MyRadioButton In PanFilter.Children
+ If Button.Text <> TargetGroup Then Continue For
+ ToCheck = Button
+ Exit For
+ Next
+ End If
+ End If
+ If ToCheck Is Nothing Then ToCheck = PanFilter.Children(0)
+ ToCheck.Checked = True
+ End If
+
+ '更新筛选结果(文件列表 UI 化)
+ UpdateFilterResult()
+ End Sub
+ Private Sub UpdateFilterResult()
Dim TargetCardName As String = If(TargetVersion <> "" OrElse TargetLoader <> CompModLoaderType.Any,
- $"所选版本:{TargetVersion} {If(TargetLoader <> CompModLoaderType.Any, TargetLoader, "")}", "")
- '初始化字典
- Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New VersionSorterWithSelect(TargetCardName))
- Dict.Add("未知版本", New List(Of CompFile))
+ $"所选版本:{If(TargetLoader <> CompModLoaderType.Any, TargetLoader.ToString & " ", "")}{TargetVersion}", "")
+ '归类到卡片下
+ Dim Dict As New SortedDictionary(Of String, List(Of CompFile))(New CardSorter(TargetCardName))
+ Dict.Add("其他版本", New List(Of CompFile))
+ Dim SupportedLoaders As New List(Of Integer)([Enum].GetValues(GetType(CompModLoaderType)))
For Each Version As CompFile In CompFileLoader.Output
For Each GameVersion In Version.GameVersions
- '决定添加到哪个版本
- Dim TargetCard As String
- If GameVersion Is Nothing Then
- TargetCard = "未知版本"
- ElseIf GameVersion.Contains("w") OrElse GameVersion.Contains("pre") OrElse GameVersion.Contains("rc") Then
- TargetCard = "快照版本"
- ElseIf GameVersion.StartsWith("1.0") Then
- TargetCard = "远古版本"
- Else
- TargetCard = GameVersion
+ '检查是否符合版本筛选器
+ If VersionFilter IsNot Nothing AndAlso
+ GetGroupedVersionName(GameVersion, IsMajorVersionFilter, True) <> VersionFilter Then Continue For
+ '决定添加到哪个卡片
+ Dim Ver As String = GetGroupedVersionName(GameVersion, False, False)
+ '遍历加入的加载器列表
+ Dim Loaders As New List(Of String)
+ If Project.ModLoaders.Count > 1 AndAlso '至少有两个加载器
+ Project.Type = CompType.Mod AndAlso '是 Mod
+ Ver.StartsWith("1.") Then '不是 “快照版本” 之类的
+ For Each Loader In Version.ModLoaders
+ If Loader = CompModLoaderType.Quilt AndAlso Setup.Get("ToolDownloadIgnoreQuilt") Then Continue For
+ If SupportedLoaders.Contains(Loader) Then Loaders.Add(Loader.ToString & " ")
+ Next
End If
- '实际进行添加
- If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile))
- If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
+ If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
+ '实际添加
+ For Each Loader In Loaders
+ Dim TargetCard As String = Loader & Ver
+ If Not Dict.ContainsKey(TargetCard) Then Dict.Add(TargetCard, New List(Of CompFile))
+ If Not Dict(TargetCard).Contains(Version) Then Dict(TargetCard).Add(Version)
+ Next
Next
Next
'添加筛选的版本的卡片
@@ -77,16 +157,16 @@
For Each Version As CompFile In CompFileLoader.Output
If Version.GameVersions.Contains(TargetVersion) AndAlso
(TargetLoader = CompModLoaderType.Any OrElse Version.ModLoaders.Contains(TargetLoader)) Then
+ '检查是否符合版本筛选器
+ If VersionFilter IsNot Nothing AndAlso
+ Not Version.GameVersions.Any(Function(v) GetGroupedVersionName(v, IsMajorVersionFilter, True) = VersionFilter) Then Continue For
If Not Dict(TargetCardName).Contains(Version) Then Dict(TargetCardName).Add(Version)
End If
Next
End If
-
-#Region "转化为 UI"
+ '转化为 UI
Try
- '清空当前
- PanMain.Children.Clear()
- '转化为 UI
+ PanResults.Children.Clear()
For Each Pair As KeyValuePair(Of String, List(Of CompFile)) In Dict
If Not Pair.Value.Any() Then Continue For
'增加卡片
@@ -94,7 +174,7 @@
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
NewCard.Children.Add(NewStack)
NewCard.SwapControl = NewStack
- PanMain.Children.Add(NewCard)
+ PanResults.Children.Add(NewCard)
'确定卡片是否展开
If Pair.Key = TargetCardName OrElse
(FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
@@ -104,20 +184,29 @@
NewCard.IsSwaped = True
End If
'增加提示
- If Pair.Key = "未知版本" Then
- NewStack.Children.Add(New MyHint With {.Text = "由于 API 的版本信息更新缓慢,可能无法识别刚更新不久的 MC 版本,只需等待几天即可自动恢复正常。", .IsWarn = False, .Margin = New Thickness(0, 0, 0, 7)})
+ If Pair.Key = "其他版本" Then
+ NewStack.Children.Add(New MyHint With {.Text = "由于版本信息更新缓慢,可能无法识别刚更新的 MC 版本,只需等待几天即可自动恢复正常。", .IsWarn = False, .Margin = New Thickness(0, 0, 0, 7)})
End If
Next
'如果只有一张卡片,展开第一张卡片
- If PanMain.Children.Count = 1 Then
- CType(PanMain.Children(0), MyCard).IsSwaped = False
+ If PanResults.Children.Count = 1 Then
+ CType(PanResults.Children(0), MyCard).IsSwaped = False
End If
Catch ex As Exception
Log(ex, "可视化工程下载列表出错", LogLevel.Feedback)
End Try
-#End Region
-
End Sub
+ Private Function GetGroupedVersionName(Name As String, MajorOnly As Boolean, FoldOldRelease As Boolean) As String
+ If Name Is Nothing Then
+ Return "其他版本"
+ ElseIf Name.Contains("w") Then
+ Return "快照版本"
+ ElseIf Name.StartsWith("1.0") OrElse Not Name.StartsWith("1.") OrElse (FoldOldRelease AndAlso Val(Name.Split(".")(1)) < 10) Then
+ Return "远古版本"
+ Else
+ Return If(MajorOnly, "1." & Name.Split(".")(1).BeforeFirst(" "), Name)
+ End If
+ End Function
#End Region
@@ -170,11 +259,7 @@
Dim LogoFileAddress As String = MyImage.GetTempPath(CompItem.Logo)
Loaders.Add(New LoaderDownload("下载整合包文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 10, .Block = True})
Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包",
- Sub()
- If ModpackInstall(Target, VersionName, Logo:=If(IO.File.Exists(LogoFileAddress), LogoFileAddress, Nothing)) Is Nothing Then
- Throw New Exception("整合包安装出现异常!")
- End If
- End Sub) With {.ProgressWeight = 0.1})
+ Sub() ModpackInstall(Target, VersionName, If(IO.File.Exists(LogoFileAddress), LogoFileAddress, Nothing))) With {.ProgressWeight = 0.1})
'启动
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged =
@@ -229,7 +314,7 @@
If Not Version.IsLoaded Then Version.Load()
If Not Version.Modable Then Return False
If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso
- Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v.Split(".")(1) = Version.Version.McCodeMain.ToString) Then Return False
+ Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v = Version.Version.McName) Then Return False
If AllowForge Is Nothing OrElse AllowFabric Is Nothing Then Return True
If AllowForge AndAlso (Version.Version.HasForge OrElse Version.Version.HasNeoForge) Then Return True
If AllowFabric AndAlso Version.Version.HasFabric Then Return True
@@ -277,7 +362,7 @@
If Project.TranslatedName = Project.RawName Then
FileName = File.FileName
Else
- Dim ChineseName As String = Project.TranslatedName.Before(" (").Before(" - ").
+ Dim ChineseName As String = Project.TranslatedName.BeforeFirst(" (").BeforeFirst(" - ").
Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
Select Case Setup.Get("ToolDownloadTranslate")
Case 0
@@ -295,10 +380,10 @@
'弹窗要求选择保存位置
Dim Target As String
Target = SelectAs("选择保存位置", FileName,
- Desc & "文件|" &
- If(Project.Type = CompType.Mod,
- If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"),
- If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
+ Desc & "文件|" &
+ If(Project.Type = CompType.Mod,
+ If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"),
+ If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
If Not Target.Contains("\") Then Exit Sub
'构造步骤加载器
Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " "
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
index 2230ba6..9b5a245 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb
@@ -1076,12 +1076,12 @@
If DisplayName.StartsWith("[" & MinecraftVersion & "]") Then Return True
If Not DisplayName.Contains("/") OrElse Not DisplayName.Contains("]") Then Return False
'直接的判断(例如 1.18.1/22w03a)
- For Each Part As String In DisplayName.Before("]").TrimStart("[").Split("/")
+ For Each Part As String In DisplayName.BeforeFirst("]").TrimStart("[").Split("/")
If Part = MinecraftVersion Then Return True
Next
'将版本名分割语素(例如 1.16.4/5)
- Dim Lefts = RegexSearch(DisplayName.Before("]"), "[a-z/]+|[0-9/]+")
- Dim Rights = RegexSearch(MinecraftVersion.Before("]"), "[a-z/]+|[0-9/]+")
+ Dim Lefts = RegexSearch(DisplayName.BeforeFirst("]"), "[a-z/]+|[0-9/]+")
+ Dim Rights = RegexSearch(MinecraftVersion.BeforeFirst("]"), "[a-z/]+|[0-9/]+")
'对每段进行判断
Dim i As Integer = 0
While True
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml
index 8a64667..bb644b1 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml
@@ -2,88 +2,90 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" AnimatedControl="{Binding ElementName=PanItem, Mode=OneWay}">
-
+
+
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
- -->
+
+
+
+
+
+
+
-
-
-
-
-
-
-
- -->
+
+
+
+
+
+
+
-
-
-
-
-
-
-
- -->
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
+
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb
index de8faf8..f2eb250 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb
@@ -1,4 +1,5 @@
Public Class PageDownloadLeft
+ Implements IRefreshable
#Region "页面切换"
@@ -91,7 +92,13 @@
'强制刷新
Public Sub Refresh(sender As Object, e As EventArgs) '由边栏按钮匿名调用
- Select Case Val(sender.Tag)
+ Refresh(Val(sender.Tag))
+ End Sub
+ Public Sub Refresh() Implements IRefreshable.Refresh
+ Refresh(FrmMain.PageCurrentSub)
+ End Sub
+ Public Sub Refresh(SubType As FormMain.PageSubType)
+ Select Case SubType
Case FormMain.PageSubType.DownloadInstall
DlClientListLoader.Start(IsForceRestart:=True)
DlOptiFineListLoader.Start(IsForceRestart:=True)
@@ -106,12 +113,14 @@
PageDownloadMod.Storage = New CompProjectStorage
PageDownloadMod.Page = 0
CompProjectCache.Clear()
+ CompFilesCache.Clear()
If FrmDownloadMod IsNot Nothing Then FrmDownloadMod.PageLoaderRestart()
ItemMod.Checked = True
Case FormMain.PageSubType.DownloadPack
PageDownloadPack.Storage = New CompProjectStorage
PageDownloadPack.Page = 0
CompProjectCache.Clear()
+ CompFilesCache.Clear()
If FrmDownloadPack IsNot Nothing Then FrmDownloadPack.PageLoaderRestart()
ItemPack.Checked = True
Case FormMain.PageSubType.DownloadClient
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
index 978b37d..bcfb637 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml
@@ -33,20 +33,17 @@
+
-
-
-
-
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb
index ae9ee47..113ff25 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadMod.xaml.vb
@@ -1,12 +1,44 @@
Public Class PageDownloadMod
Public Const PageSize = 40
+ '''
+ ''' 在切换到该页面时自动设置的目标版本。
+ '''
+ Public Shared TargetVersion As McVersion = Nothing
'加载器信息
Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject Mod", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
Public Shared Storage As New CompProjectStorage
Public Shared Page As Integer = 0
- Private Sub PageDownloadMod_Inited(sender As Object, e As EventArgs) Handles Me.Initialized
+ Private IsLoaderInited As Boolean = False
+ Private Sub PageDownloadMod_Inited(sender As Object, e As EventArgs) Handles Me.Loaded
+ '不知道从 Initialized 改成 Loaded 会不会有问题,但用 Initialized 会导致初始的筛选器修改被覆盖回默认值
+ If TargetVersion IsNot Nothing Then
+ '设置目标
+ ResetFilter() '重置筛选器
+ TextSearchVersion.Text = TargetVersion.Version.McName
+ Dim GetTargetItemByName =
+ Function(Name As String) As MyComboBoxItem
+ For Each Item As MyComboBoxItem In ComboSearchLoader.Items
+ If Item.Content = Name Then Return Item
+ Next
+ Return ComboSearchLoader.Items(0)
+ End Function
+ If TargetVersion.Version.HasForge Then
+ ComboSearchLoader.SelectedItem = GetTargetItemByName("Forge")
+ ElseIf TargetVersion.Version.HasFabric Then
+ ComboSearchLoader.SelectedItem = GetTargetItemByName("Fabric")
+ ElseIf TargetVersion.Version.HasNeoForge Then
+ ComboSearchLoader.SelectedItem = GetTargetItemByName("NeoForge")
+ End If
+ TargetVersion = Nothing
+ '如果已经完成请求,则重新开始
+ If IsLoaderInited Then StartNewSearch()
+ PanScroll.ScrollToHome()
+ End If
+ '加载器初始化
+ If IsLoaderInited Then Return
+ IsLoaderInited = True
PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
End Sub
@@ -118,7 +150,7 @@
End Sub
'重置按钮
- Private Sub BtnSearchReset_Click(sender As Object, e As EventArgs) Handles BtnSearchReset.Click
+ Private Sub ResetFilter() Handles BtnSearchReset.Click
TextSearchName.Text = ""
TextSearchVersion.Text = "全部 (也可自行输入)"
TextSearchVersion.SelectedIndex = 0
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml
index 1ca5eb0..79b34ab 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml
@@ -8,14 +8,12 @@
-
+
-
-
-
+
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb
index 27c2fd4..f843529 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadOptiFine.xaml.vb
@@ -49,8 +49,5 @@
Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
OpenWebsite("https://www.optifine.net/")
End Sub
- Private Sub BtnChina_Click(sender As Object, e As EventArgs) Handles BtnChina.Click
- OpenWebsite("https://optifine.cn/home")
- End Sub
End Class
diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
index dae0342..5ad426d 100644
--- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
+++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadPack.xaml
@@ -32,20 +32,17 @@
+
-
-
-
-
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml
index 0da64ce..1144f09 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml
@@ -24,7 +24,7 @@
+ VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMult="0.7">
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
index bfc632e..6d1ef20 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
@@ -242,7 +242,7 @@ Retry:
{"Vanilla", "原版披风"}, {"Minecon2011", "Minecon 2011 参与者披风"}, {"Minecon2012", "Minecon 2012 参与者披风"},
{"Minecon2013", "Minecon 2013 参与者披风"}, {"Minecon2015", "Minecon 2015 参与者披风"}, {"Minecon2016", "Minecon 2016 参与者披风"},
{"Cherry Blossom", "樱花披风"}, {"15th Anniversary", "15 周年纪念披风"}, {"Purple Heart", "紫色心形披风"},
- {"Follower's", "追随者披风"}, {"MCC 15th Year", "MCC 15 周年披风"}
+ {"Follower's", "追随者披风"}, {"MCC 15th Year", "MCC 15 周年披风"}, {"Minecraft Experience", "村民救援披风"}
}
Dim SelectionControl As New List(Of IMyRadio) From {New MyRadioBox With {.Text = "无披风"}}
For Each Cape In SkinData("capes")
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb
index f3033b2..416bdcf 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb
@@ -26,21 +26,15 @@
If File.Exists(Path & "modpack.zip") Then PackInstallPath = Path & "modpack.zip"
If File.Exists(Path & "modpack.mrpack") Then PackInstallPath = Path & "modpack.mrpack"
If PackInstallPath IsNot Nothing Then
- If MyMsgBox($"PCL 即将在当前文件夹下自动安装整合包。", "自动安装", "继续", "取消") = 1 Then
- '确认自动安装
- Log("[Launch] 需自动安装整合包:" & PackInstallPath, LogLevel.Debug)
- Setup.Set("LaunchFolderSelect", "$.minecraft\")
- If Not Directory.Exists(Path & ".minecraft\") Then
- Directory.CreateDirectory(Path & ".minecraft\")
- Directory.CreateDirectory(Path & ".minecraft\versions\")
- McFolderLauncherProfilesJsonCreate(Path & ".minecraft\")
- End If
- McFolderListLoader.WaitForExit(IsForceRestart:=True)
- Else
- '取消自动安装
- Log("[Launch] 取消自动安装整合包:" & PackInstallPath, LogLevel.Debug)
- PackInstallPath = Nothing
+ Log("[Launch] 需自动安装整合包:" & PackInstallPath, LogLevel.Debug)
+ Setup.Set("LaunchFolderSelect", "$.minecraft\")
+ If Not Directory.Exists(Path & ".minecraft\") Then
+ Directory.CreateDirectory(Path & ".minecraft\")
+ Directory.CreateDirectory(Path & ".minecraft\versions\")
+ McFolderLauncherProfilesJsonCreate(Path & ".minecraft\")
End If
+ PageSelectLeft.AddFolder(Path & ".minecraft\", GetFolderNameFromPath(Path), False)
+ McFolderListLoader.WaitForExit()
End If
'确认 Minecraft 文件夹存在
PathMcFolder = Setup.Get("LaunchFolderSelect").ToString.Replace("$", Path)
@@ -58,18 +52,19 @@
If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
'自动整合包安装
If PackInstallPath IsNot Nothing Then
- Dim InstallLoader = ModpackInstall(PackInstallPath)
- If InstallLoader Is Nothing Then
- Log("[Launch] 自动安装整合包失败:" & PackInstallPath)
- Else
- Log("[Launch] 自动安装整合包开始:" & PackInstallPath)
- RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.DownloadManager))
+ Try
+ Dim InstallLoader = ModpackInstall(PackInstallPath, GetFolderNameFromPath(Path))
+ Log("[Launch] 自动安装整合包已开始:" & PackInstallPath)
InstallLoader.WaitForExit()
If InstallLoader.State = LoadState.Finished Then
Log("[Launch] 自动安装整合包成功,删除安装包:" & PackInstallPath)
File.Delete(PackInstallPath)
End If
- End If
+ Catch ex As CancelledException
+ Log(ex, "自动安装整合包被用户取消:" & PackInstallPath)
+ Catch ex As Exception
+ Log(ex, "自动安装整合包失败:" & PackInstallPath, LogLevel.Msgbox)
+ End Try
End If
'确认 Minecraft 版本存在
Dim Selection As String = Setup.Get("LaunchVersionSelect")
@@ -431,7 +426,7 @@ Finish:
ElseIf Setup.Get("LoginLegacyName") = "" Then
Return New EqualableList(Of String) From {0, ""}
Else
- Return New EqualableList(Of String) From {0, If(Setup.Get("LoginLegacyName").ToString.Before("¨"), "")}
+ Return New EqualableList(Of String) From {0, If(Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨"), "")}
End If
Case 3
Return New EqualableList(Of String) From {3, Setup.Get("LaunchSkinID")}
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
index 1ddf391..595aecb 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb
@@ -1,4 +1,5 @@
Public Class PageLaunchRight
+ Implements IRefreshable
Private Sub Init() Handles Me.Loaded
PanBack.ScrollToHome()
@@ -92,7 +93,7 @@ Download:
GoTo Download
Case 3
Log("[Page] 主页预设:简单主页")
- Url = "https://gitee.com/mfn233/PCL-Mainpage/raw/main/Custom.xaml"
+ Url = "https://raw.gitcode.com/mfn233/PCL-Mainpage/raw/main/Custom.xaml"
GoTo Download
Case 4
Log("[Page] 主页预设:每日整合包推荐")
@@ -104,7 +105,7 @@ Download:
GoTo Download
Case 6
Log("[Page] 主页预设:OpenBMCLAPI 仪表盘 Lite")
- Url = "https://pcl-bmcl.milulu.xyz/"
+ Url = "https://pcl-bmcl.milu.ink/"
GoTo Download
Case 7
Log("[Page] 主页预设:主页市场")
@@ -116,12 +117,16 @@ Download:
GoTo Download
Case 9
Log("[Page] 主页预设:PCL 新功能说明书")
- Url = "https://gitee.com/wforstbreeze/whats-new-pcl/raw/main/Custom.xaml"
+ Url = "https://raw.gitcode.com/WForst-Breeze/WhatsNewPCL/raw/main/Custom.xaml"
GoTo Download
Case 10
Log("[Page] 主页预设:OpenMCIM Dashboard")
Url = "https://files.mcimirror.top/PCL"
GoTo Download
+ Case 11
+ Log("[Page] 主页预设:杂志主页")
+ Url = "http://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Ext1nguisher/Custom.xaml"
+ GoTo Download
End Select
End Select
RunInUi(Sub() LoadContent(Content))
@@ -138,10 +143,10 @@ Download:
If Address.Contains(".xaml") Then
VersionAddress = Address.Replace(".xaml", ".xaml.ini")
Else
- VersionAddress = Address.Before("?")
+ VersionAddress = Address.BeforeFirst("?")
If Not VersionAddress.EndsWith("/") Then VersionAddress += "/"
VersionAddress += "version"
- If Address.Contains("?") Then VersionAddress += Address.After("?")
+ If Address.Contains("?") Then VersionAddress += Address.AfterLast("?")
End If
'校验版本
Dim Version As String = ""
@@ -183,7 +188,7 @@ Download:
''' 立即强制刷新自定义主页。
''' 必须在 UI 线程调用。
'''
- Public Sub ForceRefresh()
+ Public Sub ForceRefresh() Implements IRefreshable.Refresh
Log("[Page] 要求强制刷新自定义主页")
ClearCache()
'实际的刷新
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb
index 3476e70..e9ae125 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb
@@ -17,8 +17,8 @@
ComboName.ItemsSource = Nothing
Else
ComboName.ItemsSource = Setup.Get("LoginAuthEmail").ToString.Split("¨")
- ComboName.Text = Setup.Get("LoginAuthEmail").ToString.Before("¨")
- If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginAuthPass").ToString.Before("¨").Trim
+ ComboName.Text = Setup.Get("LoginAuthEmail").ToString.BeforeFirst("¨")
+ If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginAuthPass").ToString.BeforeFirst("¨").Trim
End If
End If
IsFirstLoad = False
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb
index ca21ffa..fec81e6 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb
@@ -70,9 +70,11 @@
End Try
End Sub)
End Sub
- Private Sub BtnExit_Click() Handles BtnExit.Click
+ Public Shared Sub ExitLogin() Handles BtnExit.Click
Setup.Set("CacheAuthAccess", "")
Setup.Set("CacheAuthUuid", "")
+ Setup.Set("CacheAuthName", "")
+ McLoginAuthLoader.Input = Nothing '防止因为输入的用户名密码相同,直接使用了上次登录的加载器结果
FrmLaunchLeft.RefreshPage(False, True)
End Sub
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb
index 0c47882..ed91684 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb
@@ -26,7 +26,7 @@ Public Class PageLoginLegacy
ComboName.ItemsSource = Nothing
Else
ComboName.ItemsSource = Setup.Get("LoginLegacyName").ToString.Split("¨")
- ComboName.Text = Setup.Get("LoginLegacyName").ToString.Before("¨").Trim
+ ComboName.Text = Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨").Trim
End If
End If
IsReloaded = True
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb
index 0e327d0..3b47833 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb
@@ -17,8 +17,8 @@
ComboName.ItemsSource = Nothing
Else
ComboName.ItemsSource = Setup.Get("LoginNideEmail").ToString.Split("¨")
- ComboName.Text = Setup.Get("LoginNideEmail").ToString.Before("¨")
- If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginNidePass").ToString.Before("¨").Trim
+ ComboName.Text = Setup.Get("LoginNideEmail").ToString.BeforeFirst("¨")
+ If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginNidePass").ToString.BeforeFirst("¨").Trim
End If
End If
IsFirstLoad = False
diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb
index bceb7c8..84fa773 100644
--- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb
@@ -47,8 +47,9 @@
Private Sub BtnEdit_Click(sender As Object, e As EventArgs) Handles BtnEdit.Click
OpenWebsite("https://login.mc-user.com:233/account/changepw")
End Sub
- Private Sub BtnExit_Click() Handles BtnExit.Click
+ Public Shared Sub ExitLogin() Handles BtnExit.Click
Setup.Set("CacheNideAccess", "")
+ McLoginNideLoader.Input = Nothing '防止因为输入的用户名密码相同,直接使用了上次登录的加载器结果
FrmLaunchLeft.RefreshPage(False, True)
End Sub
diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb b/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb
index c1cbe61..f1e6312 100644
--- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb
@@ -111,8 +111,6 @@ Public Class PageLinkIoi
End Sub
'复制联机码
Public Shared Sub BtnLeftCopy_Click() Handles BtnLeftCopy.Click
- ClipboardSet(IoiId.Substring(4) & SecretEncrypt(GetPlayerName), False)
- Hint("已复制联机码!", HintType.Finish)
End Sub
#End Region
diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
index 951a5dc..8142163 100644
--- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
+++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml
@@ -104,108 +104,107 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb
index d8c0a68..46a8bf4 100644
--- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb
@@ -1,4 +1,5 @@
Public Class PageOtherHelp
+ Implements IRefreshable
#Region "初始化"
@@ -79,31 +80,35 @@
End Try
End Sub
Public Shared Sub EnterHelpPage(Location As String)
- RunInThread(Sub()
- If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid)
- Dim Entry As New HelpEntry(Location)
- RunInUi(Sub()
- Dim FrmHelpDetail As New PageOtherHelpDetail
- If FrmHelpDetail.Init(Entry) Then
- FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}})
- Else
- Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", LogLevel.Debug)
- End If
- End Sub)
- End Sub)
+ RunInThread(
+ Sub()
+ If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid)
+ Dim Entry As New HelpEntry(Location)
+ RunInUi(
+ Sub()
+ Dim FrmHelpDetail As New PageOtherHelpDetail
+ If FrmHelpDetail.Init(Entry) Then
+ FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}})
+ Else
+ Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", LogLevel.Debug)
+ End If
+ End Sub)
+ End Sub)
End Sub
Public Shared Sub EnterHelpPage(Entry As HelpEntry)
- RunInThread(Sub()
- If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid)
- RunInUi(Sub()
- Dim FrmHelpDetail As New PageOtherHelpDetail
- If FrmHelpDetail.Init(Entry) Then
- FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}})
- Else
- Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", LogLevel.Debug)
- End If
- End Sub)
- End Sub)
+ RunInThread(
+ Sub()
+ If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid)
+ RunInUi(
+ Sub()
+ Dim FrmHelpDetail As New PageOtherHelpDetail
+ If FrmHelpDetail.Init(Entry) Then
+ FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}})
+ Else
+ Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", LogLevel.Debug)
+ End If
+ End Sub)
+ End Sub)
End Sub
Public Shared Function GetHelpPage(Location As String) As PageOtherHelpDetail
If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid)
@@ -122,14 +127,15 @@
If String.IsNullOrWhiteSpace(SearchBox.Text) Then
'隐藏
AniStart({
- AaOpacity(PanSearch, -PanSearch.Opacity, 100),
- AaCode(Sub()
- PanSearch.Height = 0
- PanSearch.Visibility = Visibility.Collapsed
- PanList.Visibility = Visibility.Visible
- End Sub,, True),
- AaOpacity(PanList, 1 - PanList.Opacity, 150, 30)
- }, "FrmOtherHelp Search Switch")
+ AaOpacity(PanSearch, -PanSearch.Opacity, 100),
+ AaCode(
+ Sub()
+ PanSearch.Height = 0
+ PanSearch.Visibility = Visibility.Collapsed
+ PanList.Visibility = Visibility.Visible
+ End Sub,, True),
+ AaOpacity(PanList, 1 - PanList.Opacity, 150, 30)
+ }, "FrmOtherHelp Search Switch")
Else
'构造请求
Dim QueryList As New List(Of SearchEntry(Of HelpEntry))
@@ -163,15 +169,19 @@
End If
'显示
AniStart({
- AaOpacity(PanList, -PanList.Opacity, 100),
- AaCode(Sub()
- PanList.Visibility = Visibility.Collapsed
- PanSearch.Visibility = Visibility.Visible
- PanSearch.TriggerForceResize()
- End Sub,, True),
- AaOpacity(PanSearch, 1 - PanSearch.Opacity, 150, 30)
- }, "FrmOtherHelp Search Switch")
+ AaOpacity(PanList, -PanList.Opacity, 100),
+ AaCode(
+ Sub()
+ PanList.Visibility = Visibility.Collapsed
+ PanSearch.Visibility = Visibility.Visible
+ PanSearch.TriggerForceResize()
+ End Sub,, True),
+ AaOpacity(PanSearch, 1 - PanSearch.Opacity, 150, 30)
+ }, "FrmOtherHelp Search Switch")
End If
End Sub
+ Public Sub Refresh() Implements IRefreshable.Refresh
+ PageOtherLeft.RefreshHelp()
+ End Sub
End Class
diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb
index 79aecfd..fda05ce 100644
--- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb
@@ -1,6 +1,11 @@
Public Class PageOtherHelpDetail
+ Implements IRefreshable
Public Entry As HelpEntry
+ Public Sub Refresh() Implements IRefreshable.Refresh
+ Init(New HelpEntry(Entry.RawPath))
+ End Sub
+
Private Sub PageOtherHelpDetail_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
PanBack.ScrollToTop()
End Sub
diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml
index 119a07c..874928f 100644
--- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml
+++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml
@@ -15,9 +15,9 @@
LogoScale="0.98" Logo="M149.883623 873.911618c47.094581 47.094581 101.765247 83.95121 162.783444 109.75085 63.065787 26.618676 130.226755 40.337532 199.230553 40.337532 69.003799 0 136.164767-13.514097 199.230554-40.337532 61.018196-25.79964 115.688862-62.656269 162.783444-109.75085s83.95121-101.765247 109.75085-162.783444c26.618676-63.065787 40.337532-130.226755 40.337532-199.230554 0-69.003799-13.514097-136.164767-40.337532-199.230553-25.79964-61.018196-62.656269-115.688862-109.75085-162.783444-46.889822-46.889822-101.765247-83.95121-162.783444-109.75085C648.062388 13.514097 580.90142 0 511.89762 0s-136.164767 13.514097-199.230553 40.337532c-61.018196 25.79964-115.688862 62.656269-162.783444 109.75085s-83.95121 101.765247-109.75085 162.783444C13.514097 375.732853 0 442.893821 0 511.89762s13.514097 136.164767 40.337532 199.230554c25.594881 61.018196 62.656269 115.688862 109.546091 162.783444zM97.670066 511.89762c0-228.511098 185.921216-414.227554 414.227554-414.227554 228.511098 0 414.227554 185.921216 414.227555 414.227554S740.408718 926.125175 511.89762 926.125175c-228.511098 0-414.227554-185.716457-414.227554-414.227555z M539.130574 244.277544c-8.190362-4.709458-17.609278-7.371326-27.232954-7.371325-9.623675 0-19.042591 2.457109-27.232953 7.371325-16.790242 9.623675-27.232953 27.847231-27.232953 47.299341 0 30.09958 24.366327 54.465907 54.465906 54.465906 30.09958 0 54.465907-24.366327 54.465907-54.465906 0-19.45211-10.442711-37.470906-27.232953-47.299341zM566.363527 732.218356v-284.615077c0-30.09958-24.366327-54.465907-54.465907-54.465906-30.09958 0-54.465907 24.366327-54.465906 54.465906v284.615077c0 30.09958 24.366327 54.465907 54.465906 54.465907 30.09958 0 54.465907-24.366327 54.465907-54.465907z" />
-
-
diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb
index ffa5a72..59df742 100644
--- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb
@@ -125,7 +125,12 @@
End Sub
'打开网页
- Public Shared Sub TryFeedback() Handles ItemFeedback.Click
+ Private Sub TryFeedback(sender As Object, e As RouteEventArgs) Handles ItemFeedback.Changed
+ If Not ItemFeedback.Checked Then Exit Sub
+ TryFeedback()
+ e.Handled = True
+ End Sub
+ Public Shared Sub TryFeedback()
If Not CanFeedback(True) Then Exit Sub
Select Case MyMsgBox("在提交新反馈前,建议先搜索反馈列表,以避免重复提交。" & vbCrLf & "如果无法打开该网页,请尝试使用加速器或 VPN。",
"反馈", "提交新反馈", "查看反馈列表", "取消")
@@ -135,7 +140,12 @@
OpenWebsite("https://github.com/Hex-Dragon/PCL2/issues/")
End Select
End Sub
- Public Shared Sub TryVote() Handles ItemVote.Click
+ Private Sub TryVote(sender As Object, e As RouteEventArgs) Handles ItemVote.Changed
+ If Not ItemVote.Checked Then Exit Sub
+ TryVote()
+ e.Handled = True
+ End Sub
+ Public Shared Sub TryVote()
If MyMsgBox("是否要打开新功能投票网页?" & vbCrLf & "如果无法打开该网页,请尝试使用加速器或 VPN。",
"新功能投票", "打开", "取消") = 2 Then Exit Sub
OpenWebsite("https://github.com/Hex-Dragon/PCL2/discussions/categories/%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8?discussions_q=category%3A%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8+sort%3Adate_created")
diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherTest.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherTest.xaml.vb
index af35b45..041421a 100644
--- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherTest.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherTest.xaml.vb
@@ -12,7 +12,7 @@
Public Shared Sub MemoryOptimize(ShowHint As Boolean)
If ShowHint Then Hint("为便于维护,开源内容中不包含百宝箱功能……")
End Sub
- Public Shared Sub MemoryOptimizeInternal()
+ Public Shared Sub MemoryOptimizeInternal(ShowHint As Boolean)
End Sub
Public Shared Function GetRandomCave() As String
Return "为便于维护,开源内容中不包含百宝箱功能……"
diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml
index 97e9c54..2dfe903 100644
--- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml
+++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml
@@ -9,7 +9,7 @@
-
+
diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb
index 1ef40df..2b5177a 100644
--- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb
@@ -1,4 +1,5 @@
Public Class PageSelectLeft
+ Implements IRefreshable
Private Sub PageSelectLeft_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
AddHandler McFolderListLoader.PreviewFinish, Sub() If FrmSelectLeft IsNot Nothing Then RunInUiWait(AddressOf McFolderListUI)
@@ -295,7 +296,7 @@
For i = 0 To Folders.Count - 1
If Folders(i) = "" Then Exit For
If Folders(i).ToString.EndsWith(Folder.Path) Then
- Name = Folders(i).ToString.Before(">")
+ Name = Folders(i).ToString.BeforeFirst(">")
Folders.RemoveAt(i)
Exit For
End If
@@ -347,8 +348,14 @@
End Sub
Public Sub Refresh_Click(sender As Object, e As RoutedEventArgs)
Dim Data As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
- WriteIni(Data.Path & "PCL.ini", "VersionCache", "") '删除缓存以强制要求下一次加载时更新列表
- If Data.Path = PathMcFolder Then LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
+ RefreshCurrent(Data.Path)
+ End Sub
+ Public Sub RefreshCurrent() Implements IRefreshable.Refresh
+ RefreshCurrent(PathMcFolder)
+ End Sub
+ Public Shared Sub RefreshCurrent(Folder As String)
+ WriteIni(Folder & "PCL.ini", "VersionCache", "") '删除缓存以强制要求下一次加载时更新列表
+ If Folder = PathMcFolder Then LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
End Sub
Public Sub Rename_Click(sender As Object, e As RoutedEventArgs)
Dim Folder As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
diff --git a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb
index 5b88927..f364869 100644
--- a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb
@@ -167,14 +167,16 @@
ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center)
ToolTipService.SetVerticalOffset(BtnCont, 30)
ToolTipService.SetHorizontalOffset(BtnCont, 2)
- AddHandler BtnCont.Click, Sub()
- PageVersionLeft.Version = Version
- FrmMain.PageChange(FormMain.PageType.VersionSetup, 0)
- End Sub
- AddHandler sender.MouseRightButtonUp, Sub()
- PageVersionLeft.Version = Version
- FrmMain.PageChange(FormMain.PageType.VersionSetup, 0)
- End Sub
+ AddHandler BtnCont.Click,
+ Sub()
+ PageVersionLeft.Version = Version
+ FrmMain.PageChange(FormMain.PageType.VersionSetup, 0)
+ End Sub
+ AddHandler sender.MouseRightButtonUp,
+ Sub()
+ PageVersionLeft.Version = Version
+ FrmMain.PageChange(FormMain.PageType.VersionSetup, 0)
+ End Sub
sender.Buttons = {BtnStar, BtnDel, BtnCont}
Else
Dim BtnCont As New MyIconButton With {.LogoScale = 1.15, .Logo = Logo.IconButtonOpen}
@@ -182,12 +184,8 @@
ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center)
ToolTipService.SetVerticalOffset(BtnCont, 30)
ToolTipService.SetHorizontalOffset(BtnCont, 2)
- AddHandler BtnCont.Click, Sub()
- PageVersionOverall.OpenVersionFolder(Version)
- End Sub
- AddHandler sender.MouseRightButtonUp, Sub()
- PageVersionOverall.OpenVersionFolder(Version)
- End Sub
+ AddHandler BtnCont.Click, Sub() PageVersionOverall.OpenVersionFolder(Version)
+ AddHandler sender.MouseRightButtonUp, Sub() PageVersionOverall.OpenVersionFolder(Version)
sender.Buttons = {BtnStar, BtnDel, BtnCont}
End If
End Sub
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb
index 8ef2a75..6dbe50c 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb
+++ b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb
@@ -153,6 +153,7 @@
{"UiHiddenPageSetup", New SetupEntry(False)},
{"UiHiddenPageOther", New SetupEntry(False)},
{"UiHiddenFunctionSelect", New SetupEntry(False)},
+ {"UiHiddenFunctionModUpdate", New SetupEntry(False)},
{"UiHiddenFunctionHidden", New SetupEntry(False)},
{"UiHiddenSetupLaunch", New SetupEntry(False)},
{"UiHiddenSetupUi", New SetupEntry(False)},
@@ -202,15 +203,19 @@
'加载状态:0/未读取 1/已读取未处理 2/已处理
Public State As Byte = 0
- Public Type
+ Public Type As Type
Public Sub New(Value, Optional Source = SetupSource.Normal, Optional Encoded = False)
- Me.DefaultValue = Value
- Me.DefaultValueEncoded = If(Encoded, SecretEncrypt(Value, "PCL" & UniqueAddress), Value)
- Me.Encoded = Encoded
- Me.Value = Value
- Me.Source = Source
- Type = If(Value, New Object).GetType
+ Try
+ Me.DefaultValue = Value
+ Me.Encoded = Encoded
+ Me.Value = Value
+ Me.Source = Source
+ Me.Type = If(Value, New Object).GetType
+ Me.DefaultValueEncoded = If(Encoded, SecretEncrypt(Value, "PCL" & UniqueAddress), Value)
+ Catch ex As Exception
+ Log(ex, "初始化 SetupEntry 失败", LogLevel.Feedback) '#5095 的 fallback
+ End Try
End Sub
End Class
@@ -312,6 +317,12 @@
Dim E As SetupEntry = SetupDict(Key)
[Set](Key, E.DefaultValue, E, ForceReload, Version)
End Sub
+ '''
+ ''' 获取某个设置项的默认值。
+ '''
+ Public Function GetDefault(Key As String) As String
+ Return SetupDict(Key).DefaultValue
+ End Function
Private Sub Read(Key As String, ByRef E As SetupEntry, Version As McVersion)
Try
@@ -632,6 +643,9 @@
Public Sub UiHiddenFunctionSelect(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
+ Public Sub UiHiddenFunctionModUpdate(Value As Boolean)
+ PageSetupUI.HiddenRefresh()
+ End Sub
Public Sub UiHiddenFunctionHidden(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml
index d34419c..8b692a4 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml
+++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml
@@ -7,54 +7,7 @@
PanScroll="{Binding ElementName=PanBack}">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -217,10 +170,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -232,14 +232,19 @@
-
-
+
+
+
+
+ ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。
可以使用以下替换标记实现相对路径(路径均以 \ 结尾):
· {path}:PCL 的 exe 文件所在的文件夹
· {minecraft}:.minecraft 文件夹
· {verpath}:版本文件夹(.minecraft\versions\版本名\)
· {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹
· {java}:游戏运行时的 Java 文件夹
除此之外,也支持以下替换标记:
· {user}:玩家名字
· {login}:玩家的登录方式
· {uuid}:玩家的 UUID
· {name}:游戏版本名
· {date}、{time}:当前的系统时间
· {version}:游戏对应的原版版本号
例如:
· "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
· "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
· notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件
涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb
index d9dc7d2..a30267b 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb
@@ -214,7 +214,7 @@
If(RamGame <> RamGameActual, " (可用 " & If(RamGameActual = Math.Floor(RamGameActual), RamGameActual & ".0", RamGameActual) & " GB)", "")
LabRamUsed.Text = If(RamUsed = Math.Floor(RamUsed), RamUsed & ".0", RamUsed) & " GB"
LabRamTotal.Text = " / " & If(RamTotal = Math.Floor(RamTotal), RamTotal & ".0", RamTotal) & " GB"
- LabRamWarn.Visibility = If(RamGame = 1 AndAlso Not JavaIs64Bit() AndAlso Not Is32BitSystem, Visibility.Visible, Visibility.Collapsed)
+ LabRamWarn.Visibility = If(RamGame = 1 AndAlso Not JavaIs64Bit() AndAlso Not Is32BitSystem AndAlso JavaList.Any, Visibility.Visible, Visibility.Collapsed)
If ShowAnim Then
'宽度动画
AniStart({
@@ -551,15 +551,17 @@ PreFin:
End Sub
'版本隔离警告
+ Private IsReverting As Boolean = False
Private Sub ComboArgumentIndie_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ComboArgumentIndie.SelectionChanged
If AniControlEnabled <> 0 Then Exit Sub
+ If IsReverting Then Exit Sub
If MyMsgBox("调整版本隔离后,你可能得把游戏存档、Mod 等文件手动迁移到新的游戏文件夹中。" & vbCrLf &
"如果修改后发现存档消失,把这项设置改回来就能恢复。" & vbCrLf &
"如果你不会迁移存档,不建议修改这项设置!",
"警告", "我知道我在做什么", "取消", IsWarn:=True) = 2 Then
- AniControlEnabled += 1
+ IsReverting = True
ComboArgumentIndie.SelectedItem = e.RemovedItems(0)
- AniControlEnabled -= 1
+ IsReverting = False
End If
End Sub
@@ -571,6 +573,15 @@ PreFin:
CheckAdvanceRunWait.Visibility = If(TextAdvanceRun.Text = "", Visibility.Collapsed, Visibility.Visible)
End Sub
+ 'JVM 参数重设
+ Private Sub TextAdvanceJvm_TextChanged() Handles TextAdvanceJvm.ValidatedTextChanged
+ BtnAdvanceJvmReset.Visibility = If(TextAdvanceJvm.Text = Setup.GetDefault("LaunchAdvanceJvm"), Visibility.Hidden, Visibility.Visible)
+ End Sub
+ Private Sub BtnAdvanceJvmReset_Click(sender As Object, e As EventArgs) Handles BtnAdvanceJvmReset.Click
+ Setup.Reset("LaunchAdvanceJvm")
+ Reload()
+ End Sub
+
#End Region
End Class
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml
index d3d32a3..bf1c1da 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml
+++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml
@@ -78,9 +78,8 @@
-
+
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml
index e9b7edc..0e2f912 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml
+++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml
@@ -72,10 +72,10 @@
-
+
-
-
+
+
@@ -225,6 +225,7 @@
+
@@ -247,6 +248,7 @@
+
@@ -290,8 +292,9 @@
-
-
+
+
+
diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb
index f058d56..f48e8ea 100644
--- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb
@@ -98,6 +98,7 @@
CheckHiddenPageSetup.Checked = Setup.Get("UiHiddenPageSetup")
CheckHiddenPageOther.Checked = Setup.Get("UiHiddenPageOther")
CheckHiddenFunctionSelect.Checked = Setup.Get("UiHiddenFunctionSelect")
+ CheckHiddenFunctionModUpdate.Checked = Setup.Get("UiHiddenFunctionModUpdate")
CheckHiddenFunctionHidden.Checked = Setup.Get("UiHiddenFunctionHidden")
CheckHiddenSetupLaunch.Checked = Setup.Get("UiHiddenSetupLaunch")
CheckHiddenSetupUI.Checked = Setup.Get("UiHiddenSetupUi")
@@ -148,6 +149,7 @@
Setup.Reset("UiHiddenPageSetup")
Setup.Reset("UiHiddenPageOther")
Setup.Reset("UiHiddenFunctionSelect")
+ Setup.Reset("UiHiddenFunctionModUpdate")
Setup.Reset("UiHiddenFunctionHidden")
Setup.Reset("UiHiddenSetupLaunch")
Setup.Reset("UiHiddenSetupUi")
@@ -175,7 +177,7 @@
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboBackgroundSuit.SelectionChanged, ComboCustomPreset.SelectionChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex)
End Sub
- Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckMusicStop.Change, CheckMusicRandom.Change, CheckMusicAuto.Change, CheckBackgroundColorful.Change, CheckLogoLeft.Change, CheckLauncherLogo.Change, CheckHiddenFunctionHidden.Change, CheckHiddenFunctionSelect.Change, CheckHiddenPageDownload.Change, CheckHiddenPageLink.Change, CheckHiddenPageOther.Change, CheckHiddenPageSetup.Change, CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change, CheckHiddenOtherHelp.Change, CheckHiddenOtherTest.Change, CheckMusicStart.Change, CheckLauncherEmail.Change
+ Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckMusicStop.Change, CheckMusicRandom.Change, CheckMusicAuto.Change, CheckBackgroundColorful.Change, CheckLogoLeft.Change, CheckLauncherLogo.Change, CheckHiddenFunctionHidden.Change, CheckHiddenFunctionSelect.Change, CheckHiddenFunctionModUpdate.Change, CheckHiddenPageDownload.Change, CheckHiddenPageLink.Change, CheckHiddenPageOther.Change, CheckHiddenPageSetup.Change, CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change, CheckHiddenOtherHelp.Change, CheckHiddenOtherTest.Change, CheckMusicStart.Change, CheckLauncherEmail.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
End Sub
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextLogoText.ValidatedTextChanged, TextCustomNet.ValidatedTextChanged
@@ -450,10 +452,10 @@ Refresh:
End If
End If
End Sub
- Private Sub LabLauncherTheme8Copy_MouseRightButtonUp() Handles LabLauncherTheme8Copy.MouseRightButtonUp
+ Private Sub LabLauncherTheme8Copy_MouseRightButtonUp() Handles LabLauncherTheme8Copy.MouseRightButtonUp, RadioLauncherTheme8.MouseRightButtonUp
OpenWebsite("https://afdian.com/a/LTCat")
End Sub
- Private Sub LabLauncherTheme9Copy_MouseRightButtonUp() Handles LabLauncherTheme9Copy.MouseRightButtonUp
+ Private Sub LabLauncherTheme9Copy_MouseRightButtonUp() Handles LabLauncherTheme9Copy.MouseRightButtonUp, RadioLauncherTheme9.MouseRightButtonUp
PageOtherLeft.TryFeedback()
End Sub
@@ -673,24 +675,26 @@ Refresh:
SliderLauncherOpacity.GetHintText = Function(v) Math.Round(40 + v * 0.1) & "%"
SliderLauncherHue.GetHintText = Function(v) v & "°"
SliderLauncherSat.GetHintText = Function(v) v & "%"
- SliderLauncherDelta.GetHintText = Function(Value As Integer)
- If Value > 90 Then
- Return "+" & (Value - 90)
- ElseIf Value = 90 Then
- Return 0
- Else
- Return Value - 90
- End If
- End Function
- SliderLauncherLight.GetHintText = Function(Value As Integer)
- If Value > 20 Then
- Return "+" & (Value - 20)
- ElseIf Value = 20 Then
- Return 0
- Else
- Return Value - 20
- End If
- End Function
+ SliderLauncherDelta.GetHintText =
+ Function(Value As Integer)
+ If Value > 90 Then
+ Return "+" & (Value - 90)
+ ElseIf Value = 90 Then
+ Return 0
+ Else
+ Return Value - 90
+ End If
+ End Function
+ SliderLauncherLight.GetHintText =
+ Function(Value As Integer)
+ If Value > 20 Then
+ Return "+" & (Value - 20)
+ ElseIf Value = 20 Then
+ Return 0
+ Else
+ Return Value - 20
+ End If
+ End Function
SliderBackgroundOpacity.GetHintText = Function(v) Math.Round(v * 0.1) & "%"
SliderBackgroundBlur.GetHintText = Function(v) v & " 像素"
End Sub
diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb
index a12b5f7..e44d3e3 100644
--- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionLeft.xaml.vb
@@ -88,17 +88,7 @@
#End Region
Public Sub Refresh(sender As Object, e As EventArgs) '由边栏按钮匿名调用
- '强制刷新
- Try
- CompProjectCache.Clear()
- File.Delete(PathTemp & "Cache\LocalMod.json")
- Log("[Mod] 由于点击刷新按钮,清理本地 Mod 信息缓存")
- Catch ex As Exception
- Log(ex, "强制刷新时清理本地 Mod 信息缓存失败")
- End Try
- If FrmVersionMod IsNot Nothing Then FrmVersionMod.ReloadModList(True) '无需 Else,还没加载刷个鬼的新
- ItemMod.Checked = True
- Hint("正在刷新……", Log:=False)
+ PageVersionMod.Refresh()
End Sub
Public Sub Reset(sender As Object, e As EventArgs)
diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml
index 854458e..d00296d 100644
--- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml
+++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml
@@ -16,11 +16,13 @@
+
-
-
-
-
+
+
+
+
+
@@ -37,10 +39,19 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
index f064346..459a65b 100644
--- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb
@@ -1,4 +1,5 @@
Public Class PageVersionMod
+ Implements IRefreshable
#Region "初始化"
@@ -37,6 +38,24 @@
SearchBox.Text = ""
End If
End Sub
+ '强制刷新
+ Private Sub RefreshSelf() Implements IRefreshable.Refresh
+ Refresh()
+ End Sub
+ Public Shared Sub Refresh()
+ '强制刷新
+ Try
+ CompProjectCache.Clear()
+ CompFilesCache.Clear()
+ File.Delete(PathTemp & "Cache\LocalMod.json")
+ Log("[Mod] 由于点击刷新按钮,清理本地 Mod 信息缓存")
+ Catch ex As Exception
+ Log(ex, "强制刷新时清理本地 Mod 信息缓存失败")
+ End Try
+ If FrmVersionMod IsNot Nothing Then FrmVersionMod.ReloadModList(True) '无需 Else,还没加载刷个鬼的新
+ FrmVersionLeft.ItemMod.Checked = True
+ Hint("正在刷新……", Log:=False)
+ End Sub
Private Sub LoaderInit() Handles Me.Initialized
PageLoaderInit(Load, PanLoad, PanAllBack, Nothing, McModLoader, AddressOf LoadUIFromLoaderOutput, AutoRun:=False)
@@ -136,13 +155,13 @@
'''
Public Sub RefreshUI()
If PanList Is Nothing Then Exit Sub
- Dim ShowMods = GetShowingMods(True).ToList()
+ Dim ShowingMods = If(IsSearching, SearchResult, If(McModLoader.Output, New List(Of McMod))).Where(Function(m) CanPassFilter(m)).ToList
'重新列出列表
AniControlEnabled += 1
- If ShowMods.Any() Then
+ If ShowingMods.Any() Then
PanList.Visibility = Visibility.Visible
PanList.Children.Clear()
- For Each TargetMod In ShowMods
+ For Each TargetMod In ShowingMods
Dim Item As MyLocalModItem = ModItems(TargetMod.RawFileName)
Item.Checked = SelectedMods.Contains(TargetMod.RawFileName) '更新选中状态
PanList.Children.Add(Item)
@@ -151,7 +170,7 @@
PanList.Visibility = Visibility.Collapsed
End If
AniControlEnabled -= 1
- SelectedMods = SelectedMods.Where(Function(m) ShowMods.Any(Function(s) s.RawFileName = m)).ToList '取消选中已经不显示的 Mod
+ SelectedMods = SelectedMods.Where(Function(m) ShowingMods.Any(Function(s) s.RawFileName = m)).ToList '取消选中已经不显示的 Mod
RefreshBars()
End Sub
@@ -169,7 +188,7 @@
Dim DisabledCount As Integer = 0
Dim UpdateCount As Integer = 0
Dim UnavalialeCount As Integer = 0
- For Each ModItem In GetShowingMods(False)
+ For Each ModItem In If(IsSearching, SearchResult, If(McModLoader.Output, New List(Of McMod)))
AnyCount += 1
If ModItem.CanUpdate Then UpdateCount += 1
If ModItem.State.Equals(McMod.McModState.Fine) Then EnabledCount += 1
@@ -298,14 +317,71 @@
''' 全选。
'''
Private Sub BtnManageSelectAll_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageSelectAll.Click
- ChangeAllSelected(SelectedMods.Count < GetShowingMods(True).Count)
+ ChangeAllSelected(SelectedMods.Count < PanList.Children.Count)
End Sub
'''
''' 安装 Mod。
'''
- Private Sub BtnManageInstall_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageInstall.Click
- Hint("将 Mod 文件直接拖入 PCL 窗口即可安装!")
+ Private Sub BtnManageInstall_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageInstall.Click, BtnHintInstall.Click
+ Dim FileList = SelectFiles("Mod 文件(*.jar;*.litemod;*.disabled;*.old)|*.jar;*.litemod;*.disabled;*.old", "选择要安装的 Mod")
+ If Not FileList.Any Then Return
+ InstallMods(FileList)
+ End Sub
+ '''
+ ''' 尝试安装 Mod。
+ ''' 返回输入的文件是否为一个 Mod 文件,仅用于判断拖拽行为。
+ '''
+ Public Shared Function InstallMods(FilePathList As IEnumerable(Of String)) As Boolean
+ Dim Extension As String = FilePathList.First.AfterLast(".").ToLower
+ '检查文件扩展名
+ If Not {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then Return False
+ Log("[System] 文件为 jar/litemod 格式,尝试作为 Mod 安装")
+ '检查回收站:回收站中的文件有错误的文件名
+ If FilePathList.First.Contains(":\$RECYCLE.BIN\") Then
+ Hint("请先将文件从回收站还原,再尝试安装!", HintType.Critical)
+ Return True
+ End If
+ '获取并检查目标版本
+ Dim TargetVersion As McVersion = McVersionCurrent
+ If FrmMain.PageCurrent = FormMain.PageType.VersionSetup Then TargetVersion = PageVersionLeft.Version
+ If FrmMain.PageCurrent = FormMain.PageType.VersionSelect OrElse TargetVersion Is Nothing OrElse Not TargetVersion.Modable Then
+ '正在选择版本,或当前版本不能安装 Mod
+ Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!")
+ ElseIf Not (FrmMain.PageCurrent = FormMain.PageType.VersionSetup AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.VersionMod) Then
+ '未处于 Mod 管理页面
+ If MyMsgBox($"是否要将这{If(FilePathList.Count = 1, "个", "些")}文件作为 Mod 安装到 {TargetVersion.Name}?", "Mod 安装确认", "确定", "取消") = 1 Then GoTo Install
+ Else
+ '处于 Mod 管理页面
+Install:
+ Try
+ For Each ModFile In FilePathList
+ Dim NewFileName = GetFileNameFromPath(ModFile).Replace(".disabled", "")
+ If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227
+ CopyFile(ModFile, TargetVersion.PathIndie & "mods\" & NewFileName)
+ Next
+ If FilePathList.Count = 1 Then
+ Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "")}!", HintType.Finish)
+ Else
+ Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Finish)
+ End If
+ '刷新列表
+ If FrmMain.PageCurrent = FormMain.PageType.VersionSetup AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.VersionMod Then
+ LoaderFolderRun(McModLoader, TargetVersion.PathIndie & "mods\", LoaderFolderRunType.ForceRun)
+ End If
+ Catch ex As Exception
+ Log(ex, "复制 Mod 文件失败", LogLevel.Msgbox)
+ End Try
+ End If
+ Return True
+ End Function
+
+ '''
+ ''' 下载 Mod。
+ '''
+ Private Sub BtnManageDownload_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageDownload.Click, BtnHintDownload.Click
+ PageDownloadMod.TargetVersion = PageVersionLeft.Version '将当前版本设置为筛选器
+ FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadMod)
End Sub
#End Region
@@ -332,9 +408,11 @@
Private Sub ChangeAllSelected(Value As Boolean)
AniControlEnabled += 1
SelectedMods.Clear()
- For Each Item As MyLocalModItem In GetShowingMods(True).Where(Function(m) ModItems.ContainsKey(m.RawFileName)).Select(Function(m) ModItems(m.RawFileName))
- Item.Checked = Value
- If Value Then SelectedMods.Add(Item.Entry.RawFileName)
+ For Each Item As MyLocalModItem In ModItems.Values
+ '#4992,Mod 从过滤器看可能不应在列表中,但因为刚切换状态所以依然保留在列表中,所以应该从列表 UI 判断,而非从过滤器判断
+ Dim ShouldSelected As Boolean = Value AndAlso PanList.Children.Contains(Item)
+ Item.Checked = ShouldSelected
+ If ShouldSelected Then SelectedMods.Add(Item.Entry.RawFileName)
Next
AniControlEnabled -= 1
RefreshBars()
@@ -384,14 +462,6 @@
Unavailable = 4
End Enum
- '''
- ''' 获取所有应该显示在 UI 中的 Mod。
- '''
- Private Function GetShowingMods(ApplyFilter As Boolean) As IEnumerable(Of McMod)
- If McModLoader.Output Is Nothing Then Return New List(Of McMod)
- Return If(IsSearching, SearchResult, McModLoader.Output).Where(Function(m) Not ApplyFilter OrElse CanPassFilter(m))
- End Function
-
'''
''' 检查该 Mod 项是否符合当前筛选的类别。
'''
@@ -510,8 +580,8 @@
Public Shared UpdatingVersions As New List(Of String)
Public Sub UpdateMods(ModList As IEnumerable(Of McMod))
'更新前警告
- If Not Setup.Get("HintUpdateMod") Then
- If MyMsgBox($"新版本 Mod 可能不兼容老版本的存档或者其他 Mod,这可能导致游戏崩溃,甚至存档损坏!{vbCrLf}除非整合包作者要求你更新,否则不要私自更新整合包里的 Mod!{vbCrLf}在更新 Mod 前,请先备份存档,并检查它的更新日志!{vbCrLf}更新时,老版本的 Mod 会被移动到回收站,以防万一。{vbCrLf}{vbCrLf}请在认真阅读上述警告后再继续!", "Mod 更新警告", "我已了解上述风险,继续更新", "取消", IsWarn:=True) = 1 Then
+ If Not Setup.Get("HintUpdateMod") OrElse ModList.Count >= 15 Then
+ If MyMsgBox($"新版本 Mod 可能不兼容旧存档或者其他 Mod,这可能导致游戏崩溃,甚至永久损坏存档!{vbCrLf}如果你在游玩整合包,请千万不要自行更新 Mod!{vbCrLf}{vbCrLf}在更新前,请先备份存档,并检查 Mod 的更新日志。{vbCrLf}如果更新后出现问题,你也可以在回收站找回更新前的 Mod。", "Mod 更新警告", "我已了解风险,继续更新", "取消", IsWarn:=True) = 1 Then
Setup.Set("HintUpdateMod", True)
Else
Exit Sub
diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml
index 6dfb1fa..378e63e 100644
--- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml
+++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml
@@ -213,7 +213,7 @@
+ ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。
在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。
可以使用以下替换标记实现相对路径(路径均以 \ 结尾):
· {path}:PCL 的 exe 文件所在的文件夹
· {minecraft}:.minecraft 文件夹
· {verpath}:版本文件夹(.minecraft\versions\版本名\)
· {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹
· {java}:游戏运行时的 Java 文件夹
除此之外,也支持以下替换标记:
· {user}:玩家名字
· {login}:玩家的登录方式
· {uuid}:玩家的 UUID
· {name}:游戏版本名
· {date}、{time}:当前的系统时间
· {version}:游戏对应的原版版本号
例如:
· "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
· "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
· notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件
涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb
index fbf344d..bc2ed25 100644
--- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb
+++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb
@@ -173,7 +173,7 @@
If(RamGame <> RamGameActual, " (可用 " & If(RamGameActual = Math.Floor(RamGameActual), RamGameActual & ".0", RamGameActual) & " GB)", "")
LabRamUsed.Text = If(RamUsed = Math.Floor(RamUsed), RamUsed & ".0", RamUsed) & " GB"
LabRamTotal.Text = " / " & If(RamTotal = Math.Floor(RamTotal), RamTotal & ".0", RamTotal) & " GB"
- LabRamWarn.Visibility = If(RamGame = 1 AndAlso Not JavaIs64Bit(PageVersionLeft.Version) AndAlso Not Is32BitSystem, Visibility.Visible, Visibility.Collapsed)
+ LabRamWarn.Visibility = If(RamGame = 1 AndAlso Not JavaIs64Bit(PageVersionLeft.Version) AndAlso Not Is32BitSystem AndAlso JavaList.Any, Visibility.Visible, Visibility.Collapsed)
If ShowAnim Then
'宽度动画
AniStart({
@@ -488,15 +488,17 @@ PreFin:
#Region "其他设置"
'版本隔离警告
+ Private IsReverting As Boolean = False
Private Sub ComboArgumentIndie_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ComboArgumentIndie.SelectionChanged
If AniControlEnabled <> 0 Then Exit Sub
+ If IsReverting Then Exit Sub
If MyMsgBox("调整版本隔离后,你可能得把游戏存档、Mod 等文件手动迁移到新的游戏文件夹中。" & vbCrLf &
"如果修改后发现存档消失,把这项设置改回来就能恢复。" & vbCrLf &
"如果你不会迁移存档,不建议修改这项设置!",
"警告", "我知道我在做什么", "取消", IsWarn:=True) = 2 Then
- AniControlEnabled += 1
+ IsReverting = True
ComboArgumentIndie.SelectedItem = e.RemovedItems(0)
- AniControlEnabled -= 1
+ IsReverting = False
End If
End Sub
diff --git a/Plain Craft Launcher 2/Resources/Help.zip b/Plain Craft Launcher 2/Resources/Help.zip
index 972bf25..0edd70f 100644
Binary files a/Plain Craft Launcher 2/Resources/Help.zip and b/Plain Craft Launcher 2/Resources/Help.zip differ
diff --git a/Plain Craft Launcher 2/Resources/ModData.txt b/Plain Craft Launcher 2/Resources/ModData.txt
index 69e47c2..a44a30e 100644
--- a/Plain Craft Launcher 2/Resources/ModData.txt
+++ b/Plain Craft Launcher 2/Resources/ModData.txt
@@ -17,7 +17,7 @@ powerconverters-portablejims-fork|能源转换 (PowerConverters)
modular-forcefield-system|模块化力场系统*
minechem-recompile|化学 (MineChem) - 非官方重编译版¨73373|化学 (MineChem) - 已失效
-iron-chests@cyberanner-ironchest|更多箱子*¨iron-chests-for-fabric|更多箱子 (Iron Chests)¨iron-chests-fabric@|更多箱子 (Iron Chests)
+iron-chests@|更多箱子*¨iron-chests-for-fabric@cyberanner-ironchest|更多箱子 (Iron Chests)¨iron-chests-fabric@|更多箱子 (Iron Chests)
balkons-weaponmod|更多武器 (Balkon's WeaponMod)
advanced-machines|高级机械 (AdvancedMachines)
advanced-solar-panels|高级太阳能*
@@ -175,8 +175,8 @@ extracells2|更多存储单元2 (Extra Cells 2)
billund-223258|乐高 (Billund)
-alchemyplusplus|炼金++ (Alchemy++)
-better-bows|更好弓箭系统 (Better Archery Mod)
+alchemyplusplus|炼金++ (AlchemyPlusPlus)
+better-bows|更好弓箭系统 (Better Archery)
mumblelink|Mumble语音链接*
ender-io@enderio|末影接口 (Ender IO)
@@ -475,7 +475,7 @@ more-swords-mod|更多剑 (MoreSwords)
thaumic-bases|神秘基础学*¨thaumic-bases-unofficial|神秘基础学 (Thaumic Bases)
essentialcraft-3|源质魔法3 (EssentialCraft 3)
-hardcore-questing-mode|困难任务*
+hardcore-questing-mode@hqm|困难任务*
unidict|矿辞统一 (UniDict)
thermal-dynamics@|热动力学*
zoology|动物学*
@@ -672,7 +672,7 @@ real-time-chat-translation-mod|实时聊天翻译*
practical-logistics-2|实用物流监控2*
energyadditions|高级能源 (EnergyAdditions)
-advanced-generators|高级发电机*
+advanced-generators@|高级发电机*
bdlib
pressure-pipes|压力管道*
@@ -789,7 +789,7 @@ simple-void-world|简单虚空世界*
shetiphiancore@¨shetiphiancore-fabric
shadowmc
scannable@|扫描器*
-rebornstorage|存储重置 (Reborn Storage)
+rebornstorage@|存储重置 (Reborn Storage)
quantumstorage|量子存储 (QuantumStorage)
p455w0rds-library
mtlib
@@ -831,7 +831,7 @@ teletoro|远程传送 (TeleToro)
re-zero-kara-hajimeru-isekai-seikatsu|RE:从零开始的异世界 (Re: Zero kara hajimeru isekai seikatsu)
minewatch
thaumcraft-inventory-scanning|神秘时代物品栏扫描*
-cyclic|循环*
+cyclic@|循环*
redstoneplusplus|红石++ (Redstone++)
ctm|连接纹理 (ConnectedTexturesMod)
@@ -962,7 +962,7 @@ solar-expansion
blue-power|蓝石力量 (Blue power)
redstone-armory|红石军械库*
qmunitylib
-
+quest-for-blue-name
the-last-smith|最后的太刀匠人*
mineamp|我的音乐 (MineAmp)
quiverbow|Quiver Bow - 官方原版¨quiverbow-restrung|Quiver Bow - 重制版
@@ -972,7 +972,7 @@ meecreeps@|使命必达先生 (MeeCreeps)
streams|溪流*
blockcraftery|方块工匠*
-bedrockores|基岩矿簇 (Bedrock Ores)
+bedrockores@|基岩矿簇 (Bedrock Ores)
chat-bubbles|聊天泡泡*
refined-storage-addons@|精致存储附属*
foamfix-optimization-mod@foamfix|泡沫修复 (FoamFix)
@@ -1005,7 +1005,7 @@ the-autologin-mod-for-authme-server|自动登录 (AutoLogin)
ROOST|鸡窝 (Roost)
croparia@|矿石作物/魔种之咏*
simple-corn|简单玉米*
-thaumic-jei
+thaumic-jei@
tinkers-steelworks|匠魂炼钢厂 (Tinkers' Steelworks)
unicode-font-extension|Unicode 字体扩展*
placeable-items|可放置物品*
@@ -1119,7 +1119,7 @@ lambda-craft|半条命 (LambdaCraft)
vivecraft@¨vivecraft-forge-extensions
super-sound-muffler|超级消音器*
armorplus@|装备扩充 (ArmorPlus)
-inspirations|灵感*
+inspirations@|灵感*
tree-growing-simulator|跳舞树成长*
personal-cars
@@ -1169,7 +1169,7 @@ inventory-crafting-grid|背包工作台*
kleeslabs@|更好地破坏半砖 (KleeSlabs)¨kleeslabs-fabric|更好地破坏半砖 (KleeSlabs)
gregtechce|格雷科技社区版 (GregTech Community Edition)
-blur@blur-fabric|界面背景模糊*¨blur-fabric|界面背景模糊 (Blur)
+blur@blur-plus|界面背景模糊*¨blur-fabric|界面背景模糊 (Blur)
fast-leaf-decay|树叶快速腐烂*
enable-cheats|开启作弊模式*
findit|找到它 (Findit!)
@@ -1213,7 +1213,7 @@ in-game-account-switcher@|游戏内账号切换 (In-Game Account Switcher)
consecration@|圣化*
ignite-hud|燃点HUD (Ignite HUD)
mrcrayfishs-gun-mod|MrCrayfish的枪 (MrCrayfish's Gun Mod)
-bloodmoon|血月 (bloodmoon)
+bloodmoon|血月*
obfuscate
runic-dungeons|符文地牢 (Runic Dungeon)
poop|屎 (Poop Mod)
@@ -1243,7 +1243,7 @@ the-mists-of-riov|神秘世界 (The Mists of RioV Mod)
nsr-no-respawn-screen|无重生屏幕 (No Respawn Screen)
more-bees|蜜蜂拓展*
evilnotchlib
-tpalette|调色板 (TPalette)
+tpalette-forge|调色板 (TPalette)¨tpalette|调色板 (TPalette) - 文件覆盖
career-bees|职业蜜蜂*
@@ -1436,7 +1436,7 @@ new-tardis-mod
advanced-chimneys|高级烟囱*
regeneration|神秘博士 - 再生 (Doctor Who - Regeneration)
-more-planets-gc-addon
+stevekungs-lib
make-zoom-zoom|更快的加载 (MakeZoomZoom)
minecraft-virtual-machines|Minecraft虚拟机*
cavern2|洞穴 II (Cavern II)
@@ -1698,7 +1698,7 @@ huajiage-infinite-galaxy|滑稽纪元II:无尽星河 (Huaji Age II:Infinite Gala
cqrepoured|寻找巧克力重铸版 (Chocolate Quest Repoured)
fabricproxy@|Fabric 群组支持 (FabricProxy)
ex-sartagine|锅具*
-xaeros-minimap@|Xaero的小地图 (Xaero's Minimap) - 完整版¨xaeros-minimap-fair-play-edition@xaeros-minimap-fair|Xaero的小地图 (Xaero's Minimap) - 公平竞争版
+xaeros-minimap|Xaero的小地图 (Xaero's Minimap) - 默认版(功能完整)¨xaeros-minimap-fair-play-edition|Xaero的小地图 (Xaero's Minimap) - 公平竞争版(功能部分缺失)¨@xaeros-minimap|Xaero的小地图 (Xaero's Minimap) - 完整版¨@xaeros-minimap-fair|Xaero的小地图 (Xaero's Minimap) - 公平竞争版
everlastingabilities-potioncore|永恒能力-药水核心 (EverlastingAbilities-PotionCore)
optifabric
the-emerald-haven|翡翠天堂*
@@ -1959,7 +1959,7 @@ iron-chest-minecarts|更多箱子矿车*
nether-chest|下界箱子*
mob-kill-messages|击杀信息通知*
-betterdispenser|能喂食的发射器 (Better Dispenser)
+betterdispenser|能喂食的发射器 (BetterDispenser)
shulkerboxdisplay|潜影盒显示器 (ShulkerBoxDisplay)
mycommands|我的命令 (MyCommands)
@@ -2037,7 +2037,7 @@ modular-magic|模块化魔法*
magic-kingdoms-mod|魔法王国 (Magic Kingdoms Mod/Schools of Magic Mod)
zollern-galaxy|卓伦星系*
-macaws-bridges|Macaw的桥梁 (Macaw's Bridges)
+macaws-bridges@|Macaw的桥梁 (Macaw's Bridges)
trample-stopper|防止踩踏*¨trample-stopper-fabric|防止踩踏 (Trample Stopper)
macaws-roofs@|Macaw的屋顶 (Macaw's Roofs)
@@ -2135,7 +2135,7 @@ arcanum|奥秘*
random-enchants|随机附魔*
much-more-spiders-v2|更多种类的蜘蛛 (Much More Spiders)
compressed-items
-no-tree-punching|无树可撸*
+no-tree-punching@|无树可撸*
harvest-festival-legacy|丰收物语移植版*
friendlymobs|友好的怪物 (FriendlyMobs)
simplecore-api@|简单前置 (SimpleCore API)
@@ -2346,7 +2346,7 @@ fishs-undead-rising|Fish的不死崛起/Fish的亡灵崛起 (Fish's Undead Risin
cloth-config@
just-map
too-realistic-inventory|真实背包 (Realistic Inventory)
-mob-farm|生物农场 (Mob farm)
+mob-farm|生物农场*
acceleratorcraft|加速器工艺 (AcceleratorCraft)
minecraft-spongebob-squarepants-mod-for-the-1-7-10
utility-worlds|实用世界*
@@ -2570,8 +2570,8 @@ angrysun|炙热太阳 (AngrySun)
its-not-long-enough|与现实相同的昼夜交替 (It's Not Long Enough)
sunscreen-gel|防晒霜*
muya1-7-10|姆亚核心 (MuyaCore)
-macaws-furniture|Macaw的家具 (Macaw's Furniture)
-macaws-doors|Macaw的门 (Macaw's Doors)
+macaws-furniture@|Macaw的家具 (Macaw's Furniture)
+macaws-doors@|Macaw的门 (Macaw's Doors)
blueprint@
geyser-mod
not-enough-pets@|更多宠物*
@@ -2751,7 +2751,7 @@ mobs-attempt-parkour@
identity|化身*¨identity-on-forge|化身 (Identity)
industrial-revolution@|工业革命*
art-of-alchemy|炼金艺术 (Art of Alchemy)
-lan-server-properties|自定义局域网联机*
+lan-server-properties@|自定义局域网联机*
immersive-intelligence@|沉浸智能*
analyzeio
@@ -2835,7 +2835,7 @@ rustic-thaumaturgy|神秘乡村*
thallium|铊*
haema@
evil-ores
-unsuspicious-stew|炖菜解谜/炖菜效果显示*
+unsuspicious-stew@|炖菜解谜/炖菜效果显示*
tfc-seasonal
imblockerfabric@imblocker|输入法冲突修复 (IMBlockerFabric)
saomclib
@@ -2915,7 +2915,7 @@ costumes|服装*
eyemod-phone
upgrade-aquatic@|碧海新生*
tfc-ambiental
-macaws-trapdoors|Macaw的活板门 (Macaw's Trapdoors)
+macaws-trapdoors@|Macaw的活板门 (Macaw's Trapdoors)
zenutil
better-beacon-effect|更好的信标效果*
@@ -2967,14 +2967,14 @@ time-to-live
dual-hotbar-1-12-2|双重快捷栏1.12.2 (Dual Hotbars 1.12.2)
cha-s|可合成的马铠和鞍 (Craftable Horse Armour & Saddle)
dual-hotbar|双重快捷栏 (Dual Hotbars)
-travellers-boots
+travellers-boots@
cofh-vanilla-satchels
betteranimalsplus|更多动物 (Better Animals Plus)
packagedauto@|封包合成 (PackagedAuto)
packagedexcrafting@|封包合成拓展 (PackagedExCrafting)
-compactstorage|紧凑存储 (compactstorage)¨@compact_storage|紧凑存储 (compactstorage) - 已失效
+compactstorage@compact-storage|紧凑存储 (compactstorage)
useful-backpacks@|实用背包*
conquest-reforged@|征服者*
steelseries-gamesense
@@ -3508,7 +3508,7 @@ emotecraft@|表情工艺*¨emotecraft-forge|表情工艺 (Emotecraft)
pattysmorestuff@
hats|帽子*
smoother-bedrock|平滑基岩层*
-c2me-fabric@|C^2M 引擎 (C^2M-Engine/Concurrent Chunk Management Engine)
+c2me-fabric@|C^2M 引擎 (C^2M-Engine/Concurrent Chunk Management Engine)¨@c2me-neoforge|C^2M 引擎 (C^2M-Engine/Concurrent Chunk Management Engine)
datapack-anvil
nuclear-science@|核科学*
glaretorch|强光火把 (Glare Torch)
@@ -3578,7 +3578,7 @@ simple-drawers|简单的抽屉*
charmonium¨charmonium-reforged@charmonium
xnicex@
krate
-chickensshed|鸡棚重置版 (ChickensShed)
+chickensshed@|鸡棚重置版 (ChickensShed)
chickenshed
expanded-storage@|扩展存储*¨expanded-storage-fabric|扩展存储 (Expanded Storage)¨expanded-storage-forge|扩展存储 (Expanded Storage)
project-mmo@
@@ -3598,7 +3598,7 @@ simply-tea|简单的茶! (Simply Tea!)
buttermilk
diet@|均衡饮食*
brazilian-fields|巴西风情*
-ae2-extras|AE2附加 (AE2 Extras)
+ae2-extras|AE2 附加 (AE2 Extras)
animalium|动物*
mob-origins@moborigins|生物起源*
better-default-biomes|更好的默认生物群系*
@@ -3612,7 +3612,7 @@ mc-modsurement@allurement!
dwarf-miner-totem|矮人矿工*
yungs-better-portals|YUNG 的传送门机制重构 (YUNG's Better Portals)
german-road-signs-mod|德国交通标志*
-iguana-in-a-blanket|真实调整 (Iguana in a Blanket)
+iguana-in-a-blanket@iguana|真实调整 (Iguana in a Blanket)
anthill-inside|蚂蚁物流*
nei-integration
uncrafting-grinder|分解磨床*
@@ -3663,7 +3663,7 @@ wool-temples@|羊毛神殿*
exp-bottling|经验装瓶 (EXP Bottling)
buildersaddition@
gt-remastered|格雷科技重制版 (GT: Remastered)
-tips|提示*
+tips@|提示*
Interactio
advancement-book|进度之书*
drawers-tooltip|抽屉提示*
@@ -3736,13 +3736,13 @@ engineers-workshop-reborn
crimson-xp-charm|经验护符 (Crimson XP)
locatebiome
enderman-evolution
-sophisticated-backpacks|精妙背包*
+sophisticated-backpacks@|精妙背包*
age-of-exile
whoosh
gregtech-intergalactical|泛银河系格雷科技 (GregTech Intergalactical)
catalogue|模组目录*¨catalogue-fabric|模组目录 (Catalogue)
libblockattributes
-balance-of-exile
+
dungeons-of-exile
lots-more-food-forge@lots-more-food¨lots-more-food-fabric
@@ -3776,7 +3776,7 @@ flower-seeds
astemirs-forest-craft
astromine-foundations|天体矿工:基础 (Astromine: Foundations)
-create-stuff-additions@|机械动力:物品附加 (Create Stuff & Additions)
+create-stuff-additions|机械动力:物品附加 (Create Stuff & Additions)¨@create-stuff-additions|机械动力:物品附加 (Create Stuff & Additions) - 未及时更新
slab-machines|台阶型设备*
more-create-stuffs|更多机械动力物品*
rsinfinitybooster|RS 无限范围增幅卡 (RSInfinityBooster)
@@ -3887,7 +3887,7 @@ tis-3d@tis3d
entity-nan-health-fix|假死修复 (Entity NaN Health Fix)
ferritecore@ferrite-core|铁氧体磁芯 (FerriteCore)¨ferritecore-fabric|铁氧体磁芯 (FerriteCore)
thaumcraft-research-patcher
-masterful-machinery
+masterful-machinery@
minecraft-earth-mod|Derec 的地球生物 (Derec's Earth Mobs)
scotts-essential
drawerfps|储物抽屉渲染配置 (DrawerFPS)
@@ -4087,7 +4087,7 @@ fps-reducre-for-fabric|FPS减速器(Fabric) (FPS Reducer (For Fabric))
art-artillery|艺术?火炮! (Art? Artillery!)
minemenufabric@|我的菜单 Fabric 版 (MineMenuFabric)
@tabtps
-afkpeace@
+afkpeace|AFKPeace - 停止更新¨@afkpeace
smooth-chunks|平滑区块加载*¨@smooth-chunks|平滑区块加载 (Smooth Chunks) - 已失效
@@ -4172,7 +4172,7 @@ tool-progression|工具进阶*
a-paimon|派蒙*
-
+@bh-creative
music-maker-mod
penguin-lib
flywheel@|飞轮*
@@ -4218,7 +4218,7 @@ tfc-medicinal
water-flasks
structure-world
-macaws-lights-and-lamps|Macaw的灯 (Macaw's Lights and Lamps)
+macaws-lights-and-lamps@|Macaw的灯 (Macaw's Lights and Lamps)
terrarian-slimes@
create-gears|机械动力:齿轮附加*
simple-big-backpack
@@ -4296,7 +4296,7 @@ superhotmc
bag-of-yurting@|帐篷袋 (Bag of Yurting)
better-combat-rebirth|更好的战斗:重生*
iron-and-gold-from-1-17|来自 1.17 的铁和金 (iron and gold from 1.17)
-immersive-cooking|沉浸烹饪*
+immersive-cooking@|沉浸烹饪*
structured-crafting
random-shulker-colours@|随机潜影贝颜色*¨random-shulker-colours-fabric|随机潜影贝颜色 (Random Shulker Colours)
create-automated
@@ -4548,7 +4548,7 @@ better-furnaces-reforged@|更好的熔炉重铸版 (BetterFurnaces Reforged)
schools-of-magic-second-semester|魔法学校:第二学期 (Schools of Magic: Second Semester)
dark-loading-screen@|深色加载界面*
-hals-exploration-mod
+hals-exploration-mod@hals%20exploration%20mod
farmers-delight-cookbook-addon|农夫乐事:烹饪书拓展 (Farmer's Delight Cookbook Addon)
heads-down-display@head-down-display
mrcrayfish-more-furniture-mod|MrCrayfish 的更多家具 (MrCrayfish's More Furniture Mod)
@@ -4591,7 +4591,7 @@ detail-armor-bar-forge@detail-armor-bar|细节盔甲 (Detail Armor Bar)¨detail-
wings-horns-hooves-the-ultimate-unicorn-mod
project-rankine@rankine|兰金计划*
tinkers-mechworks@
-qdc-quantum-dis-assembly-craft|量子拆解工艺 (Quantum Dis-Assembly Craft)
+qdc-core-4-0@qdc-core-4.0|量子拆解工艺 (Quantum Dis-Assembly Craft)¨qdc-quantum-dis-assembly-craft|量子拆解工艺 (Quantum Dis-Assembly Craft) - 旧
william-wythers-overhauled-overworld@wwoo¨expanded-ecosphere@
infinite-music
cobbler|可靠的潜影贝工厂 (Shulker's Faithful Factories/Cobbler)
@@ -4649,7 +4649,7 @@ maidens-marvelous-materials
nekoration@|猫咪装饰*
tomb-many-graves-2
fins-and-tails|鳍和尾巴 (Fins and Tails)
-smarter-farmers-farmers-replant@|更聪明的农夫 (Smarter Farmers/Farmers Replant)
+smarter-farmers-farmers-replant@|更聪明的农夫 (Smarter Farmers / Farmers Replant)
peculiars|独特风味*
draggable-resource-packs@draggable-lists|可拖动列表/可拖动资源包 (Draggable Lists/Draggable Resource Packs)
fastchest|快速箱子渲染 (FastChest) - 已不再更新¨@fastchest|快速箱子渲染 (FastChest) - 在此处更新
@@ -4816,7 +4816,7 @@ hourglass@|沙漏*
relics-mod@|遗物 (Relics)
comfortable-nether|舒适下界*
arcanecraft-ii|奥法工艺2 (ArcaneCraft II)
-presence-footsteps-forge|脚步声Forge版 (Presence Footsteps (Forge))
+presence-footsteps-forge@resence-footsteps-forge|脚步声Forge版 (Presence Footsteps (Forge))
aardvarks-weird-wonderful-wild
@@ -4848,7 +4848,7 @@ dark-caverns|暗黑深穴*
-milk-all-the-mobs¨milk-all-the-mobs-fabric
+milk-all-the-mobs@¨milk-all-the-mobs-fabric
roadrunner
pokecube-aoi
grim-statues|Grim的雕像*
@@ -4878,7 +4878,7 @@ ex-nihilo-random|无中生有:随想 (Ex Nihilo: Random)
fabrictailor|离线皮肤切换 (Fabric Tailor)
ambientworld
-
+@custom-raid|自定义袭击 (Custom Raid)
apple-trees-revived|苹果树:复生*
potatos-lucky-block|马铃薯幸运方块 (Potato's Lucky block)
even-more-tnt
@@ -5141,7 +5141,7 @@ refined-relocation-2|简单分类2*
ftb-sluice
sky-villages-forge@sky-villages|天空村庄 (Sky Villages)¨sky-villages-fabric|天空村庄 (Sky Villages)
gui-clock@¨gui-clock-fabric-version
-hand-over-your-items¨hand-over-your-items-fabric
+hand-over-your-items@¨hand-over-your-items-fabric
koopas-critters
krypton-reforged|氪Forge版*
item-counter|物品计数器*
@@ -5196,7 +5196,7 @@ more-respawn-anchors|更多重生锚*¨more-respawn-anchors-forge|更多重生
werewolves-become-a-beast@werewolves|狼人 (Werewolves)
omnipotent-card@|万用卡牌*
-does-it-tick
+does-it-tick@
public-gui-announcement|公开GUI显示*
wet-lava-sponge
ripples-of-the-past¨@ripples-of-the-past|Ripples of the Past - 最新版(包括公开测试版)
@@ -5298,7 +5298,7 @@ mythicmetals@|神话金属 (Mythic Metals)
creeper-firework@|烟花苦力怕*
second-chance@second-chance-forge¨second-chance-forge
promenade@
-london-underground@the-tube|伦敦地铁 (The London Underground)
+london-underground@the-tube|伦敦地铁 (MTR London Underground Addon)
dynamiclights-reforged@sodium-dynamic-lights|钠/Embeddium:动态光源 (Sodium/Embeddium Dynamic Lights)
the-wild-mod@|荒野更新*
tuff-depth|凝灰岩深度*
@@ -5308,7 +5308,7 @@ framework¨framework-fabric
anointed-items
-golden-age-combat|黄金时代的战斗*
+golden-age-combat@|黄金时代的战斗*
magnesium-extras|钠/Embeddium:附属 (Sodium/Embeddium Extras) - 全部¨@sodium-extras|钠/Embeddium:附属 (Sodium/Embeddium Extras)
chest-tracker@|箱子追踪*
advancementinfo@|进度信息展示 (AdvancementInfo)
@@ -5324,7 +5324,7 @@ speedrunigt@
archmagus
slimyboyos@
fireplace-lib@¨fireplace-lib-forge
-immersive-geology|沉浸地质学*
+immersive-geology@|沉浸地质学*
wool-tweaks@|羊毛调整*¨wool-tweaks-fabric|羊毛调整 (Wool Tweaks)
tools-complement@
adventtic
@@ -5345,17 +5345,17 @@ eggtab-fabric|独立刷怪蛋列表 (Egg Tab)¨eggtab-forge|独立刷怪蛋列
always-a-wither-skull@|必得凋灵骷髅头颅 (Always a Wither Skull)¨always-a-wither-skull-fabric|必得凋灵骷髅头颅 (Always a Wither Skull)
anvil-restoration@|铁砧修复*¨anvil-restoration-fabric|铁砧修复 (Anvil Restoration)
hide-hands-fabric@hide-hands|隐藏主副手 (Hide Hands)¨hide-hands|隐藏主副手*
-better-beacon-placement-fabric@better-beacon-placement|更好的信标放置 (Better Beacon Placement)¨better-beacon-placement|更好的信标放置*
+better-beacon-placement@|更好的信标放置*¨better-beacon-placement-fabric|更好的信标放置 (Better Beacon Placement)
dead-totems
functional-storage@|功能性存储*
the-wild-update|荒野更新 1.19 (The Wild Update 1.19)
archeology@|考古学 (CapsLock Archeology)
-trinkets-and-baubles|饰品与小玩意 (Trinkets and Baubles)
+trinkets-and-baubles@|饰品与小玩意 (Trinkets and Baubles)
rope-ladders|绳梯*
skewers-updated|烤串更新版*
-keep-my-soil-tilled-fabric|保持肥沃 (Keep My Soil Tilled)¨keep-my-soil-tilled|保持肥沃*
+keep-my-soil-tilled@|保持肥沃*¨keep-my-soil-tilled-fabric|保持肥沃 (Keep My Soil Tilled)
double-doors@|双开门*¨double-doors-fabric|双开门 (Double Doors)
expanded-armor-enchanting@|盔甲附魔扩展*
expanded-weapon-enchanting@|武器附魔扩展*
@@ -5371,7 +5371,7 @@ leap@
cameraoverhaul@
enchantment-id-extender@eide
creeper-overhaul@|苦力怕改革/苦力怕革新*
-cool-elytra-roll
+cool-elytra-roll@
camera-overhaul-forge
blame¨blame-fabric
patboxs-banhammer@banhammer
@@ -5416,7 +5416,7 @@ customnpc-plus@|自定义NPC+ (CustomNPC+)
ingredient-extension-api@
wireless-networks
-compass-manhunt
+compass-manhunt@
exlines-furniture@
tinkers-archery|工匠箭术 (Tinkers' Archery)
designer-modeling|设计师建模*
@@ -5495,7 +5495,7 @@ mcdw@|我的世界:地下城武器 (MC Dungeons Weapons)
beta-creepers
-macaws-paintings|Macaw的画 (Macaw's Paintings)
+macaws-paintings@|Macaw的画 (Macaw's Paintings)
dyenamics
multi-piston
blood-magic@|血魔法*
@@ -5604,7 +5604,7 @@ botany-pots-ore-planting@|植物盆栽矿石种植*
satin-api@
easy-magic@|简易附魔台*
-enlightend¨@enlightened-end|Enlightend/Enlightened End/Nourished End - 已失效¨@enlightend|Enlightend/Enlightened End/Nourished End - 未失效
+enlightend@|末地启明 (Enlightend/Enlightened End/Nourished End)
rubidium@|铷*
cultural-delights@|多元乐事*
@@ -5682,7 +5682,7 @@ power-utilities-remastered|能源转换重制*
create-gear-addon
gun-mod-tl
-energymeter
+energymeter@
@headindex|头颅菜单 (Head Index)
quantum-generators|量子发电机*
simply-quarries|简易采石场*
@@ -5775,7 +5775,7 @@ creatures-of-the-snow@creatures-from-the-snow-fabric|雪地里的生物! (Crea
collisions-lib@
wooled-boots@|羊毛靴子*
zawa-evolved|野生动物园:进化 (Zoo and Wild Animals: Evolved)
-bongo@
+bongo@|宾果游戏*
impersonate@
calemi-core@ccore
@@ -5823,7 +5823,7 @@ zettai-ars
cant-sleep-clowns-will-eat-me@|夜不能寐 (Can't Sleep Clowns Will Eat Me)
colony-cards|殖民地卡牌*
autoharvest|自动收获 (AutoHarvest)
-realistic-block-physics
+realistic-block-physics@
domestication-innovation@|驯养革新*
snuffles@|魄罗*
flan-forge@flan¨flan
@@ -5878,7 +5878,7 @@ robins-ruby-mod
just-needed@justneeded¨just-needed-fabric
nodami-remake|伤害免疫机制移除重制版 (NoDamIRemake)
-had-enough-items|HEI物品管理器*
+had-enough-items@|HEI物品管理器*
worldinfo
@bang
block-helper@
@@ -5889,7 +5889,7 @@ gregicprobe
travelers-index
dimension-data-fix|维度数据修复*
-gtce-bees
+gtce-bees|GTCE 蜜蜂 (GTCE Bees)
armory-expansion-bits-and-pieces
@@ -6135,7 +6135,7 @@ the-binding-of-isaac-tears-mod
humbling-bundle@|慈善捆绑包*
grindstone-sharper-tools@¨grindstone-sharper-tools-fabric
nutritious-milk@¨nutritious-milk-fabric|Nutritious Milk - 文件已失效
-extract-poison¨extract-poison-fabric
+extract-poison@¨extract-poison-fabric
zombie-villagers-from-spawner@¨zombie-villagers-from-spawner-fabric
vine-climber
healing-soup@¨healing-soup-fabric
@@ -6159,7 +6159,7 @@ orcz
sandwichable@
@shelve-refabricated
mod-erate-loading-screen@moderate-loading-screen
-shrink_
+shrink_@shrink
cable-tiers
jumbo-furnace@
no-villager-death-messages@
@@ -6217,7 +6217,7 @@ atm-additions
extra-tags|额外标签*
advancedchatlog@AdvancedChatLog
crafting-station|合成站*
-sons-of-sins@
+sons-of-sins@|七罪之子*
advancedchathud@AdvancedChatHUD
fuzes-relics
chirpys-wildlife@wildlife-fabric
@@ -6321,7 +6321,7 @@ colored-allays|染色悦灵*
phantasm@ends-phantasm
emerald-craft-mod@emerald-craft|绿宝石工艺*
roughly-enough-professions-rep@|REI工作方块 (Roughly Enough Professions)
-sophisticated-core|精妙核心*
+sophisticated-core@|精妙核心*
edibles@¨edibles-fabric
reach-fix
lootjs-forge
@@ -6347,7 +6347,7 @@ illager-plushies¨illager-plushies-fabric
pillageplunder
extended-illagers-mod
midnightcontrols@
-wonderful-enchantments
+wonderful-enchantments@majruszs-enchantments
a-lot-of-useless-stuff
lankaster-origins
@@ -6578,7 +6578,7 @@ better-block-sounds@bbs
v0ids-smart-backpacks|V0id的智能背包 (V0id's Smart Backpacks)
-winterly@
+winterly@|银装素裹*
forgetmechunk@¨forgetmechunk-forge
@moremusic
@@ -6625,7 +6625,7 @@ zoomify@
golemania@
vulkanmod@
sledgehammer
-quilt-loading-screen|Quilt加载画面* - 不再更新¨@quilt-loading-screen|Quilt加载画面 (Quilt Loading Screen)
+quilt-loading-screen|Quilt 加载画面* - 不再更新¨@quilt-loading-screen|Quilt 加载画面 (Quilt Loading Screen)
amethyst-imbuement@|紫晶魔艺*
emi@
nuclear-contraptions
@@ -6679,7 +6679,7 @@ keybinds@
hat-list@hatlist
nmuk@
raven-brews-core
-raven-coffee|Raven咖啡*
+raven-coffee@raven-coffee-mod|Raven咖啡*
cqc
geode
realistic-spiders|真实的蜘蛛*
@@ -6708,7 +6708,7 @@ no-telemetry@
create-chromatic-return|机械动力:异彩化合物 (Create: Chromatic Return)
coffee-spawner
timber-mod@timber-mod-by-mycf
-sophisticated-storage|精妙存储*
+sophisticated-storage@|精妙存储*
advanced-lootable-weapons
what-the-bucket
quickhomes
@@ -7058,10 +7058,10 @@ endlessids@
@cpm-fabric|压缩空间 Fabric (Compact Machines - Fabric)
cycle-paintings@¨cycle-paintings-fabric
-fire-spread-tweaks¨fire-spread-tweaks-fabric
+fire-spread-tweaks@¨fire-spread-tweaks-fabric
anger-management
easy-elytra-takeoff@¨easy-elytra-takeoff-fabric
-stack-refill¨stack-refill-fabric
+stack-refill@¨stack-refill-fabric
light-meals@|轻食物语*
lost-and-fished@lost-fished|失而钓得 (Lost and Fished)
custom-backgrounds
@@ -7090,7 +7090,7 @@ twigs@
-@fplib
+fplib@
spongemixins¨@spongemixin1710
nock-enough-arrows
every-compat@|泛用兼容:木材 (Every Compat: Wood Good)
@@ -7172,7 +7172,7 @@ extrabotany2|额外植物学重置版 (ExtraBotany2)
terramine@
aeinfinitybooster
endertech-infinity|Endertech Infinity - 已失效¨@endertech-infinity
-more-frogs-fabric|更多青蛙 (More Frogs)
+more-frogs-fabric@morefrogs|更多青蛙 (More Frogs)
create-big-cannons@|机械动力:火炮*
@@ -7202,7 +7202,7 @@ another-furniture@|别样家具*
rayon@
-ponder
+ponder@
ender-logistics|末影物流*
@@ -7415,7 +7415,7 @@ visible-toggle-sprint@
let-me-despawn@lmd
glsl-panorama@
feyfriends@
-mccalc
+mccalc@
nekeys
crafted-forge¨crafted
cursery
@@ -7485,7 +7485,7 @@ shiny-horses@
nyx-rotn-edition
playeranimator@
-apathy-mod
+apathy-mod@apathy
auudio-forge@auudio¨auudio-fabric
easy-shulker-boxes@
@@ -7575,7 +7575,7 @@ spirit@
elytra-bounce@
no-report-button@nrb
mana-wizardry
-aileron
+aileron@
@devworld
immersive-weapons-compatibility-bridge
@@ -8373,7 +8373,7 @@ mineterrariabosses
biomes-in-jars-forge@biomes-in-jars|群系罐子 (Biomes in Jars)¨biomes-in-jars-fabric|群系罐子 (Biomes in Jars)
@bocchitheblock
craftable-potion-combinations@craftablepotioncombinations
-polylib
+polylib@
@creeper-fire-charge-fix|Creeper火焰弹修复 (Creeper Fire Charge Fix)
tags-binder@
fastcaps
@@ -8442,7 +8442,7 @@ re-ftbqkeys@|FTB任务本地化键:重置 (Re-FTBQLocalizationKeys)
enchantment-sort|附魔排序*
wrapfix|换行修复 (WrapFix)
gem-crabs|宝石蟹*
-create-rainbow-compound|机械动力:彩虹化合物 (Create: Rainbow Compound)
+create-rainbow-compound@rainbowcompound|机械动力:彩虹化合物 (Create: Rainbow Compound)
inmis-back-pack-mod-retextured
thonkutil
xp-storage@
@@ -8467,7 +8467,7 @@ treasure2-twilight-forest-loot-pack
sanity-and-insanity
crops-love-rain@
till-zombies-tear-us-apart
-difficult-raids
+difficult-raids@
gag
bleach-awaken-by-deephantom15
@@ -8549,7 +8549,7 @@ codechickenlib-unofficial@
codechickencore-unofficial@|鸡块核心非官方版 (CodeChickenCore Unofficial)
permafrost-biome
-ambient-additions
+ambient-additions@ambientadditions
sweep|扫雷 (Minesweeper)
sekclib
@@ -8606,7 +8606,7 @@ shipping@
structureutils
@cloudmusic|云音乐 (CloudMusic)
i-like-wood
-macaws-furnitures-biomes-o-plenty|Macaw的家具:超多生物群系附属 (Macaw's Furnitures - Biomes O' Plenty)
+macaws-furnitures-biomes-o-plenty@|Macaw的家具:超多生物群系附属 (Macaw's Furnitures - Biomes O' Plenty)
macaws-furnitures-oh-the-biomes-youll-go@|Macaw的家具:你将去的生物群系附属 (Macaw's Furnitures - Oh The Biomes You'll Go)
armiger
news-pillagers
@@ -8820,7 +8820,7 @@ glacier-ice
gtnhmixins@
dawn-to-dusk
open-tower-defence@|开放式塔防*
-mtr-station-decoration@station-decoration|MTR车站装饰 (MTR Station Decoration)
+mtr-station-decoration@station-decoration|MTR车站装饰 (Station Decoration)
perviaminvenire
silverbirch@silver-birch
@@ -8878,7 +8878,7 @@ even-more-creatures-mod
eerie-entities
better-weather-revived
-rlcombat|更好的战斗-RLCraft版 (RLCombat)
+rlcombat@|更好的战斗-RLCraft版 (RLCombat)
botanical-addons
@scoreboards-backup|计分板备份 (Scoreboards Backup)
hodgepodge@
@@ -8894,7 +8894,7 @@ wizards@|魔法师*
basketcase
primal-lib
biomes-youll-go-1-12-2-fixed|你将去的生物群系修复版 (Biomes You'll Go Fixed)
-rune-crafting|符文 (Runes)
+rune-crafting@runes|符文 (Runes)
controlled-random
leos-bosses|Leo的Boss (Leo's Bosses)
leos-illagers
@@ -8942,7 +8942,7 @@ ob-pandorica
no-weather-effects@
ob-tooltips
hekate-lib
-loot-journal
+loot-journal¨loot-journal-neoforge¨loot-journal-fabric
@@ -8978,7 +8978,7 @@ monoblocks
tinkers-things-json@tinkers-things|匠魂杂物 (Tinkers' Things)
free-cam¨@freecam|Freecam - 无作弊版
workings@
-@mod-loading-screen
+@mod-loading-screen|模组加载屏幕 (Mod Loading Screen)
lucky-cases
atmosfera
feruchemy-allomancy|藏金术 (Feruchemy)
@@ -9214,7 +9214,7 @@ tnt-breaks-bedrock@
from-the-north@
spruce-willis-the-xmas-tree@
sweet-potato-core-spc|地瓜核心 (Sweet Potato Core)
-merge-enchantments
+merge-enchantments@
turkey|火鸡*
snowy-weaponry@
@@ -9384,8 +9384,8 @@ blood-and-stuff@
yungs-better-nether-fortresses@|YUNG的下界要塞优化 (YUNG's Better Nether Fortresses)¨yungs-better-nether-fortresses-fabric|YUNG的下界要塞优化 (YUNG's Better Nether Fortresses)¨yungs-better-nether-fortresses-neoforge|YUNG的下界要塞优化 (YUNG's Better Nether Fortresses)
squidless
-enders-delight|末影乐事 (Ender's Delight)
-decostorage
+enders-delight@|末影乐事 (Ender's Delight)
+decostorage@decorative-storage
mahogany
aspen
unmending-potato-edition|经验不修补:土豆版*
@@ -9542,7 +9542,7 @@ opotato|哦,土豆!*
contingameime@|游戏内输入法续更版 / 游戏内输入法 Forge 重置版 (ContingameIME / IngameIME-Forge / IngameIME-Forged)
ccastroadds
aerial-hell@
-swashbucklers
+swashbucklers@
style
eatable-livestock
hunger-strike|绝食*
@@ -9575,7 +9575,7 @@ geore-nouveau
crimsonsteves-more-mobs
the-ulterlands
mt-lotr
-asjcore
+asjcore@
bane-tooltips-mod|克星信息显示*
lava-crystal
literal-sky-block
@@ -9797,12 +9797,12 @@ compressor@
hexal@|咒法拓展*
-create-encased@
+create-encased@|机械动力:封装工艺*
@treeplacer
death-knell@
moreiotas@
numismatic-overhaul@¨numismatic-overhaul-reforged
-@hexbound|咒法组构学 (Hexbound)
+hexbound-fork@|咒法组构学 (Hexbound)¨@hexbound|咒法组构学 (Hexbound) - 原-已失效
vanity-druid-pack
vanity-farcrs-colossal-weapons
debris-chunk-raw-netherite-scrap@raw-netherite-scrap|残骸碎块 (Debris Chunk)
@@ -9841,7 +9841,7 @@ variant-crafting-tables
endless-biomes@
chatimg|图片聊天 (chatImg)
-throwable-explosives
+throwable-explosives@
@skillmmo
archeon@
chattoggle@
@@ -9850,7 +9850,7 @@ enchancement@
useful-spyglass@
-befriendmobs-days-with-monster-girls|友好化生物:与怪物娘的日常 (BefriendMobs: Days with Monster Girls)
+nff-girls
launchgui
villager-armor-layer@|村民盔甲显示*
wasabi@
@@ -9971,7 +9971,7 @@ floating-block@floating-cube|浮空立方体 (Floating Cube)
curious-lanterns
river-redux@
restrictions
-create-modern-train-parts
+create-modern-train-parts@modern-train-parts
targetato
messagetweaker
@@ -9987,7 +9987,7 @@ fog-looks-good-now@
guarding@
cats-expanded@
modular-bosses
-experience-obelisk
+experience-obelisk@
here-be-no-dragons
gnumus-settlement
fading-night-vision
@@ -10096,7 +10096,7 @@ name-tag-tweaks@|命名牌调整*
funky-yoyo@funkyyoyo
pierce-arrow
tool-sharpening
-
+@ktfruaddon|群峦救援-非官方版扩展 (kTFRUAddon)
pigsteel@pigsteel-fabric¨pigsteel-forge@
@@ -10117,7 +10117,7 @@ moa-decor-bath
stealing-the-villagers-forge@¨stealing-the-villagers-fabric@
spoorn-armorattributes@spoorn-armor-attributes
connectedness@
-epic-samurais@|史诗武士 (Epic Samurai's)¨epic-samurais-fabric@epic-samruais-fabric|史诗武士 (Epic Samurai's)
+epic-samurais@|史诗武士 (Epic Samurai's / Samurai Dynasty)¨epic-samurais-fabric@epic-samruais-fabric|史诗武士 (Epic Samurai's / Samurai Dynasty)
sandwiches-n-more
enchantments-plus-fabric@enchantments-plus
purpeille@
@@ -10292,7 +10292,7 @@ tool-upgrades@|工具升级*
visiblebarriers@
aether-gravitation@|天境之引*
@sublanguage|首选语言 (Sublanguage)
-befriendmobs-api|友好化生物框架 (BefriendMobs Framework)
+nff-services
better-potion-visuals@
modern-warfare-cubed@|现代战争方块化*
extraordinary-extra-totems
@@ -10351,7 +10351,7 @@ barrels-2012
tfc-sample-drill
tfc-rosia
aether-additions
-custom-portal-api-forge@customportalapi
+custom-portal-api-forge@customportalapi|自定义传送门 API Forge 版 (Custom Portal API [Forge])
jaopca-extras
enclosure@
@@ -10499,7 +10499,7 @@ arboria
mekanism-evolution
chiseledadditions
-@tinkers_ingenuity|工匠匠心 (Tinkers Ingenuity)
+
gregtech-4|格雷科技4移植版 (GregTech 4 Rewritten)
lacrimis
productive-villagers@
@@ -10782,7 +10782,7 @@ hellions-sniffer@hellions-sniffer+
hybrid-flowers|杂交花*
-methane@
+methane|Methane - 已失效¨@methane
mushroom-villagers
@litematica-server-paster
s33r-butterfly-paintings
@@ -10808,7 +10808,7 @@ haste-enchantment
workshop-for-handsome-adventurer
desert-upgrade
ocean-recovery
-more-armor-trims
+more-armor-trims|更多盔甲纹饰*
mc-mods-the-trims@allthetrims
@bamboo-sign-editor|告示牌编辑器 (Bamboo Sign Editor)
revival-orb@
@@ -11198,7 +11198,7 @@ armor-status-hud-renewed|耐久信息显示:重生 (Armor Status HUD Renewed)
boblib
placeable-mobs@placeble-mobs
potion-blender@
-t6-auto-attack-mod@t6-auto-attack
+t6-auto-attack-mod¨@t6-auto-attack|T6's Auto Attack Mod - 已失效
forceasciifont-backport
vmtranslationupdate@vmupdate|VM汉化更新 (VM Translation Update)
trample-no-more@
@@ -11284,7 +11284,7 @@ simple-achievements
achievement-books|成就书*
villager-enchanter|村民附魔师 (VillagerEnchanter)
invocore-utility-mod
-saljus-quill
+saljus-quill@
derelict
@charged-charms
@@ -11304,7 +11304,7 @@ elfs-dark-dimension
xaeros-minimap-world-map-waystones-compability
jagms-kiwis@
@masaadditions
-@improved-trident-enchantments
+improved-trident@
mystic-bows
forgiving-world
@skillcloaks
@@ -11445,7 +11445,7 @@ dual-swords@
organizable-play-screens@
labelling-containers@
inventory-pause-forge@
-ready-player-fun
+ready-player-fun@
condensed-creative@
leaves-us-in-peace@
yellow-snow@
@@ -11509,7 +11509,7 @@ fine-tuned-calibration@finetunedcalibration
third-person-maps@
carpet-minitweaks@minitweaks
-time-in-a-bottle-forge
+time-in-a-bottle-forge@time-in-a-bottle-universal
seared-ladder-backport@seared-ladder-(backport)
wall-jumped@
red-core@
@@ -11547,7 +11547,7 @@ zombiegame|僵尸游戏 (Zombie Game)
effect-overhaul
casualness-delight@|随意乐事*
-eidolon-rebrewed
+eidolon-rebrewed@
fruity-random-teleport|紫颂果味随机传送*
pipe-master-2000|管道专家 2000 (Pipe Master 2000 / Pipe Googles)
command-macros@|命令宏*
@@ -11597,7 +11597,7 @@ cozy-foods-milk-tea
opolis-miners@
netherite-but-cheaper
@fabric-hammers
-items-displayed-fabric@items-displayed¨items-displayed-forge@
+items-displayed-fabric@items-displayed|物品陈列 (Items Displayed)¨items-displayed-forge@|物品陈列 (Items Displayed)
wood-converter
hammer-mod
@@ -11612,7 +11612,7 @@ niftycarts@
wither-dimension-whitelist
@hexlink
-usefulfood-reborn@
+usefulfood-reborn@¨usefulfood-community
ancient-warfare-2-tweaked@
cuffed@
rockn-roller@rocknroller
@@ -11667,7 +11667,7 @@ ars-oscura@|黑暗魔艺*
bobby-reforged
shut-up-gl-error@
no-spider@
-terracart-reloaded
+terracart-reloaded@
dme
fruit-stack@|果栈丰萦*
gregtech-drawers
@@ -11685,7 +11685,7 @@ quickstack
@bhs|黑洞储存 (Black Hole Storage)
collectors-album@
head-name-fix@headfix
-hostile-delight|宿敌乐事 (Unusual Delight*)
+hostile-delight@unusualdelight|异趣乐事/宿敌乐事 (Unusual Delight*)
vivecraft-compat@|ViveCraft兼容 (ViveCraft Compat)
wildlife-expanded-skunk@
keepheadnames@
@@ -11736,7 +11736,7 @@ well-behaved-mobs
ancient-realms
-
+@remove-terralith-intro-message
gambling-style
animated-recipe-book
@@ -12017,7 +12017,7 @@ tin-ore@tinore
dark-elves-of-underdark
titan-biomes
depth-striders@
-endercage@
+endercage@|末影笼*
mutationcraft@
aftershock@
limitless-concert|永无止境: 音乐会*
@@ -12136,7 +12136,7 @@ coreextensions@|核心拓展 (CoreExtensions)
@fast-items
toad-terror
@modern-industrialization-sound-addon
-achievements-optimizer
+achievements-optimizer@
automessage@auto-message
ftb-quests-optimizer@
gfarm@
@@ -12196,7 +12196,7 @@ marbleds-villager-hats@
connector-extras@
akkamaddis-simple-tungsten|Simple Tungsten - 新
-just-enough-beacons-reforged
+just-enough-beacons-reforged@
akkamaddis-additions@akkamaddis-simple-tungsten¨simple-cobalt|Simple Cobalt - 新
akkamaddis-ashenwheat@
@@ -12321,7 +12321,7 @@ terraria-calamity-mod|泰拉瑞亚灾厄 (Terraria Calamity)
darkrtp-rtp-random-teleport@darkrtp
cute-bears
additional-fruits@
-bigger-better-end-cities@
+bigger-better-end-cities@|更好的末地城*
@some-peripherals
reden@
sparse-structures@sparsestructures
@@ -12366,7 +12366,7 @@ mobile-beacon-1-18-forge
durabuilt
cavemans
balloon-box
-campfire-resting
+campfire-resting@
fizzle
grimoire-api
@@ -12377,7 +12377,7 @@ creative-experience
more-than-50
underground-jungle@
forge-soul-like-armors-reworked
-@meds-and-herbs
+meds-and-herbs@
soul-like-monsters-epic-fight-addon
souls-like-parry
tcdcommons@
@@ -12621,7 +12621,7 @@ omniwand@|全能魔杖*
-key-binding-patch|按键绑定补丁*
+key-binding-patch@|按键绑定补丁*
packet-fixer@
new-xenchant@
more-brewable-potions@
@@ -12689,7 +12689,7 @@ autofire-bow-enchant
rideableravagers@
passive-searchbar|被动搜索栏 (Passive SearchBar)
-flower-mimics
+flower-mimics@
vegan-delight|纯素乐事*
bloodmooncmsfix-bmcmsfix
evoodooers
@@ -12732,7 +12732,7 @@ modular-item-api@¨truly-modular-arsenal@¨truly-modular-archery@¨truly-modular
@actionhunger
trafficcraft@
banilla-hammers@
-everyx-hotpot|一起火锅 (EveryXHotpot)
+everyx-hotpot|一起火锅 (EveryXHotpot) - 他人代传¨@every-x-hotpot|一起火锅 (EveryXHotpot)
@hira-hira
tierability@
soul-collector@
@@ -12817,7 +12817,7 @@ medieval-buildings@
@you-thief-remastered-edition
more-slabs-stairs-and-walls@
-
+caves-canyons
dragon-mounts-legacy-continued@|龙骑士重制版延续*
embeddiumplus@
aggro-indicator
@@ -12933,7 +12933,7 @@ zombies-reworked-forge@zombies-reworked
legendary-monsters@
catontoasts-mobs
combatify@
-go-fish-updated|一起钓鱼吧!(updated) (Go Fish (updated))
+go-fish-updated|一起钓鱼吧!(更新版) (Go Fish (updated))
what-are-they-up-to@
@fumo
@@ -13017,7 +13017,7 @@ hammers-and-smithing
tetra-booster-pack@withering-boon-for-tetra
everlasting-skins
-
+decorated-pot-minecart|饰纹陶罐矿车*
legacy-console-sounds@
eye-spy@
sonicraft-demons@
@@ -13069,7 +13069,7 @@ geotagged-screenshots@
@legacy-optifabric
oneironaut@
-celestial-core|星月核心 (celestial_core)
+celestial-core|星月核心*
colorablefox|可染色狐狸/色绘你狐革 (Colorable Fox)
@@ -13175,7 +13175,7 @@ pottery-additional-pots@pottery
better-dogs-x-doggy-talents-next
@villagertimetable
towntalk
-cumulus
+cumulus@
epherolib
icterine@
notrample
@@ -13241,7 +13241,7 @@ ars-expanded-combat@ec-ars-compat
@fluiwid
revamped-phantoms@revamped_phantoms
defaultserverlist@
-green-delights|绿里乐事*
+green-delights|翠绿乐事*
@modmenu-ornithe
lost-city
digestive
@@ -13305,7 +13305,7 @@ mxtune
customui|自定义UI (CustomUI)
deadly-monsters-patched
glodium@
-aether-delight
+aether-delight|天境乐事*
dungeonz@
cazfps-axolotls
@@ -13329,7 +13329,7 @@ visible-offhand@|可见副手*
phosphorcrashfix
sound-physics-remixin|籁*
hextended-staves@
-aquaculture-delight
+aquaculture-delight|水产乐事*
vics-point-blank@
occultism-kubejs
tetra-extras@
@@ -13383,13 +13383,13 @@ better-quest-pop-up@
kiln-fabric@kiln
tetra-niche-materials
the-accurate-backrooms
-create-trains-on-trains
+create-trains-on-trains@
@campfire-torches-plus
@armor-rack
flux-networks-fabric@flux-network-fabric
@surface
poof-sounds@
-@crash-pipe
+crash-pipe@
gradeus-epic-fight-addon-soul-like-boss
zombie-more
gunscraft|枪械工艺 (Guns Craft)
@@ -13425,7 +13425,7 @@ march-of-the-ents|恩特的进军*
rndtp
in-world-buoyancy
@simply-starminer
-macos-input-fixes@
+macos-input-fixes@|MacOS输入修复 (MacOS Input Fixes)
@maxhealthfixfixfix
@astronomical
@@ -13571,11 +13571,11 @@ epic-knightsnmages-fabric@epic-knightsnmages
hotai|绷带*
zeta@
taxtowncitizen
-killer-rabbit-transformation|转化杀手兔*
+killer-rabbit-transformation@killer-bunny-tweaks|转化杀手兔 (Killer Bunny Tweaks)
bronze-viking
astikor-carts-redux@astikorcarts-redux
-third-person-shooting@third-person-shooting-zero|第三人称射击*
+third-person-shooting@third-person-shooting-zero|第三人称射击:零 (Third Person Shooting: Zero)
sight|视域*
@the-first-city
threetag-palladium@|钯 (Palladium)
@@ -13630,7 +13630,7 @@ more-variants-and-biomes
badoptimizations@
genshinimpactmod
-diagonal-walls
+diagonal-walls@
gravestones-die-classy-updated
osog-city-cars
immersive-vehicles-iav-parts-pack
@@ -13703,7 +13703,7 @@ better-babies
morecreativetabs-forge-fabric@morecreativetabs
@shove!
-sunflower-delight
+sunflower-delight@|向日葵乐事*
mystias-izakaya@mystiasizakaya|夜雀乐事*
carpet-everything
@@ -13809,7 +13809,7 @@ dirty-lens@
styled-player-list@styledplayerlist
create-love-war@
-chainmailed
+chainmailed@
serious-player-animations@
abridged@
hexvr@
@@ -13826,7 +13826,7 @@ myworldgen
medieval-buildings-end-edition
orpheus@
-@create-sweets-and-treats
+create-sweets-and-treats@
klsts-beyond-netherite
refined-polymorphism@
@@ -13841,7 +13841,7 @@ butchery
enchantment-reveal@
-copycats@
+copycats@|机械动力:伪装方块+ (Create: Copycats+)
the-great-alchemical-compendium@
desperate-measures@
block-slabs-mod
@@ -13985,7 +13985,7 @@ trajectory-estimation@|弹道估计*
-iron-repair-kits
+iron-repair-kits@
@susinsert
critters-n-crawlers@
@@ -14021,7 +14021,7 @@ deeper-caves@deeper_caves
-arborfirmacraft|林海传说 (ArborFirmaCraft)
+arborfirmacraft@arborfirmacraft-(afc)|林海传说 (ArborFirmaCraft)
enchanting-with-tfc
tfc-vessel-tooltip@
nether-gold-ore
@@ -14066,7 +14066,7 @@ prehistoric-nature-decorations
tinyfoes
pyradium
anvilcraft@|铁砧工艺:重力科技 (AnvilCraft)
-tiny-mob-farm-remastered@
+tiny-mob-farm-remastered@|迷你刷怪场:重制*
create-aquatic-ambitions@
ffl-trinkets-compat
kaleidios-guns
@@ -14100,7 +14100,7 @@ buildify@
@big-globe
dragon-finder
respackopts@
-fortuitous-feasts
+fortuitous-feasts@
monazite@|独居石*
music-control|音乐控制* - 不再更新¨@music-control|音乐控制 (Music Control)
stellarcore|星核 (StellarCore)
@@ -14124,7 +14124,7 @@ temporal-api@
callable-horse-unofficial-fabric-port|召之马来 Fabric版 (CallableHorse Unofficial Fabric port)
-shiny-horses-forge-enchantable-horse-armor
+shiny-horses-forge-enchantable-horse-armor@shiny-horses-forge
spartan-weaponry-simpleores|斯巴达的武器:简单矿石 (Spartan Weaponry: SimpleOres)
dye-depot@
@@ -14385,7 +14385,7 @@ pillar-patched
novalogin|新星登录 (Nova Login)
tfc-desire-paths@
tfc-ore-washing
-tfc-hot-or-not@
+
tfc-canes
lhmob-difficulty-increase|变强的怪物 (LH Mob Difficulty Increase)
@zombies-are-real-reforged
@@ -14406,7 +14406,7 @@ animationjs@
raids-backport
crossbows-backport
tfc-caelum@
-epic-compat-parcool
+epic-compat-parcool@
loqui@
real-worlds
@@ -14428,7 +14428,7 @@ tfc-fresh-water-everywhere@
tfc-more-swords
galleria@
constructs-casting@
-@tinkersinnovation|工匠创新 (Tinkers' Innovation)
+tinkers-innovation@tinkersinnovation|工匠创新 (Tinkers' Innovation)
delicious-delights
@vietnamsdelight
@@ -14675,14 +14675,14 @@ customemoji|自定义表情 (CustomEmoji)
sword-soaring|史诗战斗:御剑飞行 (Epic Fight - Sword Soaring)
bigger-ae2@
scalar
-trials-towers@|试炼高塔 (Trials Chambers)
+trials-towers@trials-chambers-backport¨@trials-towers|Trials Chambers - 已失效
blus-sign-pack-mts-iv
alexs-mediumcore@
sherdsapi@
@kontraption
musketeer-illager
-
+daker-acg|Daker ACG工艺 (DakerACG)
bananarangs@
remorphed@
particle-core@
@@ -14725,7 +14725,7 @@ achievement-detection-fix|成就检测修复*
@chais-inventory-sorter
-@mysteriumlibunofficial
+@myceliumlib|菌丝 (Mycelium Lib)
witcherypatch@|巫术补丁 (WitcheryPatch)
@@ -14876,7 +14876,7 @@ life-is-precious|生命是宝贵的 (Life is precious)
advanced-skills@|进阶技能*
nuts-delight
-@vegetables-delight
+vegetables-delight@
enderpack@
ingame-mod-configs|游戏内模组配置 (InGame Mod Configs)
playertag|玩家标签 (PlayerTag)
@@ -14900,7 +14900,7 @@ slashblade-resharped@|拔刀剑:重锋 (SlashBlade: Resharped)
spawn-mod@
@smooth-swapping-1.20.4-port
@create-tab-fix
-@srp-origins
+scape-and-run-origins@srp-origins
origins-extra-keybinds@origins-extra-keybinds-fabric
epic-knights-addon
@@ -14931,7 +14931,7 @@ totally-lit@
mo-shiz-mod
aetheric-tetranomicon
-arda-addon|阿尔达拓展*¨lotr-arda|阿尔达拓展 (Arda Addon) - Snow的阿尔达拓展
+arda-addon|阿尔达拓展*
@potionwarning
a-good-place@
aether-protect-your-moa@
@@ -15004,7 +15004,7 @@ what-is-stone-colorful-caves@what-is-stone-(colorful-caves)
vtones
heavy-inventories|物品负重*
vs-addition@
-gravity-torch
+gravity-torch@
lifesteal-forge-fabric@
mores-by-its-infinite
dragonite-gear
@@ -15042,7 +15042,7 @@ battlemusic@
@embyui
engineered-golems
axifier@
-renderjs
+renderjs@
@enchantment-compat
dehand@
jadecolonies
@@ -15054,7 +15054,7 @@ create-metallurgy@|机械动力:冶金学 (Create: Metallurgy)
the-shy-guy
@tea-time
@cobbreeding
-@cobblemon-myths-and-legends-addon
+@cobblemon-myths-and-legends-sidemod
@rctmod
create-klinks-n-klangs@klinksnklangs
mo-than-enough-guns@
@@ -15117,7 +15117,7 @@ cubic-villager
@morecursors|更多光标 (MoreCursors)
true-infinity
nukateams-gun-lib@ntgl
-fantastic-biomes-cave@
+fantastic-biomes-cave
nukacraft@thenukacraft
enchantment-limiter
emi-ores@
@@ -15132,7 +15132,7 @@ waystones-teleport-pets@
@sneaky-link
create-mortar@
forgelin-continuous@
-@ripples-of-the-past-killer-queen-addon
+@ripples-of-the-past-killer-queen-addon|RotP:杀手皇后附属 (Ripples of the Past: Killer Queen Addon)
ninjin-knockback-dbc-by-hedaox
wings-3
dstathud@
@@ -15198,7 +15198,7 @@ dralards-rock-candy-mod
@explosion-breaks-no-block|爆炸不破坏方块 (Explosion Breaks No Block)
via-romana@
-lithic-coins|石质硬币*
+lithic-coins
dynamic-trees-for-natures-spirit@|动态的树:自然之灵附属 (Dynamic Trees for Nature's Spirit)
gore-edition
christmas-wish-in-a-bottle
@@ -15257,7 +15257,7 @@ iap-omega-craft
iap-mekanism
industrial-agriculture-plugin-silents-mechanisms
-roads-and-roofs-tfc
+roads-and-roofs-tfc@
taxvillagearchitect
taxoceanarchitect
nethers-flora
@@ -15309,7 +15309,7 @@ lexiconfig@
@advancementsfullscreen
luckys-wardrobe@
@forkkit
-@more-affordable-than-ever
+more-affordable-than-ever-never-too-expensive@more-affordable-than-ever
what-am-i
@camoverlay
@@ -15474,18 +15474,18 @@ disable-front-perspective@
thaumcraft-6-aspects-for-jei@
@up-and-away
-@ripples-of-the-past-hermit-purple-addon
+@ripples-of-the-past-hermit-purple-addon|RotP:紫色隐者附属 (Ripples of the Past: Hermit Purple Addon)
nc-steam-additions@nuclearcraft-steam-additions
aura-cascade|气场流注*
rac-compat@
spartan-weaponry-addon-toolkit@
-
+smsn@
sneaky-tree-growing-forge@sneaky-tree-growing¨sneaky-tree-growing-fabric
hungry-zombies
@gravity-gourds
usa-delight
experience-farm
-@ad_extendra-continuation
+ad-extendra-dandi2k8-version@ad_extendra-continuation
nebulus-juice-trader@
cthulhu-fishing@
large-super-potato|大型超级马铃薯*
@@ -15516,7 +15516,7 @@ villager-in-a-bucket@
nebulus-trader-for-the-desert
nebulus-jungle-trader@nebulus-trader-for-the-jungle
mushroom-villager-trader@
-nebulus-better-portals@
+nebulus-better-portals¨@nebulus-better-portals|Nebulus Better Portals - 已失效
resource-ghouls
avaritianeo|无尽贪婪Neo (AvaritiaNeo)
create-legacy@
@@ -15529,7 +15529,7 @@ text-placeholder-api@placeholder-api|文本占位符 API (Text Placeholder API)
@tt20
kasugalib@
-
+@c2h6s-tinker|乙硫基匠魂 (C2H6S Tinker)
kubejs-mekanism-unofficial
@mediaplayer|媒体播放器 (MediaPlayer)
@@ -15538,7 +15538,7 @@ nebulus-trader-for-the-plains
mokels-more-spiders
exposure-catalog@
-skinchanger
+skinchanger@
@halflifemenu
sitting@sitting+
@@ -15619,7 +15619,7 @@ yamazakura-reforked|山樱之刃重置版 (Yamazakura reforked)
apothic-spawners
-sinocore|华夏核心 (SinoCore)
+sinocore@|华夏核心 (SinoCore)
tinted-dyes@
dynamic-trees-ecologics@|动态的树:丰富的生态附属 (Dynamic Trees - Ecologics)
craftablecapes@|可合成的披风 (Craftable Capes)
@@ -15694,7 +15694,7 @@ pet-the-frog@frog-petting
ex-nihilo-extras@
cycle-title-screen-splash@
hide-invisible-armor@
-inventory-tweaks-refoxed
+inventory-tweaks-refoxed@
bigshot@
more-immersive-aircraft
legendary-survival-overhaul|传说生存*
@@ -15733,7 +15733,7 @@ sandfilter@|砂滤器 (Sand Filter)
resaplingslayer@|雁雅得枝 (ReSaplingslayer)
cerberu@|狱牙抵战 (Cerberus)
remoreloyaltrident@|远亦得珍 (ReMoreloyaltrident)
-potionlevelfix@|药引对注 (PotionLevelFix)
+potionlevelfix@|药水等级修复/药引对注 (PotionLevelFix)
reunmending@|以验垫砧 (ReUnmending)
reghostjump@|引殃髑至 (ReGhostJump)
rebroken-blade@|隐影刀珍 (Mowzie's Mobs: ReBroken Blade)
@@ -15753,7 +15753,7 @@ remove-purpleprison-ads
timeoutfixes
forgeskyboxes@
customfishing|随液钓趣 (CustomFishing)
-
+metr0polis@metropolis
crust@
sc-structurecraft@structurecraft
@@ -15808,7 +15808,7 @@ ender-dragon-loot
oh-the-trees-youll-grow@
oh-the-biomes-weve-gone@|我们走过的生物群系 (Oh The Biomes We've Gone)
-@dblockbusterdisplays
+dblockbusterdisplays@
@waygl
@@ -15997,7 +15997,7 @@ the-masquerade-illager-boss@the-masquerade-(illager-boss)
better-armory-x
sweetys-horse-armor-tweaks@
fired-pots@
-under-the-moon
+under-the-moon@|驻月夜下 (Under the Moon)
coffeegs-colorful-world
jeb_-wool@|jeb_羊毛 (jeb_ Wool)
illage-and-spillage-finally-ported
@@ -16034,7 +16034,7 @@ aaa-particles@
@anno
compass3d@
@clockin
-diggus-maximus-reborn
+diggus-maximus-reborn@
satisfying-buttons@
item-on-chest-fabric@item-on-chest
industrialreborn@
@@ -16068,7 +16068,7 @@ boss-keys
mace-variants
shortswords@new-short-swords
bbs-mod@
-monocle
+monocle@monocle-iris
move-ui@
terrafly
achievements-mod-200@mysticrift-achievements
@@ -16153,7 +16153,7 @@ hold-easy-place@|保持简单放置*
-spartan-and-fire-lightning-edition|斯巴达之冰与火-闪电版 (Spartan and Fire - Lightning Edition)
+spartan-and-fire-lightning-edition|斯巴达之冰与火-雷电版 (Spartan and Fire - Lightning Edition)
the-twilight-forest-deforestation-edition|暮色森林 - Deforestation 版 (The Twilight Forest - Deforestation Edition)
minieffects-legacy-extended-life
@@ -16200,7 +16200,7 @@ mcfetch@
reignited-hud@
more-crafter-variants@
sharingan-addon-ahznbs-naruto-mod
-create-tacz-automation
+create-tacz-automation@
tacz-plus-timeless-and-classics-feature-addon@tacz-plus
fibers-guns-pack-for-tacz
@splinecart
@@ -16222,7 +16222,7 @@ stop-repeating-command-block-reborn@|停!循环型命令方块:重生*
parry-us@parry!|予以刀振/格挡! (Parry)
frycooks-delight@|油炸乐事 (Frycook's Delight)
-advancedae
+advancedae@
pretty-pipes-fluids|更好的管道:流体 (Pretty Pipes: Fluids)
webstone@
@@ -16291,7 +16291,7 @@ immersive-farming@|沉浸农业*
@vpb-too-many-guns
death-angels|死亡天使*
the-pale-hound
-monsters-girls
+monsters-girls@
monsters-girls-secrets-of-mermaids
dios-tiny-ore@
defence-craft
@@ -16426,7 +16426,7 @@ linear-xp-forge|验依定值/线性经验 (Linear Xp Curve)
dumplings-delight-reload@|饺子乐事:重启*
-
+auto-switch-elytra@autoswitchelytra|自动切换鞘翅*
gregtech-placeable-emitters@
@@ -16527,7 +16527,7 @@ just-another-random-spawn|遥缘调址/随机出生点*
realistic-mobs@
fullthrottle-alchemist
fullthrottle-nei
-creature-compendium
+creature-compendium@
desert-update
ancient-elements
left-behind@
@@ -16535,17 +16535,17 @@ corrupted-witherskeleton-boss-mod
mca-api
-sodium-leaf-culling@sodiumleafculling
+sodium-leaf-culling@sodiumleafculling|钠:树叶剔除*
homing-xp-orb|引验导追/归航经验球*
multiblocked2
armorstatushud-updated|耐久信息显示更新版 (ArmorStatusHUD Updated)
tfc-better-blast-furnace
tfc-textile@
tfc-woodworking@
-tfc-auroras
+tfc-auroras@auroras
greg-paintings@
gtmthings
-create-trading-floor
+create-trading-floor@
@fishy-create-stuffs|Yu的机械动力附属 (Fishy Create Stuffs)
biolith@
hungrier@
@@ -16637,7 +16637,7 @@ the-ceilands@|垂顶之地*
snowbound@snow_bound
opencomputers-icbm-classic-addon¨icbm-opencomputers|Opencomputers ICBM-Classic Addon - 教程文档
@ad-astra-pandoras-frontier
-cosmic-horizons@cosmic-horizons(cosmos)
+cosmic-horizons@cosmic-horizons-cosmos
shadow-x-netherite-scrap-from-piglin-brutes|猪灵蛮兵掉落下界合金碎片 (Netherite Scrap From Piglin Brutes)
better-modlist-neoforge@better-modlist
@@ -16667,7 +16667,7 @@ archeological@archeologicalmod
clarity
backpacked-world-of-color@
nofov
-cobalt-custom-chunk-renderer@cobaltmod
+cobalt-custom-chunk-renderer|钴 (Cobalt)¨@cobaltmod|钴 (Cobalt) - 已失效
spartacus-army-uniform
soviet-army-uniform@
german-uniforms-ww2
@@ -16675,9 +16675,9 @@ german-uniforms-ww2
tameable@
-
+slashblade-gamerelic|拔刀剑重锋附属·游戏扩增 (srelic)
theovergrowth
-jadens-nether-expansion
+jadens-nether-expansion@
configurable@
@@ -16690,14 +16690,14 @@ configurable@
patpat
@modernlifepatch|摩登生活补丁 (Modern Life Patch)
@ivr
-rusticdelight-refabricated@|乡村乐事:重织
+rusticdelight-refabricated@|乡村乐事:重织 (RusticDelight: Refabricated)
scape-and-run-meshi@
@bad-apple-world-preset
gastronomy-works@
@create-air-fabric
colorfulwater
-yungs-cave-biomes@¨yungs-cave-biomes-fabric
+yungs-cave-biomes@|YUNG的洞穴生物群系 (YUNG's Cave Biomes)¨yungs-cave-biomes-fabric|YUNG的洞穴生物群系 (YUNG's Cave Biomes)
@@ -16716,10 +16716,10 @@ tnt-plus-mod|TNT Plus - 所有¨@tnt-plus-mod|TNT Plus - 部分失效
@kelvins-better-player-animations-(port)
tokusatsurecord|特摄唱片 (Tokusatsu Record)
-origins-backgrounds-forge
+origins-backgrounds-forge¨origins-backgrounds
cataclysm-apotheosis-addon
cave-dweller-reimagined¨cave-dweller-reimagined-fabric
-out-of-combat
+out-of-combat|脱战 (Out of Combat)
soulfragment|灵魂碎片 (Soul Fragment)
create-peaceful@
@@ -16732,7 +16732,7 @@ its-magispelling-time
@dontsneakprogress|偷跑禁止 (DontSneakProgress)
@unkindled
-recipe-generator
+recipe-generator@
@carbonfltr
argonmod@|氩 (Argon)
foggy-pale-garden@
@@ -16773,7 +16773,7 @@ scape-and-run-revenants
warden-s-domain
more-wardens
hidden-realm@
-spells-gone-wrong
+spells-gone-wrong@
wandrous@
cnpc-dbc-addon@customnpc-plus-dbc-addon
salmons-genesis
@@ -16782,29 +16782,579 @@ the-afterdark
loaded-mods-checker@loadedmodschecker|存档模组核对*
-
+i-have-slept@|朕已安寝 (I have slept)
@itemstackpromax|物品堆叠ProMax (ItemStackProMax)
item-split-bug-fix|物品分裂修复*
spontaneous-replace-cobwebbed@|自然更替:蛛丝网迹 (Spontaneous-Replace: Cobwebbed)
modernconverter
frozify@
potato-library
-@swisscaves
-@title-screen-blobcat
+swisscaves@
+title-screen-blobcat@
punching-creepers@
ancient-curses
resettleable-traders-forge-fabric@resettleable-traders|流浪商人安家 (Resettleable Traders)
ihearttfc@
itemphysic-1-7-10-unofficial@itemphysic-1.7.10-unofficial|物品物理掉落非官方版 (ItemPhysic Legacy Unofficial)
jei-area-fixer
-ars-elixirum-fabric
-
+ars-elixirum¨ars-elixirum-neoforge¨ars-elixirum-forge
+gold-nugget-recycling
sodium-options-api@
crazyae|疯狂的AE (CrazyAE)
-
+ae2-crafting-tree-legacy|AE2合成树-传统版 (AE2CT-Legacy)
ae2-alchemistry-addon
novaultlimit@
-game-discs@|游戏光碟*
\ No newline at end of file
+game-discs@|游戏光碟*
+
+
+vanilla-plus-resourceful-tools
+create-horse-power@
+ars-technica
+plustic-reforged@
+spawners-plus@spawners_plus
+dracolotl
+
+sacks-n-such@
+
+
+camellialib@|山茶花核心 (CamelliaLib)
+cameliaarmory@|花朵武器库 (FlowerArmory)
+
+moonrise@moonrise-opt
+corpsecomplex-unofficial@
+@starlish
+languagereloadunofficial@
+mekanism-covers@
+enchanted-wilderness-elegant-countryside@enchanted-wilderness-elegant-countryside.|优雅乡下 (Elegant Countryside)
+better-durability-reforged|更好的耐久度:重铸*
+sos|我来助你! (SOS)
+cherry-on-1-12-2@cherry_on_1.12.2|1.12.2的樱花 (Cherry_on_1.12.2)
+scape-and-spartan-parasites|寄体斯巴达 (Scape and Spartan: Parasites)
+@ripples-of-the-past-extra-stands-addon
+the-knocker@
+vll-r-mystery
+scp-origin
+sniffers-delicacies
+fix-changed
+valkyrien-pirates@|瓦尔基里海盗*
+pathogen
+chrysalis@
+alekis-ridiculously-simple-roofs@alekiroofs
+@trails
+rainboows@
+texturized-particles@
+rple@
+reign-of-nether-rts-in-minecraft@reign-of-nether-rts|下界之治 (Reign of Nether RTS)
+the-secret-doors
+
+
+tame-tools@|驯兽工具*
+@bia
+vounierns-turrets
+seafarer-forge
+zombies-plus-frenzied-horde@
+@tetrismc
+ecliptic-seasons|节气*
+xibaoxx@|喜报 ×× (XiBao ××)
+
+
+murasama-daker|鬼妖村正 (Murasama)
+particle-storm|粒子风暴*
+@2d-minecraft
+till-it-breaks-updated@
+debark@
+till-it-breaks@
+end-reborn-expansion@end-reborn
+@origins-genshin
+
+
+the-glitched-one
+progression-reborn@
+
+@simple-info-display
+@automaticmemories
+zoom-camera@
+dpi-fix
+@item-information-display|物品信息显示 (Item Information Display)
+almanac-lib@almanac
+
+remove-blindness|移除失明 (Remove Blindess) - 不全¨@remove-blindess|移除失明 (Remove Blindess)
+simplerpgcore@
+droppable-villager-trades@
+stackupper@
+colorful-orbs@
+@idmxd
+modernxl-2-in-survival
+creepercollateral
+findmyitemsandfluids
+@numeric-experience-info
+aquapatch
+aviator-dreams
+macaws-stairs@
+cross-stitch-colours@
+gaming-deco@
+@reactive-music|韵律回响 (Reactive Music)
+easel-does-it@
+rbasamoyais-betsy-ross@betsy-ross
+
+
+
+
+
+dropped-item-tweaks@droppeditemtweaks|掉落物调整*
+movingquickly|禁用快速移动检查 (MovingQuickly)
+@soup-api
+@tsa-decorations
+@autofarm-mod
+gelato-galore-2@
+dyeable-jack-olanterns@
+white-pumpkins@
+dawn-of-the-flood@
+deatbutthreereload@|逝不过三:重开 (Death But Three Reload)
+common-weapons
+ore-silverfish-mod@
+gtbcs-spellbooks
+project-lambda
+
+
+
+
+
+@pretty-hitboxes-create-addition|可配置的碰撞箱显示-机械动力功能附加 (Pretty Hitbox-Create Addition)
+watersource-reborn@|水源:重生 (WaterSource: Reborn)
+locks-unofficial@|锁:非官方版 (Locks-Unofficial)
+
+just-in-nether@
+jinghui|镜回 (jinghui)
+@ripples-of-the-past-mandom-addon|RotP:男人领域附属 (Ripples of the Past: Mandom Addon)
+@auto-gg
+better-brightness-slider-respawn@
+
+
+animatica-foxified@
+mcchatgpt@
+@aimobs
+ambiances@ambiance|氛围! (Ambiance!)
+screw-your-items@
+mace-port
+bloodlines
+vampiric-ageing-a-vampirism-addon
+extra-enchantments-and-curses@
+enchanting-tweaker@enchanting-tweaks
+just-a-lot-more-enchantments@
+alessandrvs-enchantments@alessandrv-enchantments
+armor-abilities@
+sleepy-hollows@
+
+nametag-tweaks@nametagtweaks|名称标签调整 (Nametag (Display) Tweaks)
+@sodium-no-alerts
+headshot-respawn@|爆头:重生 (Head Shot Respawn)
+leafdecaystopper|树叶腐烂抑制器 (Leaf Decay Stopper)
+animated-loading-screen@
+@rotp_whitesnake|RotP:白蛇附属 (Whitesnake Addon (Ripples of the Past))
+@ripples-of-the-past-made-in-heaven-addon|RotP:天堂制造附属 (Ripples of the Past: Made in Heaven Addon)
+@ripples-of-the-past-c-moon-addon|RotP:新月附属 (Ripples of the Past: C-Moon Addon)
+imbued-gear@
+tacz-js@
+ipla@
+bcg-util
+sciophobia@|全局自定义文本阴影渲染*
+lithic-addon-mod
+light-blocks-from-1-17@
+light-and-shadow@
+@excavein
+spanish-delight-a-farmers-delight-add-on@spanish-delight|西班牙乐事 (Spanish Delight)
+ars-nouveaus-flavors-delight@arsdelight|新生乐事 (Ars Nouveau's Flavors & Delight / Ars Delight)
+oceanic-delight|海之乐事*
+the-player
+kelka-craftable-animals@craftableanimals
+super-hyper
+wans-ancient-beasts@wab
+invocations-spell-engine@invocations
+gearifiers@
+recall-potion-neoforge@|回忆药水 (Recall Potion)
+flowing-fluids@
+frights-and-foliage@
+blorfstone
+filinkus-s-huge-tools
+necromancer-mod
+e_kedis-electronics
+uprade-yourself
+
+smelting-touch-enchantment
+shinobiorigins-utils
+unifine
+trailier-tales@
+mixinjs-coremod
+mcwen
+rank-system|评分系统*
+
+bundle-inventory|Bundle Inventory - 问题反馈¨@bundle-inventory
+scroll-tweaks@scrolltweaks|鼠标滚轮调整*
+neko-server@
+ride-every-thing@|骑乘一切*
+cit-resewn-neopatcher@
+legendary-creatures|传说生物*
+@meowcraft-mod
+
+
+
+
+frozenlib@
+clientblock@
+eventjs
+backup-manager@
+the-root-of-fear@
+the-modifiger@
+@keypreset|键位预设 (KeyPreset)
+
+sanity-prequel|理智:前传 (Sanity: Prequel)
+ayame-paperdoll@|Ayame 纸娃娃 (Ayame PaperDoll)
+@registry-helper-lib
+@carpet-permissions
+passive-shield@
+trap-expansion
+roost-2-flying-higher
+@amber
+@liteminer
+@lvlz-better-nether
+@lvlz-better-end
+cc-shops@
+modular-machinery-reborn
+flare@
+rs-crafting-monitor-in-grid@
+@photonics
+lambdynamiclights-unofficial-neoforge@
+
+@heracles-button
+voicecontrol|声控*
+hex-ars-linker@|魔力媒质链接 (Hex-Ars Linker)
+bingolobby@|宾果游戏大厅 (BingoLobby)
+worldedit-legacy@worldedit-legacy-enhanced
+@nohealthbar
+asm-fixes-j-a-f-m
+moestweaks
+prickle@
+farming-3x3@
+trickery@
+kebab
+farmers-croptopia@
+mc-mods-trees-drop-apples
+@infinite-dimensions
+
+mofus-broken-constellations
+starlance@
+beneath@
+@simpleclientbase|简易客户端:基础 (SimpleClientBase)
+
+
+ultimate-enchantment@|终极附魔*
+ron-settings
+backpack-display@|背包物品内容显示*
+horrrs-pvz|Horrrs的植物大战僵尸*
+@optibabric
+item-restrictions@
+vintage-animations@
+the-one-who-watches@
+scp-ultimate
+herobrines-omen
+sws-wukong
+dragns-valiant-vehicles@dragns-valiant-vehicles!
+bio-factory@biofactory|机械动力:血肉工厂 (Create: Bio-Factory)
+create-ad-astra-compatibility
+create-mechanical-chicken@1.20.1-1.1.1.h-48
+zbgt@
+casinocraft
+@mql-tir5d-turtle
+toadlib@
+
+
+crosshair-tweaks@crosshairtweaks|十字准星调整*
+what-did-i-just-kill@
+scalablelux@
+weather-changer@
+iron-nugget-recycling
+@picohud
+
+gtmoreoreprocessing@
+computercraftedu
+bibliocraft-legacy
+simple-clouds@
+
+
+furniture-modcraft@several-furniture-craft
+
+spellblades-and-such-hexblade
+
+sons-of-sins-organs-additions|七罪之子:器官添加 (Sons Of Sins: Organs Additions)
+sons-of-sins-organs-museum|七罪之子:器官博物馆 (Sons of Sins: Organ Museum)
+mobs-of-sins-alexs-mobs-integration-forge|七罪之子: Alex的生物集成 (Mobs of Sins: Alex's Mobs Integration [Forge])
+stitched-sins|缝合的罪*
+@bio-delight|血肉乐事 (Biomantic Delight)
+
+the-sculpture
+goop@
+neepmeat@
+
+
+
+@huangsheng1s-more-monster|更多怪物 (HuangSheng1's More Monster)
+creeping-woods
+@zombie-apocalypse-core
+dragon-mounts-2@|龙骑士2:延续 (DragonMounts2: Continued)
+life-fruits@|生命果*
+ati-structures
+fantasy-armor@fantasy_armor
+beautiful-enchanted-books@beautiful-enchanted-books-mod-edition
+
+
+void-fog@voidfog
+@legacy-rocket-model|旧版火箭模型 (Legacy Rocket Model)
+
+
+
+tinker-i-o-ce|工匠接口社区版 (Tinker I/O CE)
+more-shield-variants@
+
+bendy-items
+paladins-oath
+
+roundabout-the-jojo-mod@roundabout_the_jojo_mod
+
+
+enviromine-continuation@
+@toffys-hooks
+mutants-buff
+
+
+terrablenderfix@
+craterlib@
+@caramel-chat
+spark-unforged@
+pack-mode-reborn
+mc-mods-the-wood-weve-got@all-the-wood-weve-got
+bibliowoods-legacy
+hydrological@
+unilib@
+
+modchu_playerformlittlemaidfml
+quiet|迁噪碍音/玩家禁言*
+
+@bettertab
+modular-machinery-reborn-mekanism@
+
+dawn-of-time-roa-edition
+buildpaste¨buildpaste-for-fabric
+mutils@
+better-campfires@|更好的营火*
+@mtr-renfe-addon
+@gt-community-additions
+more-create-burners|机械动力:燃烧室附加*
+create-logistics@
+create-pneumatic-equipment@
+collisiondamage|碰撞伤害 (CollisionDamage)
+@absolutely-proprietary
+tensura-reincarnated@
+transformer|奥特化身:无限 (Becomes Ultraman:Infinity)
+henshin|变身*
+ridiculous-world
+
+quartz_craft@|石英工艺 (Quartz_Craft)
+cursed-stare@
+legendblade|传世之刃 (legendblade)
+@hypothermic-reforged
+scape-and-run-parasites-extra@
+lauchs-shutters@shutters
+golden-foods@golden-foods!
+@alexscaves-delight
+@spmreborn|烤地瓜:重生 (Sweet Potato Reborn)
+dragon-fight-config-endergetic-addon
+
+
+
+celestial-forge|星月再锻*
+mahjongcraft@|麻将工艺 (MahjongCraft)
+formidulus@
+ames-stranger-things
+herobrine-origins
+milkable-blazes@
+
+furniture-beetle@
+mekanism-x-create-northstar@
+@createz
+create-smart-crafter@
+create-fuel-and-water-information@create-fuel-water-information
+thematic@
+projects@more-composter-variants
+more-fletching-tables@
+more-grindstone-variants@
+more-bed-variants@
+more-loom-variants@
+more-feeding-trough-variants@
+more-smoker-variants@
+manascore@
+ames-mobs-configuration|AME生物配置
+display-delight@
+realistic-torches-roa-edition
+
+
+@slime
+@x-backup
+iron-barrels-forge@iron-barrels
+spectral-decorations@
+
+
+trims-on-tools@
+galacticraft-automatic-resources|星系自动资源*
+
+@lx-light-assist-tool|轻辅助工具 (light assist tool)
+
+
+roberts-building-pack|Robert的建筑扩展包 (Robert's Building Pack)
+arcanus-continuum@
+ultimate-chess@
+sparkweave@
+visualjs
+lights-out
+a-night-stalker
+the-faceless-duo
+scape-and-run-parasites-meteorite@
+cravencrafts-bloody-bits@
+
+
+
+fastlang
+min-3-hall-a@
+modular-machinery-reborn-energistics@
+tweaks-for-galactic-science
+java-version-checker
+chatcopyrite
+
+terracart
+noteblock-backport@
+scape-and-run-parasite-dimension@srdimension
+hexdebug@|咒术调试 (HexDebug)
+paths-of-sin@
+@mapperplugin
+@enchantment-decomposition|附魔分解 (Enchantment Dismantling)
+hide-key-binding@|隐藏按键绑定*
+
+inline@
+fluffy-fur@
+
+
+head-cutter|玩家剪头*
+salty-s-realistic-forging@saltys-realistic-forging
+@vs-wakes-compat
+@vs-crumbles
+@vs-ship-in-a-bottle
+rustic-pancakes@
+ice-and-fire-delight@|冰火传说乐事 (Ice and Fire Delight)
+additional-dragons
+enigmatic-unity
+ephemera@
+theurgy-kubejs@
+immersive-lanterns@
+txnilib@
+default-key-setup@|默认按键配置*
+the-man-king
+create-arms-race@
+powered-flashlight@
+vmc-mc@virtual-motion-capture-for-minecraft
+@hexcellular
+hex-conjuring@|咒术构筑*
+hexjs@
+craftsense@
+
+zenkorium-creatures
+zhengelss-techguns-addon
+more-artifacts
+
+tfcgenviewer@
+terra-math@
+lukis-crazy-chambers
+tumbleweed-wasteland
+irons-jewelry
+atlas-api
+loading-screen-messages
+
+nemos-invertory-sorting@nemos-inventory-sorting
+@better-ux
+@hudmini
+ribs-panning
+hotkettles@
+gift-drop@
+dragns-livestock-overhaul@
+storage-drawers-unofficial|储物抽屉非官方版*
+
+centrifuge-tiers-reproduced@
+dense-mekanism@
+simple-missles@
+galosphere-spellbooks
+discerning-the-eldritch
+@hexcassettes
+wardens-plus
+ender-wyrmlings
+
+
+new-classic-battle-towers
+chitin-equipment@
+mowzies-cataclysm
+stardew-fishing-fabric@
+piglin-slayer@
+cataclysm-tools@
+witherite-gear
+faunus@
+oo-ee-a-e-a@
+
+
+
+sodium-embeddium-options-mod-compat@sodium-options-mod-compat
+secureseed-reborn
+creative-eats
+mazerooms
+
+@chitinous_ties
+brewable-dragons-breath@|龙息可酿造 (Brewable Dragon's Breath)
+flerovium
+
+
+gathering-torches-become-sunlight|薪火,造炬成阳*
+
+
+no-arrows-in-you-respawn¨@no-arrows-in-yourespawn|No Arrows In You: Respawn - 审核中
+
+glowcase@
+hitbox-api@
+@polynametag
+broken-nametags@
+@compostable-flesh
+a-cute-little-crock-pot@
+@bountifulharvest
+wasteland-grocers
+arcane-tablet
+@unflavoured-pipes
+curvy-pipes
+
+
+classic-bar-legacy|经典状态条 延续版*
+glowing-eyeblossom@
+openlink@|开放式联机 (OpenLink)
+@vs-grapples
+@mydriasis
+no-mob-spawning-on-plants
+matmos2
+durability-rework@
+more-villagers-re-employed@
+similsax-transtructors
+tcw-bedrock-breaker
+apothic-reforge-tokens
+advanced-skills-remastered@|进阶技能:重制版 (Advanced Skills: Remastered)
+monsters-and-dungeons
+cultivate-the-eternal-realm@IwYRM3LA
+too-much-bosses
+valoria@
+glowroot@
\ No newline at end of file
diff --git a/Plain Craft Launcher 2/Resources/java-wrapper.jar b/Plain Craft Launcher 2/Resources/java-wrapper.jar
index 29d7632..bd14bd6 100644
Binary files a/Plain Craft Launcher 2/Resources/java-wrapper.jar and b/Plain Craft Launcher 2/Resources/java-wrapper.jar differ
diff --git a/README.md b/README.md
index 8c12114..99e8076 100644
--- a/README.md
+++ b/README.md
@@ -1,27 +1,17 @@
-# Plain Craft Launcher 源代码库
+# Plain Craft Launcher
-[](https://github.com/Hex-Dragon/PCL2/)
-[](https://github.com/Hex-Dragon/PCL2/issues)
-[](https://afdian.com/@LTCat)
+[](https://github.com/Hex-Dragon/PCL2/)
+[](https://github.com/Hex-Dragon/PCL2/issues)
+[](https://space.bilibili.com/11343203/dynamic)
+[](https://afdian.com/@LTCat)
+
+包含 PCL 的大部分源代码,包括 UI 库、动画模块、下载模块、Minecraft 启动模块等!
+代码并不是实时更新的,它会在每次 PCL 发布更新时同步一次。
+非常感谢社区的大力支持!
-## 介绍
-
-这里提供了 PCL 的大多数源代码,包括 UI 库、动画模块、下载模块、Minecraft 启动模块等!
-
-PCL 的代码绝大多数其实都是几年前学生时代的产物了……那时候英语还不过关……所以经常出现奇葩命名,还有令人高血压的高耦合啊,没做单例啊,瞎勾八乱糊啊之类的问题……额,我也不可能把这一堆玩意儿再从头写一次,各位就基于能跑就行的原则凑合凑合着看吧,求求别喷了……
-
-
-
-## 相关内容
-- [PCL 功能投票](https://github.com/Hex-Dragon/PCL2/discussions/2):来参加投票吧,开发者会优先处理票数较高的帖子!
-- [程序下载](https://afdian.com/p/0164034c016c11ebafcb52540025c377):下载免费的正式版 PCL。
-- [帮助文档库](https://github.com/LTCatt/PCL2Help):PCL 帮助文档在 GitHub 上的存储库(是的,帮助库在另一个 Repo……)
-
-
-
-## 一些无趣的小细节
-- 别想在这里面找到解密游戏的线索,那部分的代码被我抠掉了
-- 解锁隐藏主题的相关代码也被抠掉了,所以别想着用翻源代码这种歪门邪道来绕过解密了.jpg
-- 源代码库并不是即时更新的,而是在每次 PCL 发布更新时(手动)同步一次
+### 相关资源
+- [PCL 下载](https://afdian.com/p/0164034c016c11ebafcb52540025c377):下载可免费使用的正式版 PCL!
+- [PCL 功能投票](https://github.com/Hex-Dragon/PCL2/discussions/2):来参加投票吧,开发者会优先处理票数较高的项目!
+- [帮助文档库](https://github.com/LTCatt/PCL2Help):PCL 内置帮助文档的存储库
diff --git a/最新正式版.zip b/最新正式版.zip
index a8fad44..29be464 100644
Binary files a/最新正式版.zip and b/最新正式版.zip differ