Compare commits

...
64 Commits
Author SHA1 Message Date
龙腾猫跃 6f6744dfd2 2.10.8 2025-09-12 23:40:01 +08:00
龙腾猫跃 2210da6fda 2.10.7 2025-09-10 01:07:30 +08:00
龙腾猫跃 ee385912f8 Merge pull request #6933 from pynickle/fix/issue-6876
imp(VersionOverall): 优化版本重命名处理逻辑
2025-09-09 20:31:50 +08:00
龙腾猫跃 47c3c163ed Merge pull request #6664 from shatyuka/fix/setup-binding
fix: 动画绑定失败
2025-09-09 20:18:27 +08:00
龙腾猫跃 45b6582f30 Merge branch 'main' into fix/setup-binding 2025-09-09 20:18:18 +08:00
龙腾猫跃 6f9262ef4f Merge pull request #7020 from PCL-Community/#7003
chore(ModCrash): 崩溃识别增加
2025-09-07 04:31:39 +08:00
龙腾猫跃 46fd4c1e8d Merge pull request #7031 from PCL-Community/#6908
fix(ModModpack): 安装整合包时忽略配置中设置的 IsStar 值
2025-09-04 23:13:19 +08:00
龙腾猫跃 c3d79e1f18 Merge pull request #7028 from PCL-Community/#6978
feat(PageVersionExport): 打包整合包时支持添加 TaCZ 枪包
2025-09-04 23:11:29 +08:00
龙腾猫跃 f63e9a896c Merge pull request #7043 from PCL-Community/#7030
feat(PageSelectLeft): 将要删除的游戏文件夹是系统关键目录时警告用户
2025-09-04 23:01:38 +08:00
龙腾猫跃 9c9d98084a Merge pull request #7052 from pynickle/imp/issue-7032-official
imp(mod-crash): 优化玩家实体导致崩溃的提示信息
2025-09-04 21:21:31 +08:00
龙腾猫跃 cfbde4ad1c Merge pull request #7056 from Open-KFC/IsSwaped-delegate
fix(MyCard): IsSwaped 未正确转发
2025-09-04 21:14:23 +08:00
龙腾猫跃 46b96d6408 Merge pull request #7050 from pynickle/style/chinese-official
style: 去除中文逗号
2025-09-04 21:05:40 +08:00
龙腾猫跃 6f3bad680c Merge pull request #7057 from PCL-Community/#7025
fix(ModLaunch): 未将部分错误识别为超时
2025-09-04 17:58:10 +08:00
龙腾猫跃 ad5207470d Merge pull request #7058 from pynickle/fix/issue-7023-official
fix(mod-launch): 修复刷新登录时出现 400 报错,未进行错误处理
2025-09-04 17:50:36 +08:00
龙腾猫跃 b936608ec7 Merge pull request #7071 from PCL-Community/#7070
fix(ModCrash): 错误分析误报 night config 存在问题,但实际上是配置文件损坏
2025-09-04 00:19:47 +08:00
龙腾猫跃 dc7f01dfdd Merge pull request #7151 from lingting/main
Java搜索 支持jet 的基础sdk 以及 ~/.jdks 没匹配到可用项修复
2025-09-02 20:52:38 +08:00
龙腾猫跃 3528bf5a3d Merge pull request #6866 from LuoYun-Team/MusicCount
fix(music): 计算音乐文件数量逻辑有误
2025-09-01 20:57:39 +08:00
龙腾猫跃 f211df1ea2 Merge pull request #6648 from PCL-Community/feat#6610
feat: 允许为单个版本关闭 Mod 更新功能
2025-09-01 20:33:07 +08:00
lingting 9a3df4adec feat(java): Java搜索支持 Jet的sdk且同时忽略jet 的jcef sdk 2025-08-27 16:35:46 +08:00
lingting b09750ffff fix(java): 尝试修复从 ~/.jdks 中搜索Java时未匹配到任何可用项 2025-08-27 16:32:56 +08:00
wyc-26 2f74640de5 fix(ModCrash): 忘写 Then 2025-08-16 18:45:02 +08:00
wyc-26 78a5536bc7 fix(ModCrash): 错误分析误报 night config 存在问题,但实际上是配置文件损坏 2025-08-16 16:12:52 +08:00
ENC_Euphony 54c45ff54b 加入封号处理 2025-08-15 20:37:30 +08:00
ENC_Euphony fe39495f2e Update ModLaunch.vb 2025-08-15 16:25:03 +08:00
ENC_Euphony e2c24a7d44 fix(mod-launch): 修复刷新登录时出现 400 报错,未进行错误处理 2025-08-15 15:18:03 +08:00
wyc-26 37b069c572 fix(ModLaunch): 未将部分错误识别为超时 2025-08-15 14:33:10 +08:00
Open-KFC 5622e50a54 fix(MyCard): IsSwaped 未正确转发 2025-08-15 12:29:27 +08:00
ENC_Euphony 86d1d387a5 imp(mod-crash): 优化玩家实体导致崩溃的提示信息 2025-08-15 01:08:27 +08:00
ENC_Euphony 7f2f7df05f style: 去除中文逗号 2025-08-15 00:44:50 +08:00
wyc-26 b285ffa401 feat(PageSelectLeft): 将要删除的游戏文件夹是系统关键目录时警告用户 2025-08-14 15:36:32 +08:00
龙腾猫跃 8e095ddaed 2.10.6 正式版 2025-08-14 01:29:27 +08:00
wyc-26 afc08cc243 fix(ModModpack): 安装整合包时忽略配置中设置的 IsStar 值 2025-08-13 16:15:32 +08:00
wyc-26 bac349a54c feat(PageVersionExport): 打包整合包时支持添加 TaCZ 枪包 2025-08-13 16:04:18 +08:00
wyc-26 02c766ac08 chore(ModCrash): 崩溃识别增加 2025-08-13 10:12:38 +08:00
龙腾猫跃 273cee69e5 fix: IsSwaped 在加壳后失效 2025-08-13 01:33:11 +08:00
龙腾猫跃 adf52d56b7 2.10.6 2025-08-13 01:08:21 +08:00
龙腾猫跃 1d0947181f Merge pull request #6970 from youzi-3222/auto-repl-colon
feat(PageVersionSetup): 自动将服务器地址替换为半角冒号
2025-08-12 19:47:21 +08:00
龙腾猫跃 f67ef9c2c5 Merge pull request #6904 from MoYuan-CN/pr/term-optimize
imp: 修改参数展示名
2025-08-12 19:11:57 +08:00
龙腾猫跃 28640dcdf5 Merge pull request #6942 from LuoYun-Team/MMC-Modpack-Fix
fix(Launch): 修复 HMCL 安装的部分整合包没法启动
2025-08-12 18:59:49 +08:00
龙腾猫跃 88e87011af Merge pull request #6971 from pynickle/style/swapped
style: 一个 typo 修复
2025-08-12 04:17:46 +08:00
龙腾猫跃 c22f925807 Merge pull request #6976 from LuoYun-Team/inst-tip
chore(tip): 移除提示
2025-08-12 04:14:30 +08:00
龙腾猫跃 5785ffdfb3 Merge pull request #6980 from Light-Beacon/main
主页按钮加入非加密设置的写入功能
2025-08-12 04:11:13 +08:00
龙腾猫跃 59857c3391 Merge pull request #6984 from Light-Beacon/change-news-homepage-link
新闻主页链接使用SSL
2025-08-12 03:31:06 +08:00
龙腾猫跃 c90d96e65d Merge pull request #6709 from ABA2396/pcl2
fix: 规避 WPF 剪贴板卡顿,修复剪切不清除文本的问题
2025-08-11 22:04:01 +08:00
Nattiden 838cb3c842 news homepage use ssl 2025-08-08 21:37:53 +08:00
Nattiden d133138984 实现 #6973 2025-08-08 14:55:38 +08:00
薄奚梦灵 128b8001ff chore(tip): 移除注册表项目 2025-08-08 11:02:50 +08:00
薄奚梦灵 c7e0dd3816 chore(tip): 移除提示 2025-08-08 10:59:56 +08:00
龙腾猫跃 8e0f53c881 2.10.5 正式版 2025-08-08 03:11:24 +08:00
youzi-3222 68483876f3 feat(PageVersionSetup): 替换中文冒号不弹窗提示 2025-08-07 21:20:42 +08:00
ENC_Euphony 10a5a30968 Update Plain Craft Launcher 2.vbproj 2025-08-07 19:30:37 +08:00
ENC_Euphony fdc56a2a4b style: 一个 typo 修复 2025-08-07 16:15:40 +08:00
youzi-3222 490626a293 feat(PageVersionSetup): 自动将服务器地址替换为半角冒号 2025-08-07 12:53:25 +08:00
薄奚梦灵 ce91fe6245 fix(launch): missing " 2025-08-03 13:29:35 +08:00
薄奚梦灵 5a841de3ba fix(Launch): 修复 HMCL 安装的部分整合包没法启动 2025-08-03 13:26:16 +08:00
ENC_Euphony fc910b1955 ref(VersionOverall): 优化代码 2025-08-02 18:33:43 +08:00
ENC_Euphony 340e7457f8 imp(VersionOverall): 优化版本重命名处理逻辑 2025-08-01 23:27:22 +08:00
墨渊 b76266a69d imp: 修改参数展示名 2025-07-29 02:07:54 +08:00
墨渊 5fc0693892 imp: 修改参数展示名
JVM 参数头部 → Java 虚拟机参数
2025-07-29 02:06:41 +08:00
薄奚梦灵 73d9eed9a9 fix(music): 计算音乐文件数量逻辑有误 2025-07-24 20:03:04 +08:00
uye 5aad129121 fix: 规避 WPF 剪贴板卡顿,修复剪切不清除文本的问题
支持 (Rich)TextBox 复制/剪切/粘贴 和 DataGrid 复制,TextBox默认生效,可通过附加属性 ClipboardInterceptor.EnableSafeClipboard 启用
2025-07-03 22:44:56 +08:00
shatyuka 065b69b346 fix: 动画绑定失败 2025-06-28 05:44:00 +08:00
wyc-26 c708aca3fb refactor: 移到高级启动选项里面 2025-06-27 09:32:47 +08:00
wyc-26 e188f7392c feat: 允许为单个版本关闭 Mod 更新功能 2025-06-26 16:01:29 +08:00
102 changed files with 3126 additions and 2298 deletions

No files matched your search

+3
View File
@@ -1,6 +1,7 @@
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:behaviors="clr-namespace:PCL.Controls.Behaviors"
xmlns:local="clr-namespace:PCL"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="FormMain.xaml"
@@ -302,6 +303,7 @@
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="behaviors:ClipboardInterceptor.EnableSafeClipboard" Value="True" />
</Style>
<Style TargetType="PasswordBox">
<Setter Property="FontSize" Value="13" />
@@ -343,6 +345,7 @@
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="behaviors:ClipboardInterceptor.EnableSafeClipboard" Value="True" />
</Style>
<!-- ComboBox -->
+24 -10
View File
@@ -19,6 +19,9 @@ Public Class Application
'开始
Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
Try
'动态 DLL 调用(必须尽量在前面,否则模块加载 CacheCow 等 DLL 就可能导致崩溃)
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf AssemblyResolve
'开始
SecretOnApplicationStart()
'检查参数调用
If e.Args.Length > 0 Then
@@ -67,9 +70,9 @@ Public Class Application
If Not CheckPermission(PathTemp) Then Throw New Exception("PCL 没有对 " & PathTemp & " 的访问权限")
Catch ex As Exception
If PathTemp = IO.Path.GetTempPath() & "PCL\" Then
MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & "错误原因:" & GetExceptionDetail(ex), "缓存文件夹不可用")
MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDetail(), "缓存文件夹不可用")
Else
MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & "错误原因:" & GetExceptionDetail(ex), "缓存文件夹不可用")
MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDetail(), "缓存文件夹不可用")
Setup.Set("SystemSystemCache", "")
PathTemp = IO.Path.GetTempPath() & "PCL\"
End If
@@ -104,13 +107,18 @@ WaitRetry:
ToolTipService.PlacementProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(Primitives.PlacementMode.Bottom))
ToolTipService.HorizontalOffsetProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(8.0))
ToolTipService.VerticalOffsetProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(4.0))
'设置网络配置默认值
ServicePointManager.Expect100Continue = False
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
ServicePointManager.DefaultConnectionLimit = 10000
ServicePointManager.UseNagleAlgorithm = False
ServicePointManager.EnableDnsRoundRobin = True
ServicePointManager.ReusePort = True
'设置初始窗口
If Setup.Get("UiLauncherLogo") Then
FrmStart = New SplashScreen("Images\icon.ico")
FrmStart.Show(False, True)
End If
'动态 DLL 调用
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf AssemblyResolve
'日志初始化
LogStart()
'添加日志
@@ -136,10 +144,6 @@ WaitRetry:
Setup.Load("ToolDownloadThread")
Setup.Load("ToolDownloadCert")
Setup.Load("ToolDownloadSpeed")
'网络配置初始化
ServicePointManager.Expect100Continue = True
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
ServicePointManager.DefaultConnectionLimit = 1024
'计时
Log("[Start] 第一阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
ApplicationStartTick = GetTimeTick()
@@ -154,7 +158,7 @@ WaitRetry:
FilePath = PathWithName
Catch
End Try
MsgBox(GetExceptionDetail(ex, True) & vbCrLf & "PCL 所在路径:" & If(String.IsNullOrEmpty(FilePath), "获取失败", FilePath), MsgBoxStyle.Critical, "PCL 初始化错误")
MsgBox(ex.GetDetail(True) & vbCrLf & "PCL 所在路径:" & If(String.IsNullOrEmpty(FilePath), "获取失败", FilePath), MsgBoxStyle.Critical, "PCL 初始化错误")
FormMain.EndProgramForce(ProcessReturnValues.Exception)
End Try
End Sub
@@ -167,10 +171,20 @@ WaitRetry:
'异常
Private Sub Application_DispatcherUnhandledException(sender As Object, e As DispatcherUnhandledExceptionEventArgs) Handles Me.DispatcherUnhandledException
On Error Resume Next
'触发页面的 Dispatcher
If FrmMain?.PageLeft IsNot Nothing AndAlso TypeOf FrmMain.PageLeft Is IDispatcherUnhandledException Then
CType(FrmMain.PageLeft, IDispatcherUnhandledException).DispatcherUnhandledException(sender, e)
If e.Handled Then Return
End If
If FrmMain?.PageRight IsNot Nothing AndAlso TypeOf FrmMain.PageRight Is IDispatcherUnhandledException Then
CType(FrmMain.PageRight, IDispatcherUnhandledException).DispatcherUnhandledException(sender, e)
If e.Handled Then Return
End If
'正常处理
e.Handled = True
If IsProgramEnded Then Return
FeedbackInfo()
Dim Detail As String = GetExceptionDetail(e.Exception, True)
Dim Detail As String = e.Exception.GetDetail(True)
If Detail.Contains("System.Windows.Threading.Dispatcher.Invoke") OrElse Detail.Contains("MS.Internal.AppModel.ITaskbarList.HrInit") OrElse Detail.Contains("未能加载文件或程序集") OrElse
Detail.Contains(".NET Framework") Then ' “自动错误判断” 的结果分析
OpenWebsite("https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-offline-installer")
@@ -0,0 +1,187 @@
' Author: uye (owner of the MaaAssistantArknights team)
' Original Source: MaaAssistantArknights project - https://github.com/MaaAssistantArknights/MaaAssistantArknights
' License: Apache License 2.0 (this file only)
'
' This file is originally developed for MaaAssistantArknights and licensed under AGPL v3.0.
' As the original author and copyright holder,
' I hereby re-license this file under the Apache License 2.0 for use in the Plain Craft Launcher project.
'
' This file is contributed under the spirit of good faith and open cooperation.
' It does not implement any core launcher functions of PCL.
'
' Description:
' Provides a WPF clipboard handling fix to avoid OpenClipboard exceptions
' in TextBox, RichTextBox, and DataGrid under Windows focus issues or clipboard hooks.
'
' Date: 2025-07-03
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input
Imports System.Windows.Documents
Imports System.Linq
Namespace Controls.Behaviors
Public NotInheritable Class ClipboardInterceptor
Private Sub New()
End Sub
Public Shared ReadOnly EnableSafeClipboardProperty As DependencyProperty =
DependencyProperty.RegisterAttached("EnableSafeClipboard", GetType(Boolean), GetType(ClipboardInterceptor),
New PropertyMetadata(False, AddressOf OnEnableSafeClipboardChanged))
Public Shared Sub SetEnableSafeClipboard(element As DependencyObject, value As Boolean)
element.SetValue(EnableSafeClipboardProperty, value)
End Sub
Public Shared Function GetEnableSafeClipboard(element As DependencyObject) As Boolean
Return CBool(element.GetValue(EnableSafeClipboardProperty))
End Function
Private Shared Sub OnEnableSafeClipboardChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
If TypeOf d Is TextBox AndAlso CBool(e.NewValue) Then
AddCommandBindingsToTextBox(DirectCast(d, TextBox))
ElseIf TypeOf d Is RichTextBox AndAlso CBool(e.NewValue) Then
AddCommandBindingsToRichTextBox(DirectCast(d, RichTextBox))
ElseIf TypeOf d Is DataGrid AndAlso CBool(e.NewValue) Then
AddCommandBindingsToDataGrid(DirectCast(d, DataGrid))
End If
End Sub
Private Shared Sub AddCommandBindingsToTextBox(tb As TextBox)
tb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Copy, AddressOf OnCopyTextBox))
tb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Cut, AddressOf OnCutTextBox))
tb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Paste, AddressOf OnPasteTextBox))
End Sub
Private Shared Sub AddCommandBindingsToRichTextBox(rtb As RichTextBox)
rtb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Copy, AddressOf OnCopyRichTextBox))
rtb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Cut, AddressOf OnCutRichTextBox))
rtb.CommandBindings.Add(New CommandBinding(ApplicationCommands.Paste, AddressOf OnPasteRichTextBox))
End Sub
Private Shared Sub AddCommandBindingsToDataGrid(dg As DataGrid)
dg.CommandBindings.Add(New CommandBinding(ApplicationCommands.Copy, AddressOf OnCopyDataGrid))
End Sub
Private Shared Sub OnCopyTextBox(sender As Object, e As ExecutedRoutedEventArgs)
Dim tb = TryCast(sender, TextBox)
If tb Is Nothing OrElse tb.SelectionLength <= 0 Then Return
Try
Forms.Clipboard.Clear()
Forms.Clipboard.SetDataObject(tb.SelectedText, True)
Catch
End Try
e.Handled = True
End Sub
Private Shared Sub OnCutTextBox(sender As Object, e As ExecutedRoutedEventArgs)
Dim tb = TryCast(sender, TextBox)
If tb Is Nothing OrElse tb.SelectionLength <= 0 Then Return
Try
Forms.Clipboard.Clear()
Forms.Clipboard.SetDataObject(tb.SelectedText, True)
Catch
End Try
tb.SelectedText = String.Empty
e.Handled = True
End Sub
Private Shared Sub OnPasteTextBox(sender As Object, e As ExecutedRoutedEventArgs)
Dim tb = TryCast(sender, TextBox)
If tb Is Nothing Then Return
If Forms.Clipboard.ContainsText() Then
Dim pasteText = Forms.Clipboard.GetText()
Dim start = tb.SelectionStart
tb.SelectedText = pasteText
tb.CaretIndex = start + pasteText.Length
tb.SelectionLength = 0
End If
e.Handled = True
End Sub
Private Shared Sub OnCopyRichTextBox(sender As Object, e As ExecutedRoutedEventArgs)
Dim rtb = TryCast(sender, RichTextBox)
If rtb Is Nothing Then Return
Dim textRange = New TextRange(rtb.Selection.Start, rtb.Selection.End)
If String.IsNullOrEmpty(textRange.Text) Then Return
Try
Forms.Clipboard.Clear()
Forms.Clipboard.SetDataObject(textRange.Text, True)
Catch
End Try
e.Handled = True
End Sub
Private Shared Sub OnCutRichTextBox(sender As Object, e As ExecutedRoutedEventArgs)
Dim rtb = TryCast(sender, RichTextBox)
If rtb Is Nothing Then Return
Dim selection = New TextRange(rtb.Selection.Start, rtb.Selection.End)
If String.IsNullOrEmpty(selection.Text) Then Return
Try
Forms.Clipboard.Clear()
Forms.Clipboard.SetDataObject(selection.Text, True)
Catch
End Try
selection.Text = String.Empty
e.Handled = True
End Sub
Private Shared Sub OnPasteRichTextBox(sender As Object, e As ExecutedRoutedEventArgs)
Dim rtb = TryCast(sender, RichTextBox)
If rtb Is Nothing Then Return
If Not Forms.Clipboard.ContainsText() Then Return
Dim pasteText = Forms.Clipboard.GetText()
Dim selection = rtb.Selection
selection.Text = pasteText
Dim caretPos = selection.End
rtb.CaretPosition = caretPos
rtb.Selection.Select(caretPos, caretPos)
e.Handled = True
End Sub
Private Shared Sub OnCopyDataGrid(sender As Object, e As ExecutedRoutedEventArgs)
Dim dg = TryCast(sender, DataGrid)
If dg Is Nothing OrElse dg.SelectedCells Is Nothing OrElse dg.SelectedCells.Count = 0 Then Return
Dim sb = New System.Text.StringBuilder()
Dim rowGroups = dg.SelectedCells.GroupBy(Function(c) c.Item)
For Each row In rowGroups
Dim rowText = String.Join(vbTab, row.Select(Function(cell)
Dim tb = TryCast(cell.Column.GetCellContent(cell.Item), TextBlock)
Return If(tb IsNot Nothing, tb.Text, "")
End Function))
sb.AppendLine(rowText)
Next
Dim sbStr = sb.ToString().TrimEnd(ControlChars.Cr, ControlChars.Lf)
Try
Forms.Clipboard.Clear()
Forms.Clipboard.SetDataObject(sbStr, True)
Catch
End Try
e.Handled = True
End Sub
End Class
End Namespace
@@ -0,0 +1,15 @@
Imports System.Windows.Threading
''' <summary>
''' 指示页面可以通过按下 F5 或以其他方式刷新。
''' </summary>
Public Interface IRefreshable
Sub Refresh()
End Interface
''' <summary>
''' 指示页面可以处理未捕获的异常。
''' </summary>
Public Interface IDispatcherUnhandledException
Sub DispatcherUnhandledException(sender As Object, e As DispatcherUnhandledExceptionEventArgs)
End Interface
+32 -29
View File
@@ -90,7 +90,7 @@
MainGrid.Children.Add(MainSwap)
End If
'改变默认的折叠
If IsSwaped AndAlso SwapControl IsNot Nothing Then
If IsSwapped AndAlso SwapControl IsNot Nothing Then
MainSwap.RenderTransform = New RotateTransform(If(SwapLogoRight, 270, 0))
'取消由于高度变化被迫触发的高度动画
Dim RawUseAnimation As Boolean = UseAnimation
@@ -123,14 +123,6 @@
End Select
'控件转换
Select Case Type
Case 5
Dim LoadingPickaxe As New MyLoading With {.Text = "正在获取版本列表", .Margin = New Thickness(5)}
Dim Loader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Main", AddressOf DlForgeVersionMain)
LoadingPickaxe.State = Loader
Loader.Start(Stack.Tag)
AddHandler LoadingPickaxe.StateChanged, AddressOf FrmDownloadForge.Forge_StateChanged
AddHandler LoadingPickaxe.Click, AddressOf FrmDownloadForge.Forge_Click
Stack.Children.Add(LoadingPickaxe)
Case 6
ForgeDownloadListItemPreload(Stack, Stack.Tag, AddressOf ForgeSave_Click, True)
Case 8
@@ -145,9 +137,6 @@
Stack.Children.Add(McDownloadListItem(Data, AddressOf McDownloadMenuSave, True))
Case 3
Stack.Children.Add(OptiFineDownloadListItem(Data, AddressOf OptiFineSave_Click, True))
Case 4
Stack.Children.Add(LiteLoaderDownloadListItem(Data, AddressOf FrmDownloadLiteLoader.DownloadStart, False))
Case 5
Case 6
Stack.Children.Add(ForgeDownloadListItem(Data, AddressOf ForgeSave_Click, True))
Case 7
@@ -224,7 +213,7 @@
Private ActualUsedHeight As Double '回滚实际高度(例如 NaN)
Private Sub MySizeChanged(sender As Object, e As SizeChangedEventArgs) Handles Me.SizeChanged
If Not UseAnimation Then Return
Dim DeltaHeight As Double = If(IsSwaped, SwapedHeight, e.NewSize.Height) - e.PreviousSize.Height
Dim DeltaHeight As Double = If(IsSwapped, SwapedHeight, e.NewSize.Height) - e.PreviousSize.Height
'卡片的进入时动画已被页面通用切换动画替代
If e.PreviousSize.Height = 0 OrElse IsHeightAnimating OrElse Math.Abs(DeltaHeight) < 1 OrElse ActualHeight = 0 Then Return
StartHeightAnimation(DeltaHeight, e.PreviousSize.Height, False)
@@ -269,18 +258,18 @@
Sub()
IsHeightAnimating = False
Height = ActualUsedHeight
If IsSwaped AndAlso SwapControl IsNot Nothing Then SwapControl.Visibility = Visibility.Collapsed
If IsSwapped AndAlso SwapControl IsNot Nothing Then SwapControl.Visibility = Visibility.Collapsed
End Sub,, True))
AniStart(AnimList, "MyCard Height " & Uuid)
IsHeightAnimating = True
ActualUsedHeight = If(IsSwaped, SwapedHeight, Height)
ActualUsedHeight = If(IsSwapped, SwapedHeight, Height)
Height = PreviousHeight
End Sub
''' <summary>
''' 通知 MyCard,控件内容已改变,需要中断动画并更新高度。
''' </summary>
Public Sub TriggerForceResize()
Height = If(IsSwaped, SwapedHeight, Double.NaN)
Height = If(IsSwapped, SwapedHeight, Double.NaN)
AniStop("MyCard Height " & Uuid)
IsHeightAnimating = False
End Sub
@@ -300,26 +289,40 @@
''' <summary>
''' 是否已被折叠。
''' </summary>
Public Property IsSwaped As Boolean
Public Property IsSwapped As Boolean
Get
Return _IsSwaped
Return _IsSwapped
End Get
Set(value As Boolean)
If _IsSwaped = value Then Return
_IsSwaped = value
If _IsSwapped = value Then Return
_IsSwapped = value
If SwapControl Is Nothing Then Return
'展开
If Not IsSwaped AndAlso TypeOf SwapControl Is StackPanel Then StackInstall(SwapControl, SwapType, Title)
If Not IsSwapped AndAlso TypeOf SwapControl Is StackPanel Then StackInstall(SwapControl, SwapType, Title)
'若尚未加载,会在 Loaded 事件中触发无动画的折叠,不需要在这里进行
If Not IsLoaded Then Return
'更新高度
SwapControl.Visibility = Visibility.Visible
TriggerForceResize()
'改变箭头
AniStart(AaRotateTransform(MainSwap, If(_IsSwaped, If(SwapLogoRight, 270, 0), 180) - CType(MainSwap.RenderTransform, RotateTransform).Angle, 250,, New AniEaseOutFluent(AniEasePower.ExtraStrong)), "MyCard Swap " & Uuid, True)
AniStart(AaRotateTransform(MainSwap, If(_IsSwapped, If(SwapLogoRight, 270, 0), 180) - CType(MainSwap.RenderTransform, RotateTransform).Angle, 250,, New AniEaseOutFluent(AniEasePower.ExtraStrong)), "MyCard Swap " & Uuid, True)
End Set
End Property
Private _IsSwaped As Boolean = False
Private _IsSwapped As Boolean = False
''' <summary>
''' 是否已被折叠。(已过时,请使用 IsSwapped)
''' </summary>
<Obsolete("IsSwaped 存在拼写错误,请换用 IsSwapped 属性。")>
Public Property IsSwaped As Boolean
Get
Return GetValue(IsSwapedProperty)
End Get
Set(value As Boolean)
SetValue(IsSwapedProperty, value)
End Set
End Property
Public Shared ReadOnly IsSwapedProperty As DependencyProperty = DependencyProperty.Register("IsSwaped", GetType(Boolean), GetType(MyCard), New PropertyMetadata(False,
Sub(sender, e) If sender IsNot Nothing AndAlso TypeOf sender Is MyCard Then CType(sender, MyCard).IsSwapped = CType(e.NewValue, Boolean)))
Public Property SwapLogoRight As Boolean = False
Private IsMouseDown As Boolean = False
@@ -328,8 +331,8 @@
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
(SwapControl Is Nothing OrElse Pos > If(IsSwaped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return '检测点击位置;或已经不在可视树上的误判
If Not IsSwapped AndAlso
(SwapControl Is Nothing OrElse Pos > If(IsSwapped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return '检测点击位置;或已经不在可视树上的误判
IsMouseDown = True
End Sub
Private Sub MyCard_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
@@ -337,8 +340,8 @@
IsMouseDown = False
Dim Pos As Double = Mouse.GetPosition(Me).Y
If Not IsSwaped AndAlso
(SwapControl Is Nothing OrElse Pos > If(IsSwaped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return '检测点击位置;或已经不在可视树上的误判
If Not IsSwapped AndAlso
(SwapControl Is Nothing OrElse Pos > If(IsSwapped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return '检测点击位置;或已经不在可视树上的误判
Dim ee = New RouteEventArgs(True)
RaiseEvent PreviewSwap(Me, ee)
@@ -347,8 +350,8 @@
Return
End If
IsSwaped = Not IsSwaped
Log("[Control] " & If(IsSwaped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title))
IsSwapped = Not IsSwapped
Log("[Control] " & If(IsSwapped, "折叠卡片", "展开卡片") & 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
+12 -51
View File
@@ -25,7 +25,7 @@
''' <summary>
''' 与 Image 的 Source 类似。
''' 若输入以 http 开头的字符串,则会尝试下载图片然后显示,图片会保存为本地缓存。
''' 若输入以 http 开头的字符串,则会尝试下载图片然后显示;若 EnableCache 设为 True,图片还会保存为本地缓存。
''' 支持 WebP 格式的图片。
''' </summary>
Public Shadows Property Source As String '覆写 Image 的 Source 属性
@@ -46,7 +46,7 @@
Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyImage).Source = e.NewValue.ToString())))
''' <summary>
''' 当 Source 首次下载失败时,会从该备用地址加载图片。
''' 若 Source 是一个网络图片,该地址将作为第二下载源。
''' </summary>
Public Property FallbackSource As String
Get
@@ -111,74 +111,35 @@
Return
End If
'从缓存加载网络图片
Dim Url As String = Source
Dim Retried As Boolean = False
Dim TempPath As String = GetTempPath(Url)
Dim TempFile As New FileInfo(TempPath)
Dim EnableCache As Boolean = Me.EnableCache
Dim TempPath As String = GetTempPath(Source) & If(EnableCache, "", GetUuid()) '不启用缓存时加上随机字符串,避免冲突
Dim TempFile As New FileInfo(TempPath)
If EnableCache AndAlso TempFile.Exists Then
ActualSource = TempPath
If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Return '无需刷新缓存
End If
RunInNewThread(
Sub()
Dim TempDownloadingPath As String = Nothing
Try
RetryStart:
'下载
ActualSource = LoadingSource '显示加载中图片
TempDownloadingPath = TempPath & RandomInteger(0, 10000000)
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)
ElseIf EnableCache Then
ActualSource = LoadingSource '显示加载中的占位图片
NetDownloadByLoader(
If(String.IsNullOrEmpty(FallbackSource), {Source}, {Source, FallbackSource}),
TempPath, SimulateBrowserHeaders:=True)
If EnableCache Then
'保存缓存并显示
If File.Exists(TempPath) Then File.Delete(TempPath)
FileSystem.Rename(TempDownloadingPath, TempPath)
RunInUi(Sub() ActualSource = TempPath)
Else
'直接显示
RunInUiWait(Sub() ActualSource = TempDownloadingPath)
File.Delete(TempDownloadingPath)
RunInUiWait(Sub() ActualSource = TempPath)
File.Delete(TempPath)
End If
Catch ex As Exception
Try
If TempPath IsNot Nothing Then File.Delete(TempPath)
If TempDownloadingPath IsNot Nothing Then File.Delete(TempDownloadingPath)
Catch
End Try
If Not Retried Then
'更换备用地址
Log(ex, $"下载图片可重试地失败({Url})", LogLevel.Developer)
Retried = True
Url = If(FallbackSource, Source)
'空
If Url Is Nothing Then
ActualSource = Nothing
Return
End If
'本地图片
If Not Url.StartsWithF("http") Then
ActualSource = Url
Return
End If
'从缓存加载网络图片
TempPath = GetTempPath(Url)
TempFile = New FileInfo(TempPath)
If EnableCache AndAlso TempFile.Exists() Then
ActualSource = TempPath
If (Date.Now - TempFile.CreationTime) < FileCacheExpiredTime Then Return '无需刷新缓存
End If
'下载
If Source = Url Then Thread.Sleep(1000) '延迟 1s 重试
GoTo RetryStart
Else
Log(ex, $"下载图片失败({Url})", LogLevel.Hint)
End If
Log(ex, $"下载图片失败", LogLevel.Hint)
End Try
End Sub, "MyImage PicLoader " & GetUuid() & "#", ThreadPriority.BelowNormal)
End Sub
@@ -79,11 +79,7 @@ Public Class MyLoading
Do While Ex.InnerException IsNot Nothing
Ex = Ex.InnerException
Loop
LabText.Text = StrTrim(Ex.Message)
If {"远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝",
"操作已超时", "操作超时", "服务器超时", "连接超时"}.Any(Function(s) LabText.Text.Contains(s)) Then
LabText.Text = "网络环境不佳,请稍后重试,或使用 VPN 以改善网络环境"
End If
LabText.Text = If(Ex.IsNetworkRelated(), "网络环境不佳,请稍后再试,或使用 VPN 改善网络环境", StrTrim(Ex.Message))
End If
Else
LabText.Text = TextError
@@ -3,15 +3,15 @@
Private Uuid As Integer = GetUuid()
'执行逐个进入动画的控件
Public Property AnimatedControl As FrameworkElement
Public Property AnimatedControl As String '需要在 Loaded 之后才能获取到控件,所以不能用 Binding 直接绑定(#6664)
Get
Return GetValue(AnimatedControlProperty)
End Get
Set(value As FrameworkElement)
Set(value As String)
SetValue(AnimatedControlProperty, value)
End Set
End Property
Public Shared ReadOnly AnimatedControlProperty As DependencyProperty = DependencyProperty.Register("AnimatedControl", GetType(FrameworkElement), GetType(MyPageLeft), New PropertyMetadata(Nothing))
Public Shared ReadOnly AnimatedControlProperty As DependencyProperty = DependencyProperty.Register("AnimatedControl", GetType(String), GetType(MyPageLeft), New PropertyMetadata(Nothing))
Public Sub TriggerShowAnimation()
If AnimatedControl Is Nothing Then
@@ -84,7 +84,7 @@
'遍历获取所有需要生成动画的控件
Private Function GetAllAnimControls(Optional IgnoreInvisibility As Boolean = False) As List(Of FrameworkElement)
Dim AllControls As New List(Of FrameworkElement)
GetAllAnimControls(AnimatedControl, AllControls, IgnoreInvisibility)
GetAllAnimControls(FindName(AnimatedControl), AllControls, IgnoreInvisibility)
Return AllControls
End Function
Private Sub GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement), IgnoreInvisibility As Boolean)
@@ -105,7 +105,3 @@
End Sub
End Class
Public Interface IRefreshable
Sub Refresh()
End Interface
@@ -3,16 +3,16 @@
Public PageUuid As Integer = GetUuid()
'“返回顶部” 按钮检测的滚动区域
Public Property PanScroll As MyScrollViewer
Public Property PanScroll As String '需要在 Loaded 之后才能获取到控件,所以不能用 Binding 直接绑定(#6664)
Get
Return GetValue(PanScrollProperty)
End Get
Set(value As MyScrollViewer)
Set(value As String)
SetValue(PanScrollProperty, value)
End Set
End Property
Private Shared ReadOnly PanScrollProperty =
DependencyProperty.Register("PanScroll", GetType(MyScrollViewer), GetType(MyPageRight), New PropertyMetadata(Nothing))
DependencyProperty.Register("PanScroll", GetType(String), GetType(MyPageRight), New PropertyMetadata(Nothing))
'当前状态
Public Enum PageStates
+1 -1
View File
@@ -264,7 +264,7 @@
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
AniStart({
AaColor(Me, BorderBrushProperty, ForeColorName, AnimationTime),
AaColor(Me, BorderBrushProperty, ForeColorName, AnimationTime),
AaColor(Me, BackgroundProperty, BackColorName, AnimationTime)
}, "MyTextBox Color " & Uuid)
Else
@@ -57,7 +57,7 @@
Private Const AnimationTimeIn As Integer = 100
Private Const AnimationTimeOut As Integer = 200
Private ColorName As String
Private Sub RefreshColor() Handles Me.MouseEnter, Me.MouseLeave, Me.IsEnabledChanged, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp
Private Sub RefreshColor() Handles Me.MouseEnter, Me.MouseLeave, Me.IsEnabledChanged, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp
'判断当前颜色
Dim ForeName As String
Dim Time As Integer
+52 -20
View File
@@ -11,6 +11,27 @@ Public Class FormMain
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
'统计更新日志条目
#If BETA Then
If LastVersion < 369 Then 'Release 2.10.8
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "新增:允许在版本设置中设置禁止更新 Mod,以防整合包玩家误操作"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:若整合包需要 PCL 不兼容的加载器,允许选择跳过它的安装"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "删除:由于已不再需要,删除手动安装包下载功能"))
FeatureCount += 21
BugCount += 32
End If
If LastVersion < 367 Then 'Release 2.10.6
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:启用 MCIM 社区资源镜像源,以缓解社区资源难以下载的问题"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:正版登录出错时无法给出正确的错误信息"))
FeatureCount += 9
BugCount += 9
End If
If LastVersion < 365 Then 'Release 2.10.5
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:下载资源时,会单独记忆每种资源上次下载到的文件夹,以防混淆"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:网络底层框架与下载稳定性"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法启动一部分 LabyMod 和 GTNH 客户端"))
FeatureCount += 22
BugCount += 26
End If
If LastVersion < 361 Then 'Release 2.10.3
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法安装部分使用老版本 PCL 导出的整合包"))
End If
@@ -83,6 +104,25 @@ Public Class FormMain
'3:BUG+ IMP* FEAT-
'2:BUG* IMP-
'1:BUG-
If LastVersion < 370 Then 'Snapshot 2.10.8
If LastVersion >= 368 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化"))
FeatureCount += 3
BugCount += 4
End If
If LastVersion < 368 Then 'Snapshot 2.10.7
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "新增:允许在版本设置中设置禁止更新 Mod,以防整合包玩家误操作"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:若整合包需要 PCL 不兼容的加载器,允许选择跳过它的安装"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "删除:由于已不再需要,删除手动安装包下载功能"))
FeatureCount += 19
BugCount += 28
End If
If LastVersion < 366 Then 'Snapshot 2.10.6
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:启用 MCIM 社区资源镜像源,以缓解社区资源难以下载的问题"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:正版登录出错时无法给出正确的错误信息"))
FeatureCount += 9
BugCount += 9
End If
If LastVersion < 364 Then 'Snapshot 2.10.5
If LastVersion >= 363 Then
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法添加新的正版账号"))
@@ -268,11 +308,6 @@ Public Class FormMain
AddHandler Closing, Sub() Helper.RemoveDragHook()
AddHandler Helper.DragDrop, Sub() FileDrag(Helper.DropFilePaths)
End If
'If IsAdmin() Then '下列代码没用(#2531)
' ChangeWindowMessageFilter(&H233, 1)
' ChangeWindowMessageFilter(&H4A, 1)
' ChangeWindowMessageFilter(&H49, 1)
'End If
'切换到首页
If Not IsNothing(FrmLaunchLeft.Parent) Then FrmLaunchLeft.SetValue(ContentPresenter.ContentProperty, Nothing)
If Not IsNothing(FrmLaunchRight.Parent) Then FrmLaunchRight.SetValue(ContentPresenter.ContentProperty, Nothing)
@@ -389,6 +424,8 @@ Public Class FormMain
Catch ex As Exception
Log(ex, "清理自动更新文件失败")
End Try
'上报
Telemetry("启动")
End Sub, "初始化", ThreadPriority.Lowest)
Log("[Start] 第三阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
@@ -566,7 +603,7 @@ Public Class FormMain
FeedbackInfo()
Log("请在 https://github.com/Meloong-Git/PCL/issues 提交错误报告,以便于作者解决此问题!")
IsLogShown = True
ShellOnly(Path & "PCL\Log1.txt")
StartProcess(Path & "PCL\Log1.txt")
End If
Thread.Sleep(500) '防止 PCL 在记事本打开前就被掐掉
End If
@@ -874,7 +911,7 @@ Public Class FormMain
'错误报告分析
Try
Log("[System] 尝试进行错误报告分析")
Dim Analyzer As New CrashAnalyzer(GetUuid())
Dim Analyzer As New CrashAnalyzer
Analyzer.Import(FilePath)
If Not Analyzer.Prepare() Then Exit Try
Analyzer.Analyze()
@@ -1009,18 +1046,12 @@ Public Class FormMain
''' </summary>
Public Enum PageSubType
[Default] = 0
DownloadInstall = 1
DownloadClient = 4
DownloadOptiFine = 5
DownloadForge = 6
DownloadNeoForge = 7
DownloadFabric = 8
DownloadLiteLoader = 9
DownloadMod = 11
DownloadPack = 12
DownloadDataPack = 13
DownloadResourcePack = 14
DownloadShader = 15
DownloadInstall = 0
DownloadMod = 2
DownloadPack = 3
DownloadDataPack = 4
DownloadResourcePack = 5
DownloadShader = 6
SetupLaunch = 0
SetupUI = 1
SetupSystem = 2
@@ -1498,7 +1529,8 @@ Public Class FormMain
End Function
Private Function BtnExtraBack_GetRealChild() As MyScrollViewer
If PanMainRight.Child Is Nothing OrElse TypeOf PanMainRight.Child IsNot MyPageRight Then Return Nothing
Return CType(PanMainRight.Child, MyPageRight).PanScroll
Dim Page As MyPageRight = PanMainRight.Child
Return Page.FindName(Page.PanScroll)
End Function
#End Region
+126 -153
View File
@@ -1,6 +1,6 @@
Imports System.Globalization
Imports System.IO.Compression
Imports System.Reflection
Imports System.Net.Sockets
Imports System.Runtime.CompilerServices
Imports System.Security.Cryptography
Imports System.Security.Principal
@@ -13,13 +13,13 @@ Public Module ModBase
#Region "声明"
'下列版本信息由更新器自动修改
Public Const VersionBaseName As String = "2.10.5" '不含分支前缀的显示用版本名
Public Const VersionStandardCode As String = "2.10.5." & VersionBranchCode '标准格式的四段式版本号
Public Const VersionBaseName As String = "2.10.8" '不含分支前缀的显示用版本名
Public Const VersionStandardCode As String = "2.10.8." & VersionBranchCode '标准格式的四段式版本号
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
#If BETA Then
Public Const VersionCode As Integer = 361 'Release
Public Const VersionCode As Integer = 367 'Release
#Else
Public Const VersionCode As Integer = 364 'Snapshot
Public Const VersionCode As Integer = 370 'Snapshot
#End If
'自动生成的版本信息
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
@@ -765,17 +765,6 @@ Public Module ModBase
Return FilePath
End Function
''' <summary>
''' 从文件路径或者 Url 获取不包含路径与扩展名的文件名。不包含文件名将会抛出异常。
''' </summary>
Public Function GetFileNameWithoutExtentionFromPath(FilePath As String) As String
Dim Name As String = GetFileNameFromPath(FilePath)
If Name.Contains(".") Then
Return Name.Substring(0, Name.LastIndexOfF("."))
Else
Return Name
End If
End Function
''' <summary>
''' 从文件夹路径获取文件夹名。
''' </summary>
Public Function GetFolderNameFromPath(FolderPath As String) As String
@@ -791,8 +780,8 @@ Public Module ModBase
Public Sub CopyFile(FromPath As String, ToPath As String)
Try
'还原文件路径
If Not FromPath.Contains(":\") Then FromPath = Path & FromPath
If Not ToPath.Contains(":\") Then ToPath = Path & ToPath
FromPath = If(FromPath.Contains(":\"), FromPath, Path & FromPath)
ToPath = If(ToPath.Contains(":\"), ToPath, Path & ToPath)
'如果复制同一个文件则跳过
If FromPath = ToPath Then Return
'确保目录存在
@@ -861,7 +850,7 @@ Public Module ModBase
''' <param name="Append">是否将文件内容追加到当前文件,而不是覆盖它。</param>
Public Sub WriteFile(FilePath As String, Text As String, Optional Append As Boolean = False, Optional Encoding As Encoding = Nothing)
'处理相对路径
If Not FilePath.Contains(":\") Then FilePath = Path & FilePath
FilePath = If(FilePath.Contains(":\"), FilePath, Path & FilePath)
'确保目录存在
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
'写入文件
@@ -886,7 +875,7 @@ Public Module ModBase
''' <param name="Append">是否将文件内容追加到当前文件,而不是覆盖它。</param>
Public Sub WriteFile(FilePath As String, Content As Byte(), Optional Append As Boolean = False)
'处理相对路径
If Not FilePath.Contains(":\") Then FilePath = Path & FilePath
FilePath = If(FilePath.Contains(":\"), FilePath, Path & FilePath)
'确保目录存在
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
'写入文件
@@ -1283,7 +1272,7 @@ Re:
Return Nothing
Catch ex As Exception
Log(ex, "检查文件出错")
Return GetExceptionSummary(ex)
Return ex.GetBrief()
End Try
End Function
End Class
@@ -1309,16 +1298,13 @@ Re:
Else
'以 zip 方式解压
Using Archive = ZipFile.Open(CompressFilePath, ZipArchiveMode.Read, If(Encode, Encoding.GetEncoding("GB18030")))
Dim TotalCount As Integer = Archive.Entries.Count
Dim TotalCount As Long = Archive.Entries.Count
For Each Entry As ZipArchiveEntry In Archive.Entries
If ProgressIncrementHandler IsNot Nothing Then ProgressIncrementHandler(1 / TotalCount)
If ProgressIncrementHandler IsNot Nothing AndAlso TotalCount > 0 Then ProgressIncrementHandler(1 / TotalCount)
Dim DestinationPath As String = IO.Path.Combine(DestDirectory, Entry.FullName)
If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then
Continue For '不创建空文件夹
Else
Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
Entry.ExtractToFile(DestinationPath, True)
End If
If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then Continue For '不创建空文件夹
Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
Entry.ExtractToFile(DestinationPath, True)
Next
End Using
End If
@@ -1329,11 +1315,20 @@ Re:
''' </summary>
Public Function DeleteDirectory(Path As String, Optional IgnoreIssue As Boolean = False) As Integer
If Not Directory.Exists(Path) Then Return 0
If Not Path.EndsWithF("\") Then Path &= "\"
If Path.EndsWith(":\") OrElse
Path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\" OrElse
Path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) & "\" OrElse
Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) & "\" Then '#7030
Throw New UnauthorizedAccessException("这是重要的系统文件夹,无法删除:" & Path)
End If
'实际删除
Dim DeletedCount As Integer = 0
Dim Files As String()
Try
Files = Directory.GetFiles(Path)
Catch ex As DirectoryNotFoundException '#4549
If Not Directory.Exists(Path) Then Return 0 '可能已被其他线程删除
Log(ex, $"疑似为孤立符号链接,尝试直接删除({Path})", LogLevel.Developer)
Directory.Delete(Path)
Return 0
@@ -1364,6 +1359,7 @@ RetryFile:
RetryDir:
Try
Directory.Delete(Path, True)
Catch ex As DirectoryNotFoundException
Catch ex As Exception
If Not RetriedDir AndAlso Not RunInUi() Then
RetriedDir = True
@@ -1387,17 +1383,17 @@ RetryDir:
ToPath = ToPath.Replace("/", "\")
If Not ToPath.EndsWithF("\") Then ToPath &= "\"
Dim AllFiles = EnumerateFiles(FromPath).ToList
Dim FileCount As Integer = AllFiles.Count
Dim FileCount As Long = AllFiles.Count
For Each File In AllFiles
CopyFile(File.FullName, File.FullName.Replace(FromPath, ToPath))
If ProgressIncrementHandler IsNot Nothing Then ProgressIncrementHandler(1 / FileCount)
If ProgressIncrementHandler IsNot Nothing AndAlso FileCount > 0 Then ProgressIncrementHandler(1 / FileCount)
Next
End Sub
''' <summary>
''' 遍历文件夹中的所有文件。
''' </summary>
Public Function EnumerateFiles(Directory As String) As IEnumerable(Of FileInfo)
Dim Info As New DirectoryInfo(ShortenPath(Directory))
Dim Info As New DirectoryInfo(Directory)
If Not Info.Exists Then Return New List(Of FileInfo)
Return Info.EnumerateFiles("*", SearchOption.AllDirectories)
End Function
@@ -1405,13 +1401,15 @@ RetryDir:
''' <summary>
''' 若路径长度大于指定值,则将长路径转换为短路径。
''' </summary>
Public Function ShortenPath(LongPath As String, Optional ShortenThreshold As Integer = 247) As String
If LongPath.Length <= ShortenThreshold Then Return LongPath
Public Function ShortenPath(LongPath As String) As String
If LongPath.Length <= 200 OrElse LongPath.StartsWithF("http", True) Then Return LongPath
If Not Directory.Exists(LongPath) AndAlso Not File.Exists(LongPath) Then Return LongPath
Dim ShortPath As New StringBuilder(260)
GetShortPathName(LongPath, ShortPath, 260)
Return ShortPath.ToString
ShortenPath = ShortPath.ToString
If String.IsNullOrEmpty(ShortenPath) Then Return LongPath
End Function
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (ByVal lpszLongPath As String, ByVal lpszShortPath As StringBuilder, ByVal cchBuffer As Integer) As Integer
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (lpszLongPath As String, lpszShortPath As StringBuilder, cchBuffer As Integer) As Integer
#End Region
@@ -1420,10 +1418,10 @@ RetryDir:
Public vbRQ As Char = Convert.ToChar(8221)
''' <summary>
''' 提取 Exception 的具体描述与堆栈。
''' 提取 Exception 与 Inner Exception 的详细描述与堆栈信息。返回内容总是多于一行。
''' </summary>
''' <param name="ShowAllStacks">是否必须显示所有堆栈。通常用于判定堆栈信息。</param>
Public Function GetExceptionDetail(Ex As Exception, Optional ShowAllStacks As Boolean = False) As String
<Extension> Public Function GetDetail(Ex As Exception, Optional ShowAllStacks As Boolean = False) As String
If Ex Is Nothing Then Return "无可用错误信息!"
'获取最底层的异常
@@ -1449,32 +1447,18 @@ RetryDir:
IsInner = True
Loop
'常见错误(记得同时修改下面的)
Dim CommonReason As String = Nothing
If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is BadImageFormatException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then
CommonReason = "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。"
ElseIf TypeOf InnerEx Is UnauthorizedAccessException Then
CommonReason = "PCL 的权限不足。请尝试右键 PCL,选择以管理员身份运行。"
ElseIf TypeOf InnerEx Is OutOfMemoryException Then
CommonReason = "你的电脑运行内存不足,导致 PCL 无法继续运行。请在关闭一部分不需要的程序后再试。"
ElseIf TypeOf InnerEx Is Runtime.InteropServices.COMException Then
CommonReason = "由于操作系统或显卡存在问题,导致出现错误。请尝试重启 PCL。"
ElseIf {"远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝",
"操作已超时", "操作超时", "服务器超时", "连接超时"}.Any(Function(s) DescList.Any(Function(l) l.Contains(s))) Then
CommonReason = "你的网络环境不佳,导致难以连接到服务器。请稍后重试,或使用 VPN 以改善网络环境。"
End If
'构造输出信息
If CommonReason Is Nothing Then
Dim UsualReason As String = AnalyzeUsualReason(InnerEx, Ex, DescList)
If UsualReason Is Nothing Then
Return DescList.Join(vbCrLf)
Else
Return CommonReason & vbCrLf & vbCrLf & "————————————" & vbCrLf & "详细错误信息:" & vbCrLf & DescList.Join(vbCrLf)
Return UsualReason & vbCrLf & vbCrLf & "————————————" & vbCrLf & "详细错误信息:" & vbCrLf & DescList.Join(vbCrLf)
End If
End Function
''' <summary>
''' 提取 Exception 描述,汇总到一行。
''' 提取 Exception 与 Inner Exception 的描述,汇总到一行。
''' </summary>
Public Function GetExceptionSummary(Ex As Exception) As String
<Extension> Public Function GetBrief(Ex As Exception) As String
If Ex Is Nothing Then Return "无可用错误信息!"
'获取最底层的异常
@@ -1492,29 +1476,32 @@ RetryDir:
DescList = DescList.Distinct.ToList
Dim Desc As String = Join(DescList, vbCrLf & "→ ")
'常见错误(记得同时修改上面的)
Dim CommonReason As String = Nothing
If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is BadImageFormatException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then
CommonReason = "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。"
ElseIf TypeOf InnerEx Is UnauthorizedAccessException Then
CommonReason = "PCL 的权限不足。请尝试右键 PCL,选择以管理员身份运行。"
ElseIf TypeOf InnerEx Is OutOfMemoryException Then
CommonReason = "你的电脑运行内存不足,导致 PCL 无法继续运行。请在关闭一部分不需要的程序后再试。"
ElseIf TypeOf InnerEx Is Runtime.InteropServices.COMException Then
CommonReason = "由于操作系统或显卡存在问题,导致出现错误。请尝试重启 PCL。"
ElseIf {"远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝",
"操作已超时", "操作超时", "服务器超时", "连接超时"}.Any(Function(s) Desc.Contains(s)) Then
CommonReason = "你的网络环境不佳,导致难以连接到服务器。请稍后重试,或使用 VPN 以改善网络环境。"
End If
'构造输出信息
If CommonReason IsNot Nothing Then
Return CommonReason & "详细错误:" & DescList.First
Dim UsualReason As String = AnalyzeUsualReason(InnerEx, Ex, DescList)
If UsualReason IsNot Nothing Then
Return UsualReason & "详细错误:" & DescList.First
Else
DescList.Reverse() '让最深层错误在最左边
Return Join(DescList, " ← ")
End If
End Function
Private Function AnalyzeUsualReason(InnerEx As Exception, OuterEx As Exception, DescList As List(Of String)) As String
If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is BadImageFormatException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then
Return "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。"
ElseIf TypeOf InnerEx Is UnauthorizedAccessException Then
Return "PCL 的权限不足。请尝试右键 PCL 选择以管理员身份运行。"
ElseIf TypeOf InnerEx Is OutOfMemoryException Then
Return "你的电脑运行内存不足,导致 PCL 无法继续运行。请在关闭一部分不需要的程序后再试。"
ElseIf TypeOf InnerEx Is Runtime.InteropServices.COMException Then
Return "由于操作系统或显卡存在问题,导致出现错误。请尝试重启 PCL。"
ElseIf TypeOf InnerEx Is SocketException AndAlso DescList.Any(Function(l) l.Contains("WSAStartup")) Then
Return "请尝试卸载中国移动云盘,然后再试。"
ElseIf OuterEx.IsNetworkRelated() Then
Return "你的网络环境不佳,请稍后再试,或使用 VPN 改善网络环境。"
Else
Return Nothing
End If
End Function
''' <summary>
''' 返回一个枚举对应的字符串。
@@ -1556,7 +1543,7 @@ RetryDir:
Return JsonConvert.DeserializeObject(Data, New JsonSerializerSettings With {.DateTimeZoneHandling = DateTimeZoneHandling.Local})
Catch ex As Exception
Dim Length As Integer = If(Data, "").Length
Throw New Exception("格式化 JSON 失败:" & If(Length > 2000, Data.Substring(0, 500) & $"...(全长 {Length} 个字符)..." & Right(Data, 500), Data))
Throw New Exception("格式化 JSON 失败:" & If(Length > 2000, Data.Substring(0, 500) & $"...(全长 {Length} 个字符)..." & Right(Data, 500), Data), ex)
End Try
End Function
@@ -2029,8 +2016,8 @@ RetryDir:
'构造函数
Public Sub New()
End Sub
Public Sub New(data As IEnumerable(Of KeyValuePair(Of TKey, TValue)))
For Each DataItem In data
Public Sub New(Data As IEnumerable(Of KeyValuePair(Of TKey, TValue)))
For Each DataItem In Data
_Dictionary.Add(DataItem.Key, DataItem.Value)
Next
End Sub
@@ -2186,7 +2173,7 @@ RetryDir:
''' 返回程序的返回代码,如果运行失败将抛出异常。
''' </summary>
Public Function RunAsAdmin(Argument As String) As Integer
Dim NewProcess = Process.Start(New ProcessStartInfo(PathWithName) With {.Verb = "runas", .Arguments = Argument})
Dim NewProcess = StartProcess(New ProcessStartInfo(PathWithName) With {.Verb = "runas", .Arguments = Argument})
NewProcess.WaitForExit()
Return NewProcess.ExitCode
End Function
@@ -2345,46 +2332,21 @@ NextElement:
End Class
''' <summary>
''' 前台运行文件。
''' 启动进程并返回进程实例,若失败则抛出异常。
''' 会自动进行长路径处理。
''' </summary>
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
''' <param name="Arguments">运行参数。</param>
Public Sub ShellOnly(FileName As String, Optional Arguments As String = "")
Try
FileName = ShortenPath(FileName)
Using Program As New Process
Program.StartInfo.Arguments = Arguments
Program.StartInfo.FileName = FileName
Log("[System] 执行外部命令:" & FileName & " " & Arguments)
Program.Start()
End Using
Catch ex As Exception
Log(ex, "打开文件或程序失败:" & FileName, LogLevel.Msgbox)
End Try
End Sub
Public Function StartProcess(FileName As String, Optional Arguments As String = "") As Process
Return StartProcess(New ProcessStartInfo With {.FileName = FileName, .Arguments = Arguments})
End Function
''' <summary>
''' 前台运行文件并返回返回值。
''' 启动进程并返回进程实例,若失败则抛出异常。
''' 会自动进行长路径处理。
''' </summary>
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
''' <param name="Arguments">运行参数。</param>
''' <param name="Timeout">等待该程序结束的最长时间(毫秒)。超时会返回 Result.Timeout。</param>
Public Function ShellAndGetExitCode(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000) As ProcessReturnValues
Try
Using Program As New Process
Program.StartInfo.Arguments = Arguments
Program.StartInfo.FileName = FileName
Log("[System] 执行外部命令并等待返回码:" & FileName & " " & Arguments)
Program.Start()
If Program.WaitForExit(Timeout) Then
Return Program.ExitCode
Else
Return ProcessReturnValues.Timeout
End If
End Using
Catch ex As Exception
Log(ex, "执行命令失败:" & FileName, LogLevel.Msgbox)
Return ProcessReturnValues.Fail
End Try
Public Function StartProcess(StartInfo As ProcessStartInfo) As Process
StartInfo.FileName = ShortenPath(StartInfo.FileName)
If Not String.IsNullOrEmpty(StartInfo.WorkingDirectory) Then StartInfo.WorkingDirectory = ShortenPath(StartInfo.WorkingDirectory)
Log("[System] 启动进程:" & StartInfo.FileName & " " & StartInfo.Arguments)
Return Process.Start(StartInfo)
End Function
''' <summary>
''' 静默运行文件并返回输出流字符串。执行失败会抛出异常。
@@ -2392,10 +2354,11 @@ NextElement:
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
''' <param name="Arguments">运行参数。</param>
''' <param name="Timeout">等待该程序结束的最长时间(毫秒)。超时会抛出错误。</param>
Public Function ShellAndGetOutput(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000, Optional WorkingDirectory As String = Nothing) As String
Public Function StartProcessAndGetOutput(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000,
Optional WorkingDirectory As String = Nothing) As String
Dim Info = New ProcessStartInfo With {
.Arguments = Arguments,
.FileName = FileName,
.FileName = ShortenPath(FileName),
.UseShellExecute = False,
.CreateNoWindow = True,
.RedirectStandardError = True,
@@ -2410,7 +2373,7 @@ NextElement:
End If
End If
Log("[System] 执行外部命令并等待返回结果:" & FileName & " " & Arguments)
Using Program As New Process() With {.StartInfo = Info}
Using Program As New Process With {.StartInfo = Info}
Program.Start()
Dim Result As String = Program.StandardOutput.ReadToEnd & Program.StandardError.ReadToEnd
Program.WaitForExit(Timeout)
@@ -2512,17 +2475,14 @@ NextElement:
''' <summary>
''' 尝试从字典中获取某项,如果该项不存在,则返回默认值。
''' </summary>
<Extension> Public Function GetOrDefault(Of TKey, TValue)(Dict As Dictionary(Of TKey, TValue), Key As TKey, Optional DefaultValue As TValue = Nothing) As TValue
If Dict.ContainsKey(Key) Then
Return Dict(Key)
Else
Return DefaultValue
End If
<Extension> Public Function GetOrDefault(Of TKey, TValue)(Dict As IDictionary(Of TKey, TValue), Key As TKey, Optional DefaultValue As TValue = Nothing) As TValue
Dim Result As TValue
Return If(Dict.TryGetValue(Key, Result), Result, DefaultValue)
End Function
''' <summary>
''' 将某项添加到以列表作为值的字典中。
''' </summary>
<Extension> Public Sub AddToList(Of TKey, TValue)(Dict As Dictionary(Of TKey, List(Of TValue)), Key As TKey, Value As TValue)
<Extension> Public Sub AddToList(Of TKey, TValue)(Dict As IDictionary(Of TKey, List(Of TValue)), Key As TKey, Value As TValue)
If Dict.ContainsKey(Key) Then
Dict(Key).Add(Value)
Else
@@ -2570,7 +2530,7 @@ NextElement:
Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!")
End If
Log("[System] 正在打开网页:" & Url)
Process.Start(Url)
StartProcess(Url)
Catch ex As Exception
Log(ex, "无法打开网页(" & Url & ")")
ClipboardSet(Url, False)
@@ -2584,12 +2544,12 @@ NextElement:
''' </summary>
Public Sub OpenExplorer(Location As String)
Try
Location = ShortenPath(Location.Replace("/", "\").Trim(" "c, """"c))
Location = Location.Replace("/", "\").Trim(" "c, """"c)
Log("[System] 正在打开资源管理器:" & Location)
If Location.EndsWith("\") Then
ShellOnly(Location)
StartProcess(Location)
Else
ShellOnly("explorer", $"/select,""{Location}""")
StartProcess("explorer", $"/select,""{Location}""")
End If
Catch ex As Exception
Log(ex, "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", LogLevel.Msgbox)
@@ -2641,10 +2601,6 @@ Retry:
''' 相对增减控件的左边距。
''' </summary>
Public Sub DeltaLeft(control As FrameworkElement, newValue As Double)
'安全性检查
DebugAssert(Not Double.IsNaN(newValue))
DebugAssert(Not Double.IsInfinity(newValue))
If TypeOf control Is Window Then
'窗口改变
CType(control, Window).Left += newValue
@@ -2656,8 +2612,6 @@ Retry:
Case HorizontalAlignment.Right
control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, control.Margin.Right - newValue, control.Margin.Bottom)
'control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, CType(control.Parent, Object).ActualWidth - control.ActualWidth - newValue, control.Margin.Bottom)
Case Else
DebugAssert(False)
End Select
End If
End Sub
@@ -2665,17 +2619,12 @@ Retry:
''' 设置控件的左边距。(仅针对置左控件)
''' </summary>
Public Sub SetLeft(control As FrameworkElement, newValue As Double)
DebugAssert(control.HorizontalAlignment = HorizontalAlignment.Left)
control.Margin = New Thickness(newValue, control.Margin.Top, control.Margin.Right, control.Margin.Bottom)
End Sub
''' <summary>
''' 相对增减控件的上边距。
''' </summary>
Public Sub DeltaTop(control As FrameworkElement, newValue As Double)
'安全性检查
DebugAssert(Not Double.IsNaN(newValue))
DebugAssert(Not Double.IsInfinity(newValue))
If TypeOf control Is Window Then
'窗口改变
CType(control, Window).Top += newValue
@@ -2687,11 +2636,8 @@ Retry:
Case VerticalAlignment.Bottom
control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, control.Margin.Right, control.Margin.Bottom - newValue)
'control.Margin = New Thickness(control.Margin.Left, control.Margin.Top, CType(control.Parent, Object).ActualWidth - control.ActualWidth - newValue, control.Margin.Bottom)
Case Else
DebugAssert(False)
End Select
End If
'If Double.IsNaN(newValue) OrElse Double.IsInfinity(newValue) Then Return '安全性检查
'Select Case control.VerticalAlignment
' Case VerticalAlignment.Top, VerticalAlignment.Stretch, VerticalAlignment.Center
@@ -2705,7 +2651,6 @@ Retry:
''' 设置控件的顶边距。(仅针对置上控件)
''' </summary>
Public Sub SetTop(control As FrameworkElement, newValue As Double)
DebugAssert(control.VerticalAlignment = VerticalAlignment.Top)
control.Margin = New Thickness(control.Margin.Left, newValue, control.Margin.Right, control.Margin.Bottom)
End Sub
@@ -2989,6 +2934,13 @@ Retry:
End If
End Select
'上报
If Level >= LogLevel.Hint Then
Telemetry("PCL 错误",
"Level", GetStringFromEnum(Level),
"Title", FilterUserName(FilterAccessToken(Title, "*"), "*"),
"Exception", FilterUserName(FilterAccessToken(Text, "*"), "*"))
End If
End Sub
''' <summary>
''' 输出错误信息。
@@ -2999,10 +2951,10 @@ Retry:
If TypeOf Ex Is ThreadInterruptedException Then Return
'获取错误信息
Dim ExFull As String = Desc & ":" & GetExceptionDetail(Ex)
Dim ExFull As String = $"{Desc}:{Ex.GetDetail()}"
'输出日志
Dim AppendText As String = $"[{GetTimeNow()}] <{If(Thread.CurrentThread.Name = "", "主线程", Thread.CurrentThread.Name)}> {Desc}:{GetExceptionDetail(Ex, True)}{vbCrLf}" '减轻同步锁占用
Dim AppendText As String = $"[{GetTimeNow()}] <{If(Thread.CurrentThread.Name = "", "主线程", Thread.CurrentThread.Name)}> {Desc}:{Ex.GetDetail(True)}{vbCrLf}" '减轻同步锁占用
If ModeDebug Then
SyncLock LogListLock
LogList.Append(AppendText)
@@ -3020,19 +2972,19 @@ Retry:
Case LogLevel.Normal
#If DEBUG Then
Case LogLevel.Developer
Dim ExLine As String = Desc & ":" & GetExceptionSummary(Ex)
Dim ExLine As String = Desc & ":" & Ex.GetBrief()
Hint("[开发者模式] " & ExLine, HintType.Info, False)
Case LogLevel.Debug
Dim ExLine As String = Desc & ":" & GetExceptionSummary(Ex)
Dim ExLine As String = Desc & ":" & Ex.GetBrief()
Hint("[调试模式] " & ExLine, HintType.Info, False)
#Else
Case LogLevel.Developer
Case LogLevel.Debug
Dim ExLine As String = Desc & ":" & GetExceptionSummary(Ex)
Dim ExLine As String = Desc & ":" & Ex.GetBrief()
If ModeDebug Then Hint("[调试模式] " & ExLine, HintType.Info, False)
#End If
Case LogLevel.Hint
Dim ExLine As String = Desc & ":" & GetExceptionSummary(Ex)
Dim ExLine As String = Desc & ":" & Ex.GetBrief()
Hint(ExLine, HintType.Critical, False)
Case LogLevel.Msgbox
MyMsgBox(ExFull, Title, IsWarn:=True)
@@ -3055,6 +3007,13 @@ Retry:
End If
End Select
'上报
If Level >= LogLevel.Hint Then
Telemetry("PCL 异常",
"Level", GetStringFromEnum(Level),
"Title", FilterUserName(FilterAccessToken(Title, "*"), "*"),
"Exception", FilterUserName(FilterAccessToken(ExFull, "*"), "*"))
End If
End Sub
'反馈
@@ -3091,9 +3050,23 @@ Retry:
"文件位置:" & Path)
End Sub
'断言
Public Sub DebugAssert(Exp As Boolean)
If Not Exp Then Throw New Exception("断言命中")
'遥测
Public Sub Telemetry([Event] As String, ParamArray Datas As String())
If Not Setup.Get("SystemSystemTelemetry") Then Return '用户关闭了遥测
If Not ClsBaseUrl.StartsWithF("http") Then Return '开源版没有设置遥测地址
RunInNewThread(
Sub()
Try
Log($"[System] 匿名数据上报:{[Event]}")
Dim Url As String = $"{ClsBaseUrl}&Event={WebUtility.UrlEncode([Event])}"
For i = 0 To Datas.Length - 1 Step 2
Url &= "&" & WebUtility.UrlEncode(Datas(i)) & "=" & WebUtility.UrlEncode(Datas(i + 1).Replace(vbCrLf, vbLf))
Next
NetRequestByClient(Url, MakeLog:=False)
Catch ex As Exception
Log(ex, "匿名数据上报失败")
End Try
End Sub, "Telemetry", ThreadPriority.Lowest)
End Sub
'获取当前的堆栈信息
@@ -290,11 +290,12 @@
'检验输入以确定情况
If IsForceRestart Then Return True '强制要求重启
If ((Input Is Nothing) <> (Me.Input Is Nothing)) OrElse (Input IsNot Nothing AndAlso Not Input.Equals(Me.Input)) Then Return True '输入不同
If (State = LoadState.Loading OrElse State = LoadState.Finished) AndAlso '正在加载或已结束
(IgnoreReloadTimeout OrElse ReloadTimeout = -1 OrElse LastFinishedTime = 0 OrElse GetTimeTick() - LastFinishedTime < ReloadTimeout) Then '没有超时
Return False '则不重试
If (State = LoadState.Loading OrElse State = LoadState.Finished) AndAlso '正在加载或已结束…
(IgnoreReloadTimeout OrElse ReloadTimeout = -1 OrElse
LastFinishedTime = 0 OrElse GetTimeTick() - LastFinishedTime < ReloadTimeout) Then '…且没有超时…
Return False '…则不重试
Else
Return True '需要开始
Return True '否则需要重启
End If
End Function
Public Overrides Sub Start(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = False)
+375 -231
View File
@@ -1,6 +1,7 @@
Imports System.Net.Http.Headers
Imports System.Net.Sockets
Imports System.Runtime.CompilerServices
Imports System.Threading.Tasks
Imports CacheCow.Client
Public Module ModNet
@@ -11,19 +12,29 @@ Public Module ModNet
''' </summary>
Public Function NetRequestByClient(Url As String, Optional Method As HttpMethod = Nothing,
Optional Content As Object = Nothing, Optional ContentType As String = Nothing, Optional Accept As String = "*/*",
Optional Timeout As Integer = 25000, Optional Headers As String(,) = Nothing,
Optional Encoding As Encoding = Nothing, Optional UseBrowserUserAgent As Boolean = False, Optional MakeLog As Boolean = True) As String
Optional Timeout As Integer = 25000, Optional Headers As String(,) = Nothing, Optional RequireJson As Boolean = False,
Optional Encoding As Encoding = Nothing, Optional SimulateBrowserHeaders As Boolean = False, Optional MakeLog As Boolean = True) As String
If Method Is Nothing Then Method = HttpMethod.Get
If MakeLog Then Log("[Net] 发起网络请求(" & Method.Method & "," & Url & "),最大超时 " & Timeout)
Try
Dim HeaderDictionary = If(Headers, {}).ToDictionary
If ContentType IsNot Nothing Then HeaderDictionary("Content-Type") = ContentType
If Accept IsNot Nothing Then HeaderDictionary("Accept") = Accept
Return If(Encoding, Encoding.UTF8).GetString(SendRequest(Url, Method, Content, HeaderDictionary, Timeout:=Timeout, Encoding:=Encoding, UseBrowserUserAgent:=UseBrowserUserAgent))
Catch ex As ThreadInterruptedException
Dim Result = If(Encoding, Encoding.UTF8).GetString(SendRequest(Url, Method, Content, HeaderDictionary, Timeout:=Timeout, Encoding:=Encoding, SimulateBrowserHeaders:=SimulateBrowserHeaders))
'检查结果是否为完整 JSON(在 #6683 中可能返回空,在被 GFW 截断时可能不完整)
'在此处检查并报错,可以让 NetRequestByClientRetry 等方法进行重试
If RequireJson Then
Result = Result.Trim((vbCrLf & " ").ToCharArray) 'Authlib-Injector 的结果会在末尾附带一个空行
If Not (Result.StartsWithF("{") AndAlso Result.EndsWithF("}")) AndAlso
Not (Result.StartsWithF("[") AndAlso Result.EndsWithF("]")) Then
Throw New FormatException("返回结果并非 JSON 格式:" &
If(Result.Length > 2000, Result.Substring(0, 1000) & "..." & Result.Substring(Result.Length - 1000), Result))
End If
End If
Return Result
Catch ex As FormatException
Throw
Catch ex As ResponsedWebException
If MakeLog Then Log(ex, "网络请求失败,返回内容为:" & vbCrLf & ex.Response, LogLevel.Developer)
Catch ex As ThreadInterruptedException
Throw
Catch ex As Exception
If MakeLog Then Log(ex, "网络请求失败", LogLevel.Developer)
@@ -37,8 +48,8 @@ Public Module ModNet
''' <param name="BackupUrl">如果第一次尝试失败,换用的备用 URL。</param>
Public Function NetRequestByClientRetry(Url As String, Optional Method As HttpMethod = Nothing, Optional BackupUrl As String = Nothing,
Optional Content As Object = Nothing, Optional ContentType As String = Nothing, Optional Accept As String = "*/*",
Optional Headers As String(,) = Nothing,
Optional Encoding As Encoding = Nothing, Optional UseBrowserUserAgent As Boolean = False) As String
Optional Headers As String(,) = Nothing, Optional RequireJson As Boolean = False,
Optional Encoding As Encoding = Nothing, Optional SimulateBrowserHeaders As Boolean = False) As String
Dim RetryCount As Integer = 0
Dim RetryException As Exception = Nothing
Dim StartTime As Long = GetTimeTick()
@@ -46,15 +57,15 @@ Public Module ModNet
Retry:
Select Case RetryCount
Case 0 '正常尝试
Return NetRequestByClient(Url, Method, Content, ContentType, Accept, 10000, Headers, Encoding, UseBrowserUserAgent)
Return NetRequestByClient(Url, Method, Content, ContentType, Accept, 10000, Headers, RequireJson, Encoding, SimulateBrowserHeaders)
Case 1 '慢速重试
Thread.Sleep(500)
Return NetRequestByClient(Url, Method, Content, ContentType, Accept, 30000, Headers, Encoding, UseBrowserUserAgent)
Return NetRequestByClient(Url, Method, Content, ContentType, Accept, 30000, Headers, RequireJson, Encoding, SimulateBrowserHeaders)
Case Else '快速重试
If GetTimeTick() - StartTime > 5500 Then
'若前两次加载耗费 5 秒以上,才进行重试
Thread.Sleep(500)
Return NetRequestByClient(Url, Method, Content, ContentType, Accept, 4000, Headers, Encoding, UseBrowserUserAgent)
Return NetRequestByClient(Url, Method, Content, ContentType, Accept, 4000, Headers, RequireJson, Encoding, SimulateBrowserHeaders)
Else
Throw RetryException
End If
@@ -62,6 +73,11 @@ Retry:
Catch ex As ThreadInterruptedException
Throw
Catch ex As Exception
If TypeOf ex Is ResponsedWebException Then
If CType(ex, ResponsedWebException).StatusCode = HttpStatusCode.Forbidden Then Throw
If CType(ex, ResponsedWebException).StatusCode = 429 Then Thread.Sleep(10000) 'Too Many Requests
End If
'重试
Select Case RetryCount
Case 0
RetryException = ex
@@ -81,8 +97,8 @@ Retry:
''' </summary>
Public Function NetRequestByClientMultiple(Url As String, Optional Method As HttpMethod = Nothing, Optional ThreadCount As Integer = 3,
Optional Content As Object = Nothing, Optional ContentType As String = Nothing, Optional Accept As String = "*/*",
Optional Headers As String(,) = Nothing, Optional Timeout As Integer = 25000,
Optional Encoding As Encoding = Nothing, Optional UseBrowserUserAgent As Boolean = False) As String
Optional Headers As String(,) = Nothing, Optional RequireJson As Boolean = False, Optional Timeout As Integer = 25000,
Optional Encoding As Encoding = Nothing, Optional SimulateBrowserHeaders As Boolean = False) As String
Dim Threads As New List(Of Thread)
Dim RequestResult = Nothing
Dim RequestEx As Exception = Nothing
@@ -91,7 +107,7 @@ Retry:
Dim th As New Thread(
Sub()
Try
RequestResult = NetRequestByClient(Url, Method, Content, ContentType, Accept, Timeout, Headers, Encoding, UseBrowserUserAgent)
RequestResult = NetRequestByClient(Url, Method, Content, ContentType, Accept, Timeout, Headers, RequireJson, Encoding, SimulateBrowserHeaders)
Catch ex As Exception
FailCount += 1
RequestEx = ex
@@ -130,16 +146,16 @@ RequestFinished:
''' 以多线程下载网页文件的方式获取内容。
''' 不支持缓存协商;若需缓存协商,需要换用 NetRequestByClient。
''' </summary>
Public Function NetRequestByLoader(Url As String, Optional Timeout As Integer = 45000, Optional IsJson As Boolean = False, Optional UseBrowserUserAgent As Boolean = False) As String
Return NetRequestByLoader({Url}, Timeout, IsJson, UseBrowserUserAgent)
Public Function NetRequestByLoader(Url As String, Optional Timeout As Integer = 45000, Optional IsJson As Boolean = False, Optional SimulateBrowserHeaders As Boolean = False) As String
Return NetRequestByLoader({Url}, Timeout, IsJson, SimulateBrowserHeaders)
End Function
''' <summary>
''' 以多线程下载网页文件的方式获取内容。
''' 不支持缓存协商;若需缓存协商,需要换用 NetRequestByClient。
''' </summary>
Public Function NetRequestByLoader(Urls As IEnumerable(Of String), Optional Timeout As Integer = 45000, Optional IsJson As Boolean = False, Optional UseBrowserUserAgent As Boolean = False) As String
Public Function NetRequestByLoader(Urls As IEnumerable(Of String), Optional Timeout As Integer = 45000, Optional IsJson As Boolean = False, Optional SimulateBrowserHeaders As Boolean = False) As String
Dim Temp As String = RequestTaskTempFolder() & "download.txt"
Dim NewTask As New LoaderDownload("源码获取 " & GetUuid() & "#", New List(Of NetFile) From {New NetFile(Urls, Temp, New FileChecker With {.IsJson = IsJson}, UseBrowserUserAgent)})
Dim NewTask As New LoaderDownload("源码获取 " & GetUuid() & "#", New List(Of NetFile) From {New NetFile(Urls, Temp, New FileChecker With {.IsJson = IsJson}, SimulateBrowserHeaders)})
Try
NewTask.WaitForExitTime(Timeout, TimeoutMessage:="连接服务器超时(第一下载源:" & Urls.First & ")")
NetRequestByLoader = ReadFile(Temp)
@@ -157,7 +173,7 @@ RequestFinished:
''' 通过网络请求直接下载小文件,若文件已存在将被覆盖。
''' 不建议用于下载大文件。
''' </summary>
Public Sub NetDownloadByClient(Url As String, LocalPath As String)
Public Sub NetDownloadByClient(Url As String, LocalPath As String, Optional SimulateBrowserHeaders As Boolean = False)
Log($"[Net] 通过网络请求直接下载小文件:{Url} → {LocalPath}")
'初始化文件路径
Try
@@ -168,7 +184,7 @@ RequestFinished:
End Try
'下载
Try
File.WriteAllBytes(LocalPath, SendRequest(Url, HttpMethod.Get))
File.WriteAllBytes(LocalPath, SendRequest(Url, HttpMethod.Get, SimulateBrowserHeaders:=SimulateBrowserHeaders))
Catch ex As Exception
File.Delete(LocalPath)
Throw New WebException($"通过网络请求直接下载小文件失败({LocalPath})", ex)
@@ -178,16 +194,16 @@ RequestFinished:
''' <summary>
''' 通过多线程下载引擎下载文件。
''' </summary>
Public Sub NetDownloadByLoader(Url As String, LocalPath As String, Optional LoaderToSyncProgress As LoaderBase = Nothing, Optional Check As FileChecker = Nothing, Optional UseBrowserUserAgent As Boolean = False)
NetDownloadByLoader({Url}, LocalPath, LoaderToSyncProgress, Check, UseBrowserUserAgent)
Public Sub NetDownloadByLoader(Url As String, LocalPath As String, Optional LoaderToSyncProgress As LoaderBase = Nothing, Optional Check As FileChecker = Nothing, Optional SimulateBrowserHeaders As Boolean = False)
NetDownloadByLoader({Url}, LocalPath, LoaderToSyncProgress, Check, SimulateBrowserHeaders)
End Sub
''' <summary>
''' 通过多线程下载引擎下载文件。
''' </summary>
''' <param name="Urls">文件的 Url 列表。</param>
''' <param name="LocalPath">下载的本地地址。</param>
Public Sub NetDownloadByLoader(Urls As IEnumerable(Of String), LocalPath As String, Optional LoaderToSyncProgress As LoaderBase = Nothing, Optional Check As FileChecker = Nothing, Optional UseBrowserUserAgent As Boolean = False)
Dim NewTask As New LoaderDownload($"文件下载 {GetUuid()}#", New List(Of NetFile) From {New NetFile(Urls, LocalPath, Check, UseBrowserUserAgent)})
Public Sub NetDownloadByLoader(Urls As IEnumerable(Of String), LocalPath As String, Optional LoaderToSyncProgress As LoaderBase = Nothing, Optional Check As FileChecker = Nothing, Optional SimulateBrowserHeaders As Boolean = False)
Dim NewTask As New LoaderDownload($"文件下载 {GetUuid()}#", New List(Of NetFile) From {New NetFile(Urls, LocalPath, Check, SimulateBrowserHeaders)})
Try
NewTask.WaitForExit(LoaderToSyncProgress:=LoaderToSyncProgress)
Catch ex As Exception
@@ -204,36 +220,49 @@ RequestFinished:
'基础请求函数
Private Function SendRequest(Url As String, Method As HttpMethod,
Optional Content As Object = Nothing, Optional Headers As Dictionary(Of String, String) = Nothing,
Optional UseBrowserUserAgent As Boolean = False, Optional Timeout As Integer = 25000, Optional Encoding As Encoding = Nothing) As Byte()
Optional SimulateBrowserHeaders As Boolean = False, Optional Timeout As Integer = 25000, Optional Encoding As Encoding = Nothing) As Byte()
If RunInUi() AndAlso Not Url.Contains("//127.") Then Throw New Exception("在 UI 线程执行了网络请求")
Dim Request As HttpRequestMessage = Nothing, CancelToken As CancellationTokenSource = Nothing, Response As HttpResponseMessage = Nothing
Dim Request As HttpRequestMessage = Nothing, CancelToken As CancellationTokenSource = Nothing,
Response As HttpResponseMessage = Nothing, HostIp As String = Nothing
Try
Static Client As HttpClient = ClientExtensions.CreateClient(New FileCacheStore.FileStore(PathTemp & "Cache/Http/"), New HttpClientHandler With {
.AutomaticDecompression = DecompressionMethods.Deflate Or DecompressionMethods.GZip Or DecompressionMethods.None,
.UseCookies = False '不设为 False 就不能从 Header 手动传入 Cookies
})
Url = SecretCdnSign(Url)
Request = New HttpRequestMessage(Method, Url)
'写入 Content
If Content IsNot Nothing AndAlso Request.Method <> HttpMethod.Get AndAlso Request.Method <> HttpMethod.Head Then
Dim Bytes As Byte() = If(TypeOf Content Is Byte(), Content, If(Encoding, Encoding.UTF8).GetBytes(Content.ToString))
Request.Content = New ByteArrayContent(Bytes)
Request.Content.Headers.ContentLength = Bytes.Length
If TypeOf Content Is HttpContent Then
Request.Content = DirectCast(Content, HttpContent)
ElseIf TypeOf Content Is Byte() Then
Request.Content = New ByteArrayContent(DirectCast(Content, Byte()))
ElseIf Content IsNot Nothing Then
Request.Content = New ByteArrayContent(If(Encoding, Encoding.UTF8).GetBytes(Content.ToString()))
End If
End If
'写入 Headers
If Headers IsNot Nothing Then
For Each Header In Headers
If Header.Key.ToLower = "content-type" Then
Request.Content?.Headers.TryAddWithoutValidation(Header.Key, Header.Value)
Else
Request.Headers.Add(Header.Key, Header.Value)
End If
Next
End If
SecretHeadersSign(Url, Request, UseBrowserUserAgent)
'发送请求
For Each Header In If(Headers, New Dictionary(Of String, String))
If Header.Key.ToLower = "content-type" Then
Request.Content?.Headers.TryAddWithoutValidation(Header.Key, Header.Value)
Else
Request.Headers.Add(Header.Key, Header.Value)
End If
Next
SecretHeadersSign(Url, Request, SimulateBrowserHeaders)
'DNS 解析
CancelToken = New CancellationTokenSource(Timeout)
Response = Client.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetAwaiter().GetResult()
HostIp = DNSLookup(Request, CancelToken)
If HostIp IsNot Nothing AndAlso Not IPReliability.ContainsKey(HostIp) Then
IPReliability(HostIp) = -0.01 '预先降低一点,这样快速的重复请求会使用不同的 IP 以提高成功率
End If
'发送请求
SyncLock RequestClientLock
'延迟初始化,以避免在程序启动前加载 CacheCow 导致 DLL 加载失败
If RequestClient Is Nothing Then
RequestClient = CacheCow.Client.ClientExtensions.CreateClient(New CacheCow.Client.FileCacheStore.FileStore(PathTemp & "Cache/Http/"), New HttpClientHandler With {
.AutomaticDecompression = DecompressionMethods.Deflate Or DecompressionMethods.GZip Or DecompressionMethods.None,
.UseCookies = False '不设为 False 就不能从 Header 手动传入 Cookies
})
End If
End SyncLock
Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetAwaiter().GetResult()
Dim ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
Dim ResponseBytes As Byte()
Using Stream As New MemoryStream
@@ -242,33 +271,113 @@ RequestFinished:
End Using
'输出
If Response.IsSuccessStatusCode Then
RecordIPReliability(HostIp, 0.5)
Return ResponseBytes
Else
Throw New ResponsedWebException($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Method},{Url}", If(Encoding, Encoding.UTF8).GetString(ResponseBytes))
RecordIPReliability(HostIp, -0.7)
Dim ResponseMessage = If(Encoding, Encoding.UTF8).GetString(ResponseBytes)
Throw New ResponsedWebException(
$"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Method},{Url},{HostIp}" &
If(String.IsNullOrEmpty(ResponseMessage), "", vbCrLf & ResponseMessage), Response.StatusCode, ResponseMessage)
End If
Catch ex As ThreadInterruptedException
Throw
Catch ex As ResponsedWebException
Throw
Catch ex As TaskCanceledException 'CancellationTokenSource 超时
Throw New WebException($"连接服务器超时,请检查你的网络环境是否良好({Method}, {Url})", WebExceptionStatus.Timeout)
Catch ex As Exception
Throw New Exception($"网络请求出现意外异常({Method}, {Url})", ex)
RecordIPReliability(HostIp, -1)
If TypeOf ex Is OperationCanceledException Then 'CancellationToken 超时
Throw New WebException($"连接服务器超时,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout)
ElseIf ex.IsNetworkRelated Then
Throw New WebException($"网络请求失败,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout)
Else
Throw New Exception($"网络请求出现意外异常({Method}, {Url},{HostIp})", ex)
End If
Finally
Request?.Dispose()
CancelToken?.Dispose()
Response?.Dispose()
End Try
End Function
Private RequestClient As HttpClient = Nothing
Private RequestClientLock As New Object
''' <summary>
''' 进行 DNS 解析。它仅在选择的 IP 与系统默认的不一致时才对 URL 中的 Host 进行替换。
''' 返回请求时应使用的 IP;若为 IPv6,则加上了方括号。
''' 若解析失败,则返回 Nothing。
''' </summary>
Private Function DNSLookup(Request As HttpRequestMessage, CancelToken As CancellationTokenSource) As String
Dim GetIPReliability = Function(Key) IPReliability.GetOrDefault(Key.ToString, 0)
'初步 DNS 解析
Dim Host = Request.RequestUri.Host
Dim DnsTask As Task(Of IPAddress()) = Nothing
Try
DnsTask = Dns.GetHostAddressesAsync(Host)
DnsTask.Wait(CancelToken.Token)
Catch ex As Exception
Log(ex, $"DNS 解析失败({Host})")
Return Nothing
End Try
Dim Candidates As IPAddress() = DnsTask.Result.ToArray
If Not Candidates.Any Then
Log($"[Net] DNS 解析无结果({Host})")
Return Nothing
End If
'若同时存在 IPv4 和 IPv6 地址,仅选择其中一类(因为 GFW 可能只屏蔽了 IPv4 或 IPv6)
Dim IPv4Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetwork).ToArray
Dim IPv6Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetworkV6).ToArray
If IPv4Targets.Any AndAlso IPv6Targets.Any Then
Dim IPv4Reliability = IPv4Targets.Average(Function(i) GetIPReliability(i))
Dim IPv6Reliability = IPv6Targets.Average(Function(i) GetIPReliability(i))
If Host = "api.modrinth.com" Then IPv6Reliability -= 0.1 '让 Modrinth 优先使用 IPv4 地址(#6887)
Candidates = If(IPv4Reliability >= IPv6Reliability, IPv4Targets, IPv6Targets)
End If
'选择可靠度最高的 IP
Dim MaxReliability As Double = Candidates.Max(Function(i) GetIPReliability(i))
Dim Target As IPAddress = Candidates.First(Function(i) GetIPReliability(i) = MaxReliability)
Dim TargetIp As String = If(Target.AddressFamily = AddressFamily.InterNetworkV6, $"[{Target}]", Target.ToString)
If Target IsNot Candidates.First Then
'优选结果与系统默认 IP 不一致,替换域名并设置 Host 头
If ModeDebug Then Log($"[Net] DNS 解析结果:{Host} → {Target},所有可能的 IP 与可靠度:{DnsTask.Result.Select(Function(i) $"{i} → {GetIPReliability(i):0.000}").Join(";")}")
Request.Headers.Host = Host
Dim Builder As New UriBuilder(Request.RequestUri)
Builder.Host = TargetIp
Request.RequestUri = Builder.Uri
End If
Return TargetIp
End Function
''' <summary>
''' 记录每个 IP 地址的请求可靠度。
''' 通常取值 -1 ~ +0.5,越高越好。未尝试过的 IP 应视为 0。
''' </summary>
Private IPReliability As New SafeDictionary(Of String, Double)
''' <summary>
''' 根据请求结果,记录 IP 地址的可靠度。
''' </summary>
Private Sub RecordIPReliability(IP As String, Result As Double)
If IP Is Nothing Then Return
If Not IPReliability.ContainsKey(IP) Then IPReliability(IP) = 0
IPReliability(IP) = (IPReliability(IP) + Result) / 2
End Sub
''' <summary>
''' 当 HTTP 状态码不指示成功时引发的异常。
''' 附带额外属性,可用于获取远程服务器给予的回复以及 HTTP 状态码。
''' </summary>
Public Class ResponsedWebException
Inherits WebException
''' <summary>
''' HTTP 状态码。
''' </summary>
Public StatusCode As HttpStatusCode
''' <summary>
''' 远程服务器给予的回复。
''' </summary>
Public Overloads Property Response As String
Public Sub New(Message As String, Response As String)
Public Sub New(Message As String, StatusCode As HttpStatusCode, Response As String)
MyBase.New(Message)
Me.StatusCode = StatusCode
Me.Response = Response
End Sub
End Class
@@ -277,6 +386,10 @@ RequestFinished:
#Region "多线程下载引擎"
Private ThreadClient As New HttpClient(New HttpClientHandler With {
.AutomaticDecompression = DecompressionMethods.Deflate Or DecompressionMethods.GZip Or DecompressionMethods.None
})
''' <summary>
''' 最大线程数。
''' </summary>
@@ -581,12 +694,12 @@ RequestFinished:
End SyncLock
End Function
''' <summary>
''' 是否已经没有可用源了。
''' 是否存在可用源。
''' </summary>
Public Function HasAvailableSource(Optional AllowOnceSource As Boolean = True) As Boolean
SyncLock LockSource
If AllowOnceSource AndAlso SourcesOnce.Any Then Return True
If Sources.Any(Function(s) Not s.IsFailed) Then Return True
If Sources.Any(Function(s) Not s.IsFailed) Then Return True '存在多线程可用源
If AllowOnceSource AndAlso SourcesOnce.Any Then Return True '存在单线程可用源
End SyncLock
Return False
End Function
@@ -646,9 +759,9 @@ RequestFinished:
''' </summary>
Public Check As FileChecker
''' <summary>
''' 下载时是否添加浏览器 UA。
''' 是否模拟浏览器的 UserAgent 和 Referer。
''' </summary>
Public UseBrowserUserAgent As Boolean
Public SimulateBrowserHeaders As Boolean
''' <summary>
''' 上次记速时的时间。
@@ -746,7 +859,7 @@ RequestFinished:
''' 新建一个需要下载的文件。
''' </summary>
''' <param name="LocalPath">包含文件名的本地地址。</param>
Public Sub New(Urls As IEnumerable(Of String), LocalPath As String, Optional Check As FileChecker = Nothing, Optional UseBrowserUserAgent As Boolean = False)
Public Sub New(Urls As IEnumerable(Of String), LocalPath As String, Optional Check As FileChecker = Nothing, Optional SimulateBrowserHeaders As Boolean = False)
Dim Sources As New List(Of NetSource)
Dim Count As Integer = 0
Urls = Urls.Distinct.ToArray
@@ -757,7 +870,7 @@ RequestFinished:
Me.Sources = Sources
Me.LocalPath = LocalPath
Me.Check = Check
Me.UseBrowserUserAgent = UseBrowserUserAgent
Me.SimulateBrowserHeaders = SimulateBrowserHeaders
Me.LocalName = GetFileNameFromPath(LocalPath)
End Sub
@@ -768,17 +881,17 @@ RequestFinished:
Public Function TryBeginThread() As NetThread
Try
'条件检测
If NetTaskThreadCount >= NetTaskThreadLimit OrElse Not HasAvailableSource() OrElse
(IsNoSplit AndAlso Threads IsNot Nothing AndAlso Threads.State <> NetState.Error) Then Return Nothing
If State >= NetState.Merge OrElse State = NetState.WaitForCheck Then Return Nothing
SyncLock LockState
If State < NetState.Connect Then State = NetState.Connect
End SyncLock
'初始化参数
Dim StartPosition As Long, StartSource As NetSource = Nothing
Dim Th As Thread, ThreadInfo As NetThread
SyncLock LockChain
'条件检测
SyncLock LockSource
If NetTaskThreadCount >= NetTaskThreadLimit OrElse Not HasAvailableSource() OrElse
(IsNoSplit AndAlso Threads IsNot Nothing AndAlso Threads.State <> NetState.Error) Then Return Nothing
If State >= NetState.Merge OrElse State = NetState.WaitForCheck Then Return Nothing
SyncLock LockState
If State < NetState.Connect Then State = NetState.Connect
End SyncLock
'初始化参数
'获取线程起点与下载源
'不分割
If IsNoSplit Then GoTo StartSingleThreadDownload
@@ -789,6 +902,8 @@ StartSingleThreadDownload:
Reset()
State = NetState.Get
End If
End SyncLock
SyncLock LockChain
'首个开始点
If Threads Is Nothing Then
StartPosition = 0
@@ -805,9 +920,11 @@ StartSingleThreadDownload:
End If
Next
'是否禁用多线程,以及规定碎片大小
Dim TargetUrl As String = GetSource().Url
Dim Source As NetSource = GetSource()
If Source Is Nothing Then Return Nothing
Dim TargetUrl As String = Source.Url
If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("bmclapi") OrElse TargetUrl.Contains("github.com") OrElse
TargetUrl.Contains("optifine.net") OrElse TargetUrl.Contains("modrinth") Then Return Nothing
TargetUrl.Contains("optifine.net") OrElse TargetUrl.Contains("modrinth") OrElse TargetUrl.Contains("momot.rs") Then Return Nothing
'寻找最大碎片
'FUTURE: 下载引擎重做,计算下载源平均链接时间和线程下载速度,按最高时间节省来开启多线程
Dim FilePieceMax As NetThread = Threads
@@ -850,7 +967,7 @@ StartThread:
Return ThreadInfo
Catch ex As Exception
Log(ex, "尝试开始下载线程失败(" & If(LocalName, "Nothing") & ")", LogLevel.Hint)
Fail(New Exception($"尝试开始下载线程失败({LocalName})", ex))
Return Nothing
End Try
End Function
@@ -859,7 +976,9 @@ StartThread:
''' </summary>
Private Sub Thread(Th As NetThread)
If ModeDebug OrElse Th.DownloadStart = 0 Then Log($"[Download] {LocalName}:开始,起始点 {Th.DownloadStart},{Th.Source.Url}")
Dim ResultStream As Stream = Nothing
Dim ResultStream As Stream = Nothing, HttpRequest As HttpRequestMessage = Nothing,
Response As HttpResponseMessage = Nothing, ResponseStream As Stream = Nothing,
CancelToken As CancellationTokenSource = Nothing, HostIp As String = Nothing
'部分下载源真的特别慢,并且只需要一个请求,例如 Ping 为 20s,如果增长太慢,就会造成类似 2.5s 5s 7.5s 10s 12.5s... 的极大延迟
'延迟过长会导致某些特别慢的链接迟迟不被掐死
Dim Timeout As Integer = Math.Min(Math.Max(ConnectAverage, 6000) * (1 + Th.Source.FailCount), 30000)
@@ -867,144 +986,140 @@ StartThread:
Try
Dim HttpDataCount As Integer = 0
If SourcesOnce.Contains(Th.Source) AndAlso Th <> Th.Source.SingleThread Then GoTo SourceBreak
Dim HttpRequest As New HttpRequestMessage(HttpMethod.Get, Th.Source.Url)
SecretHeadersSign(Th.Source.Url, HttpRequest, UseBrowserUserAgent)
HttpRequest = New HttpRequestMessage(HttpMethod.Get, Th.Source.Url)
SecretHeadersSign(Th.Source.Url, HttpRequest, SimulateBrowserHeaders)
CancelToken = New CancellationTokenSource(Timeout)
HostIp = DNSLookup(HttpRequest, CancelToken) 'DNS 预解析
If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New RangeHeaderValue(Th.DownloadStart, Nothing)
Dim ContentLength As Long = 0
Using CancelToken As New CancellationTokenSource(Timeout)
Static Client As New HttpClient(New HttpClientHandler With {
.AutomaticDecompression = DecompressionMethods.Deflate Or DecompressionMethods.GZip Or DecompressionMethods.None
})
Using Response As HttpResponseMessage = Client.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetAwaiter().GetResult()
If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查
If State = NetState.Error Then GoTo SourceBreak '快速中断
If ModeDebug AndAlso Response.RequestMessage.RequestUri.ToString <> Th.Source.Url Then Log($"[Download] {LocalName}:重定向至 {Response.RequestMessage.RequestUri}")
'文件大小校验
ContentLength = Response.Content.Headers.ContentLength.GetValueOrDefault(-1)
If ContentLength = -1 Then
If FileSize > 1 Then
If Th.DownloadStart = 0 Then
Log($"[Download] {LocalName}:文件大小未知,但已从其他下载源获取,不作处理")
Else
Log($"[Download] {LocalName}:ContentLength 返回了 -1,无法确定是否支持分段下载,视作不支持")
GoTo NotSupportRange
End If
Else
FileSize = -1 : IsUnknownSize = True
Log($"[Download] {LocalName}:文件大小未知")
End If
ElseIf ContentLength < 0 Then
Throw New Exception("获取片大小失败,结果为 " & ContentLength & "。")
ElseIf Th.IsFirstThread Then
If Check IsNot Nothing Then
If ContentLength < Check.MinSize AndAlso Check.MinSize > 0 Then
Throw New Exception($"文件大小不足,获取结果为 {ContentLength},要求至少为 {Check.MinSize}。")
End If
If ContentLength <> Check.ActualSize AndAlso Check.ActualSize > 0 Then
Throw New Exception($"文件大小不一致,获取结果为 {ContentLength},要求必须为 {Check.ActualSize}。")
End If
End If
FileSize = ContentLength : IsUnknownSize = False
Log($"[Download] {LocalName}:文件大小 {ContentLength}({GetString(ContentLength)})")
'若文件大小大于 50 M,进行剩余磁盘空间校验
If ContentLength > 50 * 1024 * 1024 Then
For Each Drive As DriveInfo In DriveInfo.GetDrives
Dim DriveName As String = Drive.Name.First.ToString
Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ContentLength * 1.1, 0) +
If(LocalPath.StartsWithF(DriveName), ContentLength + 5 * 1024 * 1024, 0)
If Drive.TotalFreeSpace < RequiredSpace Then
Throw New Exception(DriveName & " 盘空间不足,无法进行下载。" & vbCrLf & "需要至少 " & GetString(RequiredSpace) & " 空间,但当前仅剩余 " & GetString(Drive.TotalFreeSpace) & "。" &
If(PathTemp.StartsWithF(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", ""))
End If
Next
End If
ElseIf FileSize < 0 Then
Throw New Exception("非首线程运行时,尚未获取文件大小")
ElseIf Th.DownloadStart > 0 AndAlso ContentLength = FileSize Then
NotSupportRange:
SyncLock LockSource
If SourcesOnce.Contains(Th.Source) Then
GoTo SourceBreak
Else
SourcesOnce.Add(Th.Source)
End If
End SyncLock
Throw New WebException($"该下载源不支持分段下载:Range 起始于 {Th.DownloadStart},预期 ContentLength 为 {FileSize - Th.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}")
ElseIf Not FileSize - Th.DownloadStart = ContentLength Then
Throw New WebException($"获取到的分段大小不一致:Range 起始于 {Th.DownloadStart},预期 ContentLength 为 {FileSize - Th.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}")
End If
'Log($"[Download] {LocalName} {Info.Uuid}#:通过大小检查,文件大小 {FileSize},起始点 {Info.DownloadStart},ContentLength {ContentLength}")
Th.State = NetState.Get
SyncLock LockState
If State < NetState.Get Then State = NetState.Get
End SyncLock
'创建缓存文件
If IsNoSplit Then
Th.Temp = Nothing
Cache = New MemoryStream
ResultStream = Cache
Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetAwaiter().GetResult()
If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查
If State = NetState.Error Then GoTo SourceBreak '快速中断
If ModeDebug AndAlso Response.RequestMessage.RequestUri.ToString <> Th.Source.Url Then Log($"[Download] {LocalName}:重定向至 {Response.RequestMessage.RequestUri}")
'文件大小校验
ContentLength = Response.Content.Headers.ContentLength.GetValueOrDefault(-1)
If ContentLength = -1 Then
If FileSize > 1 Then
If Th.DownloadStart = 0 Then
Log($"[Download] {LocalName}:文件大小未知,但已从其他下载源获取,不作处理")
Else
Th.Temp = $"{PathTemp}Download\{Uuid}_{Th.Uuid}_{RandomInteger(0, 999999)}.tmp"
ResultStream = New FileStream(Th.Temp, FileMode.Create, FileAccess.Write, FileShare.Read)
Log($"[Download] {LocalName}:ContentLength 返回了 -1,无法确定是否支持分段下载,视作不支持")
GoTo NotSupportRange
End If
'开始下载
Using ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
If Setup.Get("SystemDebugDelay") Then Threading.Thread.Sleep(RandomInteger(50, 3000))
Dim ResponseBytes As Byte() = New Byte(16384) {}
HttpDataCount = ResponseStream.ReadAsync(ResponseBytes, 0, 16384, CancelToken.Token).GetAwaiter().GetResult()
While (IsUnknownSize OrElse Th.DownloadUndone > 0) AndAlso '判断是否下载完成
HttpDataCount > 0 AndAlso Not IsProgramEnded AndAlso State < NetState.Merge AndAlso (Not Th.Source.IsFailed OrElse Th.Source.SingleThread = Th)
'限速
While NetTaskSpeedLimitHigh > 0 AndAlso NetTaskSpeedLimitLeft <= 0
Threading.Thread.Sleep(16)
End While
Dim RealDataCount As Integer = If(IsUnknownSize, HttpDataCount, Math.Min(HttpDataCount, Th.DownloadUndone))
SyncLock NetTaskSpeedLimitLeftLock
If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft -= RealDataCount
End SyncLock
Dim DeltaTime = GetTimeTick() - Th.LastReceiveTime
If DeltaTime > 1000000 Then DeltaTime = 1 '时间刻反转导致出现极大值
If RealDataCount > 0 Then
'有数据
If Th.DownloadDone = 0 Then
'第一次接受到数据
Th.State = NetState.Download
SyncLock LockState
If State < NetState.Download Then State = NetState.Download
End SyncLock
SyncLock LockCount
ConnectCount += 1
ConnectTime += GetTimeTick() - Th.InitTime
End SyncLock
End If
SyncLock LockCount
Th.Source.FailCount = 0
For Each Task In Tasks
Task.FailCount = 0
Next
End SyncLock
NetManager.DownloadDone += RealDataCount
SyncLock LockDone
DownloadDone += RealDataCount
End SyncLock
Th.DownloadDone += RealDataCount
ResultStream.Write(ResponseBytes, 0, RealDataCount)
'检查速度是否过慢
If DeltaTime > 1500 AndAlso DeltaTime > RealDataCount Then '数据包间隔大于 1.5s,且速度小于 1.5K/s
Throw New TimeoutException("由于速度过慢断开链接,下载 " & RealDataCount & " B,消耗 " & DeltaTime & " ms。")
End If
Th.LastReceiveTime = GetTimeTick()
'已完成
If Th.DownloadUndone = 0 AndAlso Not IsUnknownSize Then Exit While
ElseIf Th.LastReceiveTime > 0 AndAlso DeltaTime > Timeout Then
'无数据,且已超时
Throw New TimeoutException("操作超时,无数据。")
End If
HttpDataCount = ResponseStream.Read(ResponseBytes, 0, 16384)
End While
End Using
End Using
End Using
Else
FileSize = -1 : IsUnknownSize = True
Log($"[Download] {LocalName}:文件大小未知")
End If
ElseIf ContentLength < 0 Then
Throw New Exception("获取片大小失败,结果为 " & ContentLength & "。")
ElseIf Th.IsFirstThread Then
If Check IsNot Nothing Then
If ContentLength < Check.MinSize AndAlso Check.MinSize > 0 Then
Throw New Exception($"文件大小不足,获取结果为 {ContentLength},要求至少为 {Check.MinSize}。")
End If
If ContentLength <> Check.ActualSize AndAlso Check.ActualSize > 0 Then
Throw New Exception($"文件大小不一致,获取结果为 {ContentLength},要求必须为 {Check.ActualSize}。")
End If
End If
FileSize = ContentLength : IsUnknownSize = False
Log($"[Download] {LocalName}:文件大小 {ContentLength}({GetString(ContentLength)})")
'若文件大小大于 50 M,进行剩余磁盘空间校验
If ContentLength > 50 * 1024 * 1024 Then
For Each Drive As DriveInfo In DriveInfo.GetDrives
Dim DriveName As String = Drive.Name.First.ToString
Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ContentLength * 1.1, 0) +
If(LocalPath.StartsWithF(DriveName), ContentLength + 5 * 1024 * 1024, 0)
If Drive.TotalFreeSpace < RequiredSpace Then
Throw New Exception(DriveName & " 盘空间不足,无法进行下载。" & vbCrLf & "需要至少 " & GetString(RequiredSpace) & " 空间,但当前仅剩余 " & GetString(Drive.TotalFreeSpace) & "。" &
If(PathTemp.StartsWithF(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", ""))
End If
Next
End If
ElseIf FileSize < 0 Then
Throw New Exception("非首线程运行时,尚未获取文件大小")
ElseIf Th.DownloadStart > 0 AndAlso ContentLength = FileSize Then
NotSupportRange:
SyncLock LockSource
If SourcesOnce.Contains(Th.Source) Then
GoTo SourceBreak
Else
SourcesOnce.Add(Th.Source)
End If
End SyncLock
Throw New WebException($"该下载源不支持分段下载:Range 起始于 {Th.DownloadStart},预期 ContentLength 为 {FileSize - Th.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}")
ElseIf Not FileSize - Th.DownloadStart = ContentLength Then
Throw New WebException($"获取到的分段大小不一致:Range 起始于 {Th.DownloadStart},预期 ContentLength 为 {FileSize - Th.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}")
End If
'Log($"[Download] {LocalName} {Info.Uuid}#:通过大小检查,文件大小 {FileSize},起始点 {Info.DownloadStart},ContentLength {ContentLength}")
Th.State = NetState.Get
SyncLock LockState
If State < NetState.Get Then State = NetState.Get
End SyncLock
'创建缓存文件
If IsNoSplit Then
Th.Temp = Nothing
Cache = New MemoryStream
ResultStream = Cache
Else
Th.Temp = $"{PathTemp}Download\{Uuid}_{Th.Uuid}_{RandomInteger(0, 999999)}.tmp"
ResultStream = New FileStream(Th.Temp, FileMode.Create, FileAccess.Write, FileShare.Read)
End If
'开始下载
ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
If Setup.Get("SystemDebugDelay") Then Threading.Thread.Sleep(RandomInteger(50, 3000))
Dim ResponseBytes As Byte() = New Byte(16384) {}
HttpDataCount = ResponseStream.ReadAsync(ResponseBytes, 0, 16384, CancelToken.Token).GetAwaiter().GetResult()
While (IsUnknownSize OrElse Th.DownloadUndone > 0) AndAlso '判断是否下载完成
HttpDataCount > 0 AndAlso Not IsProgramEnded AndAlso State < NetState.Merge AndAlso (Not Th.Source.IsFailed OrElse Th.Source.SingleThread = Th)
'限速
While NetTaskSpeedLimitHigh > 0 AndAlso NetTaskSpeedLimitLeft <= 0
Threading.Thread.Sleep(16)
End While
Dim RealDataCount As Integer = If(IsUnknownSize, HttpDataCount, Math.Min(HttpDataCount, Th.DownloadUndone))
SyncLock NetTaskSpeedLimitLeftLock
If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft -= RealDataCount
End SyncLock
Dim DeltaTime = GetTimeTick() - Th.LastReceiveTime
If DeltaTime > 1000000 Then DeltaTime = 1 '避免时间刻反转导致出现极大值
If RealDataCount > 0 Then
'有数据
If Th.DownloadDone = 0 Then
'第一次接受到数据
Th.State = NetState.Download
SyncLock LockState
If State < NetState.Download Then State = NetState.Download
End SyncLock
SyncLock LockCount
ConnectCount += 1
ConnectTime += GetTimeTick() - Th.InitTime
End SyncLock
End If
SyncLock LockCount
Th.Source.FailCount = 0
For Each Task In Tasks
Task.FailCount = 0
Next
End SyncLock
NetManager.DownloadDone += RealDataCount
SyncLock LockDone
DownloadDone += RealDataCount
End SyncLock
Th.DownloadDone += RealDataCount
ResultStream.Write(ResponseBytes, 0, RealDataCount)
'已完成
If Th.DownloadUndone = 0 AndAlso Not IsUnknownSize Then Exit While
'检查速度是否过慢
If DeltaTime > 5000 AndAlso DeltaTime > RealDataCount AndAlso '数据包间隔大于 5s,且速度小于 1K/s
Th.Source.SingleThread Is Nothing Then '且并非单线程下载
Throw New TimeoutException("由于速度过慢断开链接,下载 " & RealDataCount & " B,消耗 " & DeltaTime & " ms。")
End If
Th.LastReceiveTime = GetTimeTick()
ElseIf Th.LastReceiveTime > 0 AndAlso DeltaTime > Timeout Then
'无数据,且已超时
Throw New TimeoutException("操作超时,无数据。")
End If
HttpDataCount = ResponseStream.Read(ResponseBytes, 0, 16384)
End While
SourceBreak:
If State = NetState.Error OrElse (Th.Source.IsFailed AndAlso Th.Source.SingleThread <> Th) OrElse (Th.DownloadUndone > 0 AndAlso Not IsUnknownSize) Then
'被外部中断
@@ -1017,17 +1132,26 @@ SourceBreak:
'本线程完成
Th.State = NetState.Finish
If ModeDebug Then Log($"[Download] {LocalName}:完成,已下载 {Th.DownloadDone}({Th.DownloadStart}~{Th.DownloadEnd})")
RecordIPReliability(HostIp, 0.5)
End If
Catch ex As Exception
Log($"[Download] {LocalName}:出错,{If(TypeOf ex Is TaskCanceledException, $"已超时({Timeout}ms)", GetExceptionDetail(ex))}")
Log($"[Download] {LocalName}:出错,{If(TypeOf ex Is OperationCanceledException, $"已超时({Timeout}ms)", ex.GetDetail())},IP:{HostIp}")
RecordIPReliability(HostIp, -0.7)
SourceFail(Th, ex, False)
Finally
'释放资源
HttpRequest?.Dispose()
Response?.Dispose()
ResponseStream?.Dispose()
CancelToken?.Dispose()
If Not IsNoSplit Then ResultStream?.Dispose()
'改变计数
SyncLock NetTaskThreadCountLock
NetTaskThreadCount -= 1
End SyncLock
'合并
If Not IsNoSplit Then ResultStream?.Dispose()
If ((FileSize >= 0 AndAlso DownloadDone >= FileSize) OrElse (FileSize = -1 AndAlso DownloadDone > 0)) AndAlso State < NetState.Merge Then Merge(Th)
If ((FileSize >= 0 AndAlso DownloadDone >= FileSize) OrElse (FileSize = -1 AndAlso DownloadDone > 0)) AndAlso
State < NetState.Merge AndAlso Th.State <> NetState.Error Then Merge(Th)
End Try
End Sub
Private Sub SourceFail(Th As NetThread, ex As Exception, IsMergeFailure As Boolean)
@@ -1044,7 +1168,7 @@ SourceBreak:
If IsMergeFailure OrElse
ex.Message.Contains("该下载源不支持") OrElse ex.Message.Contains("未能解析") OrElse ex.Message.Contains("(404)") OrElse
ex.Message.Contains("(502)") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse ex.Message.Contains("获取到的分段大小不一致") OrElse
(ex.Message.Contains("(403)") AndAlso Not Th.Source.Url.ContainsF("bmclapi")) OrElse 'BMCLAPI 的部分源在高频率请求下会返回 403,所以不应因此禁用下载源
((ex.Message.Contains("(403)") OrElse ex.Message.Contains("(429)")) AndAlso Not Th.Source.Url.ContainsF("bmclapi")) OrElse 'BMCLAPI 的部分源在高频率请求下会返回 403/429,所以不应因此禁用下载源
(Th.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 30) AndAlso DownloadDone < 1) OrElse Th.Source.FailCount > NetTaskThreadLimit + 2 Then
'当一个下载源有多个线程在下载时,只选择其中一个线程进行后续处理
Dim IsThisFail As Boolean = False
@@ -1069,7 +1193,7 @@ SourceBreak:
'当前源失败,但还有下载源:正常地继续执行
ElseIf Not Retried AndAlso Sources.Count > 1 Then
'合并失败或首次下载失败,未重试:将所有下载源重新标记为不允许断点续传的下载源,逐个重新尝试下载
Log($"[Download] {LocalName}:文件下载失败,正在自动重试……", If(ModeDebug, LogLevel.Hint, LogLevel.Debug)) '在调试模式下给出红色提示
Hint($"{LocalName}:文件下载失败,正在自动重试……", If(ModeDebug, HintType.Critical, HintType.Info)) '在调试模式下给出红色提示
Retried = True
SyncLock LockSource
SourcesOnce.Clear()
@@ -1138,10 +1262,10 @@ SourceBreak:
Dim RetryCount As Integer = 0
Try
Retry:
'创建文件夹
If File.Exists(LocalPath) Then File.Delete(LocalPath)
Directory.CreateDirectory(GetPathFromFullPath(LocalPath))
SyncLock LockChain
'创建文件夹
If File.Exists(LocalPath) Then File.Delete(LocalPath)
Directory.CreateDirectory(GetPathFromFullPath(LocalPath))
'合并文件
If IsNoSplit Then
'仅有一个线程,从缓存中输出
@@ -1384,13 +1508,13 @@ NextElement:
If File Is Nothing Then Throw New ArgumentException("存在空文件请求!")
For Each Source As NetSource In File.Sources
If Not (Source.Url.StartsWithF("https://", True) OrElse Source.Url.StartsWithF("http://", True)) Then
Source.Ex = New ArgumentException("输入的下载链接不正确!")
Source.Ex = New ArgumentException("输入的下载链接不正确:" & Source.Url)
Source.IsFailed = True
End If
Next
If Not File.HasAvailableSource() Then Throw New ArgumentException("输入的下载链接不正确!")
If Not File.LocalPath.ToLower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确!")
If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径!")
If Not File.LocalPath.ToLower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确:" & File.LocalPath)
If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径:" & File.LocalPath)
'文件夹检测
Dim DirPath As String = New FileInfo(File.LocalPath).Directory.FullName
If Not Directory.Exists(DirPath) Then Directory.CreateDirectory(DirPath)
@@ -1520,15 +1644,19 @@ Retry:
If State > LoadState.Loading Then Return
If ExList Is Nothing OrElse Not ExList.Any() Then ExList = New List(Of Exception) From {New Exception("未知错误!")}
'寻找有效的错误信息
Dim UsefulExs = ExList.Where(Function(e) TypeOf e IsNot TaskCanceledException AndAlso TypeOf e IsNot ThreadInterruptedException).ToList
Dim UsefulExs = ExList.Where(Function(e) TypeOf e IsNot OperationCanceledException AndAlso TypeOf e IsNot ThreadInterruptedException).ToList
[Error] = If(UsefulExs.FirstOrDefault, ExList.FirstOrDefault)
'获取实际失败的文件
For Each File In Files
If File.State <> NetState.Error Then Continue For
Dim Detail As String = Join(File.Sources.Select(Function(s) $"{If(s.Ex Is Nothing, "无错误信息。", s.Ex.GetBrief())}({s.Url})"), vbCrLf)
[Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf &
"各下载源的错误如下:" & vbCrLf &
Join(File.Sources.Select(Function(s) $"{If(s.Ex?.Message, "无错误信息。")}({s.Url})"), vbCrLf),
"各下载源的错误如下:" & vbCrLf & Detail,
[Error])
'上报
Telemetry("文件下载失败",
"FileName", File.LocalName,
"Exception", Detail)
Exit For
Next
'在设置 Error 对象后再更改为失败,避免 WaitForExit 无法捕获错误
@@ -1541,7 +1669,7 @@ Retry:
'在退出同步锁后再进行日志输出
Dim ErrOutput As New List(Of String)
For Each Ex As Exception In ExList
ErrOutput.Add(GetExceptionDetail(Ex))
ErrOutput.Add(Ex.GetDetail())
Next
Log("[Download] " & Join(ErrOutput.Distinct.ToArray, vbCrLf))
End Sub
@@ -1691,7 +1819,7 @@ Retry:
For Each File As NetFile In WaitingFiles
If NetTaskThreadCount >= NetTaskThreadLimit Then Continue While '最大线程数检查
Dim NewThread = File.TryBeginThread()
If NewThread IsNot Nothing AndAlso NewThread.Source.Url.Contains("bmclapi") Then Thread.Sleep(30) '减少 BMCLAPI 请求频率(目前每分钟限制 4000 次)
If NewThread IsNot Nothing AndAlso NewThread.Source.Url.Contains("bmclapi") Then Thread.Sleep(40) '减少 BMCLAPI 请求频率(目前每分钟限制 4000 次)
Next
'为进行中的文件追加线程
If Speed >= NetTaskSpeedLimitLow Then Continue While '下载速度足够,无需新增
@@ -1711,7 +1839,7 @@ Retry:
'新增线程
If PreparingCount > DownloadingCount Then Continue For '准备中的线程已多于下载中的线程,不再新增
Dim NewThread = File.TryBeginThread()
If NewThread IsNot Nothing AndAlso NewThread.Source.Url.Contains("bmclapi") Then Thread.Sleep(30) '减少 BMCLAPI 请求频率(目前每分钟限制 4000 次)
If NewThread IsNot Nothing AndAlso NewThread.Source.Url.Contains("bmclapi") Then Thread.Sleep(40) '减少 BMCLAPI 请求频率(目前每分钟限制 4000 次)
Next
End While
Catch ex As Exception
@@ -1745,7 +1873,7 @@ Retry:
End Sub
Private IsManagerStarted As Boolean = False
'Public FileRemainList As New List(Of String)
Private DownloadCacheLock As New Object
Private IsDownloadCacheCleared As Boolean = False
''' <summary>
''' 开始一个下载任务。
@@ -1753,15 +1881,19 @@ Retry:
Public Sub Start(Task As LoaderDownload)
StartManager()
'清理缓存
If Not IsDownloadCacheCleared Then
Try
DeleteDirectory(PathTemp & "Download")
Catch ex As Exception
Log(ex, "清理下载缓存失败")
End Try
SyncLock DownloadCacheLock '防止同时开启多个下载任务时重复清理
If Not IsDownloadCacheCleared Then
Try
Log("[Net] 开始清理下载缓存")
DeleteDirectory(PathTemp & "Download")
Log("[Net] 下载缓存已清理")
Catch ex As Exception
Log(ex, "清理下载缓存失败")
End Try
Directory.CreateDirectory(PathTemp & "Download")
End If
IsDownloadCacheCleared = True
End If
Directory.CreateDirectory(PathTemp & "Download")
End SyncLock
'文件处理
SyncLock LockFiles
'添加每个文件
@@ -1836,4 +1968,16 @@ Retry:
End If
End Function
''' <summary>
''' 判断某个 Exception 是否为网络问题所导致。
''' </summary>
<Extension> Public Function IsNetworkRelated(Ex As Exception) As Boolean
Dim Detail = Ex.GetDetail()
If Detail.Contains("(403)") Then Return False
Return {
"(408)", "超时", "timeout", "网络请求失败", "连接尝试失败", "远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称",
"由于目标计算机积极拒绝", "基础连接已经关闭"
}.Any(Function(k) Detail.ContainsF(k, True))
End Function
End Module
@@ -148,7 +148,7 @@ End Class
''' </summary>
Public Class ValidateExcept
Inherits Validate
Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
Public Property Excepts As New ObjectModel.Collection(Of String)
Public Property ErrorMessage As String
Public Sub New()
ErrorMessage = "输入内容不能包含 %"
@@ -157,12 +157,15 @@ Public Class ValidateExcept
Me.Excepts = Excepts
Me.ErrorMessage = ErrorMessage
End Sub
Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能包含 %")
Me.Excepts = New ObjectModel.Collection(Of String)
Me.ErrorMessage = ErrorMessage
For Each Data As String In Excepts
Me.Excepts.Add(Data)
Next
Public Sub New(Excepts As IEnumerable(Of String), Optional ErrorMessage As String = "输入内容不能包含 %")
Me.New(
New ObjectModel.Collection(Of String)(New List(Of String)(Excepts)),
ErrorMessage)
End Sub
Public Sub New(Excepts As IEnumerable(Of Char), Optional ErrorMessage As String = "输入内容不能包含 %")
Me.New(
New ObjectModel.Collection(Of String)(Excepts.Select(Function(c) c.ToString).ToList),
ErrorMessage)
End Sub
Public Overrides Function Validate(Str As String) As String
For Each Ch As String In Excepts
@@ -181,7 +184,7 @@ End Class
''' </summary>
Public Class ValidateExceptSame
Inherits Validate
Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
Public Property Excepts As New ObjectModel.Collection(Of String)
Public Property ErrorMessage As String
Public Property IgnoreCase As Boolean = False
Public Sub New()
@@ -191,13 +194,15 @@ Public Class ValidateExceptSame
Me.ErrorMessage = ErrorMessage
Me.IgnoreCase = IgnoreCase
End Sub
Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能为 %", Optional IgnoreCase As Boolean = False)
Me.Excepts = New ObjectModel.Collection(Of String)
For Each Data As String In Excepts
Me.Excepts.Add(Data)
Next
Me.ErrorMessage = ErrorMessage
Me.IgnoreCase = IgnoreCase
Public Sub New(Excepts As IEnumerable(Of String), Optional ErrorMessage As String = "输入内容不能为 %", Optional IgnoreCase As Boolean = False)
Me.New(
New ObjectModel.Collection(Of String)(New List(Of String)(Excepts)),
ErrorMessage, IgnoreCase)
End Sub
Public Sub New(Except As String, Optional ErrorMessage As String = "输入内容不能为 %", Optional IgnoreCase As Boolean = False)
Me.New(
New ObjectModel.Collection(Of String) From {Except},
ErrorMessage, IgnoreCase)
End Sub
Public Overrides Function Validate(Str As String) As String
If Str Is Nothing Then Return ErrorMessage.Replace("%", "null")
@@ -347,7 +347,7 @@
Case 4475 : Tags.Add("冒险")
Case 4476 : Tags.Add("探索")
Case 4477 : Tags.Add("小游戏")
Case 4471 : Tags.Add("科幻")
Case 4474 : Tags.Add("科幻")
Case 4736 : Tags.Add("空岛")
Case 5128 : Tags.Add("原版改良")
Case 4487 : Tags.Add("FTB")
@@ -1161,9 +1161,9 @@ Retry:
ElseIf [Error] IsNot Nothing Then
'有结果但是有错误
If CurseForgeFailed Then
Storage.ErrorMessage = $"无法连接到 CurseForge,所以目前仅显示了来自 Modrinth 的内容,搜索结果可能不全。{vbCrLf}请稍后重试,或使用 VPN 以改善网络环境。"
Storage.ErrorMessage = $"无法连接到 CurseForge,所以目前仅显示了来自 Modrinth 的内容,搜索结果可能不全。{vbCrLf}请稍后再试,或使用 VPN 改善网络环境。"
Else
Storage.ErrorMessage = $"无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,搜索结果可能不全。{vbCrLf}请稍后重试,或使用 VPN 以改善网络环境。"
Storage.ErrorMessage = $"无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,搜索结果可能不全。{vbCrLf}请稍后再试,或使用 VPN 改善网络环境。"
End If
End If
@@ -1354,7 +1354,7 @@ Retry:
''' </summary>
''' <param name="LocalAddress">目标本地文件夹,或完整的文件路径。会自动判断类型。</param>
Public Function ToNetFile(LocalAddress As String) As NetFile
Return New NetFile(DownloadUrls, LocalAddress & If(LocalAddress.EndsWithF("\"), FileName, ""), New FileChecker(Hash:=Hash), UseBrowserUserAgent:=True)
Return New NetFile(DownloadUrls, LocalAddress & If(LocalAddress.EndsWithF("\"), FileName, ""), New FileChecker(Hash:=Hash), SimulateBrowserHeaders:=True)
End Function
'实例化
@@ -1395,10 +1395,9 @@ Retry:
If Hash Is Nothing Then Hash = CType(Data("hashes"), JArray).ToList.FirstOrDefault(Function(s) s("algo").ToObject(Of Integer) = 2)?("value")
'DownloadAddress
Dim Url = Data("downloadUrl").ToString
If Url = "" Then Url = $"https://media.forgecdn.net/files/{CInt(Id.ToString.Substring(0, 4))}/{CInt(Id.ToString.Substring(4))}/{FileName}"
Url = Url.Replace(FileName, WebUtility.UrlEncode(FileName)) '对文件名进行编码
DownloadUrls = HandleCurseForgeDownloadUrls(Url) '对脑残 CurseForge 的下载地址进行多种修正
DownloadUrls.AddRange(DownloadUrls.Select(Function(u) DlSourceModGet(u)).ToList) '添加镜像源,这个写法是为了让镜像源排在后面
If Url = "" Then Url = $"https://edge.forgecdn.net/files/{CInt(Id.ToString.Substring(0, 4))}/{CInt(Id.ToString.Substring(4))}/{FileName}"
DownloadUrls = HandleCurseForgeDownloadUrls(Url.Replace(FileName, WebUtility.UrlEncode(FileName))) '对脑残 CurseForge 的下载地址进行多种修正
DownloadUrls.Add(DlSourceModGet(Url)) '添加镜像源;注意 MCIM 源不支持 URL 编码后的文件名,必须传入 URL 编码前的文件名
DownloadUrls = DownloadUrls.Distinct.ToList '最终去重
'Dependencies
If Data.ContainsKey("dependencies") Then
@@ -2,7 +2,9 @@
'构造函数
Private TempFolder As String
Public Sub New(UUID As Integer)
Private TargetVersion As McVersion
Public Sub New(Optional TargetVersion As McVersion = Nothing)
Me.TargetVersion = TargetVersion
'构建文件结构
TempFolder = RequestTaskTempFolder()
Directory.CreateDirectory(TempFolder & "Temp\")
@@ -339,6 +341,7 @@ Extracted:
''' 导致崩溃的原因枚举。
''' </summary>
Private Enum CrashReason
Java虚拟机参数有误
Mod文件被解压
MixinBootstrap缺失
内存不足
@@ -482,10 +485,12 @@ Done:
'崩溃报告分析,高优先级
If LogCrash IsNot Nothing Then
If LogCrash.Contains("Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass") Then AppendReason(CrashReason.Java版本过高)
If LogCrash.Contains("Failed loading config file ") Then AppendReason(CrashReason.Mod配置文件导致游戏崩溃, {TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=Failed loading config file .+ for modid )[^\n]+"), "").TrimEnd(vbCrLf)).First, If(RegexSeek(LogCrash, "(?<=Failed loading config file ).+(?= of type)"), "").TrimEnd(vbCrLf)}) '#7071
End If
'游戏日志分析
If LogMc IsNot Nothing Then
If LogMc.Contains("Unrecognized option:") Then AppendReason(CrashReason.Java虚拟机参数有误)
If LogMc.Contains("Found multiple arguments for option fml.forgeVersion, but you asked for only one") Then AppendReason(CrashReason.版本Json中存在多个Forge)
If LogMc.Contains("The driver does not appear to support OpenGL") Then AppendReason(CrashReason.显卡不支持OpenGL)
If LogMc.Contains("java.lang.ClassCastException: java.base/jdk") Then AppendReason(CrashReason.使用JDK)
@@ -508,13 +513,13 @@ Done:
If LogMc.Contains("Couldn't set pixel format") Then AppendReason(CrashReason.显卡驱动不支持导致无法设置像素格式)
If LogMc.Contains("java.lang.OutOfMemoryError") OrElse LogMc.Contains("an out of memory error") Then AppendReason(CrashReason.内存不足)
If LogMc.Contains("java.lang.RuntimeException: Shaders Mod detected. Please remove it, OptiFine has built-in support for shaders.") Then AppendReason(CrashReason.ShadersMod与OptiFine同时安装)
If LogMc.Contains("java.lang.NoSuchMethodError: sun.security.util.ManifestEntryVerifier") Then AppendReason(CrashReason.低版本Forge与高版本Java不兼容)
If LogMc.Contains("java.lang.NoSuchMethodError: sun.security.util.ManifestEntryVerifier") OrElse LogMc.Contains("java.lang.NoSuchMethodError: 'void sun.security.util.ManifestEntryVerifier") Then AppendReason(CrashReason.低版本Forge与高版本Java不兼容)
If LogMc.Contains("1282: Invalid operation") Then AppendReason(CrashReason.光影或资源包导致OpenGL1282错误)
If LogMc.Contains("signer information does not match signer information of other classes in the same package") Then AppendReason(CrashReason.文件或内容校验失败, If(RegexSeek(LogMc, "(?<=class "")[^']+(?=""'s signer information)"), "").TrimEnd(vbCrLf))
If LogMc.Contains("Maybe try a lower resolution resourcepack?") Then AppendReason(CrashReason.材质过大或显卡配置不足)
If LogMc.Contains("java.lang.NoSuchMethodError: net.minecraft.world.server.ChunkManager$ProxyTicketManager.shouldForceTicks(J)Z") AndAlso LogMc.Contains("OptiFine") Then AppendReason(CrashReason.OptiFine导致无法加载世界)
If LogMc.Contains("Unsupported class file major version") Then AppendReason(CrashReason.Java版本不兼容)
If LogMc.Contains("com.electronwill.nightconfig.core.io.ParsingException: Not enough data available") Then AppendReason(CrashReason.NightConfig的Bug)
If LogMc.Contains("com.electronwill.nightconfig.core.io.ParsingException: Not enough data available") AndAlso Not CrashReasons.ContainsKey(CrashReason.Mod配置文件导致游戏崩溃) Then AppendReason(CrashReason.NightConfig的Bug)
If LogMc.Contains("Cannot find launch target fmlclient, unable to launch") Then AppendReason(CrashReason.Forge安装不完整)
If LogMc.Contains("Invalid paths argument, contained no existing paths") AndAlso LogMc.Contains("libraries\net\minecraftforge\fmlcore") Then AppendReason(CrashReason.Forge安装不完整)
If LogMc.Contains("Invalid module name: '' is not a Java identifier") Then AppendReason(CrashReason.Mod名称包含特殊字符)
@@ -537,8 +542,8 @@ Done:
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))
If LogMc.Contains("Incompatible mods found!") Then '#5006
AppendReason(CrashReason.Mod互不兼容, If(RegexSeek(LogMc, "(?<=Incompatible mods found![\s\S]+: )[\s\S]+?(?=\tat )"), ""))
If LogMc.Contains("Incompatible mods found!") Then '#5006, #5115
AppendReason(CrashReason.Mod互不兼容, If(RegexSeek(LogMc, "(?<=Incompatible mods found![\s\S]+: )[\s\S]+?(?=\tat )"), "").BeforeFirst("更多信息:").Replace("Some of your mods are incompatible with the game or each other!", "").Trim((vbCrLf & " ").ToCharArray))
End If
If LogMc.Contains("Missing or unsupported mandatory dependencies:") Then
AppendReason(CrashReason.Mod缺少前置或MC版本错误,
@@ -654,7 +659,7 @@ Done:
End If
'Mod 解析错误(常见于 Fabric 前置校验失败)
If LogMc.Contains("Mod resolution failed") Then AppendReason(CrashReason.Mod加载器报错)
'Mixin 失败可以导致大量 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! 不一定是崩溃原因,它可能是单纯的警报
End If
@@ -713,7 +718,7 @@ NextStack:
"preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content", "systems", "modules", "service",
"fastutil", "optifine", "internal", "platform", "override", "fabricmc", "neoforge",
"injection", "listeners", "scheduler", "minecraft", "universal", "multipart", "neoforged", "microsoft",
"transformer", "transformers", "minecraftforge", "blockentity", "spongepowered", "electronwill"
"transformer", "transformers", "minecraftforge", "blockentity", "spongepowered", "electronwill", "concurrent"
}.Contains(Word.ToLower) Then Continue For
PossibleWords.Add(Word.Trim)
Next
@@ -856,20 +861,21 @@ NextStack:
''' <summary>
''' 弹出崩溃弹窗,并指导导出崩溃报告。
''' </summary>
Public Sub Output(IsHandAnalyze As Boolean, Optional ExtraFiles As List(Of String) = Nothing)
Public Sub Output(IsManualAnalyze As Boolean, Optional ExtraFiles As List(Of String) = Nothing)
'弹窗提示
FrmMain.ShowWindowToTop()
Select Case MyMsgBox(GetAnalyzeResult(IsHandAnalyze), If(IsHandAnalyze, "错误报告分析结果", "Minecraft 出现错误"),
"确定", If(IsHandAnalyze OrElse DirectFile Is Nothing, "", "查看日志"), If(IsHandAnalyze, "", "导出错误报告"),
Button2Action:=If(IsHandAnalyze OrElse DirectFile Is Nothing, Nothing,
Dim Detail As String = GetAnalyzeResult(IsManualAnalyze)
Select Case MyMsgBox(Detail, If(IsManualAnalyze, "错误报告分析结果", "Minecraft 出现错误"),
"确定", If(IsManualAnalyze OrElse DirectFile Is Nothing, "", "查看日志"), If(IsManualAnalyze, "", "导出错误报告"),
Button2Action:=If(IsManualAnalyze OrElse DirectFile Is Nothing, Nothing,
Sub()
'弹窗选择:查看日志
If File.Exists(DirectFile.Value.Key) Then
ShellOnly(DirectFile.Value.Key)
StartProcess(DirectFile.Value.Key)
Else
Dim FilePath As String = PathTemp & "Crash.txt"
WriteFile(FilePath, Join(DirectFile.Value.Value, vbCrLf))
ShellOnly(FilePath)
StartProcess(FilePath)
End If
End Sub))
Case 3
@@ -918,6 +924,11 @@ NextStack:
End Try
OpenExplorer(FileAddress)
End Select
'上报
If IsManualAnalyze Then Return
Telemetry("Minecraft 崩溃",
"Version", If(TargetVersion Is Nothing, "null", TargetVersion.Version.ToString),
"Detail", FilterUserName(Detail, "*"))
End Sub
''' <summary>
''' 获取崩溃分析的结果描述。
@@ -938,6 +949,8 @@ NextStack:
For Each Reason In CrashReasons
Dim Additional As List(Of String) = Reason.Value
Select Case Reason.Key
Case CrashReason.Java虚拟机参数有误
Results.Add("由于 Java 参数有误,导致游戏无法继续运行。\n请检查高级选项中的 Java 虚拟机参数和游戏参数设置是否有误。")
Case CrashReason.Mod文件被解压
Results.Add("由于 Mod 文件被解压了,导致游戏无法继续运行。\n直接把整个 Mod 文件放进 Mod 文件夹中即可,若解压就会导致游戏出错。\n\n请删除 Mod 文件夹中已被解压的 Mod,然后再启动游戏。")
Case CrashReason.内存不足
@@ -1018,9 +1031,17 @@ NextStack:
End If
Case CrashReason.特定实体导致崩溃
If Additional.Count = 1 Then
Results.Add("游戏似乎因为实体 " & Additional.First & " 出现了问题。\n\n你可以创建一个新世界,并生成一个该实体,然后观察游戏的运行情况。\h")
If Additional.First.Contains("minecraft:player") Then
If Additional.First.Contains(" ") Then
Results.Add($"游戏因为位于 {Additional.First.AfterFirst(" ")} 的玩家实体导致了崩溃。\h")
Else
Results.Add($"游戏因为玩家实体导致了崩溃。\h")
End If
Else
Results.Add($"游戏因为实体 {Additional.First} 导致了崩溃。\h")
End If
Else
Results.Add("游戏似乎因为世界中的某些实体出现了问题。\n\n你可以创建一个新世界,并生成各种实体,然后观察游戏的运行情况。\h")
Results.Add($"游戏因为下列实体导致了崩溃:{Additional.Join("、")}\h")
End If
Case CrashReason.OptiFine与Forge不兼容
Results.Add("由于 OptiFine 与当前版本的 Forge 不兼容,导致了游戏崩溃。\n\n请前往 OptiFine 官网(https://optifine.net/downloads)查看 OptiFine 所兼容的 Forge 版本,并严格按照对应版本重新安装游戏。")
@@ -1102,7 +1123,7 @@ NextStack:
If(Not Results.Any(Function(r) r.EndsWithF("\h")) OrElse IsHandAnalyze, "",
vbCrLf & "如果要寻求帮助,请把错误报告文件发给对方,而不是发送这个窗口的照片或者截图。" &
If(If(PageSetupSystem.IsLauncherNewest(), True), "",
vbCrLf & vbCrLf & "此外,你正在使用老版本 PCL,更新 PCL 或许也能解决这个问题。" & vbCrLf & "你可以点击 设置 → 启动器 → 检查更新 来更新 PCL。"))
vbCrLf & vbCrLf & "此外,你正在使用老版本 PCL,更新 PCL 或许也能解决这个问题。" & vbCrLf & "你可以点击 [设置 → 其他 → 启动器 → 检查更新] 更新 PCL。"))
End Function
End Class
@@ -198,7 +198,7 @@
Private IsNewClientVersionHinted As Boolean = False
Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult))
Dim StartTime As Long = GetTimeTick()
Dim Json As JObject = GetJson(NetRequestByClientRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json"))
Dim Json As JObject = GetJson(NetRequestByClientRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json", RequireJson:=True))
Try
Dim Versions As JArray = Json("versions")
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
@@ -235,7 +235,7 @@
''' </summary>
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 = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json"))
Dim Json As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json", RequireJson:=True))
Try
Dim Versions As JArray = Json("versions")
If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
@@ -413,7 +413,7 @@
''' </summary>
Public DlOptiFineListBmclapiLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Bmclapi", AddressOf DlOptiFineListBmclapiMain)
Private Sub DlOptiFineListBmclapiMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
Dim Json As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/optifine/versionList"))
Dim Json As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/optifine/versionList", RequireJson:=True))
Try
Dim Versions As New List(Of DlOptiFineListEntry)
For Each Token As JObject In Json
@@ -483,7 +483,7 @@
''' </summary>
Public DlForgeListOfficialLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Official", AddressOf DlForgeListOfficialMain)
Private Sub DlForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
Dim Result As String = NetRequestByClientRetry("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.2.4.html", Encoding:=Encoding.Default, Accept:="text/html", UseBrowserUserAgent:=True)
Dim Result As String = NetRequestByClientRetry("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.2.4.html", Encoding:=Encoding.Default, Accept:="text/html", SimulateBrowserHeaders:=True)
If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
'获取所有版本信息
Dim Names As List(Of String) = RegexSearch(Result, "(?<=a href=""index_)[0-9.]+(_pre[0-9]?)?(?=.html)")
@@ -594,7 +594,7 @@
VersionName = Version
Me.Version = New Version(Version)
Me.Inherit = Inherit
FileVersion = Version & If(Branch Is Nothing, "", "-" & Branch)
FileVersion = Version & If(Branch Is Nothing, "", "-" & Branch)
End Sub
End Class
@@ -631,9 +631,9 @@
Try
Result = NetRequestByLoader("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_" &
Loader.Input.Replace("-", "_") & '兼容 Forge 1.7.10-pre4,#4057
".html", UseBrowserUserAgent:=True)
".html", SimulateBrowserHeaders:=True)
Catch ex As Exception
If GetExceptionSummary(ex).Contains("(404)") Then
If ex.GetBrief().Contains("(404)") Then
Throw New Exception("不可用")
Else
Throw
@@ -701,7 +701,7 @@
''' </summary>
Public Sub DlForgeVersionBmclapiMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
Dim Json As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/minecraft/" &
Loader.Input.Replace("-", "_"))) '兼容 Forge 1.7.10-pre4,#4057
Loader.Input.Replace("-", "_"), RequireJson:=True)) '兼容 Forge 1.7.10-pre4,#4057
Dim Versions As New List(Of DlForgeVersionEntry)
Try
Dim Recommended As String = McDownloadForgeRecommendedGet(Loader.Input)
@@ -835,8 +835,8 @@
Public DlNeoForgeListOfficialLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Official", AddressOf DlNeoForgeListOfficialMain)
Private Sub DlNeoForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
'获取版本列表 JSON
Dim ResultLatest As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge")
Dim ResultLegacy As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge")
Dim ResultLatest As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge", RequireJson:=True)
Dim ResultLegacy As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge", RequireJson:=True)
If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
'解析
Try
@@ -853,8 +853,8 @@
Public DlNeoForgeListBmclapiLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Bmclapi", AddressOf DlNeoForgeListBmclapiMain)
Public Sub DlNeoForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
'获取版本列表 JSON
Dim ResultLatest As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/neoforge")
Dim ResultLegacy As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/forge")
Dim ResultLatest As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/neoforge", RequireJson:=True)
Dim ResultLegacy As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/forge", RequireJson:=True)
If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
'解析
Try
@@ -959,7 +959,7 @@
''' </summary>
Public DlLiteLoaderListOfficialLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Official", AddressOf DlLiteLoaderListOfficialMain)
Private Sub DlLiteLoaderListOfficialMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://dl.liteloader.com/versions/versions.json"))
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://dl.liteloader.com/versions/versions.json", RequireJson:=True))
Try
Dim Json As JObject = Result("versions")
Dim Versions As New List(Of DlLiteLoaderListEntry)
@@ -987,7 +987,7 @@
''' </summary>
Public DlLiteLoaderListBmclapiLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Bmclapi", AddressOf DlLiteLoaderListBmclapiMain)
Private Sub DlLiteLoaderListBmclapiMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json"))
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json", RequireJson:=True))
Try
Dim Json As JObject = Result("versions")
Dim Versions As New List(Of DlLiteLoaderListEntry)
@@ -1058,7 +1058,7 @@
''' </summary>
Public DlFabricListOfficialLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Official", AddressOf DlFabricListOfficialMain)
Private Sub DlFabricListOfficialMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://meta.fabricmc.net/v2/versions"))
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://meta.fabricmc.net/v2/versions", RequireJson:=True))
Try
Dim Output = New DlFabricListResult With {.IsOfficial = True, .SourceName = "Fabric 官方源", .Value = Result}
If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
@@ -1073,7 +1073,7 @@
''' </summary>
Public DlFabricListBmclapiLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Bmclapi", AddressOf DlFabricListBmclapiMain)
Private Sub DlFabricListBmclapiMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/fabric-meta/v2/versions"))
Dim Result As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/fabric-meta/v2/versions", RequireJson:=True))
Try
Dim Output = New DlFabricListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Result}
If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
@@ -1106,30 +1106,31 @@
Public Function DlModRequest(Url As String, Optional Method As HttpMethod = Nothing,
Optional Content As String = Nothing, Optional ContentType As String = Nothing) As JToken
Dim Urls As New List(Of KeyValuePair(Of String, Integer))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10)) '至少 10s,要不然有时候远端服务器来不及完成
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
'Dim McimUrl As String = DlSourceModGet(Url)
'If McimUrl <> Url Then
' Select Case Setup.Get("ToolDownloadMod")
' Case 0
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
' Case 1
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10))
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
' Case Else
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10))
' Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
' Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
' End Select
'End If
Dim McimUrl As String = DlSourceModGet(Url)
If McimUrl <> Url Then
Select Case Setup.Get("ToolDownloadMod")
Case 0
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
Case 1
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10)) '至少 10s,要不然有时候远端服务器来不及完成
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
Case Else
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
End Select
Else
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
End If
Dim Exs As String = ""
For Each Source In Urls
Try
Return GetJson(NetRequestByClient(Source.Key, Method, Content, ContentType, Timeout:=Source.Value * 1000, Encoding:=Encoding.UTF8))
Return GetJson(NetRequestByClient(Source.Key, Method, Content, ContentType, Timeout:=Source.Value * 1000, Encoding:=Encoding.UTF8, RequireJson:=True))
Catch ex As Exception
Exs += ex.Message + vbCrLf
End Try
@@ -1232,7 +1233,14 @@
'Mod 下载源
Public Function DlSourceModGet(Original As String) As String
Return Original
Return Original.
Replace("api.modrinth.com", "mod.mcimirror.top/modrinth").
Replace("staging-api.modrinth.com", "mod.mcimirror.top/modrinth").
Replace("cdn.modrinth.com", "mod.mcimirror.top").
Replace("api.curseforge.com", "mod.mcimirror.top/curseforge").
Replace("edge.forgecdn.net", "mod.mcimirror.top").
Replace("mediafilez.forgecdn.net", "mod.mcimirror.top").
Replace("media.forgecdn.net", "mod.mcimirror.top")
End Function
'Loader 自动切换
@@ -10,7 +10,7 @@
'路径
''' <summary>
''' Java.exe 文件的完整路径。
''' java.exe 文件的完整路径。
''' </summary>
Public ReadOnly Property PathJava As String
Get
@@ -18,15 +18,7 @@
End Get
End Property
''' <summary>
''' Javaw.exe 文件的完整路径。
''' </summary>
Public ReadOnly Property PathJavaw As String
Get
Return PathFolder & "javaw.exe"
End Get
End Property
''' <summary>
''' Javaw.exe 文件所在文件夹的路径,以 \ 结尾。
''' java.exe 文件所在文件夹的路径,以 \ 结尾。
''' </summary>
Public PathFolder As String
''' <summary>
@@ -102,20 +94,13 @@
Dim Output As String = Nothing
Try
'确定文件存在
If Not File.Exists(PathJavaw) Then
Throw New FileNotFoundException("未找到 javaw.exe 文件", PathJavaw)
End If
If Not File.Exists(PathFolder & "java.exe") Then
Throw New FileNotFoundException("未找到 java.exe 文件", PathFolder & "java.exe")
End If
If File.Exists(PathFolder & "pdf-bookmark") Then
Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326
End If
If Not File.Exists(PathJava) Then Throw New FileNotFoundException("未找到 java.exe 文件", PathJava)
If File.Exists(PathFolder & "pdf-bookmark") Then Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326
IsJre = Not File.Exists(PathFolder & "javac.exe")
'运行 -version
Output = ShellAndGetOutput(PathFolder & "java.exe", "-version", 15000).ToLower
Output = StartProcessAndGetOutput(PathJava, "-version", 15000).ToLower
If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败")
If ModeDebug Then Log("[Java] Java 检查输出:" & PathFolder & "java.exe" & vbCrLf & Output)
If ModeDebug Then Log("[Java] Java 检查输出:" & PathJava & vbCrLf & Output)
If Output.Contains("/lib/ext exists") Then Throw New ApplicationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试")
If Output.Contains("a fatal error") Then Throw New ApplicationException("无法运行该 Java,该 Java 或系统存在问题")
'获取详细信息
@@ -136,17 +121,17 @@
End If
Is64Bit = Output.Contains("64-bit")
If Version.Minor <= 4 OrElse Version.Minor >= 100 Then Throw New ApplicationException("分析详细信息失败,获取的版本为 " & Version.ToString)
'基于 #3649,在 64 位系统上禁用 32 位 Java
'#3649:在 64 位系统上禁用 32 位 Java
If Not Is64Bit AndAlso Not Is32BitSystem Then Throw New Exception("该 Java 为 32 位版本,请安装 64 位的 Java")
'基于 #2249 发现 JRE 17 似乎也导致了 Forge 安装失败,干脆禁用更多版本的 JRE
'#2249:JRE 17 似乎会导致 Forge 安装失败,干脆禁用更多版本的 JRE
If IsJre AndAlso VersionCode >= 16 Then Throw New Exception("由于高版本 JRE 对游戏的兼容性很差,因此不再允许使用。你可以使用对应版本的 JDK,而非 JRE!")
Catch ex As ApplicationException
Throw ex
Catch ex As ThreadInterruptedException
Throw ex
Catch ex As Exception
Log("[Java] 检查失败的 Java 输出:" & PathFolder & "java.exe" & vbCrLf & If(Output, "无程序输出"))
Throw New Exception("检查 Java 失败(" & If(PathJavaw, "Nothing") & ")", ex)
Log("[Java] 检查失败的 Java 输出:" & If(PathJava, "Nothing") & vbCrLf & If(Output, "无程序输出"))
Throw New Exception("检查 Java 失败(" & If(PathJava, "Nothing") & ")", ex)
End Try
IsChecked = True
End Sub
@@ -460,8 +445,8 @@ NoUserJava:
''' 将 Java 按照适用性排序。
''' </summary>
Public Function JavaSorter(Left As JavaEntry, Right As JavaEntry) As Boolean
Dim PathInfo As New DirectoryInfo(ShortenPath(Path))
Dim PathMcInfo As New DirectoryInfo(ShortenPath(PathMcFolder))
Dim PathInfo As New DirectoryInfo(Path)
Dim PathMcInfo As New DirectoryInfo(PathMcFolder)
'1. 尽量在当前文件夹或当前 Minecraft 文件夹
Dim ProgramPathParent As String, MinecraftPathParent As String = ""
ProgramPathParent = If(PathInfo.Parent, PathInfo).FullName
@@ -533,7 +518,7 @@ NoUserJava:
JavaSearchFolder(Disk.Name, JavaPreList, False)
Next
'查找 .jdks 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.jdks\", JavaPreList, False)
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.jdks\", JavaPreList, False, True)
'查找 APPDATA 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\", JavaPreList, False)
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) & "\", JavaPreList, False)
@@ -661,7 +646,7 @@ Wait:
Private Sub JavaSearchFolder(OriginalPath As String, ByRef Results As Dictionary(Of String, Boolean), Source As Boolean, Optional IsFullSearch As Boolean = False)
Try
Log("[Java] 开始" & If(IsFullSearch, "完全", "部分") & "遍历查找:" & OriginalPath)
JavaSearchFolder(New DirectoryInfo(ShortenPath(OriginalPath)), Results, Source, IsFullSearch)
JavaSearchFolder(New DirectoryInfo(OriginalPath), Results, Source, IsFullSearch)
Catch ex As UnauthorizedAccessException
Log("[Java] 遍历查找 Java 时遭遇无权限的文件夹:" & OriginalPath)
Catch ex As Exception
@@ -689,7 +674,7 @@ Wait:
"应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot",
"runtime", "x86", "x64", "forge", "原版", "optifine", "官方", "启动", "hmcl", "mod", "高清",
"download", "launch", "程序", "path", "version", "baka", "pcl", "zulu", "local", "packages",
"4297127d64ec6", "1.", "启动"}
"4297127d64ec6", "1.", "启动", "jbr"}
For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories
If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接
Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).ToLower '用于搜索的字符串
@@ -66,7 +66,7 @@ Public Module ModLaunch
''' </summary>
Public Sub McLaunchLog(Text As String)
Text = FilterUserName(FilterAccessToken(Text, "*"), "*")
RunInUi(Sub() FrmLaunchRight.LabLog.Text += vbCrLf & "[" & GetTimeNow() & "] " & Text)
RunInUi(Sub() FrmLaunchRight.LabLog.Text += $"{vbCrLf}[{GetTimeNow()}] {Text}")
Log("[Launch] " & Text)
End Sub
@@ -101,6 +101,8 @@ Public Module ModLaunch
If Not ex.Message.StartsWithF("$$") Then Hint(ex.Message, HintType.Critical)
Throw
End Try
Dim IsSavingBatch As Boolean = CurrentLaunchOptions?.SaveBatch IsNot Nothing
'正式加载
Try
'构造主加载器
@@ -145,9 +147,15 @@ Public Module ModLaunch
Select Case LaunchLoader.State
Case LoadState.Finished
Hint(McVersionCurrent.Name & " 启动成功!", HintType.Finish)
'上报
If Not IsSavingBatch Then
Telemetry("Minecraft 启动成功",
"Version", McVersionCurrent.Version.ToString,
"LoginType", GetStringFromEnum(CType(Setup.Get("LoginType"), McLoginType)))
End If
Case LoadState.Aborted
If AbortHint Is Nothing Then
Hint(If(CurrentLaunchOptions?.SaveBatch Is Nothing, "已取消启动!", "已取消导出启动脚本!"), HintType.Info)
Hint(If(IsSavingBatch, "已取消导出启动脚本!", "已取消启动!"), HintType.Info)
Else
Hint(AbortHint, HintType.Finish)
End If
@@ -162,7 +170,7 @@ NextInner:
If CurrentEx.Message.StartsWithF("$") Then
'若有以 $ 开头的错误信息,则以此为准显示提示
'若错误信息为 $$,则不提示
If Not CurrentEx.Message = "$$" Then MyMsgBox(CurrentEx.Message.TrimStart("$"), If(CurrentLaunchOptions?.SaveBatch Is Nothing, "启动失败", "导出启动脚本失败"))
If Not CurrentEx.Message = "$$" Then MyMsgBox(CurrentEx.Message.TrimStart("$"), If(IsSavingBatch, "导出启动脚本失败", "启动失败"))
Throw
ElseIf CurrentEx.InnerException IsNot Nothing Then
'检查下一级错误
@@ -170,10 +178,17 @@ NextInner:
GoTo NextInner
Else
'没有特殊处理过的错误信息
McLaunchLog("错误:" & GetExceptionDetail(ex))
McLaunchLog("错误:" & ex.GetDetail())
Log(ex,
If(CurrentLaunchOptions?.SaveBatch Is Nothing, "Minecraft 启动失败", "导出启动脚本失败"), LogLevel.Msgbox,
If(CurrentLaunchOptions?.SaveBatch Is Nothing, "启动失败", "导出启动脚本失败"))
If(IsSavingBatch, "导出启动脚本失败", "Minecraft 启动失败"), LogLevel.Msgbox,
If(IsSavingBatch, "导出启动脚本失败", "启动失败"))
'上报
If Not IsSavingBatch Then
Telemetry("Minecraft 启动失败",
"Version", McVersionCurrent.Version.ToString,
"LoginType", GetStringFromEnum(CType(Setup.Get("LoginType"), McLoginType)),
"Exception", FilterUserName(FilterAccessToken(ex.GetDetail(), "*"), "*"))
End If
Throw
End If
End Try
@@ -594,12 +609,8 @@ SkipLogin:
McLoginRequestValidate(Data)
GoTo LoginFinish
Catch ex As Exception
Dim AllMessage = GetExceptionDetail(ex)
McLaunchLog("验证登录失败:" & AllMessage)
If (AllMessage.Contains("超时") OrElse AllMessage.Contains("imeout")) AndAlso Not AllMessage.Contains("403") Then
McLaunchLog("已触发超时登录失败")
Throw New Exception("$登录失败:你的网络环境不佳,导致难以连接到海外服务器。" & vbCrLf & "请稍后重试,或使用加速器或 VPN 以改善网络环境。")
End If
Log(ex, "验证登录失败")
If IsNetworkRelated(ex) Then Throw New Exception("$登录失败:你的网络环境不佳,导致难以连接到海外服务器。" & vbCrLf & "请稍后再试,或使用加速器、VPN 改善网络环境。")
End Try
Data.Progress = 0.25
'尝试刷新登录
@@ -609,7 +620,7 @@ Refresh:
McLoginRequestRefresh(Data, NeedRefresh)
GoTo LoginFinish
Catch ex As Exception
McLaunchLog("刷新登录失败:" & GetExceptionDetail(ex))
McLaunchLog("刷新登录失败:" & ex.GetDetail())
If WasRefreshed Then Throw New Exception("二轮刷新登录失败", ex)
End Try
Data.Progress = If(NeedRefresh, 0.85, 0.45)
@@ -619,7 +630,7 @@ Refresh:
If Data.IsAborted Then Throw New ThreadInterruptedException
NeedRefresh = McLoginRequestLogin(Data)
Catch ex As Exception
McLaunchLog("登录失败:" & GetExceptionDetail(ex))
McLaunchLog("登录失败:" & ex.GetDetail())
Throw
End Try
If NeedRefresh Then
@@ -711,7 +722,7 @@ LoginFinish:
New JProperty("requestUser", True)
).ToString(Newtonsoft.Json.Formatting.None),
Headers:={{"Accept-Language", "zh-CN"}},
ContentType:="application/json; charset=utf-8"))
ContentType:="application/json; charset=utf-8", RequireJson:=True))
'将登录结果输出
If LoginJson("selectedProfile") Is Nothing Then Throw New Exception("选择的角色 " & Setup.Get("Cache" & Data.Input.Token & "Name") & " 无效!")
Data.Output.AccessToken = LoginJson("accessToken").ToString
@@ -741,7 +752,7 @@ LoginFinish:
Data.Input.BaseUrl & "/authenticate", HttpMethod.Post,
Content:=RequestData.ToString(Newtonsoft.Json.Formatting.None),
Headers:={{"Accept-Language", "zh-CN"}},
ContentType:="application/json; charset=utf-8"))
ContentType:="application/json; charset=utf-8", RequireJson:=True))
'检查登录结果
If LoginJson("availableProfiles").Count = 0 Then
If Data.Input.ForceReselectProfile Then Hint("你还没有创建角色,无法更换!", HintType.Critical)
@@ -799,13 +810,14 @@ LoginFinish:
McLaunchLog("登录成功(Login, " & Data.Input.Token & ")")
Return NeedRefresh
Catch ex As Exception
Dim AllMessage As String = GetExceptionSummary(ex)
Dim AllMessage As String = ex.GetBrief()
Log(ex, "登录失败原始错误信息", LogLevel.Normal)
'读取服务器返回的错误
If TypeOf ex Is ResponsedWebException Then
Dim ErrorMessage As String = Nothing
Try
ErrorMessage = GetJson(DirectCast(ex, ResponsedWebException).Response)("errorMessage")
Dim Response = DirectCast(ex, ResponsedWebException).Response
If ErrorMessage.ContainsF("errorMessage", True) Then ErrorMessage = GetJson(Response)("errorMessage")
Catch
End Try
If Not String.IsNullOrWhiteSpace(ErrorMessage) Then
@@ -823,7 +835,7 @@ LoginFinish:
End If
End If
'通用关键字检测
If AllMessage.Contains("403") Then
If AllMessage.Contains("(403)") Then
Select Case Data.Input.Type
Case McLoginType.Auth
Throw New Exception("$登录失败,以下为可能的原因:" & vbCrLf &
@@ -837,8 +849,8 @@ LoginFinish:
If(Data.Input.UserName.Contains("@"), "", " - 登录账号应为邮箱或统一通行证账号,而非游戏角色 ID。" & vbCrLf) &
" - 只注册了账号,但没有加入对应服务器。")
End Select
ElseIf AllMessage.Contains("超时") OrElse AllMessage.Contains("imeout") OrElse AllMessage.Contains("网络请求失败") Then
Throw New Exception("$登录失败:你的网络环境不佳,导致难以连接到海外服务器。" & vbCrLf & "请稍后重试,或使用加速器或 VPN 以改善网络环境。")
ElseIf ex.IsNetworkRelated() Then
Throw New Exception("$登录失败:你的网络环境不佳,导致难以连接到海外服务器。" & vbCrLf & "请稍后再试,或使用加速器、VPN 改善网络环境。")
ElseIf ex.Message.StartsWithF("$") Then
Throw
Else
@@ -857,7 +869,7 @@ Retry:
McLaunchLog("开始微软登录步骤 1/6(原始登录)")
Dim PrepareJson As JObject = GetJson(NetRequestByClientRetry("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", HttpMethod.Post,
Content:=$"client_id={OAuthClientId}&tenant=/consumers&scope=XboxLive.signin%20offline_access",
ContentType:="application/x-www-form-urlencoded"))
ContentType:="application/x-www-form-urlencoded", RequireJson:=True))
McLaunchLog("网页登录地址:" & PrepareJson("verification_uri").ToString)
'弹窗
@@ -891,10 +903,18 @@ Retry:
ContentType:="application/x-www-form-urlencoded",
Headers:={{"Accept-Language", "en-US,en;q=0.5"}, {"X-Requested-With", "XMLHttpRequest"}},
ThreadCount:=2)
Catch ex As Exception
If ex.Message.ContainsF("must sign in again", True) OrElse ex.Message.ContainsF("password expired", True) OrElse
(ex.Message.Contains("refresh_token") AndAlso ex.Message.Contains("is not valid")) Then '#269
Catch ex As ResponsedWebException
'修改错误列表时,同时检查 MyMsgLogin.xaml.vb 中的对应代码
Dim Response = ex.Response
If Response.ContainsF("must sign in again", True) OrElse Response.ContainsF("password expired", True) OrElse
(Response.Contains("refresh_token") AndAlso Response.Contains("is not valid")) Then '#269
Return {"Relogin", ""}
ElseIf Response.Contains("Account security interrupt") Then
MyMsgBox("该账号由于安全问题无法登陆,请前往微软账户页获取更多信息。", "登录失败", "我知道了", IsWarn:=True)
Throw New Exception("$$")
ElseIf Response.Contains("service abuse") Then
MyMsgBox("非常抱歉,该账号已被微软封禁,无法登录。", "登录失败", "我知道了", IsWarn:=True)
Throw New Exception("$$")
Else
Throw
End If
@@ -919,7 +939,7 @@ Retry:
""TokenType"": ""JWT""
}"
Dim Result As String = NetRequestByClientMultiple("https://user.auth.xboxlive.com/user/authenticate", HttpMethod.Post,
Content:=Request, ContentType:="application/json")
Content:=Request, ContentType:="application/json", RequireJson:=True)
Dim ResultJson As JObject = GetJson(Result)
Dim XBLToken As String = ResultJson("Token").ToString
Return XBLToken
@@ -941,21 +961,21 @@ Retry:
Dim Result As String
Try
Result = NetRequestByClientMultiple("https://xsts.auth.xboxlive.com/xsts/authorize", HttpMethod.Post,
Content:=Request, ContentType:="application/json")
Catch ex As Net.WebException
Content:=Request, ContentType:="application/json", RequireJson:=True)
Catch ex As ResponsedWebException
'参考 https://github.com/PrismarineJS/prismarine-auth/blob/master/src/common/Constants.js
If ex.Message.Contains("2148916227") Then
If ex.Response.Contains("2148916227") Then
MyMsgBox("该账号似乎已被微软封禁,无法登录。", "登录失败", "我知道了", IsWarn:=True)
Throw New Exception("$$")
ElseIf ex.Message.Contains("2148916233") Then
ElseIf ex.Response.Contains("2148916233") Then
If MyMsgBox("你尚未注册 Xbox 账户,请在注册后再登录。", "登录提示", "注册", "取消") = 1 Then
OpenWebsite("https://signup.live.com/signup")
End If
Throw New Exception("$$")
ElseIf ex.Message.Contains("2148916235") Then
MyMsgBox($"你的网络所在的国家或地区无法登录微软账号。{vbCrLf}请使用加速器或 VPN。", "登录失败", "我知道了")
ElseIf ex.Response.Contains("2148916235") Then
MyMsgBox($"你的网络所在的国家或地区无法登录微软账号。{vbCrLf}请使用加速器或 VPN,然后再试。", "登录失败", "我知道了")
Throw New Exception("$$")
ElseIf ex.Message.Contains("2148916238") Then
ElseIf ex.Response.Contains("2148916238") Then
If MyMsgBox("该账号年龄不足,你需要先修改出生日期,然后才能登录。" & vbCrLf &
"该账号目前填写的年龄是否在 13 岁以上?", "登录提示", "13 岁以上", "12 岁以下", "我不知道") = 1 Then
OpenWebsite("https://account.live.com/editprof.aspx")
@@ -972,15 +992,11 @@ Retry:
End If
End Try
Try '这个 Try 块仅为了追踪 #6683 而添加
Dim ResultJson As JObject = GetJson(Result)
Dim XSTSToken As String = ResultJson("Token").ToString
Dim UHS As String = ResultJson("DisplayClaims")("xui")(0)("uhs").ToString
Return {XSTSToken, UHS}
Catch
Log("[Launch] 返回内容:" & vbCrLf & Result)
Throw
End Try
Dim ResultJson As JObject = GetJson(Result)
Return {
ResultJson("Token"), 'XSTSToken
ResultJson("DisplayClaims")("xui")(0)("uhs") 'UHS
}
End Function
'微软登录步骤 4:从 {XSTSToken, UHS} 获取 Minecraft AccessToken
Private Function MsLoginStep4(Tokens As String()) As String
@@ -990,9 +1006,9 @@ Retry:
Dim Result As String
Try
Result = NetRequestByClientRetry("https://api.minecraftservices.com/authentication/login_with_xbox", HttpMethod.Post,
Content:=Request, ContentType:="application/json")
Content:=Request, ContentType:="application/json", RequireJson:=True)
Catch ex As Net.WebException
Dim Message As String = GetExceptionSummary(ex)
Dim Message As String = ex.GetBrief()
If Message.Contains("(429)") Then
Log(ex, "微软登录第 4 步汇报 429")
Throw New Exception("$登录尝试太过频繁,请等待几分钟后再试!")
@@ -1004,16 +1020,14 @@ Retry:
End If
End Try
Dim ResultJson As JObject = GetJson(Result)
Dim AccessToken As String = ResultJson("access_token").ToString
Return AccessToken
Return GetJson(Result)("access_token").ToString
End Function
'微软登录步骤 5:验证微软账号是否持有 MC,这也会刷新 XGP
Private Sub MsLoginStep5(AccessToken As String)
McLaunchLog("开始微软登录步骤 5/6")
Dim Result As String = NetRequestByClientMultiple("https://api.minecraftservices.com/entitlements/mcstore",
ContentType:="application/json", ThreadCount:=2, Headers:={{"Authorization", "Bearer " & AccessToken}})
ContentType:="application/json", ThreadCount:=2, Headers:={{"Authorization", "Bearer " & AccessToken}}, RequireJson:=True)
Try
Dim ResultJson As JObject = GetJson(Result)
If Not (ResultJson.ContainsKey("items") AndAlso ResultJson("items").Any) Then
@@ -1035,9 +1049,9 @@ Retry:
Dim Result As String
Try
Result = NetRequestByClientMultiple("https://api.minecraftservices.com/minecraft/profile",
ContentType:="application/json", ThreadCount:=2, Headers:={{"Authorization", "Bearer " & AccessToken}})
Catch ex As Net.WebException
Dim Message As String = GetExceptionSummary(ex)
ContentType:="application/json", ThreadCount:=2, Headers:={{"Authorization", "Bearer " & AccessToken}}, RequireJson:=True)
Catch ex As WebException
Dim Message As String = ex.GetBrief()
If Message.Contains("(429)") Then
Log(ex, "微软登录第 6 步汇报 429")
Throw New Exception("$登录尝试太过频繁,请等待几分钟后再试!")
@@ -1108,7 +1122,7 @@ Retry:
If Len(Uuid) = 32 Then Return Uuid
'从官网获取
Try
Dim GotJson As JObject = GetJson(NetRequestByClientRetry("https://api.mojang.com/users/profiles/minecraft/" & Name))
Dim GotJson As JObject = GetJson(NetRequestByClientRetry("https://api.mojang.com/users/profiles/minecraft/" & Name, RequireJson:=True))
If GotJson Is Nothing Then Throw New FileNotFoundException("正版玩家档案不存在(" & Name & ")")
Uuid = If(GotJson("id"), "")
Catch ex As Exception
@@ -1364,13 +1378,13 @@ Retry:
McLaunchLog("新版 Game 参数获取成功")
End If
'编码参数(#4700、#5892、#5909)
If McLaunchJavaSelected.VersionCode >= 18 Then 'Dfile.encoding 需要放在 Dstdout.encoding 后面(#6934)
If Not Arguments.Contains("-Dfile.encoding=") Then Arguments = "-Dfile.encoding=COMPAT " & Arguments
End If
If McLaunchJavaSelected.VersionCode > 8 Then
If Not Arguments.Contains("-Dstdout.encoding=") Then Arguments = "-Dstdout.encoding=UTF-8 " & Arguments
If Not Arguments.Contains("-Dstderr.encoding=") Then Arguments = "-Dstderr.encoding=UTF-8 " & Arguments
End If
If McLaunchJavaSelected.VersionCode >= 18 Then
If Not Arguments.Contains("-Dfile.encoding=") Then Arguments = "-Dfile.encoding=COMPAT " & Arguments
End If
'MJSB
Arguments = Arguments.Replace(" -Dos.name=Windows 10", " -Dos.name=""Windows 10""")
'全屏
@@ -1473,6 +1487,9 @@ Retry:
DataList.Add(Version.JsonObject("mainClass"))
End If
'处理 DataList 的换行符
DataList = DataList.Select(Function(d) d.Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, " ").Trim).ToList
Return Join(DataList, " ")
End Function
Private Function McLaunchArgumentsJvmNew(Version As McVersion) As String
@@ -1516,9 +1533,7 @@ NextVersion:
'Authlib-Injector
If McLoginLoader.Output.Type = "Auth" Then
If McLaunchJavaSelected.VersionCode >= 6 Then DataList.Add("-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT") '信任系统根证书(5252#)
Dim Server As String = If(McLoginLoader.Input.Type = McLoginType.Legacy,
"http://hiperauth.tech/api/yggdrasil-hiper/", 'HiPer 登录
Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent))
Dim Server As String = Setup.Get("VersionServerAuthServer", Version:=McVersionCurrent)
Try
Dim Response As String = NetRequestByClientRetry(Server, Encoding:=Encoding.UTF8)
DataList.Insert(0, "-javaagent:""" & PathPure & "authlib-injector.jar""=" & Server &
@@ -1540,7 +1555,7 @@ NextVersion:
'如果不合并,会导致 Forge 1.17 启动无效,它有两个 --add-exports,进一步导致其中一个在后面被去重
Dim DeDuplicateDataList As New List(Of String)
For i = 0 To DataList.Count - 1
Dim CurrentEntry As String = DataList(i)
Dim CurrentEntry As String = DataList(i).Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, " ").Trim
If DataList(i).StartsWithF("-") Then
Do While i < DataList.Count - 1
If DataList(i + 1).StartsWithF("-") Then
@@ -1692,6 +1707,7 @@ NextVersion:
GameArguments.Add("${access_token}", McLoginLoader.Output.AccessToken)
GameArguments.Add("${auth_session}", McLoginLoader.Output.AccessToken)
GameArguments.Add("${user_type}", "msa") '#1221
GameArguments.Add("${primary_jar}", Version.Path & Version.Name & ".jar") '#6942
'窗口尺寸参数
Dim GameSize As Size
@@ -1780,7 +1796,7 @@ NextVersion:
File.Delete(FilePath)
Catch ex As UnauthorizedAccessException
McLaunchLog("删除原 dll 访问被拒绝,这通常代表有一个 MC 正在运行,跳过解压:" & FilePath)
McLaunchLog("实际的错误信息:" & GetExceptionSummary(ex))
McLaunchLog("实际的错误信息:" & ex.GetDetail())
Exit For
End Try
End If
@@ -1800,7 +1816,7 @@ NextVersion:
File.Delete(FileName)
Catch ex As UnauthorizedAccessException
McLaunchLog("删除多余文件访问被拒绝,跳过删除步骤")
McLaunchLog("实际的错误信息:" & GetExceptionSummary(ex))
McLaunchLog("实际的错误信息:" & ex.GetDetail())
Return
End Try
Next
@@ -1811,9 +1827,9 @@ NextVersion:
''' </summary>
Private Function GetNativesFolder() As String
Dim Result As String = McVersionCurrent.Path & McVersionCurrent.Name & "-natives"
If IsGBKEncoding OrElse Result.IsASCII() Then Return Result
If IsGBKEncoding OrElse Result.IsASCII() Then Return ShortenPath(Result)
Result = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\bin\natives"
If Result.IsASCII() Then Return Result
If Result.IsASCII() Then Return ShortenPath(Result)
Return OsDrive & "ProgramData\PCL\natives"
End Function
@@ -1826,7 +1842,7 @@ NextVersion:
'要求 Java 使用高性能显卡
If Setup.Get("LaunchAdvanceGraphicCard") Then
Try
SetGPUPreference(McLaunchJavaSelected.PathJavaw)
SetGPUPreference(McLaunchJavaSelected.PathJava)
SetGPUPreference(PathWithName)
Catch ex As Exception
If IsAdmin() Then
@@ -1834,7 +1850,7 @@ NextVersion:
Else
Log(ex, "直接调整显卡设置失败,将以管理员权限重启 PCL 再次尝试")
Try
If RunAsAdmin($"--gpu ""{McLaunchJavaSelected.PathJavaw}""") = ProcessReturnValues.TaskDone Then
If RunAsAdmin($"--gpu ""{McLaunchJavaSelected.PathJava}""") = ProcessReturnValues.TaskDone Then
McLaunchLog("以管理员权限重启 PCL 并调整显卡设置成功")
Else
Throw New Exception("调整过程中出现异常")
@@ -2143,14 +2159,15 @@ IgnoreCustomSkin:
'执行自定义命令
If CustomCommandGlobal <> "" Then
McLaunchLog("正在执行全局自定义命令:" & CustomCommandGlobal)
Dim CustomProcess As New Process
Dim CustomProcess As Process = Nothing
Try
CustomProcess.StartInfo.FileName = "cmd.exe"
CustomProcess.StartInfo.Arguments = "/c """ & CustomCommandGlobal & """"
CustomProcess.StartInfo.WorkingDirectory = ShortenPath(PathMcFolder)
CustomProcess.StartInfo.UseShellExecute = False
CustomProcess.StartInfo.CreateNoWindow = True
CustomProcess.Start()
CustomProcess = StartProcess(New ProcessStartInfo With {
.FileName = "cmd.exe",
.Arguments = $"/c ""{CustomCommandGlobal}""",
.WorkingDirectory = PathMcFolder,
.UseShellExecute = False,
.CreateNoWindow = True
})
If Setup.Get("LaunchAdvanceRunWait") Then
Do Until CustomProcess.HasExited OrElse Loader.IsAborted
Thread.Sleep(10)
@@ -2159,7 +2176,7 @@ IgnoreCustomSkin:
Catch ex As Exception
Log(ex, "执行全局自定义命令失败", LogLevel.Hint)
Finally
If Not CustomProcess.HasExited AndAlso Loader.IsAborted Then
If CustomProcess IsNot Nothing AndAlso Not CustomProcess.HasExited AndAlso Loader.IsAborted Then
McLaunchLog("由于取消启动,已强制结束自定义命令 CMD 进程") '#1183
CustomProcess.Kill()
End If
@@ -2167,14 +2184,15 @@ IgnoreCustomSkin:
End If
If CustomCommandVersion <> "" Then
McLaunchLog("正在执行版本自定义命令:" & CustomCommandVersion)
Dim CustomProcess As New Process
Dim CustomProcess As Process = Nothing
Try
CustomProcess.StartInfo.FileName = "cmd.exe"
CustomProcess.StartInfo.Arguments = "/c """ & CustomCommandVersion & """"
CustomProcess.StartInfo.WorkingDirectory = ShortenPath(PathMcFolder)
CustomProcess.StartInfo.UseShellExecute = False
CustomProcess.StartInfo.CreateNoWindow = True
CustomProcess.Start()
CustomProcess = StartProcess(New ProcessStartInfo With {
.FileName = "cmd.exe",
.Arguments = $"/c ""{CustomCommandVersion}""",
.WorkingDirectory = PathMcFolder,
.UseShellExecute = False,
.CreateNoWindow = True
})
If Setup.Get("VersionAdvanceRunWait", Version:=McVersionCurrent) Then
Do Until CustomProcess.HasExited OrElse Loader.IsAborted
Thread.Sleep(10)
@@ -2183,7 +2201,7 @@ IgnoreCustomSkin:
Catch ex As Exception
Log(ex, "执行版本自定义命令失败", LogLevel.Hint)
Finally
If Not CustomProcess.HasExited AndAlso Loader.IsAborted Then
If CustomProcess IsNot Nothing AndAlso Not CustomProcess.HasExited AndAlso Loader.IsAborted Then
McLaunchLog("由于取消启动,已强制结束自定义命令 CMD 进程") '#1183
CustomProcess.Kill()
End If
@@ -2194,8 +2212,7 @@ IgnoreCustomSkin:
Private Sub McLaunchRun(Loader As LoaderTask(Of Integer, Process))
'启动信息
Dim GameProcess = New Process()
Dim StartInfo As New ProcessStartInfo(McLaunchJavaSelected.PathJavaw)
Dim StartInfo As New ProcessStartInfo(McLaunchJavaSelected.PathJava) '使用 javaw.exe 会导致 #6263
'设置环境变量
Dim Paths As New List(Of String)(StartInfo.EnvironmentVariables("Path").Split(";"))
@@ -2204,17 +2221,16 @@ IgnoreCustomSkin:
StartInfo.EnvironmentVariables("appdata") = ShortenPath(PathMcFolder)
'设置其他参数
StartInfo.WorkingDirectory = ShortenPath(McVersionCurrent.PathIndie)
StartInfo.WorkingDirectory = McVersionCurrent.PathIndie
StartInfo.UseShellExecute = False
StartInfo.RedirectStandardOutput = True
StartInfo.RedirectStandardError = True
StartInfo.CreateNoWindow = False
StartInfo.CreateNoWindow = True
StartInfo.Arguments = McLaunchArgument
GameProcess.StartInfo = StartInfo
'开始进程
GameProcess.Start()
McLaunchLog("已启动游戏进程:" & McLaunchJavaSelected.PathJavaw)
Dim GameProcess = StartProcess(StartInfo)
McLaunchLog("已启动游戏进程:" & McLaunchJavaSelected.PathJava)
If Loader.IsAborted Then
McLaunchLog("由于取消启动,已强制结束游戏进程") '#1631
GameProcess.Kill()
@@ -86,7 +86,7 @@ Public Module ModMinecraft
Next
If Not Renamed Then CacheMcFolderList.Add(New McFolder With {.Name = Name, .Path = Path, .Type = McFolderType.Custom})
Catch ex As Exception
MyMsgBox("失效的 Minecraft 文件夹:" & vbCrLf & Path & vbCrLf & vbCrLf & GetExceptionSummary(ex), "Minecraft 文件夹失效", IsWarn:=True)
MyMsgBox("失效的 Minecraft 文件夹:" & vbCrLf & Path & vbCrLf & vbCrLf & ex.GetBrief(), "Minecraft 文件夹失效", IsWarn:=True)
Log(ex, $"无法访问 Minecraft 文件夹 {Path}")
End Try
Next
@@ -695,7 +695,7 @@ Recheck:
Catch ex As Exception
Log(ex, "依赖版本检查出错(" & Name & ")")
State = McVersionState.Error
Info = "未知错误:" & GetExceptionSummary(ex)
Info = "未知错误:" & ex.GetBrief()
Return False
End Try
@@ -808,7 +808,7 @@ ExitDataLoad:
WriteIni(Path & "PCL\Setup.ini", "VersionOriginalSub", Version.McCodeSub)
End If
Catch ex As Exception
Info = "未知错误:" & GetExceptionSummary(ex)
Info = "未知错误:" & ex.GetBrief()
Logo = PathImage & "Blocks/RedstoneBlock.png"
State = McVersionState.Error
Log(ex, "加载版本失败(" & Name & ")", LogLevel.Feedback)
@@ -989,7 +989,7 @@ ExitDataLoad:
If ToString = "" Then
Return "原版 " & McName
Else
Return McName & ToString & If(ModeDebug, " (" & SortCode & "#)", "")
Return McName & ToString
End If
End Function
@@ -1186,6 +1186,7 @@ OnLoaded:
If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 3000))
Catch ex As ThreadInterruptedException
Catch ex As Exception
If Loader.IsAborted Then Return '#5617
WriteIni(Path & "PCL.ini", "VersionCache", "") '要求下次重新加载
Log(ex, "加载 .minecraft 版本列表失败", LogLevel.Feedback)
End Try
@@ -1592,11 +1593,11 @@ OnLoaded:
''' <summary>
''' 获取 Uuid 对应的皮肤文件地址,失败将抛出异常。
''' </summary>
Public Function McSkinGetAddress(Uuid As String, Type As String) As String
If Uuid = "" Then Throw New Exception("Uuid 为空。")
If Uuid.StartsWithF("00000") Then Throw New Exception("离线 Uuid 无正版皮肤文件。")
Public Function McSkinGetAddress(UUID As String, Type As String) As String
If UUID = "" Then Throw New Exception("UUID 为空。")
If UUID.StartsWithF("00000") AndAlso Type <> "Auth" Then Throw New Exception("离线 UUID 无正版皮肤文件:" & UUID)
'尝试读取缓存
Dim CacheSkinAddress As String = ReadIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", Uuid)
Dim CacheSkinAddress As String = ReadIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", UUID)
If Not CacheSkinAddress = "" Then Return CacheSkinAddress
'获取皮肤地址
Dim Url As String
@@ -1610,7 +1611,7 @@ OnLoaded:
Case Else
Throw New ArgumentException("皮肤地址种类无效:" & If(Type, "null"))
End Select
Dim SkinString = NetRequestByClientRetry(Url & Uuid)
Dim SkinString = NetRequestByClientRetry(Url & UUID, RequireJson:=True)
If SkinString = "" Then Throw New Exception("皮肤返回值为空,可能是未设置自定义皮肤的用户")
'处理皮肤地址
Dim SkinValue As String
@@ -1635,8 +1636,8 @@ OnLoaded:
SkinValue = If(SkinUrl.Contains("minecraft.net/"), SkinUrl.Replace("http://", "https://"), SkinUrl)
End If
'保存缓存
WriteIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", Uuid, SkinValue)
Log("[Skin] UUID " & Uuid & " 对应的皮肤文件为 " & SkinValue)
WriteIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", UUID, SkinValue)
Log("[Skin] UUID " & UUID & " 对应的皮肤文件为 " & SkinValue)
Return SkinValue
End Function
@@ -1966,7 +1967,7 @@ OnLoaded:
Try
Log("[Minecraft] 开始获取统一通行证下载信息")
'测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/
DownloadInfo = GetJson(NetRequestByClientRetry("https://auth.mc-user.com:233/" & Setup.Get("VersionServerNide", Version:=Version)))
DownloadInfo = GetJson(NetRequestByClientRetry("https://auth.mc-user.com:233/" & Setup.Get("VersionServerNide", Version:=Version), RequireJson:=True))
Catch ex As Exception
Log(ex, "获取统一通行证下载信息失败")
End Try
@@ -1983,16 +1984,20 @@ OnLoaded:
'Authlib-Injector 文件
If Setup.Get("VersionServerLogin", Version:=Version) = 4 Then
Dim TargetFile = PathPure & "\authlib-injector.jar"
Dim TargetFile = PathPure & "authlib-injector.jar"
Dim DownloadInfo As JObject = Nothing
'获取下载信息
Try
Log("[Minecraft] 开始获取 Authlib-Injector 下载信息")
DownloadInfo = GetJson(NetRequestByClientRetry(
"https://authlib-injector.yushi.moe/artifact/latest.json",
BackupUrl:="https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json"))
BackupUrl:="https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json", RequireJson:=True))
Catch ex As Exception
Log(ex, "获取 Authlib-Injector 下载信息失败")
If File.Exists(TargetFile) Then
Log(ex, "获取 Authlib-Injector 下载信息失败")
Else
Throw New Exception("获取 Authlib-Injector 下载信息失败", ex)
End If
End Try
'校验文件
If DownloadInfo IsNot Nothing Then
@@ -2415,7 +2420,12 @@ NextEntry:
Public Function FilterUserName(Raw As String, FilterChar As Char) As String
If Raw.Contains(":\Users\") Then
For Each Token In RegexSearch(Raw, "(?<=:\\Users\\)[^\\]+")
Raw = Raw.Replace(Token, New String(FilterChar, Token.Count))
Raw = Raw.Replace("\Users\" & Token, "\Users\" & New String(FilterChar, Token.Count))
Next
End If
If Raw.Contains(":/Users/") Then
For Each Token In RegexSearch(Raw, "(?<=:/Users/)[^/]+")
Raw = Raw.Replace("/Users/" & Token, "/Users/" & New String(FilterChar, Token.Count))
Next
End If
Return Raw
@@ -73,7 +73,7 @@ Public Module ModMod
Get
If _Name Is Nothing Then Load()
If _Name Is Nothing Then _Name = _ModId
If _Name Is Nothing Then _Name = GetFileNameWithoutExtentionFromPath(Path)
If _Name Is Nothing Then _Name = IO.Path.GetFileNameWithoutExtension(Path)
Return _Name
End Get
Set(value As String)
@@ -688,7 +688,7 @@ Finished:
''' </summary>
Public ReadOnly Property CanUpdate As Boolean
Get
Return Not Setup.Get("UiHiddenFunctionModUpdate") AndAlso ChangelogUrls.Any()
Return Not Setup.Get("UiHiddenFunctionModUpdate") AndAlso Not Setup.Get("VersionAdvanceDisableModUpdate", Version:=PageVersionLeft.Version) AndAlso ChangelogUrls.Any()
End Get
End Property
@@ -1113,8 +1113,8 @@ Finished:
End Sub, "Mod List Detail Loader CurseForge")
'等待线程结束
Do Until EndedThreadCount = 2
If Loader.IsAborted Then Return
Thread.Sleep(10)
If Loader.IsAborted Then Return
Loop
'保存缓存
Mods = Mods.Where(Function(m) m.Comp IsNot Nothing).ToList()
@@ -1126,6 +1126,7 @@ Finished:
Next
WriteFile(PathTemp & "Cache\LocalMod.json", Cache.ToString(If(ModeDebug, Newtonsoft.Json.Formatting.Indented, Newtonsoft.Json.Formatting.None)))
'刷新边栏
If Loader.IsAborted Then Return
If FrmVersionMod?.Filter = PageVersionMod.FilterType.CanUpdate Then
RunInUi(Sub() FrmVersionMod?.RefreshUI()) '同步 “可更新” 列表 (#4677)
Else
@@ -1212,7 +1213,7 @@ Finished:
If ReqVersionHead = ReqVersionTail Then
VersionRequire = "应为 " & ReqVersionHead
ElseIf ReqVersionHead.Contains(".") AndAlso ReqVersionTail.Contains(".") Then
VersionRequire = "应为 " & ReqVersionHead & " 至 " & ReqVersionTail
VersionRequire = $"应为 {ReqVersionHead} 至 {ReqVersionTail}"
ElseIf ReqVersionHead.Contains(".") Then
If ReqVersionHeadCanEqual Then
VersionRequire = "最低应为 " & ReqVersionHead
@@ -1230,7 +1231,7 @@ Finished:
End If
'检查前置 Mod 是否存在,并获取其版本
If Not CurrentDependencies.ContainsKey(ReqId) Then
Result.Add("缺少前置 Mod:" & ReqId & If(VersionRequire = "", "", ",其版本" & VersionRequire) & "。" & vbCrLf & " - " & ModEntity.FileName)
Result.Add($"缺少前置 Mod:{ReqId}{If(VersionRequire = "", "", ",其版本" & VersionRequire)}。{vbCrLf} - {ModEntity.FileName}")
Continue For
End If
Dim CurrentVersion As String = If(CurrentDependencies(ReqId)(0), "0.0")
@@ -1239,7 +1240,7 @@ Finished:
If ReqVersionHead.Contains(".") Then
If VersionSortInteger(ReqVersionHead, CurrentVersion) > If(ReqVersionHeadCanEqual, 0, -1) Then
Result.Add(ReqId.Substring(0, 1).ToUpper & ReqId.Substring(1) & " 版本过低,其版本" & VersionRequire & ",而当前版本为 " & CurrentVersion & "。" & vbCrLf &
" - " & ModEntity.FileName & If(ReqId <> "minecraft" AndAlso ReqId <> "forge", vbCrLf & " - 前置:" & CurrentDependencies(ReqId)(1), ""))
" - " & ModEntity.FileName & If(ReqId <> "minecraft" AndAlso ReqId <> "forge", $"{vbCrLf} - 前置:{CurrentDependencies(ReqId)(1)}", ""))
Continue For
End If
End If
@@ -1247,26 +1248,26 @@ Finished:
If ReqVersionTail.Contains(".") Then
If VersionSortInteger(CurrentVersion, ReqVersionTail) > If(ReqVersionTailCanEqual, 0, -1) Then
Result.Add(ReqId.Substring(0, 1).ToUpper & ReqId.Substring(1) & " 版本过高,其版本" & VersionRequire & ",而当前版本为 " & CurrentVersion & "。" & vbCrLf &
" - " & ModEntity.FileName & If(ReqId <> "minecraft" AndAlso ReqId <> "forge", vbCrLf & " - 前置:" & CurrentDependencies(ReqId)(1), ""))
" - " & ModEntity.FileName & If(ReqId <> "minecraft" AndAlso ReqId <> "forge", $"{vbCrLf} - 前置:{CurrentDependencies(ReqId)(1)}", ""))
Continue For
End If
End If
Else
If Not CurrentDependencies.ContainsKey(Dependency.Key) Then
Result.Add("缺少前置 Mod:" & Dependency.Key & "。" & vbCrLf & " - " & ModEntity.FileName)
Result.Add($"缺少前置 Mod:{Dependency.Key}。{vbCrLf} - {ModEntity.FileName}")
Continue For
End If
End If
Next
Catch ex As Exception
Result.Add("检查 Mod 时出错:" & GetExceptionSummary(ex) & vbCrLf & " - " & ModEntity.FileName)
Result.Add($"检查 Mod 时出错:{ex.GetBrief()}{vbCrLf} - {ModEntity.FileName}")
Log(ex, "检查 Mod 时出错")
End Try
Next
If Not Result.Any() Then
Log("[Minecraft] Mod 检查未发现异常")
Else
Log("[Minecraft] Mod 检查异常结果:" & vbCrLf & Join(Result, vbCrLf))
Log($"[Minecraft] Mod 检查异常结果:{vbCrLf}{Join(Result, vbCrLf)}")
End If
Return Result
End Function
@@ -72,7 +72,7 @@ Public Module ModModpack
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
If ex.GetDetail(True).Contains("Error.WinIOError") Then
Throw New Exception("打开整合包文件失败", ex)
ElseIf File.EndsWithF(".rar", True) Then
Throw New Exception("PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", ex)
@@ -158,6 +158,7 @@ Retry:
If File.Exists(OverridesIni) Then
WriteIni(OverridesIni, "VersionArgumentIndie", 1) '开启版本隔离
WriteIni(OverridesIni, "VersionArgumentIndieV2", True)
WriteIni(OverridesIni, "IsStar", False)
CopyFile(OverridesIni, VersionIni) '覆写已有的 ini
Else
WriteIni(VersionIni, "VersionArgumentIndie", 1) '开启版本隔离
@@ -165,6 +166,15 @@ Retry:
End If
IniClearCache(VersionIni) '重置缓存,避免被安装过程中写入的 ini 覆盖
End Sub
''' <summary>
''' 弹窗提示整合包中存在不兼容的加载器。
''' 如果取消,则抛出 CancelledException。
''' </summary>
''' <exception cref="CancelledException" />
Private Sub NotifyIncompatibleLoader(LoaderName As String)
If MyMsgBox($"整合包中存在不兼容的加载器:{LoaderName}{vbCrLf}如果你知道如何手动安装它,可以先选择跳过,然后在整合包下载结束后手动安装。",
"不兼容的加载器", "取消", $"不安装 {LoaderName} 并继续") = 1 Then Throw New CancelledException
End Sub
#Region "不同类型整合包的安装方法"
@@ -210,7 +220,8 @@ Retry:
Log("[ModPack] 整合包 Fabric 版本:" & Id)
FabricVersion = Id.Replace("fabric-", "")
Else
Log("[ModPack] 未知 Mod 加载器:" & Id)
'ElseIf Id.StartsWithF("quilt-") Then
NotifyIncompatibleLoader(Id)
End If
Next
'解压
@@ -324,7 +335,7 @@ Retry:
File.Delete(Target)
End If
Next
If File.Exists(FileAddress) AndAlso GetFileNameWithoutExtentionFromPath(FileAddress) = "modpack" Then
If File.Exists(FileAddress) AndAlso IO.Path.GetFileNameWithoutExtension(FileAddress) = "modpack" Then
Log("[ModPack] 删除安装整合包文件:" & FileAddress)
File.Delete(FileAddress)
End If
@@ -375,12 +386,9 @@ Retry:
Case "fabric-loader" 'eg. 0.14.14
FabricVersion = Entry.Value.ToString
Log("[ModPack] 整合包 Fabric 版本:" & FabricVersion)
Case "quilt-loader" 'eg. 1.0.0
Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
Throw New CancelledException
Case Else
Hint($"无法安装整合包,其中出现了未知的 Mod 加载器 {Entry.Value}!", HintType.Critical)
Throw New CancelledException
'Case "quilt-loader" 'eg. 1.0.0
NotifyIncompatibleLoader(Entry.Name)
End Select
Next
'获取版本名
@@ -468,7 +476,7 @@ Retry:
File.Delete(Target)
End If
Next
If File.Exists(FileAddress) AndAlso GetFileNameWithoutExtentionFromPath(FileAddress) = "modpack" Then
If File.Exists(FileAddress) AndAlso IO.Path.GetFileNameWithoutExtension(FileAddress) = "modpack" Then
Log("[ModPack] 删除安装整合包文件:" & FileAddress)
File.Delete(FileAddress)
End If
@@ -632,7 +640,8 @@ Retry:
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
If Not Component.Contains("uid") Then Continue For
Select Case Component("uid").ToString
Case "org.lwjgl"
Log("[ModPack] 已跳过 LWJGL 项")
Case "net.minecraft"
@@ -643,9 +652,9 @@ Retry:
Request.NeoForgeVersion = Component("version")
Case "net.fabricmc.fabric-loader"
Request.FabricVersion = Component("version")
Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical)
Throw New CancelledException
Case Else
'Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
NotifyIncompatibleLoader(Component("uid"))
End Select
Next
'构造加载器
@@ -786,7 +795,7 @@ Retry:
Log("[Modpack] 找到压缩包中附带的启动器:" & Launcher)
If MyMsgBox($"整合包里似乎自带了启动器,是否换用它继续安装?{vbCrLf}即将打开:{Launcher}", "换用整合包启动器?", "换用", "不换用") = 1 Then
OpenExplorer(TargetFolder)
ShellOnly(Launcher, "--wait") '要求等待已有的 PCL 退出
StartProcess(Launcher, "--wait") '要求等待已有的 PCL 退出
Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序")
FrmMain.EndProgram(False)
Return
@@ -349,14 +349,14 @@
State = MinecraftState.Crashed
'崩溃分析
WatcherLog("Minecraft 已崩溃,将在 2 秒后开始崩溃分析")
Hint("检测到 Minecraft 出现错误,错误分析已开始……")
Hint("检测到 Minecraft 出现错误,错误分析已开始……", HintType.Critical)
FeedbackInfo()
RunInNewThread(
Sub()
Try
Thread.Sleep(2000)
WatcherLog("崩溃分析开始")
Dim Analyzer As New CrashAnalyzer(PID)
Dim Analyzer As New CrashAnalyzer(Version)
Analyzer.Collect(Version.PathIndie, LatestLog.ToList)
Analyzer.Prepare()
Analyzer.Analyze(Version)
+6 -2
View File
@@ -45,9 +45,9 @@
Dim Info As New ProcessStartInfo With {
.Arguments = If(Data.Length >= 2, Data(1), ""),
.FileName = Location,
.WorkingDirectory = ShortenPath(WorkingDir)
.WorkingDirectory = WorkingDir
}
Process.Start(Info)
StartProcess(Info)
End If
Catch ex As Exception
Log(ex, "执行打开类自定义事件失败", LogLevel.Msgbox)
@@ -115,6 +115,10 @@
PageOtherTest.StartCustomDownload(Data(0), "未知")
End Try
Case "修改设置"
Setup.Set(Data(0), Data(1))
Hint($"已写入设置:{Data(0)} → {Data(1)}", HintType.Finish)
Case Else
MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败")
End Select
@@ -397,12 +397,6 @@ EndHint:
'下载页面声明
Public FrmDownloadLeft As PageDownloadLeft
Public FrmDownloadInstall As PageDownloadInstall
Public FrmDownloadClient As PageDownloadClient
Public FrmDownloadOptiFine As PageDownloadOptiFine
Public FrmDownloadLiteLoader As PageDownloadLiteLoader
Public FrmDownloadForge As PageDownloadForge
Public FrmDownloadNeoForge As PageDownloadNeoForge
Public FrmDownloadFabric As PageDownloadFabric
Public FrmDownloadMod As PageDownloadMod
Public FrmDownloadPack As PageDownloadPack
Public FrmDownloadDataPack As PageDownloadDataPack
+2 -2
View File
@@ -79,7 +79,7 @@
If MusicState = MusicStates.Pause Then
FrmMain.BtnExtraMusic.Logo = Logo.IconPlay
FrmMain.BtnExtraMusic.LogoScale = 0.8
ToolTipText = "已暂停:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
ToolTipText = "已暂停:" & IO.Path.GetFileNameWithoutExtension(MusicCurrent)
If MusicAllList.Count > 1 Then
ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。"
Else
@@ -88,7 +88,7 @@
Else
FrmMain.BtnExtraMusic.Logo = Logo.IconMusic
FrmMain.BtnExtraMusic.LogoScale = 1
ToolTipText = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
ToolTipText = "正在播放:" & IO.Path.GetFileNameWithoutExtension(MusicCurrent)
If MusicAllList.Count > 1 Then
ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。"
Else
+12 -8
View File
@@ -12,6 +12,8 @@ Friend Module ModSecret
Public OAuthClientId As String = If(Environment.GetEnvironmentVariable("PCL_MS_CLIENT_ID"), "")
'CurseForge API Key
Public CurseForgeAPIKey As String = If(Environment.GetEnvironmentVariable("PCL_CURSEFORGE_API_KEY"), "")
'用于匿名数据收集的腾讯云日志服务上报 URL,形如 https://{region}.cls.tencentcs.com/track?topic_id={topic_id}
Public Const ClsBaseUrl As String = ""
Friend Sub SecretOnApplicationStart()
'提升 UI 线程优先级
@@ -78,15 +80,17 @@ Friend Module ModSecret
''' <summary>
''' 设置 Headers 的 UA、Referer。
''' </summary>
Friend Sub SecretHeadersSign(Url As String, ByRef Req As HttpRequestMessage, Optional UseBrowserUserAgent As Boolean = False)
If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then
Req.Headers.Add("User-Agent", "LogStatistic") '#4951
ElseIf UseBrowserUserAgent Then
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36")
Else
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode}")
Friend Sub SecretHeadersSign(Url As String, ByRef Req As HttpRequestMessage, Optional SimulateBrowserHeaders As Boolean = False)
If Not Req.Headers.UserAgent.Any Then
If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then
Req.Headers.Add("User-Agent", "LogStatistic") '#4951
ElseIf SimulateBrowserHeaders Then
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36")
Else
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode}")
End If
End If
Req.Headers.Add("Referer", $"http://{VersionCode}.open.pcl2.server/")
If Not SimulateBrowserHeaders Then Req.Headers.Add("Referer", $"http://{VersionCode}.open.pcl2.server/")
If Url.Contains("api.curseforge.com") Then Req.Headers.Add("x-api-key", CurseForgeAPIKey)
End Sub
+1 -1
View File
@@ -137,7 +137,7 @@ Public Class DragHelper
Dim fileCount As UInteger = DragQueryFile(wParam, UInteger.MaxValue, Nothing, 0)
ReDim dropFilePaths(CInt(fileCount) - 1)
For i As UInteger = 0 To fileCount - 1
For i As UInteger = 0 To CInt(fileCount) - 1
Dim sb As New StringBuilder(MAX_PATH)
Dim result As UInteger = DragQueryFile(wParam, i, sb, sb.Capacity)
If result > 0 Then dropFilePaths(i) = sb.ToString()
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*”
<Assembly: AssemblyVersion("2.10.5.0")>
<Assembly: AssemblyFileVersion("2.10.5.0")>
<Assembly: AssemblyVersion("2.10.8.0")>
<Assembly: AssemblyFileVersion("2.10.8.0")>
<Assembly: NeutralResourcesLanguage("")>
@@ -97,7 +97,7 @@
Dim Titles As New List(Of String)
If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
For Each Card As MyCard In FrmDownloadCompDetail.PanResults.Children
If Card.Title <> "" AndAlso Not Card.IsSwaped Then Titles.Add(Card.Title)
If Card.Title <> "" AndAlso Not Card.IsSwapped Then Titles.Add(Card.Title)
Next
Log("[Comp] 记录当前已展开的卡片:" & String.Join("、", Titles))
FrmMain.PageCurrent.Additional(1) = Titles
@@ -71,7 +71,7 @@
</StackPanel>
</local:MyCard>
<StackPanel x:Name="PanContent">
<local:MyHint x:Name="HintError" HasBorder="True" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,搜索结果可能不全。&#xa;请稍后重试,或使用 VPN 以改善网络环境。" Theme="Yellow" Margin="0,0,0,15" />
<local:MyHint x:Name="HintError" HasBorder="True" Text="无法连接到 Modrinth,所以目前仅显示了来自 CurseForge 的内容,搜索结果可能不全。&#xa;请稍后再试,或使用 VPN 改善网络环境。" Theme="Yellow" Margin="0,0,0,15" />
<local:MyCard x:Name="CardProjects" UseAnimation="False">
<StackPanel x:Name="PanProjects" Margin="12" />
</local:MyCard>
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadCompDetail"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<Grid Margin="25,25,25,10">
<Grid.RowDefinitions>
@@ -205,7 +205,7 @@
CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then
MyCard.StackInstall(NewStack, If(PageType = CompType.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为
Else
NewCard.IsSwaped = True
NewCard.IsSwapped = True
End If
'增加提示
If Pair.Key = "其他版本" Then
@@ -214,7 +214,7 @@
Next
'如果只有一张卡片,展开第一张卡片
If PanResults.Children.Count = 1 Then
CType(PanResults.Children(0), MyCard).IsSwaped = False
CType(PanResults.Children(0), MyCard).IsSwapped = False
End If
Catch ex As Exception
Log(ex, "可视化工程下载列表出错", LogLevel.Feedback)
@@ -290,7 +290,7 @@
Sub(MyLoader)
Select Case MyLoader.State
Case LoadState.Failed
Hint(MyLoader.Name & "失败:" & GetExceptionSummary(MyLoader.Error), HintType.Critical)
Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetBrief(), HintType.Critical)
Case LoadState.Aborted
Hint(MyLoader.Name & "已取消!", HintType.Info)
Case LoadState.Loading
@@ -424,7 +424,7 @@
If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
If Not Target.Contains("\") Then Return
'构造步骤加载器
Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " "
Dim LoaderName As String = Desc & "下载:" & IO.Path.GetFileNameWithoutExtension(Target) & " "
If Target <> DefaultFolder Then CachedFolder(Project.Type) = GetPathFromFullPath(Target)
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True})
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadDataPack"
PanScroll="{Binding ElementName=Content}">
PanScroll="Content">
<local:PageComp x:Name="Content" PageType="DataPack" TypeName="数据包" TypeNameSpaced="数据包">
<local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
<local:MyComboBoxItem Content="世界元素" Tag="/worldgen" />
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadMod"
PanScroll="{Binding ElementName=Content}">
PanScroll="Content">
<local:PageComp x:Name="Content" PageType="Mod" TypeName="Mod" TypeNameSpaced=" Mod ">
<local:MyComboBoxItem Content="全部" Tag="" IsSelected="True" />
<local:MyComboBoxItem Content="世界元素" Tag="406/worldgen" />
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadPack"
PanScroll="{Binding ElementName=Content}">
PanScroll="Content">
<local:PageComp x:Name="Content" PageType="ModPack" TypeName="整合包" TypeNameSpaced="整合包">
<local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
<local:MyComboBoxItem Tag="4484/" Content="多人" />
@@ -17,7 +17,7 @@
<local:MyComboBoxItem Tag="/kitchen-sink" Content="水槽包" />
<local:MyComboBoxItem Tag="4476/" Content="探索" />
<local:MyComboBoxItem Tag="4477/" Content="小游戏" />
<local:MyComboBoxItem Tag="4471/" Content="科幻" />
<local:MyComboBoxItem Tag="4474/" Content="科幻" />
<local:MyComboBoxItem Tag="4736/" Content="空岛" />
<local:MyComboBoxItem Tag="5128/" Content="原版改良" />
<local:MyComboBoxItem Tag="4487/" Content="FTB" ToolTip="由 FTB 官方发布" ToolTipService.HorizontalOffset="70" />
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadResourcePack"
PanScroll="{Binding ElementName=Content}">
PanScroll="Content">
<local:PageComp x:Name="Content" PageType="ResourcePack" TypeName="资源包" TypeNameSpaced="资源包">
<local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadShader"
PanScroll="{Binding ElementName=Content}">
PanScroll="Content">
<local:PageComp x:Name="Content" PageType="Shader" TypeName="光影包" TypeNameSpaced="光影包">
<local:MyComboBoxItem Tag="" Content="全部" IsSelected="True" />
@@ -449,7 +449,7 @@ pause"
'开始启动
SyncLock InstallSyncLock
Dim Info = New ProcessStartInfo With {
.FileName = Java.PathJavaw,
.FileName = Java.PathJava,
.Arguments = Arguments,
.UseShellExecute = False,
.CreateNoWindow = True,
@@ -571,7 +571,7 @@ pause"
Dim PageData As String
Try
PageData = NetRequestByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile,
Encoding:=New UTF8Encoding(False), Timeout:=15000, Accept:="text/html", UseBrowserUserAgent:=True)
Encoding:=New UTF8Encoding(False), Timeout:=15000, Accept:="text/html", SimulateBrowserHeaders:=True)
Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last)
@@ -735,7 +735,7 @@ Retry:
Dim PageData As String
Try
PageData = NetRequestByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile,
Encoding:=New UTF8Encoding(False), Timeout:=15000, Accept:="text/html", UseBrowserUserAgent:=True)
Encoding:=New UTF8Encoding(False), Timeout:=15000, Accept:="text/html", SimulateBrowserHeaders:=True)
Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources.Last)
@@ -1120,7 +1120,7 @@ Retry:
'开始启动
SyncLock InstallSyncLock
Dim Info = New ProcessStartInfo With {
.FileName = Java.PathJavaw,
.FileName = Java.PathJava,
.Arguments = Arguments,
.UseShellExecute = False,
.CreateNoWindow = True,
@@ -1647,7 +1647,7 @@ Retry:
Sub()
Try
Log("[Download] 刷新 Forge 推荐版本缓存开始")
Dim Result As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/promos")
Dim Result As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/promos", RequireJson:=True)
If Result.Length < 1000 Then Throw New Exception("获取的结果过短(" & Result & ")")
Dim ResultJson As JContainer = GetJson(Result)
'获取所有推荐版本列表
@@ -1991,7 +1991,7 @@ Retry:
Case LoadState.Finished
Hint(Loader.Name & "成功!", HintType.Finish)
Case LoadState.Failed
Hint(Loader.Name & "失败:" & GetExceptionSummary(Loader.Error), HintType.Critical)
Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Critical)
Case LoadState.Aborted
Hint(Loader.Name & "已取消!", HintType.Info)
End Select
@@ -2005,7 +2005,7 @@ Retry:
WriteIni(PathMcFolder & "PCL.ini", "VersionCache", "") '清空缓存(合并安装会先生成文件夹,这会在刷新时误判为可以使用缓存)
Hint(Loader.Name & "成功!", HintType.Finish)
Case LoadState.Failed
Hint(Loader.Name & "失败:" & GetExceptionSummary(Loader.Error), HintType.Critical)
Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Critical)
Case LoadState.Aborted
Hint(Loader.Name & "已取消!", HintType.Info)
Case LoadState.Loading
@@ -1,31 +0,0 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadClient"
PanScroll="{Binding ElementName=PanBack}">
<Grid>
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<!--<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="自动安装提示" x:Name="CardTip">
<StackPanel Margin="25,40,15,20">
<TextBlock Margin="0,0,0,2" Text="本页只提供需要在下载后手动进行安装的游戏 jar 与 json 下载。" TextWrapping="Wrap" />
<TextBlock Margin="0,0,0,11" Text="如果你想要进行自动安装,在游戏安装页选择游戏版本,然后直接安装即可。" TextWrapping="Wrap" />
<Grid Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnWeb" Grid.Column="0" MinWidth="140" Text="打开官网" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
<local:MyButton x:Name="BtnInstall" Grid.Column="1" MinWidth="140" Text="转到游戏安装页" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
</Grid>
</StackPanel>
</local:MyCard>-->
<StackPanel Name="PanMain" Margin="20,20,20,5" Grid.IsSharedSizeScope="True" />
</StackPanel>
</local:MyScrollViewer>
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40,0" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
<local:MyLoading Text="正在获取版本列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
</Grid>
</local:MyPageRight>
@@ -1,111 +0,0 @@
Public Class PageDownloadClient
Private Sub LoaderInit() Handles Me.Initialized
PageLoaderInit(Load, PanLoad, PanBack, Nothing, DlClientListLoader, AddressOf Load_OnFinish)
End Sub
Private Sub Init() Handles Me.Loaded
PanBack.ScrollToHome()
End Sub
Private Sub Load_OnFinish()
'结果数据化
Try
'归类
Dim Dict As New Dictionary(Of String, List(Of JObject)) From {
{"正式版", New List(Of JObject)}, {"预览版", New List(Of JObject)}, {"远古版", New List(Of JObject)}, {"愚人节版", New List(Of JObject)}
}
Dim Versions As JArray = DlClientListLoader.Output.Value("versions")
For Each Version As JObject In Versions
'确定分类
Dim Type As String = Version("type")
Select Case Type
Case "release"
Type = "正式版"
Case "snapshot"
Type = "预览版"
'Mojang 误分类
If Version("id").ToString.StartsWith("1.") AndAlso
Not Version("id").ToString.ToLower.Contains("combat") AndAlso
Not Version("id").ToString.ToLower.Contains("rc") AndAlso
Not Version("id").ToString.ToLower.Contains("experimental") AndAlso
Not Version("id").ToString.ToLower.Contains("pre") Then
Type = "正式版"
Version("type") = "release"
End If
'愚人节版本
Select Case Version("id").ToString.ToLower
Case "20w14infinite", "20w14∞"
Type = "愚人节版"
Version("id") = "20w14∞"
Version("type") = "special"
Version.Add("lore", GetMcFoolName(Version("id")))
Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime", "23w13a_or_b", "24w14potato", "25w14craftmine"
Type = "愚人节版"
Version("type") = "special"
Version.Add("lore", GetMcFoolName(Version("id")))
Case Else '4/1 自动视作愚人节版
Dim ReleaseDate = Version("releaseTime").Value(Of Date).ToUniversalTime().AddHours(2)
If ReleaseDate.Month = 4 AndAlso ReleaseDate.Day = 1 Then
Type = "愚人节版"
Version("type") = "special"
End If
End Select
Case "special"
'已被处理的愚人节版
Type = "愚人节版"
Case Else
Type = "远古版"
End Select
'加入辞典
Dict(Type).Add(Version)
Next
'排序
For i = 0 To Dict.Keys.Count - 1
Dict(Dict.Keys(i)) = Dict.Values(i).OrderByDescending(Function(v) v("releaseTime").Value(Of Date)).ToList
Next
'清空当前
PanMain.Children.Clear()
'添加最新版本
Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 2}
Dim TopestVersions As New List(Of JObject)
Dim Release As JObject = Dict("正式版")(0).DeepClone()
Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
TopestVersions.Add(Release)
If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
TopestVersions.Add(Snapshot)
End If
Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}
MyCard.StackInstall(PanInfo, 2)
CardInfo.Children.Add(PanInfo)
PanMain.Children.Add(CardInfo)
'添加其他版本
For Each Pair As KeyValuePair(Of String, List(Of JObject)) In Dict
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 2}
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
NewCard.IsSwaped = True
PanMain.Children.Add(NewCard)
Next
Catch ex As Exception
Log(ex, "可视化 MC 版本列表出错", LogLevel.Feedback)
End Try
End Sub
Public Sub DownloadStart(sender As MyListItem, e As Object)
McDownloadClient(NetPreDownloadBehaviour.HintWhileExists, sender.Title, sender.Tag("url").ToString)
End Sub
''介绍栏
'Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
' OpenWebsite("https://www.minecraft.net/zh-hans")
'End Sub
'Private Sub BtnInstall_Click(sender As Object, e As EventArgs) Handles BtnInstall.Click
' FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
'End Sub
End Class
@@ -1,28 +0,0 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadFabric"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="Fabric 简介" x:Name="CardTip">
<StackPanel Margin="25,40,15,20">
<TextBlock Margin="0,0,0,11" Text="Fabric Loader 是新版 Minecraft 下的轻量化 Mod 加载器,你需要先安装它才能安装各种 Fabric 模组。&#xa;本页面提供 Fabric 安装器下载,在下载后你需要手动打开安装器进行安装。" TextWrapping="Wrap" />
<Grid Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnWeb" Grid.Column="0" MinWidth="140" Text="打开官网" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardVersions" Margin="20,15,20,20" Title="版本列表">
<StackPanel x:Name="PanVersions" Margin="20,40,18,20" />
</local:MyCard>
<local:MyCard HorizontalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
<local:MyLoading Text="正在获取 Fabric 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -1,32 +0,0 @@
Public Class PageDownloadFabric
Private Sub LoaderInit() Handles Me.Initialized
PageLoaderInit(Load, PanLoad, CardVersions, CardTip, DlFabricListLoader, AddressOf Load_OnFinish)
End Sub
Private Sub Init() Handles Me.Loaded
PanBack.ScrollToHome()
End Sub
Private Sub Load_OnFinish()
'结果数据化
Try
Dim Versions As JArray = DlFabricListLoader.Output.Value("installer")
PanVersions.Children.Clear()
For Each Version In Versions
PanVersions.Children.Add(FabricDownloadListItem(Version, AddressOf Fabric_Selected))
Next
CardVersions.Title = "版本列表 (" & Versions.Count & ")"
Catch ex As Exception
Log(ex, "可视化 Fabric 版本列表出错", LogLevel.Feedback)
End Try
End Sub
Private Sub Fabric_Selected(sender As MyListItem, e As EventArgs)
McDownloadFabricLoaderSave(sender.Tag)
End Sub
Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
OpenWebsite("https://www.fabricmc.net")
End Sub
End Class
@@ -1,26 +0,0 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadForge"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="Forge 简介" x:Name="CardTip">
<StackPanel Margin="25,40,15,20">
<TextBlock Name="LabConnect" Margin="0,0,0,11" Text="Forge 是一个 Mod 加载器,你需要先安装 Forge 才能安装各种 Forge 模组。" TextWrapping="Wrap" />
<Grid Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnWeb" Grid.Column="0" MinWidth="140" Text="打开官网" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
</Grid>
</StackPanel>
</local:MyCard>
<StackPanel Name="PanMain" Margin="20,15,20,5" Grid.IsSharedSizeScope="True" />
<local:MyCard HorizontalAlignment="Center" Margin="40,50" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
<local:MyLoading Text="正在获取 Forge 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -1,61 +0,0 @@
Public Class PageDownloadForge
Private Sub LoaderInit() Handles Me.Initialized
PageLoaderInit(Load, PanLoad, PanMain, CardTip, DlForgeListLoader, AddressOf Load_OnFinish)
End Sub
Private Sub Init() Handles Me.Loaded
PanBack.ScrollToHome()
End Sub
Private Sub Load_OnFinish()
'结果数据化
Try
'清空当前
PanMain.Children.Clear()
'转化为 UI
For Each Version As String In DlForgeListLoader.Output.Value.Sort(AddressOf VersionSortBoolean)
'增加卡片
Dim NewCard As New MyCard With {.Title = Version.Replace("_p", " P"), .Margin = New Thickness(0, 0, 0, 15), .SwapType = 5}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Version}
NewCard.Children.Add(NewStack)
NewCard.SwapControl = NewStack
NewCard.IsSwaped = True
PanMain.Children.Add(NewCard)
Next
''非官方源警示
'If Setup.Get("ToolDownloadOutOfDate") AndAlso Not DlForgeListLoader.Output.IsOfficial Then
' Dim CardWarn As New MyCard With {.Title = "过期提示", .Margin = New Thickness(0, 0, 0, 15)}
' CardWarn.Children.Add(New TextBlock With {
' .Margin = New Thickness(25, MyCard.SwapedHeight, 15, 15), .VerticalAlignment = VerticalAlignment.Top, .HorizontalAlignment = HorizontalAlignment.Left, .TextTrimming = TextTrimming.None, .TextWrapping = TextWrapping.Wrap,
' .Text = "获取官方源失败,正在使用 " & DlForgeListLoader.Output.SourceName & " 镜像源,版本列表可能并非最新。" & vbCrLf & "官方源错误原因:" & If(DlForgeListLoader.Output.OfficialError, New Exception("连接服务器超时")).Message})
' PanMain.Children.Insert(0, CardWarn)
'End If
Catch ex As Exception
Log(ex, "可视化 Forge 版本列表出错", LogLevel.Feedback)
End Try
End Sub
'Forge 版本列表加载
Public Sub Forge_Click(sender As MyLoading, e As MouseButtonEventArgs)
If sender.State.LoadingState = MyLoading.MyLoadingState.Error Then
CType(sender.State, LoaderTask(Of String, List(Of DlForgeVersionEntry))).Start(IsForceRestart:=True)
End If
End Sub
Public Sub Forge_StateChanged(sender As MyLoading, newState As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState)
If newState <> MyLoading.MyLoadingState.Stop Then Return
Dim Card As MyCard = CType(sender.Parent, FrameworkElement).Parent
Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = sender.State
'载入列表
Card.SwapControl.Children.Clear()
Card.SwapControl.Tag = Loader.Output
Card.SwapType = 6
Card.StackInstall()
End Sub
'介绍栏
Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
OpenWebsite("https://files.minecraftforge.net")
End Sub
End Class
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadInstall"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<Grid>
<Grid Name="PanAllBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
@@ -27,7 +27,7 @@
<local:MyHint Text="必须安装 OptiFabric 才能正常使用 OptiFine!" Margin="0,10,0,0" x:Name="HintOptiFabric" Theme="Red" />
<local:MyHint Text="安装结束后,请在 Mod 下载中搜索 OptiFabric Origins 并下载,否则 OptiFine 会无法使用!" Margin="0,10,0,0" x:Name="HintOptiFabricOld" Theme="Yellow" />
<local:MyHint Text="OptiFine 与一部分 Mod 的兼容性不佳,请谨慎安装。" Margin="0,10,0,0" x:Name="HintModOptiFine" Theme="Yellow" />
<local:MyCard Title="Forge" Height="40" Margin="0,12,0,0" x:Name="CardForge" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<local:MyCard Title="Forge" Height="40" Margin="0,12,0,0" x:Name="CardForge" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanForge" />
<Grid x:Name="PanForgeInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
<Grid.RenderTransform>
@@ -45,7 +45,7 @@
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
</Grid>
</local:MyCard>
<local:MyCard Title="NeoForge" Height="40" Margin="0,12,0,0" x:Name="CardNeoForge" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<local:MyCard Title="NeoForge" Height="40" Margin="0,12,0,0" x:Name="CardNeoForge" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanNeoForge" />
<Grid x:Name="PanNeoForgeInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
<Grid.RenderTransform>
@@ -63,7 +63,7 @@
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
</Grid>
</local:MyCard>
<local:MyCard Title="Fabric" Height="40" Margin="0,12,0,0" x:Name="CardFabric" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<local:MyCard Title="Fabric" Height="40" Margin="0,12,0,0" x:Name="CardFabric" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanFabric" />
<Grid x:Name="PanFabricInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
<Grid.RenderTransform>
@@ -81,7 +81,7 @@
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
</Grid>
</local:MyCard>
<local:MyCard Title="Fabric API" Height="40" Margin="0,12,0,0" x:Name="CardFabricApi" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<local:MyCard Title="Fabric API" Height="40" Margin="0,12,0,0" x:Name="CardFabricApi" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanFabricApi" />
<Grid x:Name="PanFabricApiInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
<Grid.RenderTransform>
@@ -99,7 +99,7 @@
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
</Grid>
</local:MyCard>
<local:MyCard Title="OptiFine" Height="40" Margin="0,12,0,0" x:Name="CardOptiFine" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<local:MyCard Title="OptiFine" Height="40" Margin="0,12,0,0" x:Name="CardOptiFine" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top">
<StackPanel Name="PanOptiFine" />
</StackPanel>
@@ -119,7 +119,7 @@
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
</Grid>
</local:MyCard>
<local:MyCard Title="OptiFabric" Height="40" Margin="0,12,0,0" x:Name="CardOptiFabric" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<local:MyCard Title="OptiFabric" Height="40" Margin="0,12,0,0" x:Name="CardOptiFabric" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanOptiFabric" />
<Grid x:Name="PanOptiFabricInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
<Grid.RenderTransform>
@@ -137,7 +137,7 @@
Data="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
</Grid>
</local:MyCard>
<local:MyCard Title="LiteLoader" Height="40" Margin="0,12,0,0" x:Name="CardLiteLoader" IsSwaped="True" CanSwap="True" SwapLogoRight="True">
<local:MyCard Title="LiteLoader" Height="40" Margin="0,12,0,0" x:Name="CardLiteLoader" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanLiteLoader" />
<Grid x:Name="PanLiteLoaderInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
<Grid.RenderTransform>
@@ -54,18 +54,13 @@
DisabledPageAnimControls.Remove(BtnStart)
BtnStart.Show = True
CardOptiFine.IsSwaped = True
CardLiteLoader.IsSwaped = True
CardForge.IsSwaped = True
CardNeoForge.IsSwaped = True
CardFabric.IsSwaped = True
CardFabricApi.IsSwaped = True
CardOptiFabric.IsSwaped = True
If Not Setup.Get("HintInstallBack") Then
Setup.Set("HintInstallBack", True)
Hint("点击 Minecraft 项即可返回游戏主版本选择页面!")
End If
CardOptiFine.IsSwapped = True
CardLiteLoader.IsSwapped = True
CardForge.IsSwapped = True
CardNeoForge.IsSwapped = True
CardFabric.IsSwapped = True
CardFabricApi.IsSwapped = True
CardOptiFabric.IsSwapped = True
'如果在选择页面按了刷新键,选择页的东西可能会由于动画被隐藏,但不会由于加载结束而再次显示,因此这里需要手动恢复
For Each Control In GetAllAnimControls(PanSelect)
@@ -318,8 +313,8 @@
'OptiFine
Dim OptiFineError As String = LoadOptiFineGetError()
CardOptiFine.MainSwap.Visibility = If(OptiFineError Is Nothing, Visibility.Visible, Visibility.Collapsed)
If OptiFineError IsNot Nothing Then CardOptiFine.IsSwaped = True '例如在同时展开卡片时选择了不兼容项则强制折叠
SetOptiFineInfoShow(CardOptiFine.IsSwaped)
If OptiFineError IsNot Nothing Then CardOptiFine.IsSwapped = True '例如在同时展开卡片时选择了不兼容项则强制折叠
SetOptiFineInfoShow(CardOptiFine.IsSwapped)
If SelectedOptiFine Is Nothing Then
BtnOptiFineClear.Visibility = Visibility.Collapsed
ImgOptiFine.Visibility = Visibility.Collapsed
@@ -338,8 +333,8 @@
CardLiteLoader.Visibility = Visibility.Visible
Dim LiteLoaderError As String = LoadLiteLoaderGetError()
CardLiteLoader.MainSwap.Visibility = If(LiteLoaderError Is Nothing, Visibility.Visible, Visibility.Collapsed)
If LiteLoaderError IsNot Nothing Then CardLiteLoader.IsSwaped = True '例如在同时展开卡片时选择了不兼容项则强制折叠
SetLiteLoaderInfoShow(CardLiteLoader.IsSwaped)
If LiteLoaderError IsNot Nothing Then CardLiteLoader.IsSwapped = True '例如在同时展开卡片时选择了不兼容项则强制折叠
SetLiteLoaderInfoShow(CardLiteLoader.IsSwapped)
If SelectedLiteLoader Is Nothing Then
BtnLiteLoaderClear.Visibility = Visibility.Collapsed
ImgLiteLoader.Visibility = Visibility.Collapsed
@@ -355,8 +350,8 @@
'Forge
Dim ForgeError As String = LoadForgeGetError()
CardForge.MainSwap.Visibility = If(ForgeError Is Nothing, Visibility.Visible, Visibility.Collapsed)
If ForgeError IsNot Nothing Then CardForge.IsSwaped = True
SetForgeInfoShow(CardForge.IsSwaped)
If ForgeError IsNot Nothing Then CardForge.IsSwapped = True
SetForgeInfoShow(CardForge.IsSwapped)
If SelectedForge Is Nothing Then
BtnForgeClear.Visibility = Visibility.Collapsed
ImgForge.Visibility = Visibility.Collapsed
@@ -375,8 +370,8 @@
CardNeoForge.Visibility = Visibility.Visible
Dim NeoForgeError As String = LoadNeoForgeGetError()
CardNeoForge.MainSwap.Visibility = If(NeoForgeError Is Nothing, Visibility.Visible, Visibility.Collapsed)
If NeoForgeError IsNot Nothing Then CardNeoForge.IsSwaped = True
SetNeoForgeInfoShow(CardNeoForge.IsSwaped)
If NeoForgeError IsNot Nothing Then CardNeoForge.IsSwapped = True
SetNeoForgeInfoShow(CardNeoForge.IsSwapped)
If SelectedNeoForge Is Nothing Then
BtnNeoForgeClear.Visibility = Visibility.Collapsed
ImgNeoForge.Visibility = Visibility.Collapsed
@@ -396,8 +391,8 @@
CardFabric.Visibility = Visibility.Visible
Dim FabricError As String = LoadFabricGetError()
CardFabric.MainSwap.Visibility = If(FabricError Is Nothing, Visibility.Visible, Visibility.Collapsed)
If FabricError IsNot Nothing Then CardFabric.IsSwaped = True
SetFabricInfoShow(CardFabric.IsSwaped)
If FabricError IsNot Nothing Then CardFabric.IsSwapped = True
SetFabricInfoShow(CardFabric.IsSwapped)
If SelectedFabric Is Nothing Then
BtnFabricClear.Visibility = Visibility.Collapsed
ImgFabric.Visibility = Visibility.Collapsed
@@ -417,8 +412,8 @@
CardFabricApi.Visibility = Visibility.Visible
Dim FabricApiError As String = LoadFabricApiGetError()
CardFabricApi.MainSwap.Visibility = If(FabricApiError Is Nothing, Visibility.Visible, Visibility.Collapsed)
If FabricApiError IsNot Nothing OrElse SelectedFabric Is Nothing Then CardFabricApi.IsSwaped = True
SetFabricApiInfoShow(CardFabricApi.IsSwaped)
If FabricApiError IsNot Nothing OrElse SelectedFabric Is Nothing Then CardFabricApi.IsSwapped = True
SetFabricApiInfoShow(CardFabricApi.IsSwapped)
If SelectedFabricApi Is Nothing Then
BtnFabricApiClear.Visibility = Visibility.Collapsed
ImgFabricApi.Visibility = Visibility.Collapsed
@@ -438,8 +433,8 @@
CardOptiFabric.Visibility = Visibility.Visible
Dim OptiFabricError As String = LoadOptiFabricGetError()
CardOptiFabric.MainSwap.Visibility = If(OptiFabricError Is Nothing, Visibility.Visible, Visibility.Collapsed)
If OptiFabricError IsNot Nothing OrElse SelectedFabric Is Nothing Then CardOptiFabric.IsSwaped = True
SetOptiFabricInfoShow(CardOptiFabric.IsSwaped)
If OptiFabricError IsNot Nothing OrElse SelectedFabric Is Nothing Then CardOptiFabric.IsSwapped = True
SetOptiFabricInfoShow(CardOptiFabric.IsSwapped)
If SelectedOptiFabric Is Nothing Then
BtnOptiFabricClear.Visibility = Visibility.Collapsed
ImgOptiFabric.Visibility = Visibility.Collapsed
@@ -639,7 +634,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
NewCard.IsSwaped = True
NewCard.IsSwapped = True
PanMinecraft.Children.Add(NewCard)
Next
'自动选择版本
@@ -755,14 +750,14 @@
OptiFabric_Loaded()
Forge_Loaded()
NeoForge_Loaded()
CardOptiFine.IsSwaped = True
CardOptiFine.IsSwapped = True
SelectReload()
End Sub
Private Sub OptiFine_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFineClear.MouseLeftButtonUp
SelectedOptiFine = Nothing
SelectedOptiFabric = Nothing
AutoSelectedOptiFabric = False
CardOptiFine.IsSwaped = True
CardOptiFine.IsSwapped = True
e.Handled = True
Forge_Loaded()
NeoForge_Loaded()
@@ -816,12 +811,12 @@
'选择与清除
Private Sub LiteLoader_Selected(sender As MyListItem, e As EventArgs)
SelectedLiteLoader = sender.Tag
CardLiteLoader.IsSwaped = True
CardLiteLoader.IsSwapped = True
SelectReload()
End Sub
Private Sub LiteLoader_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnLiteLoaderClear.MouseLeftButtonUp
SelectedLiteLoader = Nothing
CardLiteLoader.IsSwaped = True
CardLiteLoader.IsSwapped = True
e.Handled = True
SelectReload()
End Sub
@@ -902,14 +897,14 @@
'选择与清除
Private Sub Forge_Selected(sender As MyListItem, e As EventArgs)
SelectedForge = sender.Tag
CardForge.IsSwaped = True
CardForge.IsSwapped = True
If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedOptiFine = Nothing
OptiFine_Loaded()
SelectReload()
End Sub
Private Sub Forge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnForgeClear.MouseLeftButtonUp
SelectedForge = Nothing
CardForge.IsSwaped = True
CardForge.IsSwapped = True
e.Handled = True
OptiFine_Loaded()
SelectReload()
@@ -964,13 +959,13 @@
'选择与清除
Private Sub NeoForge_Selected(sender As MyListItem, e As EventArgs)
SelectedNeoForge = sender.Tag
CardNeoForge.IsSwaped = True
CardNeoForge.IsSwapped = True
OptiFine_Loaded()
SelectReload()
End Sub
Private Sub NeoForge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnNeoForgeClear.MouseLeftButtonUp
SelectedNeoForge = Nothing
CardNeoForge.IsSwaped = True
CardNeoForge.IsSwapped = True
e.Handled = True
OptiFine_Loaded()
SelectReload()
@@ -1030,7 +1025,7 @@
SelectedFabric = sender.Tag("version").ToString
FabricApi_Loaded()
OptiFabric_Loaded()
CardFabric.IsSwaped = True
CardFabric.IsSwapped = True
SelectReload()
End Sub
Private Sub Fabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricClear.MouseLeftButtonUp
@@ -1039,7 +1034,7 @@
AutoSelectedFabricApi = False
SelectedOptiFabric = Nothing
AutoSelectedOptiFabric = False
CardFabric.IsSwaped = True
CardFabric.IsSwapped = True
e.Handled = True
SelectReload()
End Sub
@@ -1151,12 +1146,12 @@
'选择与清除
Private Sub FabricApi_Selected(sender As MyListItem, e As EventArgs)
SelectedFabricApi = sender.Tag
CardFabricApi.IsSwaped = True
CardFabricApi.IsSwapped = True
SelectReload()
End Sub
Private Sub FabricApi_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricApiClear.MouseLeftButtonUp
SelectedFabricApi = Nothing
CardFabricApi.IsSwaped = True
CardFabricApi.IsSwapped = True
e.Handled = True
SelectReload()
End Sub
@@ -1243,12 +1238,12 @@
'选择与清除
Private Sub OptiFabric_Selected(sender As MyListItem, e As EventArgs)
SelectedOptiFabric = sender.Tag
CardOptiFabric.IsSwaped = True
CardOptiFabric.IsSwapped = True
SelectReload()
End Sub
Private Sub OptiFabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFabricClear.MouseLeftButtonUp
SelectedOptiFabric = Nothing
CardOptiFabric.IsSwaped = True
CardOptiFabric.IsSwapped = True
e.Handled = True
SelectReload()
End Sub
@@ -1,114 +1,59 @@
<local:MyPageLeft x:Class="PageDownloadLeft"
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}">
xmlns:local="clr-namespace:PCL" AnimatedControl="PanItem">
<local:MyScrollViewer PanningMode="VerticalOnly" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Style="{StaticResource ScrollViewerFullMargin}">
<StackPanel Margin="0,12,0,0" Name="PanItem">
<TextBlock x:Name="LabGame" Text="Minecraft" Margin="13,6,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemInstall" Checked="True" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="1" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="游戏下载"
Logo="M12 0l-11 6v12.131l11 5.869 11-5.869v-12.066l-11-6.065zm-1 21.2l-6.664-3.555 4.201-2.801c1.08-.719-.066-2.359-1.243-1.575l-4.294 2.862v-7.901l8 4.363v8.607zm-6.867-14.63l6.867-3.746v4.426c0 1.323 2 1.324 2 0v-4.415l6.91 3.811-7.905 4.218-7.872-4.294zm8.867 6.03l8-4.269v7.8l-4.263-2.842c-1.181-.785-2.323.855-1.245 1.574l4.172 2.781-6.664 3.556v-8.6z">
<local:MyListItem x:Name="ItemInstall" Checked="True" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="0" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Minecraft"
Logo="m351.9,801.7c-8.6,0-17-3-23.7-8.4L18.9,614.7c-12.5-7.2-19.7-20.5-18.8-34.9V221c-.7-15,6.6-28.8,19.2-36L325.2,8.3c6.6-5.3,15.1-8.3,24-8.3s17.3,2.9,23.9,8.2l308.3,178c.2.1.5.3.8.5h0c12,6.7,19.4,19.8,19.4,34.1,0,13.9-7.1,26-18.7,32.5l-290.1,167.5v276l234-135.1v-168.9c0-20.8,17-37.8,37.8-37.8s37.8,17,37.8,37.8v191.7c0,16.4-10.9,31.2-26.5,36.1l-299.4,172.8c-6.7,5.4-15.1,8.3-23.7,8.3h-.9Zm-34.8-101.9v-276l-241.4-139.4v276l241.4,139.4Zm35.3-342.8l236.8-136.7-240-138.6L112.4,218.3l240,138.6Z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="1" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
<local:MyIconButton Tag="0" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemHand" IsScaleAnimationEnabled="False" Type="RadioBox" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="手动安装包"
Logo="M1000 241c-2-5-4-11-6-17-0-6-4-12-8-17-7-9-18-15-31-15-6 0-13 1-19 5l-15 15-17 17-21 21L749 381c-14 14-38 14-52 0l-54-54c-14-14-14-38 0-52l132-132 14-14 20-20 16-16c3-5 5-11 5-19 0-12-5-24-16-32-5-4-11-6-18-7-5-2-10-4-16-5-36-12-76-19-117-19-7 0-14 0-22 0-188 11-337 168-337 360 0 16 0 32 3 48L56 663c-73 74-73 193 0 267l33 33c73 73 193 73 267 0l240-241c21 4 42 5 64 5 190 0 346-146 360-333 0-8 0-17 0-27 0-44-6-86-21-125zM658 639c-28 0-54-4-79-11-4 7-10 14-16 21l-258 258c-43 43-115 43-158 0l-29-29c-43-44-43-115 0-158l212-212 46-46c5-5 12-11 19-15-8-26-12-54-12-83v-1c0-152 123-275 276-275 18 0 37 1 55 5L597 207c-52 52-52 137 0 189l29 29c52 52 137 52 189 0L930 312c2 16 4 33 4 50 0 152-123 276-276 276z" />
<TextBlock x:Name="LabHand" Visibility="Collapsed" Text="▼ 手动安装包" Padding="11,18,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemClient" Visibility="Collapsed" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Minecraft"
LogoScale="0.98" Logo="M989.7 510.8l-202.3-101c-10.8-5.4-17.7-16.5-17.7-28.6V172.7c0-26.7-16.6-50.6-41.6-59.9L550.5 46.3c-24.2-9-50.8-9-74.9 0.1l-176.9 66.8c-24.9 9.4-41.4 33.2-41.4 59.9v207.1c0 12.1-6.9 23.2-17.7 28.6l-204 101.9C13.9 521.6 0.1 543.8 0.2 568.1l0.5 226c0 23.2 12.6 44.5 32.9 55.8l223.8 124.6 1.2 0.7c18.9 10.5 41.9 10.4 60.8-0.2l2-1.1L497 873.2c9.9-5.7 22.1-5.6 32 0.1l176.7 102.5c18.9 10.7 42 10.8 61 0.3l3-1.7L992.4 851c20.4-11.3 33-32.8 33-56l-0.3-226.9c0-24.3-13.7-46.5-35.4-57.3zM321 192l115.3 46.1c27 10.8 44.7 36.9 44.7 66v163c0 5.9-6.2 9.8-11.6 7.2L339 409.5c-10.9-5.4-17.7-16.5-17.8-28.6L321 192z m-63.7 703.4L82.5 809.6c-10.9-5.4-17.9-16.5-17.9-28.7l-0.4-189.5L217.9 668c24.1 12 39.4 36.7 39.4 63.6v163.8z m64-274.3c-20.1 10.1-43.7 10-63.8 0l-0.2-0.1-149.1-75 149.1-74.4 16.8-8.4c9.2-4.6 20-4.5 29.1 0.3l18.1 9.4 129.8 64.3c5.8 2.9 6 11.1 0.2 14.2l-130 69.7z m141.9 203.8l-141.8 70.6-0.8-163.6c-0.1-27 15.1-51.8 39.2-63.9l108.8-54.5c5.3-2.7 11.6 1.2 11.6 7.1l0.8 175.6c0 12.1-6.9 23.2-17.8 28.7zM385 144l128-48 128 48-103 38.6c-16.1 6-33.8 6-49.9 0L385 144z m320 48l0.6 187.8c0 12.2-6.8 23.3-17.7 28.7l-131.4 65.7c-5.3 2.7-11.6-1.2-11.6-7.2V304.1c0-29.1 17.7-55.2 44.7-66L705 192z m0.7 710.3l-143.8-77.2c-10.4-5.6-16.9-16.4-16.9-28.2v-176c0-5.9 6.3-9.8 11.6-7.2l109.3 54.6c24 12 39.2 36.5 39.3 63.4l0.5 170.6z m-2-280.5l-129.2-70.5c-5.7-3.1-5.5-11.3 0.3-14.2l131-65.3 16.1-8.5c9.1-4.8 19.9-4.9 29.1-0.3l18.7 9.3L916.9 546l-146.2 76.4c-21.1 11-46.2 10.8-67-0.6z m66 279.4l-0.6-169.1c-0.1-27 15.1-51.7 39.3-63.8L961 592v188.7c0 11.9-6.6 22.7-17 28.3l-174.3 92.2z">
<!--Logo="M469.333333 213.333333V128a42.666667 42.666667 0 1 1 85.333334 0v85.333333h127.829333C847.722667 213.333333 981.333333 347.029333 981.333333 512.149333v319.936A106.496 106.496 0 0 1 874.730667 938.666667h-85.461334c-48.661333 0-107.221333-29.290667-136.469333-68.266667l-64-85.333333c-6.144-8.170667-23.957333-17.066667-34.24-17.066667h-85.12c-10.282667 0-28.096 8.896-34.24 17.066667l-64 85.333333c-29.226667 38.976-87.808 68.266667-136.469333 68.266667H149.269333A106.496 106.496 0 0 1 42.666667 832.085333V512.149333C42.666667 347.029333 176.277333 213.333333 341.504 213.333333H469.333333z m213.162667 85.333334H341.504A213.333333 213.333333 0 0 0 128 512.149333v319.936c0 11.818667 9.450667 21.248 21.269333 21.248h85.461334c21.802667 0 55.082667-16.64 68.202666-34.133333l64-85.333333c22.272-29.696 65.408-51.2 102.506667-51.2h85.12c37.098667 0 80.213333 21.504 102.506667 51.2l64 85.333333c13.12 17.493333 46.4 34.133333 68.202666 34.133333h85.461334a21.162667 21.162667 0 0 0 21.269333-21.248V512.149333A213.333333 213.333333 0 0 0 682.496 298.666667zM362.666667 469.333333h42.666666a42.666667 42.666667 0 1 1 0 85.333334h-42.666666v42.666666a42.666667 42.666667 0 1 1-85.333334 0v-42.666666h-42.666666a42.666667 42.666667 0 1 1 0-85.333334h42.666666v-42.666666a42.666667 42.666667 0 1 1 85.333334 0v42.666666z m341.333333-21.333333a42.666667 42.666667 0 1 1 0-85.333333 42.666667 42.666667 0 0 1 0 85.333333z m0 213.333333a42.666667 42.666667 0 1 1 0-85.333333 42.666667 42.666667 0 0 1 0 85.333333z m-106.666667-106.666666a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z m213.333334 0a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z">-->
<TextBlock Text="社区资源" Margin="13,20,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemMod" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="2" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod"
LogoScale="0.97" Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="2" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="3" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="整合包"
LogoScale="0.98" Logo="M511 995a128 128 0 0 1-57-13L70 791a126 126 0 0 1-70-113V311a126 126 0 0 1 15-60V248c1-2 3-5 5-8a127 127 0 0 1 49-42L454 13a128 128 0 0 1 112 0l383 190a126 126 0 0 1 72 113v360a126 126 0 0 1-70 115L568 984c-17 7-37 11-57 11z m42-470v370l360-178c14-7 23-21 23-38v-335L554 524zM85 330v347a42 42 0 0 0 23 38l360 178V523L85 330zM135 260l375 189 137-65L286 188 135 260z m245-118l363 197 150-71-365-180a42 42 0 0 0-37 0l-111 53z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="3" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemDataPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="数据包"
LogoScale="0.96" Logo="M445 545c18 0 33 14 33 33v149a182 182 0 1 1-182-182z m282 0a182 182 0 1 1-182 182v-149c0-18 14-33 33-33zM412 611H296a116 116 0 1 0 116 116V611z m315 0H611v116a116 116 0 1 0 116-116zM296 113a182 182 0 0 1 182 182v149a33 33 0 0 1-33 33H296a182 182 0 0 1 0-365z m431 0a182 182 0 0 1 0 365h-149a33 33 0 0 1-33-33V296A182 182 0 0 1 727 113zM296 180a116 116 0 0 0 0 232H412V296c0-62-48-112-109-115z m431 0a116 116 0 0 0-116 116V412h116c62 0 112-48 115-109l0-6a116 116 0 0 0-116-116z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="4" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemOptiFine" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="5" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="OptiFine"
LogoScale="1.00" Logo="M439.667 538.133l-323.311-174.763c-6.554-3.641-13.836-5.098-20.389-5.098-23.301 0-45.147 20.389-45.147 48.788v341.516c0 35.681 18.205 67.721 48.060 83.741l323.311 174.763c6.554 3.641 13.836 5.825 20.389 5.825 23.301 0 45.147-21.117 45.147-49.516v-341.516c0-34.953-18.205-67.721-48.060-83.741zM414.909 920.427l-281.805-152.189c-4.369-2.913-9.467-9.467-9.467-19.661v-298.553l281.805 152.189c5.825 3.641 9.467 11.651 9.467 19.661v298.553zM952.304 358.274c-6.554 0-13.836 1.456-20.389 5.098l-323.311 175.491c-29.855 16.020-48.060 48.788-48.060 84.468v340.059c0 28.399 21.845 49.516 45.147 49.516 6.554 0 13.836-1.456 20.389-5.098l323.311-175.491c29.127-16.020 48.060-48.060 48.060-83.741v-341.516c0-28.399-21.845-48.788-45.147-48.788zM924.634 747.849c0 10.194-5.098 17.476-9.467 19.661l-281.805 152.917v-297.097c0-10.194 5.098-17.476 9.467-19.661l281.805-153.646v297.825zM902.060 283.272c15.292-8.010 22.574-21.845 21.117-34.953 1.456-13.836-5.825-26.943-21.117-34.953l-329.136-171.85c-14.563-8.010-31.312-11.651-48.788-11.651 0 0 0 0 0 0 0 0 0 0 0 0s-34.224 3.641-49.516 11.651l-329.865 171.122c-15.292 8.010-21.845 21.845-21.117 35.681-0.729 13.107 5.825 26.943 21.117 34.953l329.136 171.122c14.563 8.010 32.039 11.651 49.516 11.651 0 0 0 0 0.729 0 0 0 0 0 0.729 0s34.224-3.641 49.516-11.651l327.68-171.122zM523.407 393.227c-5.825 0-11.651-1.456-16.020-3.641l-272.338-141.266 272.338-141.995c4.369-2.185 10.194-3.641 16.748-3.641 5.825 0 11.651 1.456 16.020 3.641l272.338 141.995-273.067 141.266c-3.641 2.185-9.467 3.641-16.020 3.641z">
<!--Logo="M12 0l-11 6v12.131l11 5.869 11-5.869v-12.066l-11-6.065zm-1 21.2l-6.664-3.555 4.201-2.801c1.08-.719-.066-2.359-1.243-1.575l-4.294 2.862v-7.901l8 4.363v8.607zm-6.867-14.63l6.867-3.746v4.426c0 1.323 2 1.324 2 0v-4.415l6.91 3.811-7.905 4.218-7.872-4.294zm8.867 6.03l8-4.269v7.8l-4.263-2.842c-1.181-.785-2.323.855-1.245 1.574l4.172 2.781-6.664 3.556v-8.6z">-->
<local:MyListItem x:Name="ItemResourcePack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="5" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="资源包"
LogoScale="0.81" Logo="M884.4 130.6H140.6c-41.9 0-76 34.1-76 76v613.3c0 41.9 34.1 76 76 76h743.8c41.9 0 76-34.1 76-76V206.6c0-41.9-34.1-76-76-76z m-743.8 72h743.8c2.2 0 4 1.8 4 4v371.3L796 461.7c-21.7-27.3-54.1-43.7-88.8-45-34.7-1.3-68.1 12.7-91.7 38.3L454 630c-2.8 3-7.2 3.5-10.5 1.3l-103-70.3c-31.5-21.5-72.8-22.5-105.3-2.7l-98.6 60.1V206.6c0-2.2 1.8-4 4-4z m743.8 621.3H140.6c-2.2 0-4-1.8-4-4V702.7l136.1-83c8.4-5.1 19.1-4.8 27.2 0.7l103 70.3c15.9 10.8 35.1 15.6 54.2 13.4 19-2.2 36.7-11.2 49.8-25.3l161.6-175c9.5-10.3 22.3-15.7 36.2-15.1 13.9 0.5 26.3 6.8 35.1 17.8l148.7 187v126.3c-0.1 2.3-1.9 4.1-4.1 4.1z M231.8 400.6a69.6 69.6 0 1 0 98.4-98.4 69.6 69.6 0 1 0-98.4 98.4Z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="5" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemForge" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="6" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Forge"
LogoScale="1.00" Logo="M402.807089 481.189274c-12.040221-6.991228-27.412326-2.797719-34.397415 9.242502l-8.387018 14.512529c-6.987135 12.035104-2.793626 27.40721 9.246595 34.392298 12.040221 6.985088 27.408233 2.797719 34.393321-9.242502l8.387018-14.511505C418.930301 503.437997 414.842193 488.063845 402.807089 481.189274L402.807089 481.189274zM495.028467 919.955342 59.056024 919.955342c-18.485003 0-33.532721 15.046694-33.532721 33.536814 0 18.485003 15.046694 33.532721 33.532721 33.532721l435.972443 0c18.49012 0 33.537837-15.046694 33.537837-33.532721C528.566304 935.002037 513.518586 919.955342 495.028467 919.955342L495.028467 919.955342zM997.431901 660.155295 590.482469 446.039729l90.935082-157.474544c18.485003-32.031531 7.520277-73.090669-24.51023-91.581812L395.496589 46.070268c-32.031531-18.485003-73.094762-7.520277-91.579765 24.51023L18.74697 564.277644c-18.485003 32.031531-7.521301 73.089645 24.51023 91.579765l261.408685 150.907988c32.031531 18.491143 73.095785 7.526417 91.581812-24.505114l91.364871-158.330028 392.332527 239.48128c16.016789 9.247618 36.544311 3.76372 45.792952-12.249999l83.838454-145.219429C1019.033895 689.930435 1013.444597 669.39882 997.431901 660.155295L997.431901 660.155295zM355.078041 719.704552c-9.242502 16.012695-29.774117 21.497617-45.787836 12.251022L105.923448 614.57826c-16.016789-9.242502-21.497617-29.774117-12.255115-45.787836l251.522524-435.653171c9.246595-16.012695 29.774117-21.497617 45.792952-12.249999l203.25624 117.376291c16.018835 9.242502 21.497617 29.774117 12.255115 45.786813L355.078041 719.704552 355.078041 719.704552zM884.568391 788.601712 522.115382 564.492538l33.537837-58.048067L934.875147 701.539844 884.568391 788.601712 884.568391 788.601712zM520.184403 277.8174c-12.040221-6.987135-27.41335-2.792603-34.399461 9.246595l-75.456552 130.702807c-6.985088 12.040221-2.791579 27.412326 9.242502 34.397415 12.040221 6.987135 27.412326 2.791579 34.397415-9.242502l75.458599-130.706901C536.307615 300.174594 532.219507 284.807604 520.184403 277.8174L520.184403 277.8174zM520.184403 277.8174">
<!--Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z">-->
<local:MyListItem x:Name="ItemShader" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="6" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="光影包"
LogoScale="1.04" Logo="M512 0c25 0 42 17 42 42v85c0 25-17 42-42 42s-42-17-42-42V42c0-25 17-42 42-42zM512 853c25 0 42 17 42 42v85c0 25-17 42-42 42s-42-17-42-42v-85c0-25 17-42 42-42zM209 149c-17-17-42-17-59 0-17 17-17 42 0 59l59 59c17 17 42 17 59 0 17-17 17-42 0-59L209 149zM755 755c17-17 42-17 59 0l59 59c17 17 17 42 0 59s-42 17-59 0l-59-59c-17-17-17-46 0-59zM42 469c-25 0-42 17-42 42s17 42 42 42h85c25 0 42-17 42-42s-17-42-42-42H42zM853 512c0-25 17-42 42-42h85c25 0 42 17 42 42s-17 42-42 42h-85c-25 0-42-17-42-42zM149 814c-17 17-17 42 0 59 17 17 42 17 59 0l59-59c17-17 17-42 0-59-17-17-42-17-59 0l-59 59zM755 268c-17-17-17-42 0-59l59-59c17-17 42-17 59 0s17 42 0 59l-59 59c-17 17-46 17-59 0z M512 213c-166 0-298 132-298 298s132 298 298 298 298-132 298-298-132-298-298-298z m0 512c-119 0-213-93-213-213s93-213 213-213 213 93 213 213-93 213-213 213z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="6" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemNeoForge" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="7" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="NeoForge"
LogoScale="0.95" Logo="M544.6 921.2l-23.7 32.6c14.1 10.2 33.3 10.2 47.5 0l-23.7-32.6zM114.6 608.5l-23.9 32.5 0.2 0.1 23.6-32.6z m-12.0-38.0l38.3 12.7v-0.2l-38.3-12.4z m49.2-152.6l-38.4-12.4 38.4 12.4zM250.2 114.4l-37.6-14.6a40.2 40.2 0 0 0-0.7 2.1l38.4 12.4z m4.3-6.4l27.0 29.9 0.2-0.2-27.2-29.7z m11.7-4.5V63.0v40.4z m11.7 4.5l28.0-29.0a40.5 40.5 0 0 0-0.8-0.8l-27.2 29.8z m4.4 7.3l-38.6 11.7a40.5 40.5 0 0 0 0.2 0.7l38.3-12.4zM381.0 417.7l-38.4 12.5a40.3 40.3 0 0 0 38.4 27.8v-40.3z m327.0 0v40.3c17.5 0 32.9-11.2 38.4-27.8L708.1 417.7z m98.5-303.3l-37.6-14.6a38.4 38.4 0 0 0-0.7 2.1l38.4 12.4z m4.3-6.4l27.1 29.9 0.1-0.2-27.2-29.7z m11.7-4.5v0z m11.7 4.5l28.0-29.0a38.4 38.4 0 0 0-0.8-0.8l-27.2 29.8z m4.3 7.3l-38.6 11.7a47.5 47.5 0 0 0 0.2 0.7l38.4-12.4z m98.5 303.3l-38.4 12.4 0.1 0.5 38.2-12.9z m51.2 151.9l38.7-11.3a34.5 34.5 0 0 0-0.5-1.6l-38.1 12.9z m-37.8 5.2l-430.0 312.6 47.5 65.3 429.9-312.6-47.5-65.3z m-382.5 312.6L138.3 575.8l-47.5 65.3L520.9 953.9l47.3-65.3zM138.5 576a6.4 6.4 0 0 1 2.3 3.2l-76.9 24.5c4.7 14.9 14.1 28.0 26.7 37.3l47.8-65.0z m2.3 3.2a6.4 6.4 0 0 1 0 4.0L64.1 557.9a74.3 74.3 0 0 0-0.2 45.8l76.9-24.5z m0 3.7l49.2-152.6-76.8-24.8L64.0 558.2l76.8 24.8z m49.2-152.5l98.5-303.3-76.8-25.0L113.3 405.3l76.8 25.0z m97.7-301.3a23.4 23.4 0 0 1-6.1 8.9L227.6 78.0a57.3 57.3 0 0 0-15.0 21.8l75.3 29.1z m-5.9 8.7a23.0 23.0 0 0 1-15.5 6.0V63.0a57.7 57.7 0 0 0-38.9 15.1l54.4 59.6z m-15.5 6.0a23.0 23.0 0 0 1-15.5-6.0l54.4-59.6A57.7 57.7 0 0 0 266.4 63.0v80.8z m-16.3-6.8a23.4 23.4 0 0 1-6.1-10.0l77.3-23.4a57.3 57.3 0 0 0-15.0-24.5l-56.1 58.0z m-5.8-9.2l98.4 302.5 76.8-25.0-98.5-302.5-76.8 25.0z m136.8 330.4H708.1V377.5H381.2v80.7z m365.4-27.8l98.5-303.3-76.8-25.0L669.6 405.3l76.8 25.0z m97.7-301.3a23.4 23.4 0 0 1-6.1 8.9l-54.1-59.9a57.3 57.3 0 0 0-15.0 21.8l75.3 29.1z m-5.9 8.7a23.0 23.0 0 0 1-15.5 6.0V63.0a57.7 57.7 0 0 0-38.9 15.1l54.4 59.6z m-15.5 6.0a23.0 23.0 0 0 1-15.5-6.0l54.4-59.6a57.7 57.7 0 0 0-38.9-15.1v80.8z m-16.3-6.8a23.4 23.4 0 0 1-6.1-10.0l77.3-23.4a57.4 57.4 0 0 0-14.9-24.5l-56.1 58.0z m-5.8-9.2l98.5 303.3 76.8-25.0-98.5-303.3-76.8 25.0z m98.6 303.8l51.2 151.9 76.5-25.8-51.2-151.9-76.5 25.8z m50.7 150.2a6.5 6.5 0 0 1 0.1-4.0l75.6 28.1c5.5-14.9 6.2-31.3 1.6-46.7l-77.5 22.6z m0.1-4.0a6.4 6.4 0 0 1 2.4-3.2l43.8 67.8c13.4-8.7 23.6-21.5 29.2-36.4l-75.6-28.1z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="7" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemFabric" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="8" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Fabric"
LogoScale="1.02" Logo="M826.453333 170.666667c-100.266667-93.866667-248.96-76.373333-256-75.52a31.786667 31.786667 0 0 0-26.666666 22.613333c-1.066667 3.2-101.546667 330.666667-426.666667 445.013333a29.013333 29.013333 0 0 0-7.893333 4.48l-1.493334 1.066667a29.44 29.44 0 0 0-5.973333 6.613333 31.786667 31.786667 0 0 0-3.626667 7.68 5.333333 5.333333 0 0 1 0 1.493334 30.506667 30.506667 0 0 0 0 8.96c7.466667 116.266667 45.013333 204.586667 112 262.826666a303.36 303.36 0 0 0 194.773334 71.466667h11.52a32.426667 32.426667 0 0 0 27.093333-19.626667 694.186667 694.186667 0 0 1 159.36-234.666666l-7.68 55.466666A31.786667 31.786667 0 0 0 621.44 768h4.48a32.213333 32.213333 0 0 0 31.786667-27.733333l15.573333-112.426667 112.426667 8.32a32 32 0 1 0 4.693333-64l-56.96-4.266667c36.48-25.813333 74.026667-50.56 112-75.52l51.626667-34.133333a31.573333 31.573333 0 0 0 14.08-24.746667c6.186667-115.2-21.76-203.306667-84.693334-262.826666zM620.8 573.013333l-1.706667 1.493334a219.093333 219.093333 0 0 0-87.466666-116.693334 222.933333 222.933333 0 0 0-95.146667-33.28c18.986667-21.333333 36.266667-42.666667 51.626667-64a198.613333 198.613333 0 0 1 202.453333 158.08c-20.053333 14.506667-39.893333 29.44-59.52 45.226667a29.866667 29.866667 0 0 0-10.24 9.173333z m-228.693333 292.266667a238.72 238.72 0 0 1-141.44-55.893333 213.333333 213.333333 0 0 1-34.986667-39.466667 123.946667 123.946667 0 0 0 44.373333 8.106667 168.533333 168.533333 0 0 0 69.12-16.213334 29.44 29.44 0 0 0 7.04-4.266666l106.666667-85.333334a32 32 0 1 0-39.893333-49.92L298.666667 704a78.293333 78.293333 0 0 1-69.546667 1.706667c-32.426667-17.066667-52.693333-61.653333-62.506667-93.44a709.333333 709.333333 0 0 0 202.453334-123.733334 187.52 187.52 0 0 1 128 21.333334 171.946667 171.946667 0 0 1 68.906666 109.653333 756.48 756.48 0 0 0-173.866666 245.76zM810.666667 438.4l-64 42.666667A256 256 0 0 0 529.706667 298.666667a810.666667 810.666667 0 0 0 69.12-140.8c37.973333-1.066667 123.946667 4.053333 183.68 59.946666 45.866667 42.666667 67.84 108.8 65.493333 195.84z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="8" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemLiteLoader" Visibility="Collapsed" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="9" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="LiteLoader"
LogoScale="1.06" Logo="M517.41 186.99l22.45 83.78h-55.04l-18.76-70.02c-2.85-10.63-13.78-16.95-24.42-14.1-10.63 2.85-16.95 13.78-14.1 24.42l16 59.71H388.5l-12.31-45.95c-10.45-38.99 12.69-79.08 51.69-89.52s79.08 12.68 89.53 51.68z M538.58 98c40.37 0 73.1 32.73 73.1 73.1v79.74h-53.16V171.1c0-11.01-8.93-19.94-19.94-19.94-11.01 0-19.94 8.93-19.94 19.94v79.74h-53.16V171.1c0-40.37 32.73-73.1 73.1-73.1z M512 224.26c191.58 0 346.88 155.3 346.88 346.88v61.8c0 28.85 3.33 59.94 9.98 93.27l1.29 6.28c12.43 59.1-21.15 118.2-78.28 137.78C691.18 904.75 597.9 922 512 922c-83.94 0-174.95-16.47-273.01-49.41l-6.85-2.32c-56.4-19.32-89.85-77.16-78.74-135.5l0.46-2.27c7.51-35.71 11.27-68.89 11.27-99.55v-61.8c0-189.66 152.21-343.77 341.14-346.83l5.73-0.06z m-4.64 66.49c-151.21 2.45-273.32 124.58-275.75 275.8l-0.04 4.59v61.8l-0.04 5.93c-0.45 33.74-4.7 69.49-12.65 107.3-5.53 26.27 9.4 52.53 34.79 61.23 94.08 32.23 180.19 48.15 258.32 48.15s164.25-15.92 258.32-48.15c25.39-8.7 40.32-34.97 34.79-61.23-7.95-37.81-12.2-73.56-12.65-107.3l-0.04-5.93v-61.8c0-153.33-123.05-277.91-275.79-280.39l-4.64-0.04-4.62 0.04z M500.66 717.38l-53.28-87.19c-3.83-6.26-1.85-14.44 4.41-18.27 0.76-0.46 1.56-0.85 2.39-1.15L512 589.74l57.82 21.03c6.9 2.51 10.46 10.13 7.95 17.03-0.3 0.83-0.69 1.63-1.15 2.39l-53.28 87.19c-3.83 6.26-12.01 8.24-18.27 4.41-1.8-1.1-3.31-2.61-4.41-4.41z M684.77 689.42m-46.52 0a46.52 46.52 0 1 0 93.04 0 46.52 46.52 0 1 0-93.04 0Z M339.23 689.42m-46.52 0a46.52 46.52 0 1 0 93.04 0 46.52 46.52 0 1 0-93.04 0Z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="9" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<TextBlock Text="社区资源" Margin="13,30,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemMod" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="11" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod"
LogoScale="0.97" Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="11" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="12" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="整合包"
LogoScale="0.98" Logo="M511 995a128 128 0 0 1-57-13L70 791a126 126 0 0 1-70-113V311a126 126 0 0 1 15-60V248c1-2 3-5 5-8a127 127 0 0 1 49-42L454 13a128 128 0 0 1 112 0l383 190a126 126 0 0 1 72 113v360a126 126 0 0 1-70 115L568 984c-17 7-37 11-57 11z m42-470v370l360-178c14-7 23-21 23-38v-335L554 524zM85 330v347a42 42 0 0 0 23 38l360 178V523L85 330zM135 260l375 189 137-65L286 188 135 260z m245-118l363 197 150-71-365-180a42 42 0 0 0-37 0l-111 53z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="12" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemDataPack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="13" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="数据包"
LogoScale="0.96" Logo="M445 545c18 0 33 14 33 33v149a182 182 0 1 1-182-182z m282 0a182 182 0 1 1-182 182v-149c0-18 14-33 33-33zM412 611H296a116 116 0 1 0 116 116V611z m315 0H611v116a116 116 0 1 0 116-116zM296 113a182 182 0 0 1 182 182v149a33 33 0 0 1-33 33H296a182 182 0 0 1 0-365z m431 0a182 182 0 0 1 0 365h-149a33 33 0 0 1-33-33V296A182 182 0 0 1 727 113zM296 180a116 116 0 0 0 0 232H412V296c0-62-48-112-109-115z m431 0a116 116 0 0 0-116 116V412h116c62 0 112-48 115-109l0-6a116 116 0 0 0-116-116z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="13" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemResourcePack" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="14" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="资源包"
LogoScale="0.81" Logo="M884.4 130.6H140.6c-41.9 0-76 34.1-76 76v613.3c0 41.9 34.1 76 76 76h743.8c41.9 0 76-34.1 76-76V206.6c0-41.9-34.1-76-76-76z m-743.8 72h743.8c2.2 0 4 1.8 4 4v371.3L796 461.7c-21.7-27.3-54.1-43.7-88.8-45-34.7-1.3-68.1 12.7-91.7 38.3L454 630c-2.8 3-7.2 3.5-10.5 1.3l-103-70.3c-31.5-21.5-72.8-22.5-105.3-2.7l-98.6 60.1V206.6c0-2.2 1.8-4 4-4z m743.8 621.3H140.6c-2.2 0-4-1.8-4-4V702.7l136.1-83c8.4-5.1 19.1-4.8 27.2 0.7l103 70.3c15.9 10.8 35.1 15.6 54.2 13.4 19-2.2 36.7-11.2 49.8-25.3l161.6-175c9.5-10.3 22.3-15.7 36.2-15.1 13.9 0.5 26.3 6.8 35.1 17.8l148.7 187v126.3c-0.1 2.3-1.9 4.1-4.1 4.1z M231.8 400.6a69.6 69.6 0 1 0 98.4-98.4 69.6 69.6 0 1 0-98.4 98.4Z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="14" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemShader" Type="RadioBox" IsScaleAnimationEnabled="False" Tag="15" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="光影包"
LogoScale="1.04" Logo="M512 0c25 0 42 17 42 42v85c0 25-17 42-42 42s-42-17-42-42V42c0-25 17-42 42-42zM512 853c25 0 42 17 42 42v85c0 25-17 42-42 42s-42-17-42-42v-85c0-25 17-42 42-42zM209 149c-17-17-42-17-59 0-17 17-17 42 0 59l59 59c17 17 42 17 59 0 17-17 17-42 0-59L209 149zM755 755c17-17 42-17 59 0l59 59c17 17 17 42 0 59s-42 17-59 0l-59-59c-17-17-17-46 0-59zM42 469c-25 0-42 17-42 42s17 42 42 42h85c25 0 42-17 42-42s-17-42-42-42H42zM853 512c0-25 17-42 42-42h85c25 0 42 17 42 42s-17 42-42 42h-85c-25 0-42-17-42-42zM149 814c-17 17-17 42 0 59 17 17 42 17 59 0l59-59c17-17 17-42 0-59-17-17-42-17-59 0l-59 59zM755 268c-17-17-17-42 0-59l59-59c17-17 42-17 59 0s17 42 0 59l-59 59c-17 17-46 17-59 0z M512 213c-166 0-298 132-298 298s132 298 298 298 298-132 298-298-132-298-298-298z m0 512c-119 0-213-93-213-213s93-213 213-213 213 93 213 213-93 213-213 213z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="15" ToolTip="刷新" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" LogoScale="0.85" Click="Refresh" Logo="M875.52 148.48C783.36 56.32 655.36 0 512 0 291.84 0 107.52 138.24 30.72 332.8l122.88 46.08C204.8 230.4 348.16 128 512 128c107.52 0 199.68 40.96 271.36 112.64L640 384h384V0L875.52 148.48zM512 896c-107.52 0-199.68-40.96-271.36-112.64L384 640H0v384l148.48-148.48C240.64 967.68 368.64 1024 512 1024c220.16 0 404.48-138.24 481.28-332.8L870.4 645.12C819.2 793.6 675.84 896 512 896z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageLeft>
@@ -11,7 +11,7 @@
''' <summary>
''' 勾选事件改变页面。
''' </summary>
Private Sub PageCheck(sender As MyListItem, e As RouteEventArgs) Handles ItemInstall.Check, ItemClient.Check, ItemOptiFine.Check, ItemForge.Check, ItemNeoForge.Check, ItemLiteLoader.Check, ItemMod.Check, ItemFabric.Check, ItemPack.Check, ItemResourcePack.Check, ItemShader.Check, ItemDataPack.Check
Private Sub PageCheck(sender As MyListItem, e As RouteEventArgs) Handles ItemInstall.Check, ItemMod.Check, ItemPack.Check, ItemResourcePack.Check, ItemShader.Check, ItemDataPack.Check
'尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0
'若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False)
If sender.Tag IsNot Nothing Then PageChange(Val(sender.Tag))
@@ -23,24 +23,6 @@
Case FormMain.PageSubType.DownloadInstall
If FrmDownloadInstall Is Nothing Then FrmDownloadInstall = New PageDownloadInstall
Return FrmDownloadInstall
Case FormMain.PageSubType.DownloadClient
If FrmDownloadClient Is Nothing Then FrmDownloadClient = New PageDownloadClient
Return FrmDownloadClient
Case FormMain.PageSubType.DownloadOptiFine
If FrmDownloadOptiFine Is Nothing Then FrmDownloadOptiFine = New PageDownloadOptiFine
Return FrmDownloadOptiFine
Case FormMain.PageSubType.DownloadForge
If FrmDownloadForge Is Nothing Then FrmDownloadForge = New PageDownloadForge
Return FrmDownloadForge
Case FormMain.PageSubType.DownloadNeoForge
If FrmDownloadNeoForge Is Nothing Then FrmDownloadNeoForge = New PageDownloadNeoForge
Return FrmDownloadNeoForge
Case FormMain.PageSubType.DownloadLiteLoader
If FrmDownloadLiteLoader Is Nothing Then FrmDownloadLiteLoader = New PageDownloadLiteLoader
Return FrmDownloadLiteLoader
Case FormMain.PageSubType.DownloadFabric
If FrmDownloadFabric Is Nothing Then FrmDownloadFabric = New PageDownloadFabric
Return FrmDownloadFabric
Case FormMain.PageSubType.DownloadMod
If FrmDownloadMod Is Nothing Then FrmDownloadMod = New PageDownloadMod
Return FrmDownloadMod
@@ -163,24 +145,6 @@
FrmDownloadDataPack.PageLoaderRestart()
End If
ItemDataPack.Checked = True
Case FormMain.PageSubType.DownloadClient
DlClientListLoader.Start(IsForceRestart:=True)
ItemClient.Checked = True
Case FormMain.PageSubType.DownloadOptiFine
DlOptiFineListLoader.Start(IsForceRestart:=True)
ItemOptiFine.Checked = True
Case FormMain.PageSubType.DownloadForge
DlForgeListLoader.Start(IsForceRestart:=True)
ItemForge.Checked = True
Case FormMain.PageSubType.DownloadNeoForge
DlNeoForgeListLoader.Start(IsForceRestart:=True)
ItemNeoForge.Checked = True
Case FormMain.PageSubType.DownloadLiteLoader
DlLiteLoaderListLoader.Start(IsForceRestart:=True)
ItemLiteLoader.Checked = True
Case FormMain.PageSubType.DownloadFabric
DlFabricListLoader.Start(IsForceRestart:=True)
ItemFabric.Checked = True
End Select
Hint("正在刷新……", Log:=False)
End Sub
@@ -191,55 +155,4 @@
FrmDownloadInstall.ExitSelectPage()
End Sub
'展开手动安装
Private Sub ItemHand_Click(sender As Object, e As RouteEventArgs) Handles ItemHand.Changed
If ItemHand.Checked = False Then Return
e.Handled = True
AniControlEnabled += 1
If Not Setup.Get("HintHandInstall") Then
Setup.Set("HintHandInstall", True)
If MyMsgBox("手动安装包功能提供了 OptiFine、Forge 等组件的 .jar 安装文件下载,但无法自动安装。" & vbCrLf &
"在自动安装页面先选择 MC 版本,然后就可以选择 OptiFine、Forge 等组件,让 PCL 自动进行安装了。", "自动安装提示", "返回自动安装", "继续下载手动安装包") = 1 Then
FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.Download}, FormMain.PageSubType.DownloadInstall)
AniControlEnabled -= 1
Return
End If
End If
ItemHand.Visibility = Visibility.Collapsed
LabGame.Visibility = Visibility.Collapsed
LabHand.Visibility = Visibility.Visible
ItemClient.Visibility = Visibility.Visible
ItemOptiFine.Visibility = Visibility.Visible
ItemFabric.Visibility = Visibility.Visible
ItemForge.Visibility = Visibility.Visible
ItemNeoForge.Visibility = Visibility.Visible
ItemLiteLoader.Visibility = Visibility.Visible
RunInThread(
Sub()
Thread.Sleep(20)
RunInUiWait(Sub() ItemClient.SetChecked(True, True, True))
AniControlEnabled -= 1
End Sub)
End Sub
'折叠手动安装
Private Sub LabHand_Click(sender As Object, e As MouseButtonEventArgs) Handles LabHand.MouseLeftButtonUp
e.Handled = True
AniControlEnabled += 1
ItemHand.Visibility = Visibility.Visible
LabGame.Visibility = Visibility.Visible
LabHand.Visibility = Visibility.Collapsed
ItemClient.Visibility = Visibility.Collapsed
ItemOptiFine.Visibility = Visibility.Collapsed
ItemNeoForge.Visibility = Visibility.Collapsed
ItemFabric.Visibility = Visibility.Collapsed
ItemForge.Visibility = Visibility.Collapsed
ItemLiteLoader.Visibility = Visibility.Collapsed
RunInThread(
Sub()
Thread.Sleep(20)
RunInUiWait(Sub() ItemInstall.SetChecked(True, True, True))
AniControlEnabled -= 1
End Sub)
End Sub
End Class
@@ -1,26 +0,0 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadLiteLoader"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="LiteLoader 简介" x:Name="CardTip">
<StackPanel Margin="25,40,15,20">
<TextBlock Name="LabConnect" Margin="0,0,0,11" Text="与 Forge 类似,LiteLoader 可以用于加载老版本 Minecraft 中的 LiteLoader 模组。" TextWrapping="Wrap" />
<Grid Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnWeb" Grid.Column="0" MinWidth="140" Text="打开官网" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
</Grid>
</StackPanel>
</local:MyCard>
<StackPanel Name="PanMain" Margin="20,15,20,5" Grid.IsSharedSizeScope="True" />
<local:MyCard HorizontalAlignment="Center" Margin="40,50" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
<local:MyLoading Text="正在获取 LiteLoader 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -1,52 +0,0 @@
Public Class PageDownloadLiteLoader
Private Sub LoaderInit() Handles Me.Initialized
PageLoaderInit(Load, PanLoad, PanMain, CardTip, DlLiteLoaderListLoader, AddressOf Load_OnFinish)
End Sub
Private Sub Init() Handles Me.Loaded
PanBack.ScrollToHome()
End Sub
Private Sub Load_OnFinish()
'结果数据化
Try
'归类
Dim Dict As New Dictionary(Of String, List(Of DlLiteLoaderListEntry))
For VersionCode As Integer = 30 To 0 Step -1
Dict.Add("1." & VersionCode, New List(Of DlLiteLoaderListEntry))
Next
Dict.Add("未知版本", New List(Of DlLiteLoaderListEntry))
For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
Dim MainVersion As String = "1." & Version.Inherit.Split(".")(1)
If Dict.ContainsKey(MainVersion) Then
Dict(MainVersion).Add(Version)
Else
Dict("未知版本").Add(Version)
End If
Next
'清空当前
PanMain.Children.Clear()
'转化为 UI
For Each Pair As KeyValuePair(Of String, List(Of DlLiteLoaderListEntry)) In Dict
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 10}
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
NewCard.IsSwaped = True
PanMain.Children.Add(NewCard)
Next
Catch ex As Exception
Log(ex, "可视化 LiteLoader 版本列表出错", LogLevel.Feedback)
End Try
End Sub
Public Sub DownloadStart(sender As MyListItem, e As Object)
McDownloadLiteLoader(sender.Tag)
End Sub
Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
OpenWebsite("https://www.liteloader.com")
End Sub
End Class
@@ -1,27 +0,0 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadNeoForge"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="NeoForge 简介" x:Name="CardTip">
<StackPanel Margin="25,40,15,20">
<TextBlock Margin="0,0,0,11" Text="NeoForge 是 Minecraft 1.20.1+ 的 Mod 加载器,你需要先安装它才能安装各种 NeoForge 模组,它也兼容一些 Forge 模组。&#xa;本页面提供 NeoForge 安装器下载,在下载后你需要手动打开安装器进行安装。" TextWrapping="Wrap" />
<Grid Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnWeb" Grid.Column="0" MinWidth="140" Text="打开官网" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight"
EventType="打开网页" EventData="https://neoforged.net/" />
</Grid>
</StackPanel>
</local:MyCard>
<StackPanel Name="PanMain" Margin="20,15,20,5" Grid.IsSharedSizeScope="True" />
<local:MyCard HorizontalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
<local:MyLoading Text="正在获取 NeoForge 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -1,34 +0,0 @@
Public Class PageDownloadNeoForge
Private Sub LoaderInit() Handles Me.Initialized
PageLoaderInit(Load, PanLoad, PanMain, CardTip, DlNeoForgeListLoader, AddressOf Load_OnFinish)
End Sub
Private Sub Init() Handles Me.Loaded
PanBack.ScrollToHome()
End Sub
Private Sub Load_OnFinish()
'结果数据化
Try
'归类
Dim Dict = DlNeoForgeListLoader.Output.Value.GroupBy(Function(d) d.Inherit).OrderByDescending(Function(g) g.Key).
ToDictionary(Function(g) g.Key, Function(g) g.ToList())
'清空当前
PanMain.Children.Clear()
'转化为 UI
For Each Pair As KeyValuePair(Of String, List(Of DlNeoForgeListEntry)) In Dict
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 13}
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
NewCard.IsSwaped = True
PanMain.Children.Add(NewCard)
Next
Catch ex As Exception
Log(ex, "可视化 NeoForge 版本列表出错", LogLevel.Feedback)
End Try
End Sub
End Class
@@ -1,26 +0,0 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadOptiFine"
PanScroll="{Binding ElementName=PanBack}">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="5">
<local:MyCard Margin="20,20,20,0" Grid.IsSharedSizeScope="True" Title="OptiFine 简介" x:Name="CardTip">
<StackPanel Margin="25,40,15,20">
<TextBlock Name="LabConnect" Margin="0,0,0,11" Text="OptiFine 又称为高清修复,以允许安装光影、使用高清材质、提高游戏性能,但与 Mod 的兼容性不佳。" TextWrapping="Wrap" />
<Grid Height="35">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnWeb" Grid.Column="0" MinWidth="140" Text="打开官网" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
</Grid>
</StackPanel>
</local:MyCard>
<StackPanel Name="PanMain" Margin="20,15,20,5" Grid.IsSharedSizeScope="True" />
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
<local:MyLoading Text="正在获取 OptiFine 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
@@ -1,53 +0,0 @@
Public Class PageDownloadOptiFine
Private Sub LoaderInit() Handles Me.Initialized
PageLoaderInit(Load, PanLoad, PanMain, CardTip, DlOptiFineListLoader, AddressOf Load_OnFinish)
End Sub
Private Sub Init() Handles Me.Loaded
PanBack.ScrollToHome()
End Sub
Private Sub Load_OnFinish()
'结果数据化
Try
'归类
Dim Dict As New Dictionary(Of String, List(Of DlOptiFineListEntry))
Dict.Add("快照版本", New List(Of DlOptiFineListEntry))
For VersionCode As Integer = 50 To 0 Step -1
Dict.Add("1." & VersionCode, New List(Of DlOptiFineListEntry))
Next
For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
If Version.Inherit.StartsWith("1.") Then
Dim MainVersion As String = "1." & Version.NameDisplay.Split(".")(1).Split(" ")(0)
If Dict.ContainsKey(MainVersion) Then
Dict(MainVersion).Add(Version)
Else
Dict("快照版本").Add(Version)
End If
Else
Dict("快照版本").Add(Version)
End If
Next
'清空当前
PanMain.Children.Clear()
'转化为 UI
For Each Pair As KeyValuePair(Of String, List(Of DlOptiFineListEntry)) In Dict
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 3}
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
NewCard.IsSwaped = True
PanMain.Children.Add(NewCard)
Next
Catch ex As Exception
Log(ex, "可视化 OptiFine 版本列表出错", LogLevel.Feedback)
End Try
End Sub
Private Sub BtnWeb_Click(sender As Object, e As EventArgs) Handles BtnWeb.Click
OpenWebsite("https://www.optifine.net/")
End Sub
End Class
@@ -87,7 +87,7 @@
LabTitle.Text = "登录 Minecraft"
LabCaption.Text =
$"登录网页将自动开启,请在网页中输入 {UserCode}(已自动复制)。" & vbCrLf & vbCrLf &
$"如果网络环境不佳,网页可能一直加载不出来,届时请使用加速器或 VPN 以改善网络环境。" & vbCrLf &
$"如果网络环境不佳,网页可能一直加载不出来,届时请使用加速器或 VPN 改善网络环境。" & vbCrLf &
$"你也可以用其他设备打开 {Website} 并输入上述代码。"
Btn1.EventData = Website
Btn2.EventData = UserCode
@@ -114,7 +114,7 @@
"scope=XboxLive.signin%20offline_access",
ContentType:="application/x-www-form-urlencoded",
Timeout:=5000 + UnknownFailureCount * 5000,
MakeLog:=False)
MakeLog:=False, RequireJson:=True)
'获取结果
Dim ResultJson As JObject = GetJson(Result)
McLaunchLog($"令牌过期时间:{ResultJson("expires_in")} 秒")
@@ -122,6 +122,7 @@
Finished({ResultJson("access_token").ToString, ResultJson("refresh_token").ToString})
Return
Catch ex As Exception
'修改错误列表时,同时修改 ModLaunch.MsLoginStep1Refresh 中的对应代码
If TypeOf ex Is ResponsedWebException Then
Dim Response = CType(ex, ResponsedWebException).Response
If Response.Contains("authorization_declined") Then
@@ -243,19 +243,21 @@
If Not IsNothing(PageNew) AndAlso Not IsNothing(PageNew.Parent) Then PageNew.SetValue(ContentPresenter.ContentProperty, Nothing)
If Anim Then
'动画
Dispatcher.Invoke(Sub()
'执行动画
AniStart({
AaOpacity(PanLogin, -PanLogin.Opacity, 100,, New AniEaseOutFluent),
AaCode(Sub()
AniControlEnabled += 1
PanLogin.Children.Clear()
PanLogin.Children.Add(PageNew)
AniControlEnabled -= 1
End Sub, 100),
AaOpacity(PanLogin, 1, 100, 120, New AniEaseInFluent)
}, "FrmLogin PageChange")
End Sub, Threading.DispatcherPriority.Render)
Dispatcher.Invoke(
Sub()
'执行动画
AniStart({
AaOpacity(PanLogin, -PanLogin.Opacity, 100,, New AniEaseOutFluent),
AaCode(
Sub()
AniControlEnabled += 1
PanLogin.Children.Clear()
PanLogin.Children.Add(PageNew)
AniControlEnabled -= 1
End Sub, 100),
AaOpacity(PanLogin, 1, 100, 120, New AniEaseInFluent)
}, "FrmLogin PageChange")
End Sub, Threading.DispatcherPriority.Render)
Else
'无动画
AniControlEnabled += 1
@@ -390,14 +392,14 @@ UnknownType:
Result = McSkinDownload(Result)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Data.Output = Result
Catch ex As ThreadInterruptedException
Data.Output = ""
Return
Catch ex As Exception
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Return
ElseIf GetExceptionSummary(ex).Contains("429") Then
If ex.GetBrief.Contains("(429)") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Log("[Minecraft] 获取正版皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", LogLevel.Hint)
ElseIf GetExceptionSummary(ex).Contains("未设置自定义皮肤") Then
ElseIf ex.GetBrief.Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载")
Else
@@ -460,11 +462,11 @@ UseDefault:
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & ID)
Data.Output = Result
End If
Catch ex As ThreadInterruptedException
Data.Output = ""
Return
Catch ex As Exception
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Return
ElseIf GetExceptionSummary(ex).Contains("429") Then
If ex.GetBrief.Contains("(429)") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(ID)) & ".png"
Log("获取离线登录使用的正版皮肤失败(" & ID & "):获取皮肤太过频繁,请 5 分钟后再试!")
Else
@@ -512,14 +514,14 @@ UseDefault:
Result = McSkinDownload(Result)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Data.Output = Result
Catch ex As ThreadInterruptedException
Data.Output = ""
Return
Catch ex As Exception
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Return
ElseIf GetExceptionSummary(ex).Contains("429") Then
If ex.GetBrief.Contains("(429)") Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 获取统一通行证皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", LogLevel.Hint)
ElseIf GetExceptionSummary(ex).Contains("未设置自定义皮肤") Then
ElseIf ex.GetBrief.Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载")
Else
@@ -548,26 +550,26 @@ Finish:
RunInUi(Sub() If FrmLoginAuthSkin IsNot Nothing AndAlso FrmLoginAuthSkin.Skin IsNot Nothing Then FrmLoginAuthSkin.Skin.Clear())
'获取 Url
Dim UserName As String = Data.Input(0)
Dim Uuid As String = Data.Input(1)
Dim UUID As String = Data.Input(1)
If UserName = "" Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 获取 Authlib-Injector 皮肤失败,ID 为空")
GoTo Finish
End If
Try
Dim Result As String = McSkinGetAddress(Uuid, "Auth")
Dim Result As String = McSkinGetAddress(UUID, "Auth")
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Result = McSkinDownload(Result)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Data.Output = Result
Catch ex As ThreadInterruptedException
Data.Output = ""
Return
Catch ex As Exception
If ex.GetType.Name = "ThreadInterruptedException" Then
Data.Output = ""
Return
ElseIf GetExceptionSummary(ex).Contains("429") Then
If ex.GetBrief.Contains("(429)") Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 获取 Authlib-Injector 皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", LogLevel.Hint)
ElseIf GetExceptionSummary(ex).Contains("未设置自定义皮肤") Then
ElseIf ex.GetBrief.Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/Steve.png"
Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载")
Else
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PCL"> <!-- 不知道为啥只有这个文件不能在 XAML 设置 PanScroll -->
xmlns:local="clr-namespace:PCL" PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
<StackPanel x:Name="PanCustom">
@@ -1,9 +1,10 @@
Public Class PageLaunchRight
Implements IRefreshable
Imports System.Windows.Threading
Public Class PageLaunchRight
Implements IRefreshable, IDispatcherUnhandledException
Private Sub Init() Handles Me.Loaded
PanBack.ScrollToHome()
PanScroll = PanBack '不知道为啥不能在 XAML 设置
PanLog.Visibility = If(ModeDebug, Visibility.Visible, Visibility.Collapsed)
'快照版提示
#If BETA Then
@@ -28,7 +29,7 @@
''' 刷新主页。
''' </summary>
Private Sub Refresh() Handles Me.Loaded
RunInNewThread(
RunInThread(
Sub()
Try
SyncLock RefreshLock
@@ -37,37 +38,20 @@
Catch ex As Exception
Log(ex, "加载 PCL 主页自定义信息失败", If(ModeDebug, LogLevel.Msgbox, LogLevel.Hint))
End Try
End Sub, $"刷新主页 #{GetUuid()}")
End Sub)
End Sub
Private Sub RefreshReal()
Dim Content As String = ""
Dim Url As String
Dim Content As String = Nothing, Url As String = Nothing
Select Case Setup.Get("UiCustomType")
Case 1
'加载本地文件
Log("[Page] 主页自定义数据来源:本地文件")
Content = ReadFile(Path & "PCL\Custom.xaml") 'ReadFile 会进行存在检测
Case 2
'联网下载
Url = Setup.Get("UiCustomNet")
Download:
'加载联网文件
If String.IsNullOrWhiteSpace(Url) Then Exit Select
If Url = Setup.Get("CacheSavedPageUrl") AndAlso File.Exists(PathTemp & "Cache\Custom.xaml") Then
'缓存可用
Log("[Page] 主页自定义数据来源:联网缓存文件")
Content = ReadFile(PathTemp & "Cache\Custom.xaml")
'后台更新缓存
OnlineLoader.Start(Url)
Else
'缓存不可用
Log("[Page] 主页自定义数据来源:联网全新下载")
Hint("正在加载主页……")
RunInUiWait(Sub() LoadContent("")) '在加载结束前清空页面
Setup.Set("CacheSavedPageVersion", "")
OnlineLoader.Start(Url) '下载完成后将会再次触发更新
Return
End If
Case 3
'预设
Select Case Setup.Get("UiCustomPreset")
Case 0
Log("[Page] 主页预设:你知道吗")
@@ -89,50 +73,58 @@ Download:
</local:MyCard>"
Case 2
Log("[Page] 主页预设:Minecraft 新闻")
Url = "http://pcl.mcnews.thestack.top"
GoTo Download
Url = "https://mcnews.meloong.com"
Case 3
Log("[Page] 主页预设:简单主页")
Url = "https://raw.gitcode.com/mfn233/PCL-Mainpage/raw/main/Custom.xaml"
GoTo Download
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/MFn233/Custom.xaml"
Case 4
Log("[Page] 主页预设:每日整合包推荐")
Url = "https://pclsub.sodamc.com/"
GoTo Download
Case 5
Log("[Page] 主页预设:Minecraft 皮肤推荐")
Url = "https://forgepixel.com/pcl_sub_file"
GoTo Download
Case 6
Log("[Page] 主页预设:OpenBMCLAPI 仪表盘 Lite")
Url = "https://pcl-bmcl.milu.ink/"
GoTo Download
Case 7
Log("[Page] 主页预设:主页市场")
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/JingHai-Lingyun/Custom.xaml"
GoTo Download
Case 8
Log("[Page] 主页预设:更新日志")
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Joker2184/UpdateHomepage.xaml"
GoTo Download
Case 9
Log("[Page] 主页预设:PCL 新功能说明书")
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 = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Ext1nguisher/Custom.xaml"
GoTo Download
Case 12
Log("[Page] 主页预设:PCL GitHub 仪表盘")
Url = "https://raw.gitcode.com/Deep-Dark-Forest/PCL2-GitHub-Dashboard-Homepage/raw/main/custom.xaml"
GoTo Download
Url = "https://ddf.pcl-community.org/Custom.xaml"
End Select
End Select
'联网下载
If Not String.IsNullOrWhiteSpace(Url) Then
If Url = Setup.Get("CacheSavedPageUrl") AndAlso File.Exists(PathTemp & "Cache\Custom.xaml") Then
'缓存可用
Log("[Page] 主页自定义数据来源:联网缓存文件")
Content = ReadFile(PathTemp & "Cache\Custom.xaml")
'后台更新缓存
OnlineLoader.Start(Url)
Else
'缓存不可用
Log("[Page] 主页自定义数据来源:联网全新下载")
Hint("正在加载主页……")
RunInUiWait(Sub() LoadContent(Nothing)) '在加载结束前清空页面
Setup.Set("CacheSavedPageVersion", "")
OnlineLoader.Start(Url) '下载完成后将会再次触发更新
Return
End If
End If
'同步到 UI
RunInUi(Sub() LoadContent(Content))
End Sub
Private RefreshLock As New Object
@@ -170,15 +162,13 @@ Download:
Log($"[Page] 无法检查联网主页版本,将直接下载,检查源:{VersionAddress}")
End Try
'实际下载
If NeedDownload Then
Dim FileContent As String = NetRequestByClientRetry(Address)
Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}")
Setup.Set("CacheSavedPageUrl", Address)
Setup.Set("CacheSavedPageVersion", Version)
WriteFile(PathTemp & "Cache\Custom.xaml", FileContent)
End If
'要求刷新
RunInUi(AddressOf Refresh) '不直接调用 Refresh,以防止死循环(#6245)
If Not NeedDownload Then Return
Dim FileContent As String = NetRequestByClientRetry(Address)
Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}")
Setup.Set("CacheSavedPageUrl", Address)
Setup.Set("CacheSavedPageVersion", Version)
WriteFile(PathTemp & "Cache\Custom.xaml", FileContent)
Refresh() '要求刷新
Catch ex As Exception
Log(ex, $"下载主页失败({Address})", If(ModeDebug, LogLevel.Msgbox, LogLevel.Hint))
End Try
@@ -216,19 +206,19 @@ Download:
''' 必须在 UI 线程调用。
''' </summary>
Private Sub LoadContent(Content As String)
SyncLock LoadContentLock
'如果加载目标内容一致则不加载
Dim Hash = Content.GetHashCode()
If Hash = LoadedContentHash Then Return
LoadedContentHash = Hash
'实际加载内容
PanCustom.Children.Clear()
If String.IsNullOrWhiteSpace(Content) Then
Log($"[Page] 实例化:清空主页 UI,来源为空")
Return
End If
Dim LoadStartTime As Date = Date.Now
Try
Try
SyncLock LoadContentLock
'如果加载目标内容一致则不加载
Dim Hash = If(Content, "").GetHashCode()
If Hash = LoadedContentHash Then Return
LoadedContentHash = Hash
'实际加载内容
PanCustom.Children.Clear()
If String.IsNullOrWhiteSpace(Content) Then
Log($"[Page] 实例化:清空主页 UI,来源为空")
Return
End If
Dim LoadStartTime As Date = Date.Now
'修改时应同时修改 PageOtherHelpDetail.Init
Content = HelpArgumentReplace(Content)
Do While Content.Contains("xmlns")
@@ -237,26 +227,38 @@ Download:
Content = "<StackPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:sys=""clr-namespace:System;assembly=mscorlib"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:local=""clr-namespace:PCL;assembly=Plain Craft Launcher 2"">" & Content & "</StackPanel>"
Log($"[Page] 实例化:加载主页 UI 开始,最终内容长度:{Content.Count}")
PanCustom.Children.Add(GetObjectFromXML(Content))
Catch ex As Exception
If ModeDebug Then
Log(ex, "加载失败的主页内容:" & vbCrLf & Content)
If MyMsgBox(If(TypeOf ex Is UnauthorizedAccessException, ex.Message, $"主页内容编写有误,请根据下列错误信息进行检查:{vbCrLf}{GetExceptionSummary(ex)}"),
"加载主页界面失败", "重试", "取消") = 1 Then
GoTo Refresh '防止 SyncLock 死锁
End If
Else
Log(ex, "加载主页界面失败", LogLevel.Hint)
End If
Return
End Try
Dim LoadCostTime = (Date.Now - LoadStartTime).Milliseconds
Log($"[Page] 实例化:加载主页 UI 完成,耗时 {LoadCostTime}ms")
If LoadCostTime > 3000 Then Hint($"主页加载过于缓慢(花费了 {Math.Round(LoadCostTime / 1000, 1)} 秒),请向主页作者反馈此问题,或暂时停止使用该主页")
End SyncLock
Return
Refresh:
ForceRefresh()
'加载计时
Dim LoadCostTime = (Date.Now - LoadStartTime).Milliseconds
Log($"[Page] 实例化:加载主页 UI 完成,耗时 {LoadCostTime}ms")
If LoadCostTime > 3000 Then Hint($"主页加载过于缓慢(花费了 {Math.Round(LoadCostTime / 1000, 1)} 秒),请向主页作者反馈此问题,或暂时停止使用该主页")
End SyncLock
Catch ex As Exception
Log(ex, "加载失败的主页内容:" & vbCrLf & Content)
OnLoadContentFailed(ex)
End Try
End Sub
''' <summary>
''' 加载主页失败时调用。
''' </summary>
Private Sub OnLoadContentFailed(ex As Exception)
If ModeDebug OrElse Setup.Get("UiCustomType") = 1 Then
Log(ex, "加载主页失败")
If MyMsgBox(If(TypeOf ex Is UnauthorizedAccessException, ex.Message, $"主页内容编写有误,请根据下列错误信息进行检查:{vbCrLf}{ex.GetBrief}"),
"加载主页失败", "重试", "取消") = 1 Then ForceRefresh()
Else
Log(ex, "加载主页失败", LogLevel.Hint)
End If
End Sub
''' <summary>
''' 捕获主页在 Measure 和 Arrange 阶段抛出的异常。
''' </summary>
Private Sub DispatcherUnhandledException(sender As Object, e As DispatcherUnhandledExceptionEventArgs) Implements IDispatcherUnhandledException.DispatcherUnhandledException
If TypeOf e.Exception IsNot Markup.XamlParseException Then Return
e.Handled = True
LoadContent(Nothing)
OnLoadContentFailed(e.Exception)
End Sub
Private LoadedContentHash As Integer = -1
Private LoadContentLock As New Object
@@ -86,22 +86,21 @@
IsChanging = True
'开始实际获取
RunInNewThread(
Async Sub()
Sub()
Try
Retry:
If McLoginMsLoader.State = LoadState.Loading Then McLoginMsLoader.WaitForExit() '等待登录结束
Do While McLoginMsLoader.State = LoadState.Loading '等待登录结束
Thread.Sleep(10)
Loop
If McLoginMsLoader.State = LoadState.Failed Then Throw New Exception("登录失败", McLoginMsLoader.Error)
Dim AccessToken As String = Setup.Get("CacheMsV2Access")
Dim Uuid As String = Setup.Get("CacheMsV2Uuid")
Dim Client As New Net.Http.HttpClient With {.Timeout = New TimeSpan(0, 0, 30)}
Client.DefaultRequestHeaders.Authorization = New Net.Http.Headers.AuthenticationHeaderValue("Bearer", AccessToken)
Client.DefaultRequestHeaders.Accept.Add(New Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*"))
Client.DefaultRequestHeaders.UserAgent.Add(New Net.Http.Headers.ProductInfoHeaderValue("MojangSharp", "0.1"))
Dim Contents As New Net.Http.MultipartFormDataContent From {
{New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"},
{New Net.Http.ByteArrayContent(ReadFileBytes(SkinInfo.LocalFile)), "file", GetFileNameFromPath(SkinInfo.LocalFile)}
}
Dim Result As String = Await (Await Client.PostAsync(New Uri("https://api.minecraftservices.com/minecraft/profile/skins"), Contents)).Content.ReadAsStringAsync
Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/skins", HttpMethod.Post,
Content:=New Net.Http.MultipartFormDataContent From {
{New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"},
{New Net.Http.ByteArrayContent(ReadFileBytes(SkinInfo.LocalFile)), "file", GetFileNameFromPath(SkinInfo.LocalFile)}
},
Headers:={{"Authorization", "Bearer " & AccessToken}, {"Accept", "*/*"}, {"User-Agent", "MojangSharp/0.1"}})
If Result.Contains("request requires user authentication") Then
Hint("正在登录,将在登录完成后继续更改皮肤……")
McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
@@ -122,8 +121,8 @@ Retry:
Next
Throw New Exception("未知错误(" & Result & ")")
Catch ex As Exception
If ex.GetType.Equals(GetType(Tasks.TaskCanceledException)) Then
Hint("更改皮肤失败:与 Mojang 皮肤服务器的连接超时,请检查你的网络是否通畅!", HintType.Critical)
If TypeOf ex Is OperationCanceledException Then
Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Critical)
Else
Log(ex, "更改皮肤失败", LogLevel.Hint)
End If
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageLinkFeedback"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
<local:MyCard Title="关于" Margin="0,0,0,15">
@@ -4,7 +4,7 @@
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageLinkIoi"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<Grid>
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Orientation="Vertical" Margin="25,10">
@@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PCL"
mc:Ignorable="d" AnimatedControl="{Binding ElementName=PanItem}" MinWidth="150">
mc:Ignorable="d" AnimatedControl="PanItem" MinWidth="150">
<StackPanel Orientation="Vertical" x:Name="PanItem" Margin="0,12,0,0">
<TextBlock Text="联机方式" Margin="13,6,5,4" Opacity="0.6" FontSize="12" />
<local:MyListItem x:Name="ItemHiper" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="1" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="HiPer"
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageOtherAbout"
PanScroll="{Binding ElementName=PanBack}" RenderOptions.BitmapScalingMode="LowQuality">
PanScroll="PanBack" RenderOptions.BitmapScalingMode="LowQuality">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10" Grid.IsSharedSizeScope="True">
<local:MyCard Margin="0,15" Title="关于">
@@ -17,7 +17,7 @@
<ColumnDefinition />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<local:MyListItem IsHitTestVisible="False" Title="龙腾猫跃" Margin="-5,0,15,0" Info="Plain Craft Launcher 的作者!" Grid.Row="0" Grid.Column="1" />
<local:MyListItem IsHitTestVisible="False" Title="龙腾猫跃" Margin="-5,0,15,0" Info="Plain Craft Launcher 的开发者!" Grid.Row="0" Grid.Column="1" />
<local:MyListItem IsHitTestVisible="False" Title="Plain Craft Launcher 2" Margin="-5,0,15,0" Info="当前版本:%VERSION%(%VERSIONCODE%.%BRANCH%)" Grid.Row="1" Grid.Column="1" x:Name="ItemAboutPcl" />
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/Logo.png" Grid.Row="1" Margin="3">
<Image.Clip>
@@ -29,7 +29,7 @@
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip>
</Image>
<local:MyButton Text="赞助作者" Grid.Column="2" Grid.Row="0" Height="35" EventType="打开网页" EventData="https://afdian.com/a/LTCat" />
<local:MyButton Text="赞助 PCL !" Grid.Column="2" Grid.Row="0" Height="35" EventType="打开网页" EventData="https://afdian.com/a/LTCat" ColorType="Highlight" />
<local:MyButton Text="查看源代码" Grid.Column="2" Grid.Row="1" Height="35" EventType="打开网页" EventData="https://github.com/Hex-Dragon/PCL2" />
</Grid>
</local:MyCard>
@@ -51,11 +51,12 @@
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<local:MyListItem Title="bangbang93" Margin="-5,0,15,0" IsHitTestVisible="False" Info="提供 BMCLAPI 镜像源和 Forge 安装工具,详见 https://bmclapi.bangbang93.com" Grid.Row="0" Grid.Column="1" />
<local:MyButton x:Name="BtnAboutBmclapi" Text="赞助镜像源" Grid.Row="0" Grid.Column="2" Height="35" />
<local:MyButton Text="赞助镜像源" Grid.Row="0" Grid.Column="2" Height="35" EventType="打开网页" EventData="https://afdian.com/a/bangbang93" />
<local:MyListItem Title="MC 百科" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 Mod 名称的中文翻译和更多相关信息!" Grid.Row="1" Grid.Column="1" />
<local:MyButton x:Name="BtnAboutWiki" Text="打开百科" Grid.Row="1" Grid.Column="2" Height="35" />
<local:MyListItem Title="00ll00" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 Java Launch Wrapper 和一些重要服务支持!" Grid.Row="2" Grid.Column="1" />
<local:MyListItem Title="z0z0r4" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 MCIM 中国 Mod 下载镜像源和帮助库图床!" Grid.Row="3" Grid.Column="1" />
<local:MyButton Text="打开百科" Grid.Row="1" Grid.Column="2" Height="35" EventType="打开网页" EventData="https://www.mcmod.cn" />
<local:MyListItem Title="z0z0r4" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 MCIM 社区资源镜像源和帮助库图床!" Grid.Row="2" Grid.Column="1" />
<local:MyButton Text="MCIM 主页" Grid.Row="2" Grid.Column="2" Height="35" EventType="打开网页" EventData="https://github.com/mcmod-info-mirror" />
<local:MyListItem Title="00ll00" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 Java Launch Wrapper 和一些重要服务支持!" Grid.Row="3" Grid.Column="1" />
<local:MyListItem Title="Patrick" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="设计并制作了 PCL 图标,让我从做图标的水深火热中得到了解脱……" Grid.Row="4" Grid.Column="1" />
<local:MyListItem Title="Hao_Tian" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="在内测中找出了一大堆没人想得到的诡异 Bug,有非同寻常的 Bug 体质" Grid.Row="5" Grid.Column="1" />
<local:MyListItem Title="Minecraft 中文论坛" Margin="-5,0,15,0" IsHitTestVisible="False" Info="虽然已经关站了,但感谢此前提供了 MCBBS 镜像源……" Grid.Row="6" Grid.Column="1" />
@@ -70,12 +71,12 @@
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip>
</Image>
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/00ll00.png" Grid.Row="2" Margin="3">
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/z0z0r4.png" Grid.Row="2" Margin="3">
<Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip>
</Image>
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/z0z0r4.png" Grid.Row="3" Margin="3">
<Image Source="/Plain Craft Launcher 2;component/Images/Heads/00ll00.png" Grid.Row="3" Margin="3">
<Image.Clip>
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip>
@@ -104,288 +105,288 @@
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="赞助者">
<StackPanel Margin="25,40,10,20">
<TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 6 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
<WrapPanel Margin="0,0,0,10"> <TextBlock Width="120" Margin="0,1.5" Text="星月" />
<TextBlock Width="120" Margin="0,1.5" Text="Nemo" />
<TextBlock Width="120" Margin="0,1.5" Text="长歌当天" />
<TextBlock Width="120" Margin="0,1.5" Text="飒黎lIlIlI" />
<TextBlock Width="120" Margin="0,1.5" Text="hy" />
<TextBlock Width="120" Margin="0,1.5" Text="SaDhhJe" />
<TextBlock Width="120" Margin="0,1.5" Text="风铃子啊" />
<TextBlock Width="120" Margin="0,1.5" Text="柠娜" />
<TextBlock Width="120" Margin="0,1.5" Text="W丶北辰" />
<TextBlock Width="120" Margin="0,1.5" Text="才KRE" />
<TextBlock Width="120" Margin="0,1.5" Text="Yang_mistakeof" />
<TextBlock Width="120" Margin="0,1.5" Text="close eyes" />
<TextBlock Width="120" Margin="0,1.5" Text="顾顾" />
<TextBlock Width="120" Margin="0,1.5" Text="LTuuxj" />
<TextBlock Width="120" Margin="0,1.5" Text="花吃" />
<TextBlock Width="120" Margin="0,1.5" Text="FICazk" />
<TextBlock Width="120" Margin="0,1.5" Text="屑屑你" />
<TextBlock Width="120" Margin="0,1.5" Text="凉凉" />
<TextBlock Width="120" Margin="0,1.5" Text="WDSJ" />
<TextBlock Width="120" Margin="0,1.5" Text="Tohka" />
<TextBlock Width="120" Margin="0,1.5" Text="lz" />
<TextBlock Width="120" Margin="0,1.5" Text="哦嚯嚯嚯皮筋头" />
<TextBlock Width="120" Margin="0,1.5" Text="陈肖杰" />
<TextBlock Width="120" Margin="0,1.5" Text="MC小满" />
<TextBlock Width="120" Margin="0,1.5" Text="残光" />
<TextBlock Width="120" Margin="0,1.5" Text="玖玖璃" />
<TextBlock Width="120" Margin="0,1.5" Text="水晶OTZ" />
<TextBlock Width="120" Margin="0,1.5" Text="伯克礼" />
<TextBlock Width="120" Margin="0,1.5" Text="白猫海贼船" />
<TextBlock Width="120" Margin="0,1.5" Text="zhang1232" />
<TextBlock Width="120" Margin="0,1.5" Text="Never" />
<TextBlock Width="120" Margin="0,1.5" Text="Fish_pomelo" />
<TextBlock Width="120" Margin="0,1.5" Text="生风" />
<TextBlock Width="120" Margin="0,1.5" Text="富士山下" />
<TextBlock Width="120" Margin="0,1.5" Text="小七" />
<TextBlock Width="120" Margin="0,1.5" Text="发呆的呆毛君" />
<TextBlock Width="120" Margin="0,1.5" Text="天黑时看月亮" />
<TextBlock Width="120" Margin="0,1.5" Text="夜枫" />
<TextBlock Width="120" Margin="0,1.5" Text="_章333_" />
<TextBlock Width="120" Margin="0,1.5" Text="孙杰" />
<TextBlock Width="120" Margin="0,1.5" Text="wby" />
<TextBlock Width="120" Margin="0,1.5" Text="封尾==" />
<TextBlock Width="120" Margin="0,1.5" Text="你与空白皆无名" />
<TextBlock Width="120" Margin="0,1.5" Text="鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="zzxniubi" />
<TextBlock Width="120" Margin="0,1.5" Text="炎燚火淼淼" />
<TextBlock Width="120" Margin="0,1.5" Text="三巿" />
<TextBlock Width="120" Margin="0,1.5" Text="奈落" />
<TextBlock Width="120" Margin="0,1.5" Text="华佗" />
<TextBlock Width="120" Margin="0,1.5" Text="oran9e" />
<TextBlock Width="120" Margin="0,1.5" Text="赤冰雨" />
<TextBlock Width="120" Margin="0,1.5" Text="Urizen" />
<TextBlock Width="120" Margin="0,1.5" Text=":)" />
<TextBlock Width="120" Margin="0,1.5" Text="skyqyzm" />
<TextBlock Width="120" Margin="0,1.5" Text="橘子皮丶" />
<TextBlock Width="120" Margin="0,1.5" Text="额外awa" />
<TextBlock Width="120" Margin="0,1.5" Text="安上月" />
<TextBlock Width="120" Margin="0,1.5" Text="念城南" />
<TextBlock Width="120" Margin="0,1.5" Text="多低山丘陵" />
<TextBlock Width="120" Margin="0,1.5" Text="书童呀" />
<TextBlock Width="120" Margin="0,1.5" Text="sxy192425" />
<TextBlock Width="120" Margin="0,1.5" Text="李好啊" />
<TextBlock Width="120" Margin="0,1.5" Text="MH_Nine" />
<TextBlock Width="120" Margin="0,1.5" Text="周先生" />
<TextBlock Width="120" Margin="0,1.5" Text="原" />
<TextBlock Width="120" Margin="0,1.5" Text="良田满穗" />
<TextBlock Width="120" Margin="0,1.5" Text="柴" />
<TextBlock Width="120" Margin="0,1.5" Text="庭师" />
<TextBlock Width="120" Margin="0,1.5" Text="。,。" />
<TextBlock Width="120" Margin="0,1.5" Text="DHLH" />
<TextBlock Width="120" Margin="0,1.5" Text="Xayj" />
<TextBlock Width="120" Margin="0,1.5" Text="绳网用户#37" />
<TextBlock Width="120" Margin="0,1.5" Text="LLLL" />
<TextBlock Width="120" Margin="0,1.5" Text="深绯红" />
<TextBlock Width="120" Margin="0,1.5" Text="奇伢七星" />
<TextBlock Width="120" Margin="0,1.5" Text="Akapigo" />
<TextBlock Width="120" Margin="0,1.5" Text="Shink_guns" />
<TextBlock Width="120" Margin="0,1.5" Text="Aqua 极&amp;坏." />
<TextBlock Width="120" Margin="0,1.5" Text="大事化小蛋糕" />
<TextBlock Width="120" Margin="0,1.5" Text="Nakiya233" />
<TextBlock Width="120" Margin="0,1.5" Text="花小妖" />
<TextBlock Width="120" Margin="0,1.5" Text="septebr" />
<TextBlock Width="120" Margin="0,1.5" Text="一只马喽" />
<TextBlock Width="120" Margin="0,1.5" Text="下暴雨BWB" />
<TextBlock Width="120" Margin="0,1.5" Text="QAQ" />
<TextBlock Width="240" Margin="0,1.5" Text="sl土豆社区服主B友" />
<TextBlock Width="120" Margin="0,1.5" Text="Wang" />
<TextBlock Width="120" Margin="0,1.5" Text="......" />
<TextBlock Width="120" Margin="0,1.5" Text="ResTmoW" />
<TextBlock Width="120" Margin="0,1.5" Text="bochibochibo" />
<TextBlock Width="120" Margin="0,1.5" Text="铸魂之灵" />
<TextBlock Width="120" Margin="0,1.5" Text="柏柏柏" />
<TextBlock Width="120" Margin="0,1.5" Text="Mart1s" />
<TextBlock Width="120" Margin="0,1.5" Text="KuruM148" />
<TextBlock Width="120" Margin="0,1.5" Text="KaiTouCrow" />
<TextBlock Width="120" Margin="0,1.5" Text="LIE-SHAN" />
<TextBlock Width="120" Margin="0,1.5" Text="慈悲方舟" />
<TextBlock Width="120" Margin="0,1.5" Text="于析" />
<TextBlock Width="120" Margin="0,1.5" Text="陌道" />
<TextBlock Width="120" Margin="0,1.5" Text="摇椅上的猫" />
<TextBlock Width="120" Margin="0,1.5" Text="五个麦卷" />
<TextBlock Width="120" Margin="0,1.5" Text="Miraclepoi" />
<TextBlock Width="120" Margin="0,1.5" Text="XiaoLI" />
<TextBlock Width="120" Margin="0,1.5" Text="啊吧啊吧的肥宅" />
<TextBlock Width="120" Margin="0,1.5" Text="不娶雨婷不改名" />
<TextBlock Width="120" Margin="0,1.5" Text="oppo19" />
<TextBlock Width="120" Margin="0,1.5" Text="博麗靈夢" />
<TextBlock Width="120" Margin="0,1.5" Text="莹 of yours" />
<TextBlock Width="120" Margin="0,1.5" Text="ChinaFZXPVP" />
<TextBlock Width="120" Margin="0,1.5" Text="城之内sama" />
<TextBlock Width="120" Margin="0,1.5" Text="ENXI" />
<TextBlock Width="120" Margin="0,1.5" Text="steve_c418" />
<TextBlock Width="120" Margin="0,1.5" Text="洛长安" />
<TextBlock Width="120" Margin="0,1.5" Text="magic_muggle" />
<TextBlock Width="120" Margin="0,1.5" Text="小猫游六喵" />
<TextBlock Width="120" Margin="0,1.5" Text="JY" />
<TextBlock Width="120" Margin="0,1.5" Text="雪豹起司可颂" />
<TextBlock Width="120" Margin="0,1.5" Text="wlsy" />
<TextBlock Width="120" Margin="0,1.5" Text="齐先生爱溜达" />
<TextBlock Width="120" Margin="0,1.5" Text="是小泠啊" />
<TextBlock Width="120" Margin="0,1.5" Text="xioyiao" />
<TextBlock Width="120" Margin="0,1.5" Text="BunnyMiku" />
<TextBlock Width="120" Margin="0,1.5" Text="dadagga" />
<TextBlock Width="120" Margin="0,1.5" Text="无极之笔" />
<TextBlock Width="120" Margin="0,1.5" Text="xiaoyu" />
<TextBlock Width="120" Margin="0,1.5" Text="王梓杰" />
<TextBlock Width="120" Margin="0,1.5" Text="wjbjjd" />
<TextBlock Width="120" Margin="0,1.5" Text="Candy_Mo" />
<TextBlock Width="120" Margin="0,1.5" Text="lettmin_" />
<TextBlock Width="120" Margin="0,1.5" Text="七九·Alnasl" />
<TextBlock Width="120" Margin="0,1.5" Text="辉" />
<TextBlock Width="120" Margin="0,1.5" Text="何为最优解" />
<TextBlock Width="120" Margin="0,1.5" Text="crazy丶天人" />
<TextBlock Width="120" Margin="0,1.5" Text="XsBlueSky" />
<TextBlock Width="120" Margin="0,1.5" Text="冬将軍" />
<TextBlock Width="120" Margin="0,1.5" Text="tiechui" />
<TextBlock Width="120" Margin="0,1.5" Text="Liu2Shi2Pu2" />
<TextBlock Width="120" Margin="0,1.5" Text="Yu_s" />
<TextBlock Width="120" Margin="0,1.5" Text="刘四妹" />
<TextBlock Width="120" Margin="0,1.5" Text="枝皙" />
<TextBlock Width="120" Margin="0,1.5" Text="CC" />
<TextBlock Width="120" Margin="0,1.5" Text="Slana23" />
<TextBlock Width="120" Margin="0,1.5" Text="MMMy" />
<TextBlock Width="120" Margin="0,1.5" Text="Venuse" />
<TextBlock Width="120" Margin="0,1.5" Text="microjie" />
<TextBlock Width="240" Margin="0,1.5" Text="Miner#Cetyleno~^" />
<TextBlock Width="120" Margin="0,1.5" Text="春江花月夜" />
<TextBlock Width="120" Margin="0,1.5" Text="落南子" />
<TextBlock Width="120" Margin="0,1.5" Text="AL1Su-爱丽丝" />
<TextBlock Width="120" Margin="0,1.5" Text="我木有呆毛" />
<TextBlock Width="120" Margin="0,1.5" Text="乌羽" />
<TextBlock Width="120" Margin="0,1.5" Text="知性de含羞草" />
<TextBlock Width="120" Margin="0,1.5" Text="星の殇" />
<TextBlock Width="120" Margin="0,1.5" Text="IED LTAM" />
<TextBlock Width="120" Margin="0,1.5" Text="格罗夫斯基" />
<TextBlock Width="120" Margin="0,1.5" Text="梦启泉" />
<TextBlock Width="120" Margin="0,1.5" Text="岁月无痕" />
<TextBlock Width="120" Margin="0,1.5" Text="????" />
<TextBlock Width="120" Margin="0,1.5" Text="超级脑壳" />
<TextBlock Width="120" Margin="0,1.5" Text="空梦" />
<TextBlock Width="120" Margin="0,1.5" Text="薛小欣" />
<TextBlock Width="120" Margin="0,1.5" Text="蛋黄豆角" />
<TextBlock Width="120" Margin="0,1.5" Text="芒果茶州" />
<TextBlock Width="120" Margin="0,1.5" Text="癫风院院长" />
<TextBlock Width="120" Margin="0,1.5" Text="三十一" />
<TextBlock Width="120" Margin="0,1.5" Text="美醉了" />
<TextBlock Width="240" Margin="0,1.5" Text="中科院在逃量子计算机" />
<TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 8 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
<WrapPanel Margin="0,0,0,10"> <TextBlock Width="120" Margin="0,1.5" Text="粒子鹰" />
<TextBlock Width="120" Margin="0,1.5" Text="暮色黄昏" />
<TextBlock Width="120" Margin="0,1.5" Text="未殃" />
<TextBlock Width="120" Margin="0,1.5" Text="咸鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="Claud_9527" />
<TextBlock Width="120" Margin="0,1.5" Text="Qqsnd" />
<TextBlock Width="120" Margin="0,1.5" Text="☆Kiana☆" />
<TextBlock Width="120" Margin="0,1.5" Text="晓枫-橘味C" />
<TextBlock Width="120" Margin="0,1.5" Text="Ferderica" />
<TextBlock Width="120" Margin="0,1.5" Text="过路人" />
<TextBlock Width="120" Margin="0,1.5" Text="寒溪" />
<TextBlock Width="120" Margin="0,1.5" Text="小咪vv" />
<TextBlock Width="120" Margin="0,1.5" Text="容小狸" />
<TextBlock Width="120" Margin="0,1.5" Text="南宫流溪" />
<TextBlock Width="120" Margin="0,1.5" Text="懒包子" />
<TextBlock Width="120" Margin="0,1.5" Text="王家有政" />
<TextBlock Width="120" Margin="0,1.5" Text="??????" />
<TextBlock Width="120" Margin="0,1.5" Text="念念" />
<TextBlock Width="120" Margin="0,1.5" Text="启233" />
<TextBlock Width="120" Margin="0,1.5" Text="爱小黎" />
<TextBlock Width="120" Margin="0,1.5" Text="北笙T-T" />
<TextBlock Width="120" Margin="0,1.5" Text="listpmater" />
<TextBlock Width="120" Margin="0,1.5" Text="朝朝超级の好运" />
<TextBlock Width="120" Margin="0,1.5" Text="低调" />
<TextBlock Width="120" Margin="0,1.5" Text="老公" />
<TextBlock Width="120" Margin="0,1.5" Text="雍仕" />
<TextBlock Width="120" Margin="0,1.5" Text="AAboss" />
<TextBlock Width="120" Margin="0,1.5" Text="闲来无事" />
<TextBlock Width="120" Margin="0,1.5" Text="omgddcsl" />
<TextBlock Width="120" Margin="0,1.5" Text="轻舟" />
<TextBlock Width="120" Margin="0,1.5" Text="浮生Yui" />
<TextBlock Width="120" Margin="0,1.5" Text="YangFK" />
<TextBlock Width="120" Margin="0,1.5" Text="一曲勺" />
<TextBlock Width="120" Margin="0,1.5" Text="时白Herhilo" />
<TextBlock Width="120" Margin="0,1.5" Text="寒冬落雨" />
<TextBlock Width="120" Margin="0,1.5" Text="柯基0v0" />
<TextBlock Width="120" Margin="0,1.5" Text="月兔" />
<TextBlock Width="120" Margin="0,1.5" Text="qkowo" />
<TextBlock Width="120" Margin="0,1.5" Text="沐白" />
<TextBlock Width="120" Margin="0,1.5" Text="每雨天" />
<TextBlock Width="120" Margin="0,1.5" Text="AiNo" />
<TextBlock Width="120" Margin="0,1.5" Text="木叶飞舞之处" />
<TextBlock Width="120" Margin="0,1.5" Text="wilbert_laogao" />
<TextBlock Width="120" Margin="0,1.5" Text="悠芸" />
<TextBlock Width="120" Margin="0,1.5" Text="黑白盗贼" />
<TextBlock Width="120" Margin="0,1.5" Text="PotCatawa" />
<TextBlock Width="120" Margin="0,1.5" Text="小王" />
<TextBlock Width="120" Margin="0,1.5" Text="花还没开" />
<TextBlock Width="240" Margin="0,1.5" Text="PixelFrontier像素边界" />
<TextBlock Width="120" Margin="0,1.5" Text="坊之岬" />
<TextBlock Width="120" Margin="0,1.5" Text="HuTu" />
<TextBlock Width="120" Margin="0,1.5" Text="爱言叶ray" />
<TextBlock Width="120" Margin="0,1.5" Text="lenrin" />
<TextBlock Width="120" Margin="0,1.5" Text="." />
<TextBlock Width="120" Margin="0,1.5" Text="枫" />
<TextBlock Width="120" Margin="0,1.5" Text="jjj" />
<TextBlock Width="120" Margin="0,1.5" Text="clilick" />
<TextBlock Width="120" Margin="0,1.5" Text="我很快乐" />
<TextBlock Width="120" Margin="0,1.5" Text="Phoenix tamer" />
<TextBlock Width="120" Margin="0,1.5" Text="Lsp77" />
<TextBlock Width="120" Margin="0,1.5" Text="太阳神" />
<TextBlock Width="120" Margin="0,1.5" Text="ikun0014" />
<TextBlock Width="120" Margin="0,1.5" Text="IncredibleYu" />
<TextBlock Width="120" Margin="0,1.5" Text="在下粉毛控" />
<TextBlock Width="120" Margin="0,1.5" Text="SuperCrazyK" />
<TextBlock Width="120" Margin="0,1.5" Text="阿柔" />
<TextBlock Width="120" Margin="0,1.5" Text="HaKNa" />
<TextBlock Width="120" Margin="0,1.5" Text="胡十一" />
<TextBlock Width="120" Margin="0,1.5" Text="菲利絲" />
<TextBlock Width="120" Margin="0,1.5" Text="迷梦的羽" />
<TextBlock Width="120" Margin="0,1.5" Text="20018" />
<TextBlock Width="120" Margin="0,1.5" Text="波比科普员" />
<TextBlock Width="120" Margin="0,1.5" Text="Xiao_JIA" />
<TextBlock Width="240" Margin="0,1.5" Text="龙腾我是你的头号粉丝" />
<TextBlock Width="120" Margin="0,1.5" Text="keer1563" />
<TextBlock Width="120" Margin="0,1.5" Text="百鬼まル" />
<TextBlock Width="120" Margin="0,1.5" Text="DPSYnt" />
<TextBlock Width="120" Margin="0,1.5" Text="七色彩羽" />
<TextBlock Width="120" Margin="0,1.5" Text="臭氧化碳" />
<TextBlock Width="120" Margin="0,1.5" Text="情来风" />
<TextBlock Width="120" Margin="0,1.5" Text="柒月" />
<TextBlock Width="120" Margin="0,1.5" Text="汪汪队队长" />
<TextBlock Width="120" Margin="0,1.5" Text="迷路的猫" />
<TextBlock Width="120" Margin="0,1.5" Text="ktyxlan_lan" />
<TextBlock Width="120" Margin="0,1.5" Text="琳琅039" />
<TextBlock Width="120" Margin="0,1.5" Text="黑色额度" />
<TextBlock Width="120" Margin="0,1.5" Text="sahaua" />
<TextBlock Width="120" Margin="0,1.5" Text="宦昭" />
<TextBlock Width="120" Margin="0,1.5" Text="镜刹" />
<TextBlock Width="120" Margin="0,1.5" Text="房石诶多" />
<TextBlock Width="120" Margin="0,1.5" Text="熊" />
<TextBlock Width="120" Margin="0,1.5" Text="NQ" />
<TextBlock Width="120" Margin="0,1.5" Text="我志永纯" />
<TextBlock Width="120" Margin="0,1.5" Text="漫城" />
<TextBlock Width="120" Margin="0,1.5" Text="憨憨的小草" />
<TextBlock Width="120" Margin="0,1.5" Text="泽涛" />
<TextBlock Width="120" Margin="0,1.5" Text="星海鹿樱" />
<TextBlock Width="120" Margin="0,1.5" Text="祭°" />
<TextBlock Width="120" Margin="0,1.5" Text="赛冷特呀" />
<TextBlock Width="120" Margin="0,1.5" Text="无妄之灾" />
<TextBlock Width="120" Margin="0,1.5" Text="ZGW2008" />
<TextBlock Width="120" Margin="0,1.5" Text="没事多喝感冒灵" />
<TextBlock Width="120" Margin="0,1.5" Text="一梦筱筱" />
<TextBlock Width="120" Margin="0,1.5" Text="twokness" />
<TextBlock Width="120" Margin="0,1.5" Text="hhy7171" />
<TextBlock Width="120" Margin="0,1.5" Text="子虚" />
<TextBlock Width="120" Margin="0,1.5" Text="猫羽" />
<TextBlock Width="120" Margin="0,1.5" Text="有氧丁真" />
<TextBlock Width="120" Margin="0,1.5" Text="dddr" />
<TextBlock Width="120" Margin="0,1.5" Text="天气热" />
<TextBlock Width="120" Margin="0,1.5" Text="Emmanuel" />
<TextBlock Width="120" Margin="0,1.5" Text="夕尽暮染" />
<TextBlock Width="120" Margin="0,1.5" Text="Bob_Marcus" />
<TextBlock Width="120" Margin="0,1.5" Text="初心无尘" />
<TextBlock Width="120" Margin="0,1.5" Text="朱利安" />
<TextBlock Width="120" Margin="0,1.5" Text="461863352" />
<TextBlock Width="120" Margin="0,1.5" Text="庭" />
<TextBlock Width="120" Margin="0,1.5" Text="Xing_K" />
<TextBlock Width="120" Margin="0,1.5" Text="yzt" />
<TextBlock Width="120" Margin="0,1.5" Text="nuycn" />
<TextBlock Width="120" Margin="0,1.5" Text="鸡人" />
<TextBlock Width="120" Margin="0,1.5" Text="爱无界i" />
<TextBlock Width="120" Margin="0,1.5" Text="这是一头灯笼花" />
<TextBlock Width="120" Margin="0,1.5" Text="肖然星辰" />
<TextBlock Width="120" Margin="0,1.5" Text="QMX" />
<TextBlock Width="120" Margin="0,1.5" Text="山外诗" />
<TextBlock Width="120" Margin="0,1.5" Text="刘" />
<TextBlock Width="120" Margin="0,1.5" Text="萧风溪水" />
<TextBlock Width="120" Margin="0,1.5" Text="风落" />
<TextBlock Width="120" Margin="0,1.5" Text="星星绒绒" />
<TextBlock Width="120" Margin="0,1.5" Text="Ciallo~(∠?ω" />
<TextBlock Width="120" Margin="0,1.5" Text="九十九" />
<TextBlock Width="120" Margin="0,1.5" Text="Guuzen" />
<TextBlock Width="120" Margin="0,1.5" Text="极光" />
<TextBlock Width="120" Margin="0,1.5" Text="9331" />
<TextBlock Width="120" Margin="0,1.5" Text="钱程" />
<TextBlock Width="120" Margin="0,1.5" Text="杏坂和人" />
<TextBlock Width="120" Margin="0,1.5" Text="jinlijsbjaj" />
<TextBlock Width="120" Margin="0,1.5" Text="海豹" />
<TextBlock Width="120" Margin="0,1.5" Text="洛玉衡kale" />
<TextBlock Width="120" Margin="0,1.5" Text="柠乔" />
<TextBlock Width="120" Margin="0,1.5" Text="N0NiL" />
<TextBlock Width="120" Margin="0,1.5" Text="阿卡零" />
<TextBlock Width="120" Margin="0,1.5" Text="ADAA" />
<TextBlock Width="120" Margin="0,1.5" Text="岚瑬" />
<TextBlock Width="120" Margin="0,1.5" Text="爱料理的猫" />
<TextBlock Width="120" Margin="0,1.5" Text="01B8" />
<TextBlock Width="120" Margin="0,1.5" Text="MCDJ喜羊羊" />
<TextBlock Width="120" Margin="0,1.5" Text="hwch55" />
<TextBlock Width="120" Margin="0,1.5" Text="棉花糖十五" />
<TextBlock Width="120" Margin="0,1.5" Text="鱼头" />
<TextBlock Width="120" Margin="0,1.5" Text="拉普兰德天下第一" />
<TextBlock Width="120" Margin="0,1.5" Text="KGIKUY" />
<TextBlock Width="120" Margin="0,1.5" Text="初洛" />
<TextBlock Width="120" Margin="0,1.5" Text="z .e.r.o" />
<TextBlock Width="120" Margin="0,1.5" Text="独孤真菜" />
<TextBlock Width="120" Margin="0,1.5" Text="阿囊" />
<TextBlock Width="120" Margin="0,1.5" Text="rrrwcsza" />
<TextBlock Width="120" Margin="0,1.5" Text="守卫军的杂鱼兵" />
<TextBlock Width="120" Margin="0,1.5" Text="念安" />
<TextBlock Width="120" Margin="0,1.5" Text="叶" />
<TextBlock Width="120" Margin="0,1.5" Text="rreorr" />
<TextBlock Width="120" Margin="0,1.5" Text="星辰大海" />
<TextBlock Width="120" Margin="0,1.5" Text="随便" />
<TextBlock Width="120" Margin="0,1.5" Text="烤着吃的鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="大概是" />
<TextBlock Width="120" Margin="0,1.5" Text="闹山麻雀" />
<TextBlock Width="240" Margin="0,1.5" Text="我是(⊙o⊙)啥?笔" />
<TextBlock Width="120" Margin="0,1.5" Text="北纬44" />
<TextBlock Width="120" Margin="0,1.5" Text="呼呼呼" />
<TextBlock Width="120" Margin="0,1.5" Text="嘎嘎不咕咕" />
<TextBlock Width="120" Margin="0,1.5" Text="kronos" />
<TextBlock Width="120" Margin="0,1.5" Text="有个好梦,同志" />
<TextBlock Width="120" Margin="0,1.5" Text="Amojun" />
<TextBlock Width="120" Margin="0,1.5" Text="bat-744" />
<TextBlock Width="120" Margin="0,1.5" Text="那谁" />
<TextBlock Width="120" Margin="0,1.5" Text="AYOSO" />
<TextBlock Width="120" Margin="0,1.5" Text="抽抽" />
<TextBlock Width="120" Margin="0,1.5" Text="柚子皮皮皮" />
<TextBlock Width="120" Margin="0,1.5" Text="白玉京" />
<TextBlock Width="120" Margin="0,1.5" Text="ALPSL" />
<TextBlock Width="120" Margin="0,1.5" Text="我爱喝兽奶" />
<TextBlock Width="120" Margin="0,1.5" Text="wwq557" />
<TextBlock Width="120" Margin="0,1.5" Text="爱莉希雅" />
<TextBlock Width="120" Margin="0,1.5" Text="上善若水" />
<TextBlock Width="120" Margin="0,1.5" Text="zztzzy" />
<TextBlock Width="120" Margin="0,1.5" Text="SHiao_Yui" />
<TextBlock Width="120" Margin="0,1.5" Text="一只花生" />
<TextBlock Width="120" Margin="0,1.5" Text="黑凤梨熊?" />
<TextBlock Width="120" Margin="0,1.5" Text="sdad" />
<TextBlock Width="120" Margin="0,1.5" Text="BLONG" />
<TextBlock Width="120" Margin="0,1.5" Text="787878" />
<TextBlock Width="120" Margin="0,1.5" Text="myry668" />
<TextBlock Width="120" Margin="0,1.5" Text="f三文鱼f" />
<TextBlock Width="120" Margin="0,1.5" Text="apqow" />
<TextBlock Width="120" Margin="0,1.5" Text="懒梦棉花糖" />
<TextBlock Width="120" Margin="0,1.5" Text="HaiMing" />
<TextBlock Width="120" Margin="0,1.5" Text="Evernight" />
<TextBlock Width="120" Margin="0,1.5" Text="CieloNeet" />
<TextBlock Width="120" Margin="0,1.5" Text="不青盆" />
<TextBlock Width="120" Margin="0,1.5" Text="Purelimiter" />
<TextBlock Width="120" Margin="0,1.5" Text="丨白丨" />
<TextBlock Width="120" Margin="0,1.5" Text="喵" />
<TextBlock Width="120" Margin="0,1.5" Text="雨过山秋" />
<TextBlock Width="120" Margin="0,1.5" Text="急了" />
<TextBlock Width="120" Margin="0,1.5" Text="歌斐木" />
<TextBlock Width="120" Margin="0,1.5" Text="公子天邪" />
<TextBlock Width="120" Margin="0,1.5" Text="爱发癫" />
<TextBlock Width="120" Margin="0,1.5" Text="洪某某" />
<TextBlock Width="120" Margin="0,1.5" Text="漫卡洛樱" />
<TextBlock Width="120" Margin="0,1.5" Text="云与海" />
<TextBlock Width="120" Margin="0,1.5" Text="子曰" />
<TextBlock Width="120" Margin="0,1.5" Text="CyrilZ" />
<TextBlock Width="120" Margin="0,1.5" Text="笑颜如花兮" />
<TextBlock Width="120" Margin="0,1.5" Text="咸鱼超人FF酱!" />
<TextBlock Width="120" Margin="0,1.5" Text="达达利鸭" />
<TextBlock Width="120" Margin="0,1.5" Text="TFofN" />
<TextBlock Width="120" Margin="0,1.5" Text="Kumo" />
<TextBlock Width="120" Margin="0,1.5" Text="江俞白" />
<TextBlock Width="120" Margin="0,1.5" Text="聆风忘年" />
<TextBlock Width="120" Margin="0,1.5" Text="五符临门" />
<TextBlock Width="120" Margin="0,1.5" Text="亭书浅墨" />
<TextBlock Width="120" Margin="0,1.5" Text="翀归滉" />
<TextBlock Width="120" Margin="0,1.5" Text="Anmuer" />
<TextBlock Width="120" Margin="0,1.5" Text="青天揽明月" />
<TextBlock Width="120" Margin="0,1.5" Text="鲫鱼崽" />
<TextBlock Width="120" Margin="0,1.5" Text="PPTNPC" />
<TextBlock Width="120" Margin="0,1.5" Text="vIccvI" />
<TextBlock Width="120" Margin="0,1.5" Text="GOOD" />
<TextBlock Width="120" Margin="0,1.5" Text="归零之诗" />
<TextBlock Width="120" Margin="0,1.5" Text="ppp" />
<TextBlock Width="120" Margin="0,1.5" Text="Ethanhmm1234" />
<TextBlock Width="120" Margin="0,1.5" Text="库里斯库拉" />
<TextBlock Width="240" Margin="0,1.5" Text="被伪安全软件坑害的普通人" />
<TextBlock Width="120" Margin="0,1.5" Text="无元亓" />
<TextBlock Width="120" Margin="0,1.5" Text="Raven" />
<TextBlock Width="120" Margin="0,1.5" Text="看看你的jjp" />
<TextBlock Width="120" Margin="0,1.5" Text="日月皆如水" />
<TextBlock Width="120" Margin="0,1.5" Text="gzwmmm" />
<TextBlock Width="120" Margin="0,1.5" Text="早上鸥" />
<TextBlock Width="120" Margin="0,1.5" Text="CJT" />
<TextBlock Width="120" Margin="0,1.5" Text="幽永森" />
<TextBlock Width="120" Margin="0,1.5" Text="东海帝皇" />
<TextBlock Width="120" Margin="0,1.5" Text="三岁" />
<TextBlock Width="120" Margin="0,1.5" Text="shui12dkhigl" />
<TextBlock Width="120" Margin="0,1.5" Text="豪猪" />
<TextBlock Width="120" Margin="0,1.5" Text="再相遇" />
<TextBlock Width="120" Margin="0,1.5" Text="?白樱Hakura" />
<TextBlock Width="120" Margin="0,1.5" Text="IssacPyromaniac" />
<TextBlock Width="120" Margin="0,1.5" Text="纯真丁一郎" />
<TextBlock Width="120" Margin="0,1.5" Text="岩之龙" />
<TextBlock Width="120" Margin="0,1.5" Text="星之金白" />
<TextBlock Width="120" Margin="0,1.5" Text="laocao" />
<TextBlock Width="120" Margin="0,1.5" Text="DLC...是什么" />
<TextBlock Width="120" Margin="0,1.5" Text="我家老米" />
<TextBlock Width="120" Margin="0,1.5" Text="TINY" />
<TextBlock Width="240" Margin="0,1.5" Text="只会coding的农民工" />
<TextBlock Width="120" Margin="0,1.5" Text="明月一行" />
<TextBlock Width="120" Margin="0,1.5" Text="nanako" />
<TextBlock Width="120" Margin="0,1.5" Text="辛霏Aiwx" />
<TextBlock Width="120" Margin="0,1.5" Text="奇妙的白给之旅" />
<TextBlock Width="120" Margin="0,1.5" Text="你咋不上天呢^_^" />
<TextBlock Width="120" Margin="0,1.5" Text="冰糕" />
<TextBlock Width="120" Margin="0,1.5" Text="sadas" />
<TextBlock Width="120" Margin="0,1.5" Text="小叮当搞快点" />
<TextBlock Width="120" Margin="0,1.5" Text="leu" />
<TextBlock Width="240" Margin="0,1.5" Text="休伯利安本来的舰长" />
<TextBlock Width="120" Margin="0,1.5" Text="天诺一字号仓鼠" />
<TextBlock Width="120" Margin="0,1.5" Text="真爱粉只因龙" />
<TextBlock Width="120" Margin="0,1.5" Text="绝望的温度" />
<TextBlock Width="120" Margin="0,1.5" Text="busituteng" />
<TextBlock Width="120" Margin="0,1.5" Text="SiC" />
<TextBlock Width="120" Margin="0,1.5" Text="契特卡拉概念机" />
<TextBlock Width="240" Margin="0,1.5" Text="我还能再在死线挣扎一会" />
<TextBlock Width="120" Margin="0,1.5" Text="02_G1nTonic" />
<TextBlock Width="120" Margin="0,1.5" Text="渊" />
<TextBlock Width="120" Margin="0,1.5" Text="1" />
<TextBlock Width="120" Margin="0,1.5" Text="小楠" />
<TextBlock Width="120" Margin="0,1.5" Text="阿冰" />
<TextBlock Width="120" Margin="0,1.5" Text="EliasG" />
<TextBlock Width="120" Margin="0,1.5" Text="jhx" />
<TextBlock Width="120" Margin="0,1.5" Text="zyccmyk" />
<TextBlock Width="120" Margin="0,1.5" Text="luxin" />
<TextBlock Width="120" Margin="0,1.5" Text="我是我" />
<TextBlock Width="120" Margin="0,1.5" Text="13462738215" />
<TextBlock Width="120" Margin="0,1.5" Text="minecraft java" />
<TextBlock Width="120" Margin="0,1.5" Text="那是小林吖" />
<TextBlock Width="120" Margin="0,1.5" Text="GITATIG" />
<TextBlock Width="120" Margin="0,1.5" Text="Musketeer" />
<TextBlock Width="120" Margin="0,1.5" Text="AuraSpeedJerry" />
<TextBlock Width="120" Margin="0,1.5" Text="luckymore" />
<TextBlock Width="120" Margin="0,1.5" Text="hcrmhj" />
<TextBlock Width="120" Margin="0,1.5" Text="我好焦灼啊" />
<TextBlock Width="120" Margin="0,1.5" Text="小王同学" />
<TextBlock Width="120" Margin="0,1.5" Text="MoDust2131" />
<TextBlock Width="120" Margin="0,1.5" Text="啊超" />
<TextBlock Width="120" Margin="0,1.5" Text="Ander·Les" />
<TextBlock Width="120" Margin="0,1.5" Text="Niko" />
<TextBlock Width="120" Margin="0,1.5" Text="五个麦卷" />
<TextBlock Width="120" Margin="0,1.5" Text="b0Ard" />
<TextBlock Width="120" Margin="0,1.5" Text="龙猫的专属粉丝" />
<TextBlock Width="120" Margin="0,1.5" Text="雾念~" />
<TextBlock Width="120" Margin="0,1.5" Text="烬灵梦" />
<TextBlock Width="120" Margin="0,1.5" Text="蝶落染花香" />
<TextBlock Width="120" Margin="0,1.5" Text="照井黎Terui_Rei" />
<TextBlock Width="120" Margin="0,1.5" Text="???狼??王?" />
<TextBlock Width="120" Margin="0,1.5" Text="Zik yeung" />
<TextBlock Width="120" Margin="0,1.5" Text="墨子吉安" />
<TextBlock Width="120" Margin="0,1.5" Text="柠果籽" />
<TextBlock Width="120" Margin="0,1.5" Text="cai1" />
<TextBlock Width="120" Margin="0,1.5" Text="小比登T^T" />
<TextBlock Width="120" Margin="0,1.5" Text="hb" />
<TextBlock Width="120" Margin="0,1.5" Text="caizzz" />
<TextBlock Width="120" Margin="0,1.5" Text="yyin" />
<TextBlock Width="120" Margin="0,1.5" Text="無言" />
<TextBlock Width="120" Margin="0,1.5" Text="修" />
<TextBlock Width="120" Margin="0,1.5" Text="改头换面" />
<TextBlock Width="120" Margin="0,1.5" Text="无敌百搭的款式" />
<TextBlock Width="120" Margin="0,1.5" Text="御坂1354号" />
<TextBlock Width="120" Margin="0,1.5" Text="木子" />
<TextBlock Width="120" Margin="0,1.5" Text="萤火焱攸" />
<TextBlock Width="120" Margin="0,1.5" Text="盼盼不是Panda" />
<TextBlock Width="120" Margin="0,1.5" Text="烤肉真香" />
<TextBlock Width="120" Margin="0,1.5" Text="ZhuTan12" />
<TextBlock Width="120" Margin="0,1.5" Text="tom" />
<TextBlock Width="120" Margin="0,1.5" Text="洛竹" />
<TextBlock Width="120" Margin="0,1.5" Text="foob" />
<TextBlock Width="120" Margin="0,1.5" Text="Garylu" />
<TextBlock Width="120" Margin="0,1.5" Text="阮绍轩" />
<TextBlock Width="120" Margin="0,1.5" Text="xin822" />
<TextBlock Width="120" Margin="0,1.5" Text="BAIgivele" />
<TextBlock Width="120" Margin="0,1.5" Text="ljc" />
<TextBlock Width="120" Margin="0,1.5" Text="暖笑" />
<TextBlock Width="120" Margin="0,1.5" Text="焦糖流酥" />
<TextBlock Width="120" Margin="0,1.5" Text="绚丽的星河" />
<TextBlock Width="120" Margin="0,1.5" Text="魔导兔" />
<TextBlock Width="120" Margin="0,1.5" Text="吾乃斗笔" />
<TextBlock Width="120" Margin="0,1.5" Text="君殇" />
<TextBlock Width="120" Margin="0,1.5" Text="沙轻" />
<TextBlock Width="120" Margin="0,1.5" Text="邓布利多" />
<TextBlock Width="120" Margin="0,1.5" Text="红薯散养专业户" />
<TextBlock Width="120" Margin="0,1.5" Text="十言" />
<TextBlock Width="120" Margin="0,1.5" Text="vvvghjvvv" />
<TextBlock Width="120" Margin="0,1.5" Text="法斯" />
<TextBlock Width="120" Margin="0,1.5" Text="DASENSUN" />
<TextBlock Width="120" Margin="0,1.5" Text="HTS" />
<TextBlock Width="120" Margin="0,1.5" Text="握不住信新心" />
<TextBlock Width="120" Margin="0,1.5" Text="sycuuj133" />
<TextBlock Width="120" Margin="0,1.5" Text="天杉大将军" />
<TextBlock Width="120" Margin="0,1.5" Text="风见翎" />
<TextBlock Width="120" Margin="0,1.5" Text="江心Rain" />
<TextBlock Width="120" Margin="0,1.5" Text="Coco" />
<TextBlock Width="120" Margin="0,1.5" Text="Ricardo" />
<TextBlock Width="120" Margin="0,1.5" Text="2969307002" />
<TextBlock Width="120" Margin="0,1.5" Text="鬼卿" />
<TextBlock Width="120" Margin="0,1.5" Text="李白" />
<TextBlock Width="120" Margin="0,1.5" Text="霜木翔凤" />
<TextBlock Width="120" Margin="0,1.5" Text="岽龙" />
<TextBlock Width="120" Margin="0,1.5" Text="joksqp" />
<TextBlock Width="240" Margin="0,1.5" Text="what are you 说啥嘞?" />
<TextBlock Width="120" Margin="0,1.5" Text="木得爱_没人疼" />
<TextBlock Width="120" Margin="0,1.5" Text="小黑子?" />
<TextBlock Width="240" Margin="0,1.5" Text="删除线Strikethrough" />
<TextBlock Width="120" Margin="0,1.5" Text="REMOTE" />
<TextBlock Width="120" Margin="0,1.5" Text="H" />
<TextBlock Width="120" Margin="0,1.5" Text="Parapha" />
<TextBlock Width="120" Margin="0,1.5" Text="南吕十三" />
<TextBlock Width="120" Margin="0,1.5" Text="米帝" />
<TextBlock Width="120" Margin="0,1.5" Text="zdxff" />
<TextBlock Width="120" Margin="0,1.5" Text="蔚空" />
<TextBlock Width="120" Margin="0,1.5" Text="cleverboy1066" />
<TextBlock Width="120" Margin="0,1.5" Text="烤老鼠" />
<TextBlock Width="120" Margin="0,1.5" Text="TS彦祖" />
<TextBlock Width="120" Margin="0,1.5" Text="狮某人" />
<TextBlock Width="120" Margin="0,1.5" Text="lmst_myh" />
<TextBlock Width="120" Margin="0,1.5" Text="耐·若何" />
<TextBlock Width="120" Margin="0,1.5" Text="qvq" />
<TextBlock Width="120" Margin="0,1.5" Text="刀客塔" />
<TextBlock Width="120" Margin="0,1.5" Text="mika" />
<TextBlock Width="120" Margin="0,1.5" Text="金尘" />
<TextBlock Width="120" Margin="0,1.5" Text="喜之狼与灰太羊" />
<TextBlock Width="120" Margin="0,1.5" Text="天才小宋" />
<TextBlock Width="120" Margin="0,1.5" Text="MdsR" />
<TextBlock Width="120" Margin="0,1.5" Text="诗和雨夜" />
<TextBlock Width="120" Margin="0,1.5" Text="Samueldong" />
<TextBlock Width="120" Margin="0,1.5" Text="BBK" />
<TextBlock Width="120" Margin="0,1.5" Text="雪枫Sople" />
<TextBlock Width="120" Margin="0,1.5" Text="一坨灰" />
<TextBlock Width="120" Margin="0,1.5" Text="RI_CK" />
<TextBlock Width="120" Margin="0,1.5" Text="ximeng22" />
<TextBlock Width="120" Margin="0,1.5" Text="天天122_" />
<TextBlock Width="120" Margin="0,1.5" Text="李小浩&amp;mod" />
<TextBlock Width="120" Margin="0,1.5" Text="Southsheng" />
</WrapPanel>
<Grid Height="35">
<Grid.ColumnDefinitions>
@@ -400,11 +401,13 @@
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="法律信息" IsSwaped="True" CanSwap="True">
<local:MyCard Margin="0,0,0,15" Title="法律信息" IsSwapped="True" CanSwap="True">
<StackPanel Margin="25,39,23,20">
<TextBlock Text="隐私说明" TextWrapping="Wrap" Margin="0,6,0,4" FontWeight="Bold" />
<TextBlock Margin="0,0,0,2" LineHeight="17" Text="本软件的 User Agent 中包含启动器的版本号,以统计各版本的用户数量。&#13;除此之外,本软件不会向开发者上传任何其他信息。" TextWrapping="Wrap" />
<TextBlock Text="其他信息" TextWrapping="Wrap" Margin="0,12,0,4" FontWeight="Bold" />
<TextBlock Text="匿名数据收集" TextWrapping="Wrap" Margin="0,6,0,4" FontWeight="Bold" />
<TextBlock Margin="0,0,0,2" LineHeight="17" Text="当下载失败、PCL 出错、游戏崩溃等事件时,PCL 会匿名上报信息,以通知龙猫 “哦吼,出错了”,让龙猫能更好地修 Bug……(PCL 不会上传或收集任何个人信息,包括上报的东西里面也没有!)&#xa;你可以在 设置 → 其他 → 启动器 中关闭上报,不过龙猫就不知道你遇到了什么 Bug 了……&#xa;详情:https://github.com/Meloong-Git/PCL/discussions/7036" TextWrapping="Wrap" />
<TextBlock Text="隐私声明与个人信息保护政策" TextWrapping="Wrap" Margin="0,10,0,4" FontWeight="Bold" />
<TextBlock Margin="0,0,0,2" LineHeight="17" Text="PCL 没有收集个人信息,所以这里其实啥都不用写……&#xa;留个这个其实只是为了让你知道 PCL 没有收集个人信息,诶嘿。" TextWrapping="Wrap" />
<TextBlock Text="其他信息" TextWrapping="Wrap" Margin="0,10,0,4" FontWeight="Bold" />
<TextBlock Margin="0,0,0,2" LineHeight="17" Text="Copyright © 龙腾猫跃 2016. All Rights Reserved.&#13;计算机软件著作权登记号:2020SR0875133&#13;违法违规行为举报投诉邮箱:[email protected]&#13;非 MINECRAFT 官方产品。未经 MOJANG 或 MICROSOFT 批准,也不与 MOJANG 或 MICROSOFT 关联。" TextWrapping="Wrap" />
<StackPanel Orientation="Horizontal" Height="35" HorizontalAlignment="Left" Margin="0,12,0,0">
<local:MyButton Text="用户协议与免责声明" Width="170" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" EventType="打开网页" EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW" />
@@ -412,7 +415,7 @@
</StackPanel>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="许可与版权声明" IsSwaped="True" CanSwap="True">
<local:MyCard Margin="0,0,0,15" Title="许可与版权声明" IsSwapped="True" CanSwap="True">
<Grid Margin="25,42,23,4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -18,12 +18,6 @@
End Sub
Private Sub BtnAboutBmclapi_Click(sender As Object, e As EventArgs) Handles BtnAboutBmclapi.Click
OpenWebsite("https://afdian.com/a/bangbang93")
End Sub
Private Sub BtnAboutWiki_Click(sender As Object, e As EventArgs) Handles BtnAboutWiki.Click
OpenWebsite("https://www.mcmod.cn")
End Sub
Public Shared Sub CopyUniqueAddress() Handles BtnDonateCopy.Click
ClipboardSet(UniqueAddress)
End Sub
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageOtherHelp"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<Grid>
<local:MyScrollViewer Visibility="Collapsed" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
@@ -55,7 +55,7 @@
If Type = "指南" Then
MyCard.StackInstall(NewStack, 11, "指南")
Else
NewCard.IsSwaped = True
NewCard.IsSwapped = True
End If
PanList.Children.Add(NewCard)
Next
@@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PCL"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanCustom" Margin="25,25,25,10">
<StackPanel.Resources>
@@ -1,7 +1,7 @@
<local:MyPageLeft x:Class="PageOtherLeft"
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}">
xmlns:local="clr-namespace:PCL" AnimatedControl="PanItem">
<StackPanel Margin="0,12,0,0" Name="PanItem">
<local:MyListItem x:Name="ItemHelp" IsScaleAnimationEnabled="False" Checked="True" Type="RadioBox" Tag="0" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="帮助"
LogoScale="0.97" Logo="M520.6 620.3c-11.3-0.6-20.1-4-26.9-10.5-6.6-6.3-8.1-11-10.1-20.8-1.9-9.5-1.5-16.7-1-24.9l0.3-5.3c0.5-9.9 3.5-19.6 8.8-28.1 5.7-9 12.5-17.2 20.8-25.1 8.6-8 17.7-15.7 27-22.9 9.4-7.2 18.7-14.8 27.7-22.7 9-7.9 16.2-15.8 22.1-24.3 6.2-9 9.3-18.8 9.3-29.4 1.2-20.3-6.5-37.7-22.8-51.3-16-13.3-37.4-20-63.5-20-13.7 0-26.3 3.3-37.4 10-10.9 6.5-20.2 14.5-27.7 23.8-7.5 9.2-13.5 19-17.9 29.2-4.5 10.6-6.7 19.4-6.7 26.8 0 9.2-3.3 16-10.1 20.8-6.9 4.8-14.6 7.3-22.8 7.3h-1.3c-9-0.3-17-3.3-24.6-9.2-7.3-5.6-11.1-14.6-11.6-27.5-0.6-11.5 1.9-26.1 7.2-43.5 5.4-17.4 14.8-34.4 28.1-50.5 13.4-16.3 31.2-30.4 52.8-41.8 21.6-11.4 49.2-17.2 81.9-17.2 26.4 0 49.6 3.9 69.1 11.7 19.4 7.7 35.4 18.2 47.5 31.1l1.6 1.7c11.8 12.6 20.3 21.7 29.4 44.4 11.6 28.9 7.1 52.1 5.5 58.5-5.8 22.6-12.6 37.7-22.7 50.4-11.7 14.6-24.9 28.2-39.2 40.4-14 11.7-39.2 33.3-39.2 33.3-13.3 11.4-19.4 22.1-18.6 32.9V587c0.5 8.7-2.4 16.1-8.8 22.8-6.2 6.4-14.8 10-26.2 10.5zM519 766.1c-13 0-23.6-4.2-32.2-12.9-8.7-8.7-13-19-13-31.4 0-12.9 4.2-23.5 12.9-32.2 8.7-8.7 19.2-12.9 32.2-12.9 13 0 23.5 4.2 32.2 12.9s12.9 19.2 12.9 32.2c0 12.4-4.2 22.7-12.9 31.4-8.6 8.6-19.2 12.9-32.1 12.9z M515 928.3c-228.1 0-413.7-185.6-413.7-413.7S286.9 100.9 515 100.9s413.7 185.6 413.7 413.7c0.1 228.1-185.5 413.7-413.7 413.7z m0-747.4c-184 0-333.7 149.7-333.7 333.7S331 848.3 515 848.3s333.7-149.7 333.7-333.7S699 180.9 515 180.9z">
@@ -132,7 +132,7 @@
End Sub
Public Shared Sub TryFeedback()
If Not CanFeedback(True) Then Return
Select Case MyMsgBox("在提交新反馈前,建议先搜索反馈列表,以避免重复提交。" & vbCrLf & "如果无法打开该网页,请使用 VPN 以改善网络环境。",
Select Case MyMsgBox("在提交新反馈前,建议先搜索反馈列表,以避免重复提交。" & vbCrLf & "如果无法打开该网页,请使用 VPN 改善网络环境。",
"反馈", "提交新反馈", "查看反馈列表", "取消")
Case 1
Feedback(True, False)
@@ -146,7 +146,7 @@
e.Handled = True
End Sub
Public Shared Sub TryVote()
If MyMsgBox("是否要打开新功能投票网页?" & vbCrLf & "如果无法打开该网页,请使用 VPN 以改善网络环境。",
If MyMsgBox("是否要打开新功能投票网页?" & vbCrLf & "如果无法打开该网页,请使用 VPN 改善网络环境。",
"新功能投票", "打开", "取消") = 2 Then Return
OpenWebsite("https://github.com/Meloong-Git/PCL/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")
End Sub
@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PCL"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<TextBlock Text="为便于维护,开源内容中不包含百宝箱功能……" HorizontalAlignment="Center" FontSize="15" Height="30" VerticalAlignment="Center" />
</local:MyScrollViewer>
@@ -1,7 +1,7 @@
<local:MyPageLeft
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PCL;assembly=" x:Class="PageSelectLeft"
AnimatedControl="{Binding ElementName=PanList, Mode=OneWay}">
AnimatedControl="PanList">
<AdornerDecorator>
<Grid>
<Grid.RowDefinitions>
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageSelectRight"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<Grid>
<Grid x:Name="PanAllBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
@@ -81,15 +81,15 @@
PanMain.Children.Add(NewCard)
'确定卡片是否展开
If Card.Key = McVersionCardType.Rubbish OrElse Card.Key = McVersionCardType.Error OrElse Card.Key = McVersionCardType.Fool Then
NewCard.IsSwaped = True
NewCard.IsSwapped = True
Else
MyCard.StackInstall(NewStack, 0, CardTitle)
End If
Next
'若只有一个卡片,则强制展开
If PanMain.Children.Count = 1 AndAlso CType(PanMain.Children(0), MyCard).IsSwaped Then
CType(PanMain.Children(0), MyCard).IsSwaped = False
If PanMain.Children.Count = 1 AndAlso CType(PanMain.Children(0), MyCard).IsSwapped Then
CType(PanMain.Children(0), MyCard).IsSwapped = False
End If
'判断应该显示哪一个页面
@@ -14,7 +14,6 @@
{"HintDownloadThread", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintNotice", New SetupEntry(0, Source:=SetupSource.Registry)},
{"HintDownload", New SetupEntry(0, Source:=SetupSource.Registry)},
{"HintInstallBack", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintHide", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintHandInstall", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintBuy", New SetupEntry(False, Source:=SetupSource.Registry)},
@@ -42,6 +41,7 @@
{"SystemSystemCache", New SetupEntry("", Source:=SetupSource.Registry)},
{"SystemSystemUpdate", New SetupEntry(0)},
{"SystemSystemActivity", New SetupEntry(0)},
{"SystemSystemTelemetry", New SetupEntry(True, Source:=SetupSource.Registry)},
{"CacheExportConfig", New SetupEntry("", Source:=SetupSource.Registry)},
{"CacheSavedPageUrl", New SetupEntry("", Source:=SetupSource.Registry)},
{"CacheSavedPageVersion", New SetupEntry("", Source:=SetupSource.Registry)},
@@ -124,7 +124,7 @@
{"ToolDownloadTranslateV2", New SetupEntry(1, Source:=SetupSource.Registry)},
{"ToolDownloadIgnoreQuilt", New SetupEntry(True, Source:=SetupSource.Registry)},
{"ToolDownloadCert", New SetupEntry(False, Source:=SetupSource.Registry)},
{"ToolDownloadMod", New SetupEntry(1, Source:=SetupSource.Registry)},
{"ToolDownloadMod", New SetupEntry(2, Source:=SetupSource.Registry)},
{"ToolModLocalNameStyle", New SetupEntry(0, Source:=SetupSource.Registry)},
{"ToolUpdateAlpha", New SetupEntry(0, Source:=SetupSource.Registry, Encoded:=True)},
{"ToolUpdateRelease", New SetupEntry(False, Source:=SetupSource.Registry)},
@@ -181,6 +181,7 @@
{"VersionAdvanceRun", New SetupEntry("", Source:=SetupSource.Version)},
{"VersionAdvanceRunWait", New SetupEntry(True, Source:=SetupSource.Version)},
{"VersionAdvanceDisableJLW", New SetupEntry(False, Source:=SetupSource.Version)},
{"VersionAdvanceDisableModUpdate", New SetupEntry(False, Source:=SetupSource.Version)},
{"VersionRamType", New SetupEntry(2, Source:=SetupSource.Version)},
{"VersionRamCustom", New SetupEntry(15, Source:=SetupSource.Version)},
{"VersionRamOptimize", New SetupEntry(0, Source:=SetupSource.Version)},
@@ -4,7 +4,7 @@
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" x:Class="PageSetupLaunch"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,25,25,10">
<local:MyCard x:Name="CardArgument" Margin="0,0,0,15" Title="启动选项">
@@ -171,7 +171,7 @@
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardSkin" Margin="0,0,0,15" Title="离线皮肤" CanSwap="True" IsSwaped="True">
<local:MyCard x:Name="CardSkin" Margin="0,0,0,15" Title="离线皮肤" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,25,15">
<local:MyHint Text="由于技术问题,此功能只保证对 1.19.2 以前的版本有效!" Theme="Yellow" Margin="0,0,0,10" />
<Grid Margin="-1,0,0,0">
@@ -218,7 +218,7 @@
</Grid>
</StackPanel>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="高级启动选项" IsSwaped="True" CanSwap="True">
<local:MyCard Margin="0,0,0,15" Title="高级选项" IsSwapped="True" CanSwap="True">
<Grid Margin="25,40,25,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -235,14 +235,14 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,25,0">
<TextBlock Text="JVM 参数头部" VerticalAlignment="Center" />
<TextBlock Text="Java 虚拟机参数" VerticalAlignment="Center" />
<local:MyIconButton Height="23" Margin="0,1,0,0" x:Name="BtnAdvanceJvmReset" VerticalAlignment="Center"
ToolTip="还原" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1"
Logo="M530 0c287 0 521 229 521 511s-233 511-521 511c-233 0-436-151-500-368a63 63 0 0 1 44-79 65 65 0 0 1 80 43c48 162 200 276 375 276 215 0 390-171 390-383s-174-383-390-383c-103 0-199 39-270 106l21-5a63 63 0 0 1 33 123l-157 42a65 65 0 0 1-90-42l-49-183a65 65 0 1 1 126-33l6 26A524 524 0 0 1 530 0z" LogoScale="0.9" />
</StackPanel>
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Tag="LaunchAdvanceJvm" Grid.Column="1" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,除非有确定把握,否则请不要修改。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。" MaxLength="4000"
Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数尾部" Margin="0,0,25,0" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchAdvanceRun" Grid.Column="1" HintText=""
@@ -255,7 +255,7 @@
<local:MyCheckBox Height="28" Text="要求 Java 使用高性能显卡" x:Name="CheckAdvanceGraphicCard" Tag="LaunchAdvanceGraphicCard"
ToolTipService.Placement="Right" ToolTip="自动在 Windows 设置 → 系统 → 屏幕 → 显示卡 中将 Java 改为使用高性能显卡。&#xa;如果电脑同时有集显和独显,这能确保 MC 使用独显进行渲染,以大幅提高性能。" />
</StackPanel>
<local:MyHint Text="你还可以在版本独立设置中找到更多高级启动选项。" Margin="0,5,0,10" Theme="Blue" Grid.Row="7" Grid.ColumnSpan="2"
<local:MyHint Text="版本独立设置中还有更多高级选项可供调整。" Margin="0,5,0,10" Theme="Blue" Grid.Row="7" Grid.ColumnSpan="2"
CanClose="True" RelativeSetup="HintMoreAdvancedSetup" />
</Grid>
</local:MyCard>
@@ -71,7 +71,7 @@
Try
Setup.Reset("LaunchArgumentTitle")
Setup.Reset("LaunchArgumentInfo")
Setup.Reset("LaunchArgumentIndieV2")
Setup.Set("LaunchArgumentIndieV2", Setup.GetDefault("LaunchArgumentIndieV2"))
Setup.Reset("LaunchArgumentVisible")
Setup.Reset("LaunchArgumentWindowType")
Setup.Reset("LaunchArgumentWindowWidth")
@@ -585,4 +585,12 @@ PreFin:
FrmMain.PageChange(FormMain.PageType.VersionSetup, FormMain.PageSubType.VersionSetup)
End Sub
'去除参数中的回车
Private Sub ReplaceEnter(sender As MyTextBox, e As TextChangedEventArgs) Handles TextAdvanceJvm.TextChanged, TextAdvanceGame.TextChanged
Dim NewText = sender.Text.Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, " ")
If NewText = sender.Text Then Return
Dim CaretIndex = sender.CaretIndex
sender.Text = NewText
sender.CaretIndex = Math.Max(0, CaretIndex - 1)
End Sub
End Class
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="PageSetupLeft"
d:DesignWidth="152" AnimatedControl="{Binding ElementName=PanItem, Mode=OneWay}">
d:DesignWidth="152" AnimatedControl="PanItem">
<StackPanel Margin="0,12,0,0" x:Name="PanItem">
<local:MyListItem x:Name="ItemLaunch" IsScaleAnimationEnabled="False" Checked="True" Tag="0" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="启动" Type="RadioBox"
LogoScale="1" Logo="M924.009688 527.92367C875.975633 601.905321 808.729835 663.317138 733.564477 712.920073 726.302532 832.878385 665.670459 944.569541 567.084624 1015.075229 558.826862 1020.965578 549.065982 1024 539.239339 1024 533.048367 1024 526.829211 1022.806899 520.929468 1020.373725 505.663413 1014.023046 494.709431 1000.278899 491.966239 983.941872 484.67611 940.755376 465.361028 892.899817 436.876917 844.546349 404.954422 853.283229 373.980771 860.385468 344.970569 865.420917 342.227376 865.92822 339.484183 866.144294 336.75978 866.144294 324.142972 866.144294 311.920734 861.174606 302.855046 852.061945L172.807046 721.685138C161.768514 710.637211 156.789431 694.863853 159.466862 679.466275 164.502312 650.390312 171.576367 619.341505 180.27567 587.362642 132.100697 558.822165 84.376661 539.450716 41.302899 532.151193 25.00345 529.370422 11.287486 518.41644 4.98378 503.103413-1.319927 487.809174 0.662312 470.316624 10.254092 456.826128 80.581284 357.958459 191.971817 297.185468 311.591927 289.857761 361.053945 214.495119 422.31545 147.061431 496.081028 98.895853 636.030826 7.54378 802.350972 0 974.730569 0 1001.223046 0 1022.680073 21.494606 1022.680073 48.034055 1022.680073 213.997211 1015.061138 387.72022 924.009688 527.92367ZM558.122275 918.528C601.506055 876.187009 631.784514 822.328367 645.81989 763.744294 602.680367 785.86833 558.563817 804.553982 515.067303 819.989138 533.358385 853.161101 548.023193 886.267303 558.122275 918.528ZM106.566459 465.807266C138.705028 475.915743 171.717284 490.627523 204.804697 508.937394 220.192881 465.337541 238.803376 421.117651 260.871046 377.865394 202.493651 391.947743 148.822899 422.282569 106.566459 465.807266ZM548.398972 179.444257C395.794789 279.09167 294.681835 493.94378 258.522422 671.678239L352.749211 766.121101C530.00455 729.877138 744.283596 628.510532 843.667963 475.474202 912.557798 369.39156 924.742459 236.562789 926.527413 96.387523 786.699743 98.172477 654.227963 110.385321 548.398972 179.444257ZM687.071119 416.617688C642.93578 416.617688 607.161541 380.74011 607.161541 336.492037 607.161541 292.234569 642.93578 256.37578 687.071119 256.37578 731.206459 256.37578 766.971303 292.234569 766.971303 336.492037 766.971303 380.74011 731.206459 416.617688 687.071119 416.617688ZM67.222312 858.008661C77.171083 825.118532 107.646826 801.171963 143.702899 801.171963 187.838239 801.171963 223.603083 837.040147 223.603083 881.297615 223.603083 917.438239 199.722275 948.017321 166.926092 957.975486L52.46356 992.763303C50.998018 993.204844 49.438532 993.458495 47.813284 993.458495 38.973064 993.458495 31.823853 986.290495 31.823853 977.431486 31.823853 975.806239 32.058716 974.237358 32.519046 972.771817L67.222312 858.008661Z">
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageSetupLink"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="HiPer">
@@ -4,7 +4,7 @@
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" x:Class="PageSetupSystem"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="下载">
@@ -62,16 +62,18 @@
<RowDefinition Height="7" />
<RowDefinition Height="28" />
<RowDefinition Height="7" />
<RowDefinition Height="28" />
<RowDefinition Height="7" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!--<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="下载源" Margin="0,0,25,0" />
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="来源" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboDownloadMod" Grid.Row="0" Grid.ColumnSpan="2" Tag="ToolDownloadMod" Grid.Column="1">
<local:MyComboBoxItem Content="尽量使用镜像源(暂时无效)" />
<local:MyComboBoxItem Content="尽量使用镜像源(可能缺少刚刚更新的版本)" />
<local:MyComboBoxItem Content="仅在官方源加载缓慢时改用镜像源" />
<local:MyComboBoxItem Content="尽量使用官方源" IsSelected="True" />
</local:MyComboBox>-->
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="文件名格式" Margin="0,0,25,0" />
<local:MyComboBox Grid.Row="0" x:Name="ComboDownloadTranslateV2" Grid.ColumnSpan="2" Tag="ToolDownloadTranslateV2" Grid.Column="1"
</local:MyComboBox>
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="文件名格式" Margin="0,0,25,0" />
<local:MyComboBox Grid.Row="2" x:Name="ComboDownloadTranslateV2" Grid.ColumnSpan="2" Tag="ToolDownloadTranslateV2" Grid.Column="1"
ToolTip="下载社区资源时,其默认文件名的格式">
<local:MyComboBoxItem Content="【机械动力】create-1.21.1-6.0.4" />
<local:MyComboBoxItem Content="[机械动力] create-1.21.1-6.0.4" IsSelected="True" />
@@ -79,13 +81,13 @@
<local:MyComboBoxItem Content="create-1.21.1-6.0.4-机械动力" />
<local:MyComboBoxItem Content="create-1.21.1-6.0.4" />
</local:MyComboBox>
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="Mod 管理样式" Margin="0,0,25,0" />
<local:MyComboBox Grid.Row="2" x:Name="ComboModLocalNameStyle" Grid.ColumnSpan="2" Tag="ToolModLocalNameStyle" Grid.Column="1"
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="Mod 管理样式" Margin="0,0,25,0" />
<local:MyComboBox Grid.Row="4" x:Name="ComboModLocalNameStyle" Grid.ColumnSpan="2" Tag="ToolModLocalNameStyle" Grid.Column="1"
ToolTip="在 Mod 管理页面中,Mod 项的显示方式">
<local:MyComboBoxItem Content="标题显示译名,详情显示文件名" IsSelected="True" />
<local:MyComboBoxItem Content="标题显示文件名,详情显示译名" />
</local:MyComboBox>
<local:MyCheckBox Margin="0,2,0,4" Text="在显示 Mod 加载器时忽略 Quilt" Grid.Row="4" Height="22" Grid.ColumnSpan="2"
<local:MyCheckBox Margin="0,2,0,4" Text="在显示 Mod 加载器时忽略 Quilt" Grid.Row="6" Height="22" Grid.ColumnSpan="2"
x:Name="CheckDownloadIgnoreQuilt" Tag="ToolDownloadIgnoreQuilt" />
</Grid>
</StackPanel>
@@ -109,7 +111,7 @@
<local:MyCheckBox Text="自动设置为中文" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="5" x:Name="CheckHelpChinese" Tag="ToolHelpChinese" />
</Grid>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="系统">
<local:MyCard Margin="0,0,0,15" Title="启动器">
<Grid Margin="25,40,25,20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
@@ -124,6 +126,7 @@
<RowDefinition Height="5" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动器更新" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboSystemUpdate" Tag="SystemSystemUpdate" Grid.Column="1">
@@ -145,7 +148,10 @@
<local:ValidateFolderPath UseMinecraftCharCheck="False" />
</local:MyTextBox.ValidateRules>
</local:MyTextBox>
<Grid Height="35" Grid.Row="6" Grid.ColumnSpan="5" Margin="0,12,0,0">
<local:MyCheckBox Margin="0,5,0,4" Text="匿名数据收集" Grid.Row="6" Height="22" Grid.ColumnSpan="2"
x:Name="CheckSystemTelemetry" Tag="SystemSystemTelemetry"
ToolTip="当下载失败、PCL 出错、游戏崩溃等事件时,PCL 会匿名上报情况,以通知龙猫 “哦吼,出错了”,让龙猫能更好地修 Bug……&#xa;你可以关闭上报,不过龙猫就不知道你遇到了什么 Bug 了……&#13;PCL 不会上传或收集任何个人信息,包括上报的东西里面也没有!&#xa;详情:https://github.com/Meloong-Git/PCL/discussions/7036" />
<Grid Height="35" Grid.Row="7" Grid.ColumnSpan="5" Margin="0,12,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
@@ -155,7 +161,7 @@
<local:MyButton Grid.Column="1" x:Name="BtnSystemSettingExp" MinWidth="140" Text="导出设置" Padding="13,0" Margin="0,0,20,0" />
<local:MyButton Grid.Column="2" x:Name="BtnSystemSettingImp" MinWidth="140" Text="导入设置" Padding="13,0" Margin="0,0,20,0" />
</Grid>
<Grid Height="35" Grid.Row="7" Grid.ColumnSpan="5" Margin="0,12,0,0" x:Name="PanDonate">
<Grid Height="35" Grid.Row="8" Grid.ColumnSpan="5" Margin="0,12,0,0" x:Name="PanDonate">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
@@ -182,7 +188,7 @@
</Grid>
</StackPanel>
</local:MyCard> -->
<local:MyCard x:Name="CardDebug" Margin="0,0,0,15" Title="调试选项" CanSwap="True" IsSwaped="True">
<local:MyCard x:Name="CardDebug" Margin="0,0,0,15" Title="调试选项" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,25,15">
<Grid x:Name="PanDebugAnim" Height="22" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
@@ -35,7 +35,7 @@
'Mod 与整合包
ComboDownloadTranslateV2.SelectedIndex = Setup.Get("ToolDownloadTranslateV2")
'ComboDownloadMod.SelectedIndex = Setup.Get("ToolDownloadMod")
ComboDownloadMod.SelectedIndex = Setup.Get("ToolDownloadMod")
ComboModLocalNameStyle.SelectedIndex = Setup.Get("ToolModLocalNameStyle")
CheckDownloadIgnoreQuilt.Checked = Setup.Get("ToolDownloadIgnoreQuilt")
@@ -50,6 +50,7 @@
ComboSystemUpdate.SelectedIndex = Setup.Get("SystemSystemUpdate")
ComboSystemActivity.SelectedIndex = Setup.Get("SystemSystemActivity")
TextSystemCache.Text = Setup.Get("SystemSystemCache")
CheckSystemTelemetry.Checked = Setup.Get("SystemSystemTelemetry")
'调试选项
CheckDebugMode.Checked = Setup.Get("SystemDebugMode")
@@ -81,6 +82,7 @@
Setup.Reset("SystemSystemCache")
Setup.Reset("SystemSystemUpdate")
Setup.Reset("SystemSystemActivity")
Setup.Reset("SystemSystemTelemetry")
Log("[Setup] 已初始化启动器页设置")
Hint("已初始化启动器页设置!", HintType.Finish, False)
@@ -92,13 +94,13 @@
End Sub
'将控件改变路由到设置改变
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckDebugMode.Change, CheckDebugDelay.Change, CheckDebugSkipCopy.Change, CheckUpdateRelease.Change, CheckUpdateSnapshot.Change, CheckHelpChinese.Change, CheckDownloadIgnoreQuilt.Change, CheckDownloadCert.Change
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckDebugMode.Change, CheckDebugDelay.Change, CheckDebugSkipCopy.Change, CheckUpdateRelease.Change, CheckUpdateSnapshot.Change, CheckHelpChinese.Change, CheckDownloadIgnoreQuilt.Change, CheckDownloadCert.Change, CheckSystemTelemetry.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
End Sub
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderDebugAnim.Change, SliderDownloadThread.Change, SliderDownloadSpeed.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value)
End Sub
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboDownloadVersion.SelectionChanged, ComboModLocalNameStyle.SelectionChanged, ComboDownloadTranslateV2.SelectionChanged, ComboSystemUpdate.SelectionChanged, ComboSystemActivity.SelectionChanged, ComboDownloadSource.SelectionChanged
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboDownloadVersion.SelectionChanged, ComboModLocalNameStyle.SelectionChanged, ComboDownloadTranslateV2.SelectionChanged, ComboSystemUpdate.SelectionChanged, ComboSystemActivity.SelectionChanged, ComboDownloadSource.SelectionChanged, ComboDownloadMod.SelectionChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex)
End Sub
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextSystemCache.ValidatedTextChanged
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageSetupUI"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="基础" x:Name="CardLauncher">
@@ -358,7 +358,7 @@ Refresh:
PanMusicDetail.Visibility = Visibility.Visible
BtnMusicClear.Visibility = Visibility.Visible
CardMusic.Title = "背景音乐(" &
EnumerateFiles(Path & "PCL\Musics\").Count(Function(f) {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(f.Extension.ToLower)) &
EnumerateFiles(Path & "PCL\Musics\").Count(Function(f) Not {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(f.Extension.ToLower)) &
" 首)"
Else
PanMusicVolume.Visibility = Visibility.Collapsed
@@ -92,7 +92,7 @@ Public Class PageSpeedLeft
Card.Children.Clear()
Card.Children.Add(GetObjectFromXML("<Path xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" Stretch=""Uniform"" Tag=""Failed"" Data=""F1 M2.5,0 L0,2.5 7.5,10 0,17.5 2.5,20 10,12.5 17.5,20 20,17.5 12.5,10 20,2.5 17.5,0 10,7.5 2.5,0Z"" Height=""15"" Width=""15"" HorizontalAlignment=""Center"" Grid.Column=""0"" Grid.Row=""0"" Fill=""{DynamicResource ColorBrush3}"" Margin=""0,1,0,0"" VerticalAlignment=""Top""/>"))
Dim Tb As TextBlock = GetObjectFromXML("<TextBlock xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" TextWrapping=""Wrap"" HorizontalAlignment=""Left"" ToolTip=""单击复制错误详情"" Grid.Column=""1"" Grid.Row=""0"" Margin=""0,0,0,5"" />")
Tb.Text = GetExceptionDetail(Loader.Error)
Tb.Text = Loader.Error.GetDetail()
AddHandler Tb.MouseLeftButtonDown,
Sub(sender As TextBlock, e As EventArgs)
ClipboardSet(sender.Text, False)
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageSpeedRight"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
<!--<local:MyCard Title="UI 的示例下载任务">
@@ -344,14 +344,11 @@ Public Class MyLocalModItem
End If
'标题与描述
Dim DescFileName As String
Select Case Entry.State
Case McMod.McModState.Fine
DescFileName = GetFileNameWithoutExtentionFromPath(Entry.Path)
Case McMod.McModState.Disabled
DescFileName = GetFileNameWithoutExtentionFromPath(Entry.Path.Replace(".disabled", "").Replace(".old", ""))
Case Else 'McMod.McModState.Unavailable
DescFileName = GetFileNameFromPath(Entry.Path)
End Select
If Entry.State = McMod.McModState.Fine OrElse Entry.State = McMod.McModState.Disabled Then
DescFileName = IO.Path.GetFileNameWithoutExtension(Entry.Path)
Else
DescFileName = GetFileNameFromPath(Entry.Path)
End If
Dim NewDescription As String
If Setup.Get("ToolModLocalNameStyle") = 1 Then
'标题显示文件名,详情显示译名
@@ -4,7 +4,7 @@
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" x:Class="PageVersionExport"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<Grid x:Name="PanAllBack">
<Grid.Resources>
<Style TargetType="local:MyCheckBox">
@@ -102,7 +102,15 @@
<local:MyCheckBox.Tag>
<local:ExportOption
Title="Mod 设置"
Rules="config/|!config/jei/world/|!config/worldedit/|config/worldedit/worldedit.properties|!config/spark/|config/spark/config.json|defaultconfigs/|journeymap/config/|journeymap/server/|TrashSlotSaveState.json|customfov.txt|gg.essential.mod/|essential/|!essential/*/|!essential/*.jar*|!essential/screenshot-checksum-caches.json|!essential/microsoft_accounts.json|paragliderSettings.nbt|local/client_config.json|local/ftbl.json|local/client/sidebar_buttons.json|local/client/ftbutilities.cfg|local/client/ftblib.cfg|local/client/xencraft.cfg|liteloader.properties|default_reference.xml|CustomSkinLoader/CustomSkinLoader.json"
Rules="config/|!config/jei/world/|!config/worldedit/|config/worldedit/worldedit.properties|!config/spark/|config/spark/config.json|defaultconfigs/|journeymap/config/|journeymap/server/|TrashSlotSaveState.json|customfov.txt|gg.essential.mod/|essential/|!essential/*/|!essential/*.jar*|!essential/screenshot-checksum-caches.json|!essential/microsoft_accounts.json|paragliderSettings.nbt|local/client_config.json|local/ftbl.json|local/client/sidebar_buttons.json|local/client/ftbutilities.cfg|local/client/ftblib.cfg|local/client/xencraft.cfg|liteloader.properties|default_reference.xml|CustomSkinLoader/CustomSkinLoader.json|!config/tacz/custom"
DefaultChecked="True" />
</local:MyCheckBox.Tag>
</local:MyCheckBox>
<local:MyCheckBox>
<local:MyCheckBox.Tag>
<local:ExportOption
Title="TaCZ 枪包"
Rules="tacz/|config/tacz/custom/"
DefaultChecked="True" />
</local:MyCheckBox.Tag>
</local:MyCheckBox>
@@ -235,7 +243,7 @@
</StackPanel>
</StackPanel>
</local:MyCard>
<local:MyCard Title="高级选项" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="高级选项" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,37,23,20">
<local:MyHint Text="建议仅在无法稳定连接 CurseForge 或 Modrinth 时才打包资源文件。&#xa;请不要公开发布含资源文件的整合包,这会违反部分 Mod 的使用协议!"
Theme="Yellow" Margin="0,2,0,8" Visibility="{Binding Checked, ElementName=CheckAdvancedInclude, Converter={StaticResource BooleanToVisibilityConverter}}" />
@@ -418,7 +418,7 @@ Public Class PageVersionExport
Log($"[Export] 使用配置文件中指定的导出路径:{ConfigPackPath}")
Catch ex As Exception
Log(ex, $"无法使用配置文件中指定的导出路径({ConfigPackPath})", LogLevel.Debug)
If MyMsgBox($"指定的路径:{ConfigPackPath}{vbCrLf}{vbCrLf}{GetExceptionDetail(ex)}", "无法使用配置文件中指定的导出路径", "确定", "取消") = 2 Then Return
If MyMsgBox($"指定的路径:{ConfigPackPath}{vbCrLf}{vbCrLf}{ex.GetDetail}", "无法使用配置文件中指定的导出路径", "确定", "取消") = 2 Then Return
End Try
End If
If PackPath Is Nothing Then
@@ -530,6 +530,7 @@ Public Class PageVersionExport
Loader.Progress = 0.97
'复制 PCL 版本设置
CopyDirectory(McVersion.Path & "PCL\", OverridesFolder & "PCL\")
WriteIni(OverridesFolder & "PCL\Setup.ini", "IsStar", False)
#If BETA Then
'复制 PCL 本体
If IncludePCL Then CopyFile(PathWithName, CacheFolder & "Plain Craft Launcher.exe")
@@ -1,7 +1,7 @@
<local:MyPageLeft x:Class="PageVersionLeft"
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}">
xmlns:local="clr-namespace:PCL" AnimatedControl="PanItem">
<StackPanel Margin="0,12,0,0" Name="PanItem">
<local:MyListItem x:Name="ItemOverall" IsScaleAnimationEnabled="False" Checked="True" Type="RadioBox" Tag="0" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="概览"
Logo="M12 0l-11 6v12.131l11 5.869 11-5.869v-12.066l-11-6.065zm-1 21.2l-6.664-3.555 4.201-2.801c1.08-.719-.066-2.359-1.243-1.575l-4.294 2.862v-7.901l8 4.363v8.607zm-6.867-14.63l6.867-3.746v4.426c0 1.323 2 1.324 2 0v-4.415l6.91 3.811-7.905 4.218-7.872-4.294zm8.867 6.03l8-4.269v7.8l-4.263-2.842c-1.181-.785-2.323.855-1.245 1.574l4.172 2.781-6.664 3.556v-8.6z" />
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageVersionMod"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<Grid>
<Grid x:Name="PanAllBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
@@ -681,7 +681,7 @@ Install:
Hint($"已成功更新 {FinishedFileNames.Count} 个 Mod!", HintType.Finish)
End Select
Case LoadState.Failed
Hint("Mod 更新失败:" & GetExceptionSummary(Loader.Error), HintType.Critical)
Hint("Mod 更新失败:" & Loader.Error.GetBrief(), HintType.Critical)
Case LoadState.Aborted
Hint("Mod 更新已中止!", HintType.Info)
Case Else
@@ -808,7 +808,7 @@ Install:
Dim ModEntry As McMod = CType(If(TypeOf sender Is MyIconButton, sender.Tag, sender), MyLocalModItem).Entry
'加载失败信息
If ModEntry.State = McMod.McModState.Unavailable Then
MyMsgBox("无法读取此 Mod 的信息。" & vbCrLf & vbCrLf & "详细的错误信息:" & GetExceptionDetail(ModEntry.FileUnavailableReason), "Mod 读取失败")
MyMsgBox("无法读取此 Mod 的信息。" & vbCrLf & vbCrLf & "详细的错误信息:" & ModEntry.FileUnavailableReason.GetDetail(), "Mod 读取失败")
Return
End If
If ModEntry.Comp IsNot Nothing Then
@@ -4,7 +4,7 @@
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" x:Class="PageVersionOverall"
PanScroll="{Binding ElementName=PanBack}" Grid.IsSharedSizeScope="True">
PanScroll="PanBack" Grid.IsSharedSizeScope="True">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,10">
<local:MyCard Margin="0,15" Title="">
@@ -109,19 +109,19 @@
Dim OldName As String = PageVersionLeft.Version.Name
Dim OldPath As String = PageVersionLeft.Version.Path
'修改此部分的同时修改快速安装的版本名检测*
Dim NewName As String = MyMsgBoxInput("重命名版本", "", OldName, New ObjectModel.Collection(Of Validate) From {New ValidateFolderName(PathMcFolder & "versions", IgnoreCase:=False)})
Dim NewName As String = MyMsgBoxInput("重命名版本", "", OldName, New ObjectModel.Collection(Of Validate) From {
New ValidateFolderName(PathMcFolder & "versions", IgnoreCase:=False), New ValidateExceptSame(OldName & "_temp", "不能使用该名称!")})
If String.IsNullOrWhiteSpace(NewName) Then Return
Dim NewPath As String = PathMcFolder & "versions\" & NewName & "\"
'获取临时中间名,以防止仅修改大小写的重命名失败
Dim TempName As String = NewName & "_temp"
Dim TempPath As String = PathMcFolder & "versions\" & TempName & "\"
Dim IsCaseChangedOnly As Boolean = NewName.ToLower = OldName.ToLower
Dim OnlyChangedCase As Boolean = NewName.ToLower = OldName.ToLower
'重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储
Dim JsonObject As JObject
Dim OldJsonPath As String = PageVersionLeft.Version.GetJsonPath()
Try
Dim JsonPath As String = PageVersionLeft.Version.GetJsonPath()
JsonObject = GetJson(ReadFile(JsonPath))
File.Delete(JsonPath)
JsonObject = GetJson(ReadFile(OldJsonPath))
Catch ex As Exception
Log(ex, "在重命名读取 json 时失败")
JsonObject = PageVersionLeft.Version.JsonObject
@@ -135,7 +135,7 @@
'重命名 jar 文件与 natives 文件夹
'不能进行遍历重命名,否则在版本名很短的时候容易误伤其他文件(#6443)
If Directory.Exists($"{NewPath}{OldName}-natives") Then
If IsCaseChangedOnly Then
If OnlyChangedCase Then
My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives", $"{OldName}natives_temp")
My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives_temp", $"{NewName}-natives")
Else
@@ -144,7 +144,7 @@
End If
End If
If File.Exists($"{NewPath}{OldName}.jar") Then
If IsCaseChangedOnly Then
If OnlyChangedCase Then
My.Computer.FileSystem.RenameFile($"{NewPath}{OldName}.jar", $"{OldName}_temp.jar")
My.Computer.FileSystem.RenameFile($"{NewPath}{OldName}_temp.jar", $"{NewName}.jar")
Else
@@ -160,10 +160,11 @@
If ReadIni(PathMcFolder & "PCL.ini", "Version") = OldName Then
WriteIni(PathMcFolder & "PCL.ini", "Version", NewName)
End If
'写入版本 Json
'更新版本 Json
Try
JsonObject("id") = NewName
WriteFile(NewPath & NewName & ".json", JsonObject.ToString)
File.Delete(NewPath & GetFileNameFromPath(OldJsonPath))
Catch ex As Exception
Log(ex, "重命名版本 json 失败")
End Try
@@ -300,7 +301,7 @@
Case LoadState.Finished
Hint(Loader.Name & "成功!", HintType.Finish)
Case LoadState.Failed
Hint(Loader.Name & "失败:" & GetExceptionSummary(Loader.Error), HintType.Critical)
Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Critical)
Case LoadState.Aborted
Hint(Loader.Name & "已取消!", HintType.Info)
End Select
@@ -4,7 +4,7 @@
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" x:Class="PageVersionSetup"
PanScroll="{Binding ElementName=PanBack}">
PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel x:Name="PanMain" Margin="25,25,25,25">
<local:MyHint Text="这些设置只对该游戏版本生效,不影响其他版本。" Theme="Blue" Margin="0,0,0,15"
@@ -192,7 +192,7 @@
<local:MyButton x:Name="BtnServerAuthLittle" Height="35" MinWidth="150" Margin="0,12,0,0" Text="设置为 LittleSkin" HorizontalAlignment="Left" ColorType="Highlight" />
</StackPanel>
</local:MyCard>
<local:MyCard x:Name="CardAdvance" Margin="0,0,0,15" Title="高级启动选项" IsSwaped="True" CanSwap="True">
<local:MyCard x:Name="CardAdvance" Margin="0,0,0,15" Title="高级选项" IsSwapped="True" CanSwap="True">
<Grid Margin="25,40,25,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
@@ -208,10 +208,10 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="JVM 参数头部" Margin="0,0,25,0" />
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="Java 虚拟机参数" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.Row="0" Grid.ColumnSpan="2" Tag="VersionAdvanceJvm" Grid.Column="1" MaxLength="4000" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,在没有确定把握的情况下请不要尝试修改。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置"
Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数尾部" Margin="0,0,25,0" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3"
@@ -219,6 +219,9 @@
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="VersionAdvanceRunWait" Visibility="Collapsed"
Text="等待命令执行完成后再继续启动" Margin="0,5,0,0" />
<StackPanel Margin="0,12,0,4" Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Left">
<local:MyCheckBox Height="28" Text="禁止更新 Mod" x:Name="CheckAdvanceDisableModUpdate" Tag="VersionAdvanceDisableModUpdate"
ToolTip="禁止为此版本更新 Mod,以防止整合包玩家误操作"
ToolTipService.Placement="Right" />
<local:MyCheckBox Height="28" Text="忽略 Java 兼容性警告" x:Name="CheckAdvanceJava" Tag="VersionAdvanceJava"
ToolTipService.Placement="Right"
ToolTip="如果手动选择了与当前版本不兼容的 Java,则自动跳过兼容性警告弹窗,强制使用手动选择的 Java。" />
@@ -61,6 +61,7 @@
CheckAdvanceAssetsV2.Checked = Setup.Get("VersionAdvanceAssetsV2", Version:=PageVersionLeft.Version)
CheckAdvanceJava.Checked = Setup.Get("VersionAdvanceJava", Version:=PageVersionLeft.Version)
CheckAdvanceDisableJLW.Checked = Setup.Get("VersionAdvanceDisableJLW", Version:=PageVersionLeft.Version)
CheckAdvanceDisableModUpdate.Checked = Setup.Get("VersionAdvanceDisableModUpdate", Version:=PageVersionLeft.Version)
Catch ex As Exception
Log(ex, "重载版本独立设置时出错", LogLevel.Feedback)
@@ -91,6 +92,7 @@
Setup.Reset("VersionAdvanceRun", Version:=PageVersionLeft.Version)
Setup.Reset("VersionAdvanceRunWait", Version:=PageVersionLeft.Version)
Setup.Reset("VersionAdvanceDisableJLW", Version:=PageVersionLeft.Version)
Setup.Reset("VersionAdvanceDisableModUpdate", Version:=PageVersionLeft.Version)
Setup.Reset("VersionArgumentJavaSelect", Version:=PageVersionLeft.Version)
JavaSearchLoader.Start(IsForceRestart:=True)
@@ -125,7 +127,7 @@
Private Shared Sub CheckBoxLikeComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndieV2.SelectionChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex = 0, Version:=PageVersionLeft.Version)
End Sub
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckAdvanceRunWait.Change, CheckAdvanceAssetsV2.Change, CheckAdvanceJava.Change, CheckAdvanceDisableJLW.Change
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckAdvanceRunWait.Change, CheckAdvanceAssetsV2.Change, CheckAdvanceJava.Change, CheckAdvanceDisableJLW.Change, CheckAdvanceDisableModUpdate.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked, Version:=PageVersionLeft.Version)
End Sub
@@ -355,6 +357,15 @@ PreFin:
#Region "服务器"
'自动替换标点
Private Sub TextServerEnter_Change() Handles TextServerEnter.TextChanged
Dim NewText = TextServerEnter.Text.Replace(":", ":").Replace("。", ".")
If NewText = TextServerEnter.Text Then Return
Dim CurrentPosition = TextServerEnter.SelectionStart '重设焦点
TextServerEnter.Text = NewText
TextServerEnter.SelectionStart = CurrentPosition
End Sub
'全局
Private ComboServerLoginLast As Integer
Private Sub ComboServerLogin_Changed() Handles ComboServerLogin.SelectionChanged, TextServerNide.ValidatedTextChanged, TextServerAuthServer.ValidatedTextChanged, TextServerAuthRegister.ValidatedTextChanged
@@ -506,4 +517,12 @@ PreFin:
FrmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupLaunch)
End Sub
'去除参数中的回车
Private Sub ReplaceEnter(sender As MyTextBox, e As TextChangedEventArgs) Handles TextAdvanceJvm.TextChanged, TextAdvanceGame.TextChanged
Dim NewText = sender.Text.Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, " ")
If NewText = sender.Text Then Return
Dim CaretIndex = sender.CaretIndex
sender.Text = NewText
sender.CaretIndex = Math.Max(0, CaretIndex - 1)
End Sub
End Class
@@ -205,7 +205,9 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Controls\Behaviors\ClipboardInterceptor.vb" />
<Compile Include="Controls\IMyRadio.vb" />
<Compile Include="Controls\Interfaces.vb" />
<Compile Include="Controls\MyComboBox.vb" />
<Compile Include="Controls\MyComboBoxItem.vb" />
<Compile Include="Controls\MyCard.vb" />
@@ -281,18 +283,12 @@
<Compile Include="Pages\PageDownload\Comp\PageDownloadMod.xaml.vb">
<DependentUpon>PageDownloadMod.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageDownload\PageDownloadFabric.xaml.vb">
<DependentUpon>PageDownloadFabric.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageDownload\PageDownloadInstall.xaml.vb">
<DependentUpon>PageDownloadInstall.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageDownload\Comp\PageDownloadCompDetail.xaml.vb">
<DependentUpon>PageDownloadCompDetail.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageDownload\PageDownloadNeoForge.xaml.vb">
<DependentUpon>PageDownloadNeoForge.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageLaunch\MyMsgLogin.xaml.vb">
<DependentUpon>MyMsgLogin.xaml</DependentUpon>
</Compile>
@@ -351,15 +347,6 @@
<Compile Include="Modules\Minecraft\ModDownload.vb" />
<Compile Include="Modules\Minecraft\ModLaunch.vb" />
<Compile Include="Modules\Minecraft\ModMinecraft.vb" />
<Compile Include="Pages\PageDownload\PageDownloadForge.xaml.vb">
<DependentUpon>PageDownloadForge.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageDownload\PageDownloadLiteLoader.xaml.vb">
<DependentUpon>PageDownloadLiteLoader.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageDownload\PageDownloadOptiFine.xaml.vb">
<DependentUpon>PageDownloadOptiFine.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageOther\PageOtherTest.xaml.vb">
<DependentUpon>PageOtherTest.xaml</DependentUpon>
</Compile>
@@ -393,9 +380,6 @@
<Compile Include="Pages\PageDownload\PageDownloadLeft.xaml.vb">
<DependentUpon>PageDownloadLeft.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageDownload\PageDownloadClient.xaml.vb">
<DependentUpon>PageDownloadClient.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\PageOther\PageOtherLeft.xaml.vb">
<DependentUpon>PageOtherLeft.xaml</DependentUpon>
</Compile>
@@ -555,10 +539,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageDownload\PageDownloadFabric.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageDownload\PageDownloadInstall.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -567,10 +547,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageDownload\PageDownloadNeoForge.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageLaunch\MyMsgLogin.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -624,18 +600,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageDownload\PageDownloadForge.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageDownload\PageDownloadLiteLoader.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageDownload\PageDownloadOptiFine.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageOther\PageOtherTest.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -680,10 +644,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageDownload\PageDownloadClient.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\PageOther\PageOtherLeft.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
+22 -18
View File
@@ -3,7 +3,7 @@
下列内容均基于 WPF 框架。你可以在继续之前先尝试自学 XAML 与 WPF 的基础,这能让你更轻松地理解下列内容。
你也可以使用 Ctrl + F 快速查找。例如,若需要改变文本颜色,则搜索 “颜色” 即可。 -->
<local:MyCard Title="纯文本" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="纯文本" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="每个 local:MyCard 代表一张卡片,你可以添加、删除格式类似的 MyCard 来添加多个卡片。每个 TextBlock 代表一段文本,你可以在 Text 属性中书写任何你想写的内容,也可以自行添加更多的 TextBlock。" />
@@ -14,17 +14,17 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="卡片、提示条" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="卡片、提示条" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<local:MyHint Text="local:MyHint 代表提示条。" />
<local:MyHint Margin="0,8,0,2" Theme="Blue"
Text="将提示条的 Theme 属性改为 Blue、Yellow 或 Red 即可修改配色。&#xA;使用左边的那堆字符可以在任意地方手动换行,如果需要使用等号、引号等特殊字符,可以自行百度 XAML 转义字符。" />
<TextBlock TextWrapping="Wrap" Margin="0,6,0,0"
Text="卡片(local:MyCard)的 Title 属性决定了它的标题。&#xA;为卡片添加 CanSwap 属性让它可以被折叠,True 代表是,False 代表否。在此基础上,再使用 IsSwaped 属性调整它是否默认被折叠。" />
Text="卡片(local:MyCard)的 Title 属性决定了它的标题。&#xA;为卡片添加 CanSwap 属性让它可以被折叠,True 代表是,False 代表否。在此基础上,再使用 IsSwapped 属性调整它是否默认被折叠。" />
</StackPanel>
</local:MyCard>
<local:MyCard Title="长宽属性、图片" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="长宽属性、图片" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4" Width="320" HorizontalAlignment="Right"
Text="任意项目都可以添加 Width 与 Height 属性来控制宽高。HorizontalAlignment 属性可以控制对齐:Center 代表居中,Right 代表居右,例如这段文本就被居右了。" />
@@ -34,7 +34,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="按钮" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="按钮" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="添加 local:MyButton 即可新建一个按钮。你需要限定它的尺寸与位置,并通过 Padding 属性进一步控制它的内边距。" />
@@ -53,7 +53,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="事件 1:打开网页、弹出窗口" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="事件 1:打开网页、弹出窗口" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
Text="将按钮的 EventType 属性设为 打开网页,然后在 EventData 属性中写入网址,即可通过点击按钮打开网页。" />
@@ -70,7 +70,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="事件 2:启动游戏" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="事件 2:启动游戏" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="将 EventType 设置为 启动游戏,EventData 设置为具体的游戏版本,即可通过点击按钮启动游戏。如果当前游戏文件夹没有该版本,则无法启动。" />
@@ -87,7 +87,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="事件 3:执行命令" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="事件 3:执行命令" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="将 EventType 设置为 执行命令(或 打开文件),EventData 设置为文件路径,即可点击打开特定文件或启动程序。" />
@@ -106,7 +106,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="事件 4:其他事件类型" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="事件 4:其他事件类型" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock Margin="0,4,0,6" FontWeight="Bold"
Text="EventType 共有以下种类:" />
@@ -138,10 +138,14 @@
Text="· 下载版本:切换到 EventData 对应的 Minecraft 下载页面"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="下载 Minecraft 1.12.2" EventType="下载版本" EventData="1.12.2"/>
<TextBlock Margin="0,4,0,4"
Text="· 修改设置:将 PCL 的特定设置修改为特定值"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="将窗口改为半透明" EventType="修改设置" EventData="UiLauncherTransparent|400"/>
</StackPanel>
</local:MyCard>
<local:MyCard Title="StackPanel 横向布局" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="StackPanel 横向布局" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
Text="你需要使用 StackPanel 在一行里塞下多个按钮。你可以仅在这个教学卡片的基础上稍作调整,来实现自己的按钮布局。" />
@@ -166,7 +170,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="列表项 1:基础" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="列表项 1:基础" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="你也可以使用列表项 “local:MyListItem” 来替代按钮,其使用方式与按钮类似。" />
@@ -183,7 +187,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="列表项 2:内置图片" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="列表项 2:内置图片" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="PCL 内置了一些 Minecraft 方块与物品图片,可以直接使用。"/>
@@ -221,7 +225,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="主题色" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="主题色" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,15"
Text="你可以用类似 {DynamicResource ColorBrush5} 的格式使用 PCL 当前的主题颜色,修改末尾的数字编号以改变颜色浓度。" />
@@ -242,7 +246,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="替换标记" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="替换标记" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="在花括号 {} 中写入特定内容,PCL 会在加载时对其进行替换。&#xa;例如,path 会被替换为 PCL 可执行文件所在文件夹({path}),用于在 EventData 中指定特定文件,或是加载图片。" />
@@ -253,7 +257,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="进阶:Grid 布局" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="进阶:Grid 布局" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="如果要实现更复杂的布局,则必须使用 Grid。Grid 可以让按钮们自动适应窗口宽度:随意拉伸 PCL 窗口,按钮大小会自动改变。" />
@@ -276,7 +280,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="进阶:图标按钮" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="进阶:图标按钮" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="MyIconTextButton 是一种带有自定义矢量图标的按钮变体,它同样支持 EventType 与 EventData 属性。&#xa;通过设置 Logo 属性来控制它的图标,设置 LogoScale 属性还可以调整图标的缩放比例。" />
@@ -301,7 +305,7 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="进阶:联网主页" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
<local:MyCard Title="进阶:联网主页" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
Text="如果你在尝试制作联网更新的主页,可以查看下方的 GitHub 讨论页。&#xa;你可以根据其中的介绍为主页添加版本号检查以节省流量,也可以通过检查 Referer 和 User Agent 来确定对方的 PCL 版本。" />
@@ -336,7 +340,7 @@ local:MyImage(图片):
local:MyCard(卡片):
- Title:设置显示的标题文本
- CanSwap:卡片是否可以折叠,True 为是,False 为否
- IsSwaped:卡片是否默认折叠,要求 CanSwap 必须为 True
- IsSwapped:卡片是否默认折叠,要求 CanSwap 必须为 True
- HorizontalAlignment:若使用,要求 CanSwap 必须为 False
- UseAnimation:是否在展开等高度改变时触发动画;True 为是(默认),False 为否
- SwapLogoRight:卡片折叠时的箭头是朝下还是朝右;True 为朝右,False 为朝下(默认)
Binary file not shown.
Loaded 100 of 102 files, more files were not shown because too many files have changed in this diff. Show more