This commit is contained in:
YIJANGs
2026-04-08 21:49:29 +08:00
85 changed files with 4326 additions and 28371 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
# These are supported funding model platforms # These are supported funding model platforms
custom: ['https://afdian.com/a/LTCat'] custom: ['https://meloong.com/afd/a/LTCat']
+1 -1
View File
@@ -365,7 +365,7 @@
<Setter Property="Background" Value="{StaticResource ColorBrushHalfWhite}" /> <Setter Property="Background" Value="{StaticResource ColorBrushHalfWhite}" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" /> <Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="FontSize" Value="13" /> <Setter Property="FontSize" Value="13" />
<Setter Property="MaxDropDownHeight" Value="160" /> <Setter Property="MaxDropDownHeight" Value="320" />
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="ComboBox"> <ControlTemplate TargetType="ComboBox">
+14 -29
View File
@@ -51,15 +51,6 @@ Public Class Application
Else Else
Environment.Exit((My.Computer.Info.AvailablePhysicalMemory - Ram) / 1024) '返回清理的内存量(K) Environment.Exit((My.Computer.Info.AvailablePhysicalMemory - Ram) / 1024) '返回清理的内存量(K)
End If End If
#If DEBUG Then
'制作更新包
ElseIf e.Args(0) = "--edit1" Then
ExeEdit(e.Args(1), True)
Environment.Exit(ProcessReturnValues.TaskDone)
ElseIf e.Args(0) = "--edit2" Then
ExeEdit(e.Args(1), False)
Environment.Exit(ProcessReturnValues.TaskDone)
#End If
End If End If
End If End If
'初始化文件结构 '初始化文件结构
@@ -73,7 +64,7 @@ Public Class Application
MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDetail(), "缓存文件夹不可用") MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDetail(), "缓存文件夹不可用")
Else Else
MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDetail(), "缓存文件夹不可用") MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDetail(), "缓存文件夹不可用")
Setup.Set("SystemSystemCache", "") Settings.Set("SystemSystemCache", "")
PathTemp = IO.Path.GetTempPath() & "PCL\" PathTemp = IO.Path.GetTempPath() & "PCL\"
End If End If
End Try End Try
@@ -114,7 +105,7 @@ WaitRetry:
ServicePointManager.EnableDnsRoundRobin = True ServicePointManager.EnableDnsRoundRobin = True
ServicePointManager.ReusePort = True ServicePointManager.ReusePort = True
'设置初始窗口 '设置初始窗口
If Setup.Get("UiLauncherLogo") Then If Settings.Get("UiLauncherLogo") Then
FrmStart = New SplashScreen("Images\icon.ico") FrmStart = New SplashScreen("Images\icon.ico")
FrmStart.Show(False, True) FrmStart.Show(False, True)
End If End If
@@ -132,18 +123,12 @@ WaitRetry:
Log($"[Start] 管理员权限:{IsAdmin()}") Log($"[Start] 管理员权限:{IsAdmin()}")
'检测异常环境 '检测异常环境
If Path.Contains(IO.Path.GetTempPath()) OrElse Path.Contains("AppData\Local\Temp\") Then If Path.Contains(IO.Path.GetTempPath()) OrElse Path.Contains("AppData\Local\Temp\") Then
MyMsgBox("请将 PCL 从压缩包中解压后再使用!" & vbCrLf & "如果不会解压,可以在网上寻找教程。", "尚未解压", "我知道了", IsWarn:=True) MyMsgBox("请将 PCL 从压缩包中解压后再使用!" & vbCrLf & "如果不会解压,可以在网上寻找教程。", "需要解压!", "我知道了", IsWarn:=True, ForceWait:=True)
FormMain.EndProgramForce(ProcessReturnValues.Cancel) FormMain.EndProgramForce(ProcessReturnValues.Cancel)
End If End If
If Is32BitSystem Then If Is32BitSystem Then
MyMsgBox("PCL 和新版 Minecraft 均不再支持 32 位系统,部分功能将无法使用。" & vbCrLf & "非常建议重装为 64 位系统后再进行游戏!", "环境警告", "我知道了", IsWarn:=True) MyMsgBox("PCL 和新版 Minecraft 均不再支持 32 位系统,部分功能将无法使用。" & vbCrLf & "非常建议重装为 64 位系统后再进行游戏!", "环境警告", "我知道了", IsWarn:=True)
End If End If
'设置初始化
Setup.Load("SystemDebugMode")
Setup.Load("SystemDebugAnim")
Setup.Load("ToolDownloadThread")
Setup.Load("ToolDownloadCert")
Setup.Load("ToolDownloadSpeed")
'计时 '计时
Log("[Start] 第一阶段加载用时:" & GetTimeMs() - ApplicationStartTick & " ms") Log("[Start] 第一阶段加载用时:" & GetTimeMs() - ApplicationStartTick & " ms")
ApplicationStartTick = GetTimeMs() ApplicationStartTick = GetTimeMs()
@@ -165,7 +150,7 @@ WaitRetry:
'结束 '结束
Private Sub Application_SessionEnding(sender As Object, e As SessionEndingCancelEventArgs) Handles Me.SessionEnding Private Sub Application_SessionEnding(sender As Object, e As SessionEndingCancelEventArgs) Handles Me.SessionEnding
FrmMain.EndProgram(False) FrmMain?.EndProgram(False)
End Sub End Sub
'异常 '异常
@@ -228,36 +213,36 @@ WaitRetry:
'控件模板事件 '控件模板事件
Private Sub MyIconButton_Click(sender As Object, e As EventArgs) Private Sub MyIconButton_Click(sender As Object, e As EventArgs)
Select Case Setup.Get("LoginType") Select Case Settings.Get("LoginType")
Case McLoginType.Ms Case McLoginType.Ms
'微软 '微软
Dim MsJson As JObject = GetJson(Setup.Get("LoginMsJson")) Dim MsJson As JObject = GetJson(Settings.Get("LoginMsJson"))
MsJson.Remove(sender.Tag) MsJson.Remove(sender.Tag)
Setup.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None)) Settings.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None))
If FrmLoginMs.ComboAccounts.SelectedItem Is sender.Parent Then FrmLoginMs.ComboAccounts.SelectedIndex = 0 If FrmLoginMs.ComboAccounts.SelectedItem Is sender.Parent Then FrmLoginMs.ComboAccounts.SelectedIndex = 0
FrmLoginMs.ComboAccounts.Items.Remove(sender.Parent) FrmLoginMs.ComboAccounts.Items.Remove(sender.Parent)
Case McLoginType.Legacy Case McLoginType.Legacy
'离线 '离线
Dim Names As New List(Of String) Dim Names As New List(Of String)
Names.AddRange(Setup.Get("LoginLegacyName").ToString.Split("¨")) Names.AddRange(Settings.Get("LoginLegacyName").ToString.Split("¨"))
Names.Remove(sender.Tag) Names.Remove(sender.Tag)
Setup.Set("LoginLegacyName", Join(Names, "¨")) Settings.Set("LoginLegacyName", Names.Join("¨"c))
FrmLoginLegacy.ComboName.ItemsSource = Names FrmLoginLegacy.ComboName.ItemsSource = Names
FrmLoginLegacy.ComboName.Text = If(Names.Any, Names(0), "") FrmLoginLegacy.ComboName.Text = If(Names.Any, Names(0), "")
Case Else Case Else
'第三方 '第三方
Dim Token As String = GetStringFromEnum(Setup.Get("LoginType")) Dim Token As String = GetStringFromEnum(Settings.Get("LoginType"))
Dim Dict As New Dictionary(Of String, String) Dim Dict As New Dictionary(Of String, String)
Dim Names As New List(Of String) Dim Names As New List(Of String)
Dim Passs As New List(Of String) Dim Passs As New List(Of String)
If Not Setup.Get("Login" & Token & "Email") = "" Then Names.AddRange(Setup.Get("Login" & Token & "Email").ToString.Split("¨")) If Not Settings.Get("Login" & Token & "Email") = "" Then Names.AddRange(Settings.Get("Login" & Token & "Email").ToString.Split("¨"))
If Not Setup.Get("Login" & Token & "Pass") = "" Then Passs.AddRange(Setup.Get("Login" & Token & "Pass").ToString.Split("¨")) If Not Settings.Get("Login" & Token & "Pass") = "" Then Passs.AddRange(Settings.Get("Login" & Token & "Pass").ToString.Split("¨"))
For i = 0 To Names.Count - 1 For i = 0 To Names.Count - 1
Dict.Add(Names(i), Passs(i)) Dict.Add(Names(i), Passs(i))
Next Next
Dict.Remove(sender.Tag) Dict.Remove(sender.Tag)
Setup.Set("Login" & Token & "Email", Join(Dict.Keys, "¨")) Settings.Set("Login" & Token & "Email", Dict.Keys.Join("¨"c))
Setup.Set("Login" & Token & "Pass", Join(Dict.Values, "¨")) Settings.Set("Login" & Token & "Pass", Dict.Values.Join("¨"c))
Select Case Token Select Case Token
Case "Nide" Case "Nide"
FrmLoginNide.ComboName.ItemsSource = Dict.Keys FrmLoginNide.ComboName.ItemsSource = Dict.Keys
@@ -1,18 +1,17 @@
Public Module LazyLoadBehavior Public Class LazyLoadBehavior
''' <summary> ''' <summary>
''' 指定首次进入 ScrollViewer 的可视范围时执行的操作。 ''' 指定首次进入 ScrollViewer 的可视范围时执行的操作。
''' </summary> ''' </summary>
<Runtime.CompilerServices.Extension()> Public Shared Sub OnFirstEnterScrollViewerViewport(obj As DependencyObject, value As Action)
Public Sub OnFirstEnterScrollViewerViewport(obj As DependencyObject, value As Action)
obj.SetValue(IsInViewportProperty, value) obj.SetValue(IsInViewportProperty, value)
End Sub End Sub
Private ReadOnly IsInViewportProperty As DependencyProperty = Private Shared ReadOnly IsInViewportProperty As DependencyProperty =
DependencyProperty.RegisterAttached("IsInViewport", GetType(Action), GetType(LazyLoadBehavior), DependencyProperty.RegisterAttached("IsInViewport", GetType(Action), GetType(LazyLoadBehavior),
New PropertyMetadata(Nothing, AddressOf OnIsInViewportChanged)) New PropertyMetadata(Nothing, AddressOf OnIsInViewportChanged))
Private Sub OnIsInViewportChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs) Private Shared Sub OnIsInViewportChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
Dim Element = TryCast(d, FrameworkElement) Dim Element = TryCast(d, FrameworkElement)
If Element Is Nothing OrElse e.NewValue Is Nothing Then Return If Element Is Nothing OrElse e.NewValue Is Nothing Then Return
@@ -36,7 +35,7 @@
AddHandler Element.LayoutUpdated, Handler AddHandler Element.LayoutUpdated, Handler
End Sub End Sub
Private Function FindParentScrollViewer(d As DependencyObject) As ScrollViewer Private Shared Function FindParentScrollViewer(d As DependencyObject) As ScrollViewer
While d IsNot Nothing While d IsNot Nothing
If TypeOf d Is ScrollViewer Then Return CType(d, ScrollViewer) If TypeOf d Is ScrollViewer Then Return CType(d, ScrollViewer)
d = VisualTreeHelper.GetParent(d) d = VisualTreeHelper.GetParent(d)
@@ -44,4 +43,4 @@
Return Nothing Return Nothing
End Function End Function
End Module End Class
@@ -2,6 +2,7 @@
<ContentProperty("Inlines")> <ContentProperty("Inlines")>
Public Class MyCheckBox Public Class MyCheckBox
Implements ISettingControl
'基础 '基础
@@ -72,7 +73,7 @@ Public Class MyCheckBox
AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True) AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True)
}, "MyCheckBox Scale " & Uuid) }, "MyCheckBox Scale " & Uuid)
AniStart({ AniStart({
AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush2"), "ColorBrushGray4"), AnimationTimeOfCheck) AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush2"), "ColorBrushGray5"), AnimationTimeOfCheck)
}, "MyCheckBox BorderColor " & Uuid) }, "MyCheckBox BorderColor " & Uuid)
AniStart({ AniStart({
AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2) AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2)
@@ -85,7 +86,7 @@ Public Class MyCheckBox
AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True) AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True)
}, "MyCheckBox Scale " & Uuid) }, "MyCheckBox Scale " & Uuid)
AniStart({ AniStart({
AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfCheck) AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush1"), "ColorBrushGray5"), AnimationTimeOfCheck)
}, "MyCheckBox BorderColor " & Uuid) }, "MyCheckBox BorderColor " & Uuid)
AniStart({ AniStart({
AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2) AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2)
@@ -99,11 +100,11 @@ Public Class MyCheckBox
If Checked Then If Checked Then
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 1 CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 1
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 1 CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 1
ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray4")) ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray5"))
Else Else
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 0 CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 0
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 0 CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 0
ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4")) ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
End If End If
End If End If
End Sub End Sub
@@ -178,18 +179,18 @@ Public Class MyCheckBox
Else Else
'不可用 '不可用
AniStart({ AniStart({
AaColor(ShapeBorder, Border.BorderBrushProperty, ColorGray4 - ShapeBorder.BorderBrush, AnimationTimeOfMouseOut) AaColor(ShapeBorder, Border.BorderBrushProperty, ColorGray5 - ShapeBorder.BorderBrush, AnimationTimeOfMouseOut)
}, "MyCheckBox BorderColor " & Uuid) }, "MyCheckBox BorderColor " & Uuid)
AniStart({ AniStart({
AaColor(LabText, TextBlock.ForegroundProperty, ColorGray4 - LabText.Foreground, AnimationTimeOfMouseOut) AaColor(LabText, TextBlock.ForegroundProperty, ColorGray5 - LabText.Foreground, AnimationTimeOfMouseOut)
}, "MyCheckBox TextColor " & Uuid) }, "MyCheckBox TextColor " & Uuid)
End If End If
Else Else
'无动画 '无动画
AniStop("MyCheckBox TextColor " & Uuid) AniStop("MyCheckBox TextColor " & Uuid)
AniStop("MyCheckBox BorderColor " & Uuid) AniStop("MyCheckBox BorderColor " & Uuid)
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray4")) LabText.SetResourceReference(TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray5"))
ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4")) ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray5"))
End If End If
End Sub End Sub
Private Sub Checkbox_MouseEnterAnimation() Handles Me.MouseEnter Private Sub Checkbox_MouseEnterAnimation() Handles Me.MouseEnter
@@ -203,11 +204,27 @@ Public Class MyCheckBox
Private Sub Checkbox_MouseLeaveAnimation() Handles Me.MouseLeave Private Sub Checkbox_MouseLeaveAnimation() Handles Me.MouseLeave
If Not IsEnabled Then Return 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误 If Not IsEnabled Then Return 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
AniStart({ AniStart({
AaColor(LabText, TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray4"), AnimationTimeOfMouseOut) AaColor(LabText, TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray5"), AnimationTimeOfMouseOut)
}, "MyCheckBox TextColor " & Uuid) }, "MyCheckBox TextColor " & Uuid)
AniStart({ AniStart({
AaColor(ShapeBorder, Border.BorderBrushProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfMouseOut) AaColor(ShapeBorder, Border.BorderBrushProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray5"), AnimationTimeOfMouseOut)
}, "MyCheckBox BorderColor " & Uuid) }, "MyCheckBox BorderColor " & Uuid)
End Sub End Sub
#Region "设置"
Private Sub RefreshSetting(NewValue As String) Implements ISettingControl.RefreshSetting
Checked = Boolean.Parse(NewValue)
End Sub
Private Function GetCurrentSetting() As String Implements ISettingControl.GetCurrentSetting
Return Checked.ToString
End Function
Private Sub SaveSetting() Handles Me.Change
SettingService.SaveSetting(Me)
End Sub
#End Region
End Class End Class
@@ -1,5 +1,6 @@
Public Class MyComboBox Public Class MyComboBox
Inherits ComboBox Inherits ComboBox
Implements ISettingControl
Public Event TextChanged(sender As Object, e As TextChangedEventArgs) Public Event TextChanged(sender As Object, e As TextChangedEventArgs)
'基础 '基础
@@ -137,4 +138,44 @@
If IsLoaded AndAlso AniControlEnabled = 0 Then RaiseCustomEvent() If IsLoaded AndAlso AniControlEnabled = 0 Then RaiseCustomEvent()
End Sub End Sub
#Region "设置"
Private Sub RefreshSetting(NewValue As String) Implements ISettingControl.RefreshSetting
Dim TargetItem = Items.OfType(Of DependencyObject)().FirstOrDefault(Function(i) Val(If(SettingService.GetValue(i), -1)) = NewValue)
If TargetItem IsNot Nothing Then
SelectedItem = TargetItem
ElseIf Items.Count > NewValue Then
SelectedIndex = NewValue
Else
Log($"[Setting] 尝试显示设置 {SettingService.GetKey(Me)},但没有找到设置值 {NewValue} 的对应项", LogLevel.Debug)
SelectedIndex = -1
SelectedItem = Nothing
'Dim Key As String = SettingService.GetKey(Me)
'Dim DefaultValue = Settings.GetDefault(Key)
'If DefaultValue = NewValue Then
' Log($"[Setting] 尝试显示设置 {Key},但没有找到设置值 {NewValue} 的对应项,这可能是因为程序版本太老了", LogLevel.Hint)
'Else
' Log($"[Setting] 尝试显示设置 {Key},但没有找到设置值 {NewValue} 的对应项,已重置该设置", LogLevel.Debug)
' Settings.Reset(Key)
' RefreshSetting(DefaultValue)
'End If
End If
End Sub
Private Function GetCurrentSetting() As String Implements ISettingControl.GetCurrentSetting
If SelectedItem Is Nothing Then Return Nothing
If TypeOf SelectedItem Is DependencyObject Then
Return Val(If(SettingService.GetValue(SelectedItem), SelectedIndex))
Else
Return SelectedIndex
End If
End Function
Private Sub SaveSetting() Handles Me.SelectionChanged
If SelectedItem Is Nothing Then Return
SettingService.SaveSetting(Me)
End Sub
#End Region
End Class End Class
@@ -99,19 +99,22 @@ Public Class MyHint
End Property End Property
Public Property RelativeSetup As String = "" Public Property RelativeSetup As String = ""
Private Sub MyHint_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded Private Sub MyHint_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
If CanClose AndAlso Setup.Get(RelativeSetup) Then Visibility = Visibility.Collapsed If CanClose AndAlso Settings.Get(RelativeSetup) Then Visibility = Visibility.Collapsed
End Sub End Sub
Private Sub BtnClose_Click(sender As Object, e As EventArgs) Handles BtnClose.Click Private Sub BtnClose_Click(sender As Object, e As EventArgs) Handles BtnClose.Click
Setup.SetSafe(RelativeSetup, True) Settings.SetSafe(RelativeSetup, True)
AniDispose(Me, False) AniDispose(Me, False)
End Sub End Sub
'触发点击事件 '触发点击事件
Public Event Click(sender As Object, e As MouseButtonEventArgs)
Private IsMouseDown As Boolean = False Private IsMouseDown As Boolean = False
Private Sub MyHint_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp Private Sub MyHint_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
If Not IsMouseDown Then Return If Not IsMouseDown Then Return
IsMouseDown = False IsMouseDown = False
Log("[Control] 按下提示条" & If(String.IsNullOrEmpty(Name), "", ":" & Name)) Log("[Control] 按下提示条" & If(String.IsNullOrEmpty(Name), "", ":" & Name))
RaiseEvent Click(sender, e)
If e.Handled Then Return
e.Handled = True e.Handled = True
RaiseCustomEvent() '自定义事件 RaiseCustomEvent() '自定义事件
End Sub End Sub
@@ -7,7 +7,7 @@
If IconControl IsNot Nothing Then IconControl.Data = (New GeometryConverter).ConvertFromString(Icon) If IconControl IsNot Nothing Then IconControl.Data = (New GeometryConverter).ConvertFromString(Icon)
End If End If
'对父级设置透明度 '对父级设置透明度
CType(Parent, ContextMenu).Opacity = Setup.Get("UiLauncherTransparent") / 1000 + 0.4 CType(Parent, ContextMenu).Opacity = Settings.Get("UiLauncherTransparent") / 1000 + 0.4
End Sub End Sub
'基础 '基础
@@ -129,7 +129,7 @@
RaiseEvent PageEnter() RaiseEvent PageEnter()
Select Case PageState Select Case PageState
Case PageStates.Empty Case PageStates.Empty
If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Aborted Then If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Interrupted Then
'如果加载器在进入页面时不启动(例如联机),那么在此时就会有 State = Waiting '如果加载器在进入页面时不启动(例如联机),那么在此时就会有 State = Waiting
PageState = PageStates.ContentEnter PageState = PageStates.ContentEnter
TriggerEnterAnimation(PanAlways, If(PanContent, Child)) TriggerEnterAnimation(PanAlways, If(PanContent, Child))
@@ -142,7 +142,7 @@
End If End If
Case PageStates.ContentExit Case PageStates.ContentExit
'和上面的一样,但是不管 PanAlways '和上面的一样,但是不管 PanAlways
If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Aborted Then If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Interrupted Then
PageState = PageStates.ContentEnter PageState = PageStates.ContentEnter
TriggerEnterAnimation(If(PanContent, Child)) TriggerEnterAnimation(If(PanContent, Child))
ElseIf PageLoader.State = LoadState.Loading Then ElseIf PageLoader.State = LoadState.Loading Then
@@ -318,9 +318,9 @@
Case PageStates.LoaderExit Case PageStates.LoaderExit
PageState = PageStates.ContentExit PageState = PageStates.ContentExit
End Select End Select
Case LoadState.Finished, LoadState.Aborted, LoadState.Waiting Case LoadState.Finished, LoadState.Interrupted, LoadState.Waiting
If Not (OldState = LoadState.Failed OrElse OldState = LoadState.Loading) Then Return If Not (OldState = LoadState.Failed OrElse OldState = LoadState.Loading) Then Return
If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Stop/Abort)") If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Stop/Interrupt)")
'运行结束 '运行结束
'需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit '需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit
Select Case PageState Select Case PageState
@@ -2,7 +2,7 @@
<ContentProperty("Inlines")> <ContentProperty("Inlines")>
Public Class MyRadioBox Public Class MyRadioBox
Implements IMyRadio Implements IMyRadio, ISettingControl
'基础 '基础
@@ -116,7 +116,7 @@ Public Class MyRadioBox
AaOpacity(ShapeDot, 1 - ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.6) AaOpacity(ShapeDot, 1 - ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.6)
}, "MyRadioBox Dot " & Uuid) }, "MyRadioBox Dot " & Uuid)
AniStart({ AniStart({
AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush2", "ColorBrushGray4")), AnimationTimeOfCheck) AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush2", "ColorBrushGray5")), AnimationTimeOfCheck)
}, "MyRadioBox BorderColor " & Uuid) }, "MyRadioBox BorderColor " & Uuid)
Else Else
'由有变无 '由有变无
@@ -128,7 +128,7 @@ Public Class MyRadioBox
AaOpacity(ShapeDot, -ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.2) AaOpacity(ShapeDot, -ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.2)
}, "MyRadioBox Dot " & Uuid) }, "MyRadioBox Dot " & Uuid)
AniStart({ AniStart({
AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush1", "ColorBrushGray4")), AnimationTimeOfCheck) AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush1", "ColorBrushGray5")), AnimationTimeOfCheck)
}, "MyRadioBox BorderColor " & Uuid) }, "MyRadioBox BorderColor " & Uuid)
End If End If
Else Else
@@ -141,13 +141,13 @@ Public Class MyRadioBox
ShapeDot.Height = 9 ShapeDot.Height = 9
ShapeDot.Opacity = 1 ShapeDot.Opacity = 1
ShapeDot.Margin = New Thickness(5.5, 0, 0, 0) ShapeDot.Margin = New Thickness(5.5, 0, 0, 0)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray4")) ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray5"))
Else Else
ShapeDot.Width = 0 ShapeDot.Width = 0
ShapeDot.Height = 0 ShapeDot.Height = 0
ShapeDot.Opacity = 0 ShapeDot.Opacity = 0
ShapeDot.Margin = New Thickness(10, 0, 0, 0) ShapeDot.Margin = New Thickness(10, 0, 0, 0)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4")) ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
End If End If
End If End If
End Sub End Sub
@@ -209,15 +209,15 @@ Public Class MyRadioBox
Radiobox_MouseLeaveAnimation() Radiobox_MouseLeaveAnimation()
Else Else
'不可用 '不可用
AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, ColorGray4 - ShapeBorder.Stroke, AnimationTimeOfMouseOut), "MyRadioBox BorderColor " & Uuid) AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, ColorGray5 - ShapeBorder.Stroke, AnimationTimeOfMouseOut), "MyRadioBox BorderColor " & Uuid)
AniStart(AaColor(LabText, TextBlock.ForegroundProperty, ColorGray4 - LabText.Foreground, AnimationTimeOfMouseOut), "MyRadioBox TextColor " & Uuid) AniStart(AaColor(LabText, TextBlock.ForegroundProperty, ColorGray5 - LabText.Foreground, AnimationTimeOfMouseOut), "MyRadioBox TextColor " & Uuid)
End If End If
Else Else
'无动画 '无动画
AniStop("MyRadioBox BorderColor " & Uuid) AniStop("MyRadioBox BorderColor " & Uuid)
AniStop("MyRadioBox TextColor " & Uuid) AniStop("MyRadioBox TextColor " & Uuid)
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray4")) LabText.SetResourceReference(TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray5"))
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4")) ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray5"))
End If End If
End Sub End Sub
Private Sub Radiobox_MouseEnterAnimation() Handles Me.MouseEnter Private Sub Radiobox_MouseEnterAnimation() Handles Me.MouseEnter
@@ -227,14 +227,30 @@ Public Class MyRadioBox
Private Sub Radiobox_MouseLeaveAnimation() Handles Me.MouseLeave Private Sub Radiobox_MouseLeaveAnimation() Handles Me.MouseLeave
If Not Me.IsEnabled Then Return 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误 If Not Me.IsEnabled Then Return 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
If IsLoaded AndAlso AniControlEnabled = 0 Then If IsLoaded AndAlso AniControlEnabled = 0 Then
AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfMouseOut), "MyRadioBox BorderColor " & Uuid) AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray5"), AnimationTimeOfMouseOut), "MyRadioBox BorderColor " & Uuid)
AniStart(AaColor(LabText, TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"), AnimationTimeOfMouseOut), "MyRadioBox TextColor " & Uuid) AniStart(AaColor(LabText, TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"), AnimationTimeOfMouseOut), "MyRadioBox TextColor " & Uuid)
Else Else
AniStop("MyRadioBox BorderColor " & Uuid) AniStop("MyRadioBox BorderColor " & Uuid)
AniStop("MyRadioBox TextColor " & Uuid) AniStop("MyRadioBox TextColor " & Uuid)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4")) ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray5"))
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4")) LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
End If End If
End Sub End Sub
#Region "设置"
Private Sub RefreshSetting(NewValue As String) Implements ISettingControl.RefreshSetting
Checked = NewValue = SettingService.GetValue(Me)
End Sub
Private Function GetCurrentSetting() As String Implements ISettingControl.GetCurrentSetting
Return If(Checked, SettingService.GetValue(Me), Nothing)
End Function
Private Sub SaveSetting() Handles Me.Check
SettingService.SaveSetting(Me)
End Sub
#End Region
End Class End Class
@@ -1,4 +1,5 @@
Public Class MySlider Public Class MySlider
Implements ISettingControl
'基础 '基础
@@ -188,4 +189,20 @@
End If End If
End Sub End Sub
#Region "设置"
Private Sub RefreshSetting(NewValue As String) Implements ISettingControl.RefreshSetting
Value = Val(NewValue)
End Sub
Private Function GetCurrentSetting() As String Implements ISettingControl.GetCurrentSetting
Return Value
End Function
Private Sub SaveSetting() Handles Me.Change
SettingService.SaveSetting(Me)
End Sub
#End Region
End Class End Class
+25 -1
View File
@@ -1,5 +1,6 @@
Public Class MyTextBox Public Class MyTextBox
Inherits TextBox Inherits TextBox
Implements ISettingControl
'自定义属性 '自定义属性
@@ -44,7 +45,13 @@
Public Uuid As Integer = GetUuid() Public Uuid As Integer = GetUuid()
Public Shared Event ValidateChanged(sender As Object, e As EventArgs) Public Shared Event ValidateChanged(sender As Object, e As EventArgs)
Public ChangedEventList As New List(Of RoutedEventHandler) Private _ChangedEventList As List(Of RoutedEventHandler)
Public ReadOnly Property ChangedEventList As List(Of RoutedEventHandler)
Get
If _ChangedEventList Is Nothing Then _ChangedEventList = New List(Of RoutedEventHandler)
Return _ChangedEventList
End Get
End Property
Public Custom Event ValidatedTextChanged As RoutedEventHandler Public Custom Event ValidatedTextChanged As RoutedEventHandler
AddHandler(value As RoutedEventHandler) AddHandler(value As RoutedEventHandler)
ChangedEventList.Add(value) ChangedEventList.Add(value)
@@ -295,4 +302,21 @@
Private Sub MyTextBox_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp Private Sub MyTextBox_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp
If e.Key = Key.Enter Then RaiseCustomEvent() If e.Key = Key.Enter Then RaiseCustomEvent()
End Sub End Sub
#Region "设置"
Private Sub RefreshSetting(NewValue As String) Implements ISettingControl.RefreshSetting
Text = NewValue
End Sub
Private Function GetCurrentSetting() As String Implements ISettingControl.GetCurrentSetting
Return Text
End Function
Private Sub SaveSetting() Handles Me.ValidatedTextChanged
SettingService.SaveSetting(Me)
End Sub
#End Region
End Class End Class
@@ -4,7 +4,7 @@
Private Initializer As Func(Of T) Private Initializer As Func(Of T)
Public Sub New(Initializer As Func(Of T)) Public Sub New(Initializer As Func(Of T))
Me.Initializer = Initializer Me.Initializer = Initializer
OnFirstEnterScrollViewerViewport(AddressOf Init) LazyLoadBehavior.OnFirstEnterScrollViewerViewport(Me, AddressOf Init)
End Sub End Sub
''' <summary> ''' <summary>
@@ -34,7 +34,7 @@ Public Class MyVirtualizingElement
Private Initializer As Func(Of FrameworkElement) Private Initializer As Func(Of FrameworkElement)
Public Sub New(Initializer As Func(Of FrameworkElement)) Public Sub New(Initializer As Func(Of FrameworkElement))
Me.Initializer = Initializer Me.Initializer = Initializer
OnFirstEnterScrollViewerViewport(AddressOf Init) LazyLoadBehavior.OnFirstEnterScrollViewerViewport(Me, AddressOf Init)
End Sub End Sub
''' <summary> ''' <summary>
+2 -1
View File
@@ -95,7 +95,8 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition /> <RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Canvas x:Name="ImgBack" IsHitTestVisible="False" Grid.Row="1" RenderOptions.BitmapScalingMode="LowQuality" /> <Canvas x:Name="ImgBack" IsHitTestVisible="False" Grid.Row="1" RenderOptions.BitmapScalingMode="LowQuality"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Grid x:Name="PanTitle" Height="48"> <Grid x:Name="PanTitle" Height="48">
<Grid.Background> <Grid.Background>
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0"> <LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
+272 -198
View File
@@ -11,6 +11,38 @@ Public Class FormMain
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String)) Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
'统计更新日志条目 '统计更新日志条目
#If BETA Then #If BETA Then
If LastVersion < 391 Then 'Release 2.12.6.2
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:会为部分 Forge / NeoForge 选择不支持的 Java"))
BugCount += 4
End If
If LastVersion < 389 Then 'Release 2.12.6.1
If LastVersion = 387 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法使用 Java 25+ 启动 Forge"))
FeatureCount += 4
BugCount += 3
End If
If LastVersion < 387 Then 'Release 2.12.6
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:降低 Minecraft 的内存占用"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:Minecraft 使用 Java 25+ 时的一个性能问题"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法下载 NeoForge 26.1"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:部分关键词搜不到资源,特别是中文 Mod 搜索经常没有结果"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:老版本 Windows 无法启动游戏"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:连接 Mojang 的服务可能失败,提示错误码 421"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法访问爱发电"))
FeatureCount += 24
BugCount += 19
End If
If LastVersion < 383 Then 'Release 2.12.3
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:部分关键词搜不到资源,特别是中文 Mod 搜索经常没有结果"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:下载可能完全卡住,或是下载进度反复回退"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:内存管理设置,可以选择 G1GC、ZGC 或分代 ZGC"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:来自 Modrinth 的文件下载速度"))
FeatureCount += 15
BugCount += 16
End If
If LastVersion < 381 Then 'Release 2.12.2
FeatureCount += 3
BugCount += 13
End If
If LastVersion < 379 Then 'Release 2.12.1 If LastVersion < 379 Then 'Release 2.12.1
If LastVersion >= 376 Then If LastVersion >= 376 Then
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "删除:暂时隐藏联机入口……不过只是暂时关闭,它还会回来的!")) FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "删除:暂时隐藏联机入口……不过只是暂时关闭,它还会回来的!"))
@@ -72,64 +104,54 @@ Public Class FormMain
FeatureCount += 9 FeatureCount += 9
BugCount += 26 BugCount += 26
End If End If
If LastVersion < 355 Then 'Release 2.9.3
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:Minecraft 会优先使用独立显卡运行"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:简化下载新版本第二步的 UI"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:使用新的版本隔离策略"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:添加了在全局启动设置与版本独立设置之间互相跳转的按钮"))
FeatureCount += 20
BugCount += 28
End If
If LastVersion < 352 Then 'Release 2.9.1
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:导出整合包功能"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:支持在超长路径下安装、启动游戏"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法安装 1.21 OptiFine"))
FeatureCount += 23
BugCount += 10
End If
If LastVersion < 349 Then 'Release 2.8.13
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:网络环境不佳时,Mod、整合包页面的加载速度"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:部分电脑无法打开程序"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:可能无法识别、更新 Mod"))
FeatureCount += 6
BugCount += 14
End If
If LastVersion < 347 Then 'Release 2.8.12
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增:Mod 管理页面添加下载 Mod、安装 Mod 选项"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增:Mod 详情页面支持按加载器、游戏版本进行分类和筛选"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:支持安装同时包含 modpack 文件和启动器的懒人包"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:整合包导入流程"))
FeatureCount += 43
BugCount += 37
End If
If LastVersion < 342 Then 'Release 2.8.9
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增:支持下载原版服务端"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:本地 Mod 的标题支持选择显示 Mod 原始文件名"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:搜索后启用/禁用 Mod 时出错"))
FeatureCount += 17
BugCount += 13
End If
If LastVersion < 340 Then 'Release 2.8.8
If LastVersion = 338 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:数个与新正版登录相关的严重 Bug"))
FeatureCount += 3
BugCount += 7
End If
If LastVersion < 338 Then 'Release 2.8.7
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "优化:使用新的正版登录方式,以提高安全性"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:安装整合包、检索 Mod 的稳定性"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法加载部分 Mod 的图标"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:在 Mod 管理页面删除 Mod 导致报错"))
FeatureCount += 11
BugCount += 21
End If
#Else #Else
'5: FEAT+ '5: FEAT+
'4: IMP+ FEAT* '4: IMP+ FEAT*
'3:BUG+ IMP* FEAT- '3:BUG+ IMP* FEAT-
'2:BUG* IMP- '2:BUG* IMP-
'1:BUG- '1:BUG-
If LastVersion < 390 Then 'Snapshot 2.12.6.2
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:会为部分 Forge / NeoForge 选择不支持的 Java"))
BugCount += 4
End If
If LastVersion < 388 Then 'Snapshot 2.12.6.1
If LastVersion = 386 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法使用 Java 25+ 启动 Forge"))
FeatureCount += 4
BugCount += 3
End If
If LastVersion < 386 Then 'Snapshot 2.12.6
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:Minecraft 使用 Java 25+ 时的一个性能问题"))
If LastVersion = 384 OrElse LastVersion = 385 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法正常重命名游戏版本"))
If LastVersion = 385 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法显示 Modrinth 整合包的版本列表"))
BugCount += 1
End If
If LastVersion < 385 Then 'Snapshot 2.12.5
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法下载 NeoForge 26.1"))
If LastVersion = 384 Then
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:下载可能失败,提示下载管理刷新线程出错"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法保存选择的 Minecraft 文件夹"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:使用中文搜索 Mod 时,部分结果会忽略筛选条件"))
End If
FeatureCount += 3
BugCount += 6
End If
If LastVersion < 384 Then 'Snapshot 2.12.4
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:降低 Minecraft 的内存占用"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:部分关键词搜不到资源,特别是中文 Mod 搜索经常没有结果"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:老版本 Windows 无法启动游戏"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:连接 Mojang 的服务可能失败,提示错误码 421"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法访问爱发电"))
FeatureCount += 21
BugCount += 14
End If
If LastVersion < 382 Then 'Snapshot 2.12.3
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:下载可能完全卡住,或是下载进度反复回退"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:内存管理设置,可以选择 G1GC、ZGC 或分代 ZGC"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:来自 Modrinth 的文件下载速度"))
FeatureCount += 15
BugCount += 16
End If
If LastVersion < 380 Then 'Snapshot 2.12.2 If LastVersion < 380 Then 'Snapshot 2.12.2
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法搜索 CurseForge 上的社区资源"))
FeatureCount += 3 FeatureCount += 3
BugCount += 13 BugCount += 13
End If End If
@@ -235,81 +257,6 @@ Public Class FormMain
FeatureCount += 9 FeatureCount += 9
BugCount += 26 BugCount += 26
End If End If
If LastVersion < 354 Then 'Snapshot 2.9.3
If LastVersion = 352 Then
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:低版本 MC 没有声音"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:若不安装 Mod 加载器,则无法安装 OptiFine 1.14+"))
End If
FeatureCount += 8
BugCount += 8
End If
If LastVersion < 352 Then 'Snapshot 2.9.2
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:Minecraft 会优先使用独立显卡运行"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:简化下载新版本第二步的 UI"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:使用新的版本隔离策略"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:添加了在全局启动设置与版本独立设置之间互相跳转的按钮"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:使用快照版导出带 PCL 的整合包可能失败"))
FeatureCount += 12
BugCount += 20
End If
If LastVersion < 351 Then 'Snapshot 2.9.1
If LastVersion = 350 Then
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "优化:对导出整合包功能进行了 7 项优化,详见完整更新日志"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法进行第三方登录"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:在部分版本下,打开导出页面会导致启动器崩溃"))
BugCount += 1
End If
BugCount += 2
End If
If LastVersion < 350 Then 'Snapshot 2.9.0
FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:导出整合包功能"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:支持在超长路径下安装、启动游戏"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法安装 1.21 OptiFine"))
FeatureCount += 21
BugCount += 10
End If
If LastVersion < 348 Then 'Snapshot 2.8.13
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:网络环境不佳时,Mod、整合包页面的加载速度"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:部分电脑无法打开程序"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:可能无法识别、更新 Mod"))
FeatureCount += 6
BugCount += 14
End If
If LastVersion < 346 Then 'Snapshot 2.8.12
If LastVersion = 345 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:帮助页面报错"))
End If
If LastVersion < 345 Then 'Snapshot 2.8.11
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增:Mod 管理页面添加下载 Mod、安装 Mod 选项"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增:Mod 详情页面支持按加载器、游戏版本进行分类和筛选"))
FeatureCount += 23
BugCount += 21
End If
If LastVersion < 343 Then 'Snapshot 2.8.10
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:支持安装同时包含 modpack 文件和启动器的懒人包"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:整合包导入流程"))
FeatureCount += 20
BugCount += 16
End If
If LastVersion < 341 Then 'Snapshot 2.8.9
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "新增:支持下载原版服务端"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:本地 Mod 的标题支持选择显示 Mod 原始文件名"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:搜索后启用/禁用 Mod 时出错"))
FeatureCount += 17
BugCount += 13
End If
If LastVersion < 339 Then 'Snapshot 2.8.8
If LastVersion = 337 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:数个与新正版登录相关的严重 Bug"))
FeatureCount += 3
BugCount += 7
End If
If LastVersion < 337 Then 'Snapshot 2.8.7
FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "优化:使用新的正版登录方式,以提高安全性"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:安装整合包、检索 Mod 的稳定性"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法加载部分 Mod 的图标"))
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:在 Mod 管理页面删除 Mod 导致报错"))
FeatureCount += 11
BugCount += 21
End If
#End If #End If
'整理更新日志文本 '整理更新日志文本
Dim ContentList As New List(Of String) Dim ContentList As New List(Of String)
@@ -325,12 +272,12 @@ Public Class FormMain
If(BugCount > 0, "修复了 " & BugCount & " 个 Bug", "") & If(BugCount > 0, "修复了 " & BugCount & " 个 Bug", "") &
",详见完整更新日志") ",详见完整更新日志")
End If End If
Dim Content As String = "· " & Join(ContentList, vbCrLf & "· ") Dim Content As String = "· " & ContentList.Join(vbCrLf & "· ")
'输出更新日志 '输出更新日志
RunInNewThread( RunInNewThread(
Sub() Sub()
If MyMsgBox(Content, "PCL 已更新至 " & VersionDisplayName, "确定", "完整更新日志") = 2 Then If MyMsgBox(Content, "PCL 已更新至" & VersionDisplayName, "确定", "完整更新日志") = 2 Then
OpenWebsite("https://afdian.com/a/LTCat?tab=feed") OpenWebsite("https://meloong.com/afd/a/LTCat?tab=feed")
End If End If
End Sub, "UpdateLog Output") End Sub, "UpdateLog Output")
End Sub End Sub
@@ -344,7 +291,7 @@ Public Class FormMain
FrmLaunchLeft = New PageLaunchLeft FrmLaunchLeft = New PageLaunchLeft
FrmLaunchRight = New PageLaunchRight FrmLaunchRight = New PageLaunchRight
'版本号改变 '版本号改变
Dim LastVersion As Integer = Setup.Get("SystemLastVersionReg") Dim LastVersion As Integer = Settings.Get("SystemLastVersionReg")
If LastVersion < VersionCode Then If LastVersion < VersionCode Then
'触发升级 '触发升级
UpgradeSub(LastVersion) UpgradeSub(LastVersion)
@@ -353,21 +300,21 @@ Public Class FormMain
DowngradeSub(LastVersion) DowngradeSub(LastVersion)
End If End If
'版本隔离设置迁移 '版本隔离设置迁移
If Setup.IsUnset("LaunchArgumentIndieV2") Then If Not Settings.HasSaved("LaunchArgumentIndieV2") Then
If Not Setup.IsUnset("LaunchArgumentIndie") Then If Settings.HasSaved("LaunchArgumentIndie") Then
Log("[Start] 从老 PCL 迁移版本隔离") Log("[Start] 从老 PCL 迁移版本隔离")
Setup.Set("LaunchArgumentIndieV2", Setup.Get("LaunchArgumentIndie")) Settings.Set("LaunchArgumentIndieV2", Settings.Get("LaunchArgumentIndie"))
ElseIf Not Setup.IsUnset("LaunchVersionSelect") Then ElseIf HasIniKey("Setup", "LaunchVersionSelect") Then
Log("[Start] 从老 PCL 升级,但此前未调整版本隔离,使用老的版本隔离默认值") Log("[Start] 从老 PCL 升级,但此前未调整版本隔离,使用老的版本隔离默认值")
Setup.Set("LaunchArgumentIndieV2", Setup.GetDefault("LaunchArgumentIndie")) Settings.Set("LaunchArgumentIndieV2", Settings.GetDefault("LaunchArgumentIndie"))
Else Else
Log("[Start] 全新的 PCL,使用新的版本隔离默认值") Log("[Start] 全新的 PCL,使用新的版本隔离默认值")
Setup.Set("LaunchArgumentIndieV2", Setup.GetDefault("LaunchArgumentIndieV2")) Settings.Set("LaunchArgumentIndieV2", Settings.GetDefault("LaunchArgumentIndieV2"))
End If End If
End If End If
'刷新主题 '刷新主题
ThemeCheckAll(False) ThemeCheckAll(False)
Setup.Load("UiLauncherTheme") ThemeRefresh(Settings.Get("UiLauncherTheme"))
'注册拖拽事件(不能直接加 Handles,否则没用;#6340) '注册拖拽事件(不能直接加 Handles,否则没用;#6340)
[AddHandler](DragDrop.DragEnterEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True) [AddHandler](DragDrop.DragEnterEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True)
[AddHandler](DragDrop.DragOverEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True) [AddHandler](DragDrop.DragOverEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True)
@@ -406,12 +353,10 @@ Public Class FormMain
End Sub End Sub
Private Sub FormMain_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded Private Sub FormMain_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
ApplicationStartTick = GetTimeMs() ApplicationStartTick = GetTimeMs()
Handle = New Interop.WindowInteropHelper(Me).Handle Handle = New WindowInteropHelper(Me).Handle
'读取设置 '读取设置
Setup.Load("UiBackgroundOpacity") UpdateBackgroundAndTitleBar()
Setup.Load("UiBackgroundBlur") PageSetupUI.HiddenRefresh()
Setup.Load("UiLogoType")
Setup.Load("UiHiddenPageDownload")
PageSetupUI.BackgroundRefresh(False, True) PageSetupUI.BackgroundRefresh(False, True)
MusicRefreshPlay(False, True) MusicRefreshPlay(False, True)
'扩展按钮 '扩展按钮
@@ -437,8 +382,8 @@ Public Class FormMain
'加载窗口 '加载窗口
ThemeRefreshMain() ThemeRefreshMain()
Try Try
Height = Setup.Get("WindowHeight") Height = Settings.Get("WindowHeight")
Width = Setup.Get("WindowWidth") Width = Settings.Get("WindowWidth")
Catch ex As Exception '修复 #2019 Catch ex As Exception '修复 #2019
Log(ex, "读取窗口默认大小失败", LogLevel.Hint) Log(ex, "读取窗口默认大小失败", LogLevel.Hint)
Height = MinHeight + 100 Height = MinHeight + 100
@@ -459,7 +404,7 @@ Public Class FormMain
HwndSource.AddHook(New Interop.HwndSourceHook(AddressOf WndProc)) HwndSource.AddHook(New Interop.HwndSourceHook(AddressOf WndProc))
AniStart({ AniStart({
AaCode(Sub() AniControlEnabled -= 1, 50), AaCode(Sub() AniControlEnabled -= 1, 50),
AaOpacity(Me, Setup.Get("UiLauncherTransparent") / 1000 + 0.4, 250, 100), AaOpacity(Me, Settings.Get("UiLauncherTransparent") / 1000 + 0.4, 250, 100),
AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 600, 100, New AniEaseOutBack(AniEasePower.Weak)), AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 600, 100, New AniEaseOutBack(AniEasePower.Weak)),
AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 500, 100, New AniEaseOutBack(AniEasePower.Weak)), AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 500, 100, New AniEaseOutBack(AniEasePower.Weak)),
AaCode( AaCode(
@@ -477,15 +422,15 @@ Public Class FormMain
Sub() Sub()
'EULA 提示 'EULA 提示
Const EulaVersion As Integer = 2 Const EulaVersion As Integer = 2
If Setup.Get("SystemEulaVersion") < EulaVersion Then If Settings.Get("SystemEulaVersion") < EulaVersion Then
Select Case MyMsgBox( Select Case MyMsgBox(
If(Setup.Get("SystemEulaVersion") = 0, If(Settings.Get("SystemEulaVersion") = 0,
"在使用 PCL 前,请先阅读用户协议与免责声明。", "在使用 PCL 前,请先阅读用户协议与免责声明。",
$"PCL 的用户协议与免责声明已更新。{vbCrLf}请阅读更新后的用户协议与免责声明。"), $"PCL 的用户协议与免责声明已更新。{vbCrLf}请阅读更新后的用户协议与免责声明。"),
"协议授权", "同意", "拒绝", "查看用户协议与免责声明", "协议授权", "同意", "拒绝", "查看用户协议与免责声明",
Button3Action:=Sub() OpenWebsite("https://shimo.im/docs/rGrd8pY8xWkt6ryW")) Button3Action:=Sub() OpenWebsite("https://shimo.im/docs/rGrd8pY8xWkt6ryW"))
Case 1 Case 1
Setup.Set("SystemEulaVersion", EulaVersion) Settings.Set("SystemEulaVersion", EulaVersion)
Case 2 Case 2
EndProgram(False) EndProgram(False)
End Select End Select
@@ -515,15 +460,15 @@ Public Class FormMain
End Sub End Sub
'根据打开次数触发的事件 '根据打开次数触发的事件
Private Sub RunCountSub() Private Sub RunCountSub()
Setup.Set("SystemCount", Setup.Get("SystemCount") + 1) Settings.Set("SystemCount", Settings.Get("SystemCount") + 1)
#If Not BETA Then #If Not BETA Then
Select Case Setup.Get("SystemCount") Select Case Settings.Get("SystemCount")
Case 1 Case 1
MyMsgBox("欢迎使用 PCL 快照版!" & vbCrLf & MyMsgBox("欢迎使用 PCL 快照版!" & vbCrLf &
"快照版包含尚未在正式版发布的测试性功能,仅用于赞助者本人尝鲜。所以请不要发给其他人或者用于制作整合包哦!" & vbCrLf & "快照版包含尚未在正式版发布的测试性功能,仅用于赞助者本人尝鲜。所以请不要发给其他人或者用于制作整合包哦!" & vbCrLf &
"如果你并非通过赞助或赞助者本人邀请进群获得的本程序,那么可能是有人在违规传播,记得提醒他一下啦。", "快照版使用说明") "如果你并非通过赞助或赞助者本人邀请进群获得的本程序,那么可能是有人在违规传播,记得提醒他一下啦。", "快照版使用说明")
End Select End Select
If Setup.Get("SystemCount") >= 99 Then If Settings.Get("SystemCount") >= 99 Then
If ThemeUnlock(6, False) Then If ThemeUnlock(6, False) Then
MyMsgBox("你已经使用了 99 次 PCL 啦,感谢你长期以来的支持!" & vbCrLf & MyMsgBox("你已经使用了 99 次 PCL 啦,感谢你长期以来的支持!" & vbCrLf &
"隐藏主题 铁杆粉 已解锁!", "提示") "隐藏主题 铁杆粉 已解锁!", "提示")
@@ -534,46 +479,44 @@ Public Class FormMain
'升级与降级事件 '升级与降级事件
Private Sub UpgradeSub(LastVersionCode As Integer) Private Sub UpgradeSub(LastVersionCode As Integer)
Log("[Start] 版本号从 " & LastVersionCode & " 升高到 " & VersionCode) Log("[Start] 版本号从 " & LastVersionCode & " 升高到 " & VersionCode)
Setup.Set("SystemLastVersionReg", VersionCode) Settings.Set("SystemLastVersionReg", VersionCode)
'检查有记录的最高版本号 '检查有记录的最高版本号
Dim LowerVersionCode As Integer Dim LowerVersionCode As Integer
#If BETA Then #If BETA Then
LowerVersionCode = Setup.Get("SystemHighestBetaVersionReg") LowerVersionCode = Settings.Get("SystemHighestBetaVersionReg")
If LowerVersionCode < VersionCode Then If LowerVersionCode < VersionCode Then
Setup.Set("SystemHighestBetaVersionReg", VersionCode) Settings.Set("SystemHighestBetaVersionReg", VersionCode)
Log("[Start] 最高版本号从 " & LowerVersionCode & " 升高到 " & VersionCode) Log("[Start] 最高版本号从 " & LowerVersionCode & " 升高到 " & VersionCode)
End If End If
#Else #Else
LowerVersionCode = Setup.Get("SystemHighestAlphaVersionReg") LowerVersionCode = Settings.Get("SystemHighestAlphaVersionReg")
If LowerVersionCode < VersionCode Then If LowerVersionCode < VersionCode Then
Setup.Set("SystemHighestAlphaVersionReg", VersionCode) Settings.Set("SystemHighestAlphaVersionReg", VersionCode)
Log("[Start] 最高版本号从 " & LowerVersionCode & " 升高到 " & VersionCode) Log("[Start] 最高版本号从 " & LowerVersionCode & " 升高到 " & VersionCode)
End If End If
#End If #End If
'迁移 EULA 版本
If Setup.Get("SystemEula") AndAlso Setup.Get("SystemEulaVersion") = 0 Then Setup.Set("SystemEulaVersion", 1)
'被移除的窗口设置选项 '被移除的窗口设置选项
If Setup.Get("LaunchArgumentWindowType") = 5 Then Setup.Set("LaunchArgumentWindowType", 1) If Settings.Get("LaunchArgumentWindowType") = 5 Then Settings.Set("LaunchArgumentWindowType", 1)
'修改主题设置项名称 '修改主题设置项名称
If LowerVersionCode <= 207 Then If LowerVersionCode <= 207 Then
Dim UnlockedTheme As New List(Of String) From {"2"} Dim UnlockedTheme As New List(Of String) From {"2"}
UnlockedTheme.AddRange(New List(Of String)(Setup.Get("UiLauncherThemeHide").ToString.Split("|"))) UnlockedTheme.AddRange(New List(Of String)(Settings.Get("UiLauncherThemeHide").ToString.Split("|")))
UnlockedTheme.AddRange(New List(Of String)(Setup.Get("UiLauncherThemeHide2").ToString.Split("|"))) UnlockedTheme.AddRange(New List(Of String)(Settings.Get("UiLauncherThemeHide2").ToString.Split("|")))
Setup.Set("UiLauncherThemeHide2", Join(UnlockedTheme.Distinct.ToList, "|")) Settings.Set("UiLauncherThemeHide2", UnlockedTheme.Distinct.ToList.Join("|"c))
End If End If
'重置欧皇彩 '重置欧皇彩
If LastVersionCode <= 115 AndAlso Setup.Get("UiLauncherThemeHide2").ToString.Split("|").Contains("13") Then If LastVersionCode <= 115 AndAlso Settings.Get("UiLauncherThemeHide2").ToString.Split("|").Contains("13") Then
Dim UnlockedTheme As New List(Of String)(Setup.Get("UiLauncherThemeHide2").ToString.Split("|")) Dim UnlockedTheme As New List(Of String)(Settings.Get("UiLauncherThemeHide2").ToString.Split("|"))
UnlockedTheme.Remove("13") UnlockedTheme.Remove("13")
Setup.Set("UiLauncherThemeHide2", Join(UnlockedTheme, "|")) Settings.Set("UiLauncherThemeHide2", UnlockedTheme.Join("|"c))
MyMsgBox("由于新版 PCL 修改了欧皇彩的解锁方式,你需要重新解锁欧皇彩。" & vbCrLf & MyMsgBox("由于新版 PCL 修改了欧皇彩的解锁方式,你需要重新解锁欧皇彩。" & vbCrLf &
"多谢各位的理解啦!", "重新解锁提醒") "多谢各位的理解啦!", "重新解锁提醒")
End If End If
'重置滑稽彩 '重置滑稽彩
If LastVersionCode <= 152 AndAlso Setup.Get("UiLauncherThemeHide2").ToString.Split("|").Contains("12") Then If LastVersionCode <= 152 AndAlso Settings.Get("UiLauncherThemeHide2").ToString.Split("|").Contains("12") Then
Dim UnlockedTheme As New List(Of String)(Setup.Get("UiLauncherThemeHide2").ToString.Split("|")) Dim UnlockedTheme As New List(Of String)(Settings.Get("UiLauncherThemeHide2").ToString.Split("|"))
UnlockedTheme.Remove("12") UnlockedTheme.Remove("12")
Setup.Set("UiLauncherThemeHide2", Join(UnlockedTheme, "|")) Settings.Set("UiLauncherThemeHide2", UnlockedTheme.Join("|"c))
MyMsgBox("由于新版 PCL 修改了滑稽彩的解锁方式,你需要重新解锁滑稽彩。" & vbCrLf & MyMsgBox("由于新版 PCL 修改了滑稽彩的解锁方式,你需要重新解锁滑稽彩。" & vbCrLf &
"多谢各位的理解啦!", "重新解锁提醒") "多谢各位的理解啦!", "重新解锁提醒")
End If End If
@@ -588,24 +531,30 @@ Public Class FormMain
End If End If
'解除帮助页面的隐藏 '解除帮助页面的隐藏
If LastVersionCode <= 205 Then If LastVersionCode <= 205 Then
Setup.Set("UiHiddenOtherHelp", False) Settings.Set("UiHiddenOtherHelp", False)
Log("[Start] 已解除帮助页面的隐藏") Log("[Start] 已解除帮助页面的隐藏")
End If End If
'单向迁移微软登录结果(#4836) '单向迁移微软登录结果(#4836)
If Not Setup.Get("CacheMsV2Migrated") Then If Not Settings.Get("CacheMsV2Migrated") Then
Setup.Set("CacheMsV2Migrated", True) Settings.Set("CacheMsV2Migrated", True)
Setup.Set("CacheMsV2OAuthRefresh", Setup.Get("CacheMsOAuthRefresh")) Settings.Set("CacheMsV2OAuthRefresh", Settings.Get("CacheMsOAuthRefresh"))
Setup.Set("CacheMsV2Access", Setup.Get("CacheMsAccess")) Settings.Set("CacheMsV2Access", Settings.Get("CacheMsAccess"))
Setup.Set("CacheMsV2ProfileJson", Setup.Get("CacheMsProfileJson")) Settings.Set("CacheMsV2ProfileJson", Settings.Get("CacheMsProfileJson"))
Setup.Set("CacheMsV2Uuid", Setup.Get("CacheMsUuid")) Settings.Set("CacheMsV2Uuid", Settings.Get("CacheMsUuid"))
Setup.Set("CacheMsV2Name", Setup.Get("CacheMsName")) Settings.Set("CacheMsV2Name", Settings.Get("CacheMsName"))
Log("[Start] 已从老版本迁移微软登录结果") Log("[Start] 已从老版本迁移微软登录结果")
End If End If
'Mod 命名设置迁移 'Mod 命名设置迁移
If Not Setup.IsUnset("ToolDownloadTranslate") AndAlso Setup.IsUnset("ToolDownloadTranslateV2") Then If Settings.HasSaved("ToolDownloadTranslate") AndAlso Not Settings.HasSaved("ToolDownloadTranslateV2") Then
Setup.Set("ToolDownloadTranslateV2", Setup.Get("ToolDownloadTranslate") + 1) Settings.Set("ToolDownloadTranslateV2", Settings.Get("ToolDownloadTranslate") + 1)
Log("[Start] 已从老版本迁移 Mod 命名设置") Log("[Start] 已从老版本迁移 Mod 命名设置")
End If End If
'重置 JVM 参数设置
If LastVersionCode <= 381 AndAlso Settings.HasSaved("LaunchAdvanceJvm") AndAlso
Settings.Get("LaunchAdvanceJvm").ToString.Replace("-XX:+UseG1GC ", "").Replace("-XX:-UseAdaptiveSizePolicy ", "").Trim = Settings.GetDefault("LaunchAdvanceJvm") Then
Settings.Reset("LaunchAdvanceJvm")
Log("[Start] 已重置 JVM 参数设置")
End If
'输出更新日志 '输出更新日志
If LastVersionCode <= 0 Then Return If LastVersionCode <= 0 Then Return
If LowerVersionCode >= VersionCode Then Return If LowerVersionCode >= VersionCode Then Return
@@ -613,7 +562,7 @@ Public Class FormMain
End Sub End Sub
Private Sub DowngradeSub(LastVersionCode As Integer) Private Sub DowngradeSub(LastVersionCode As Integer)
Log("[Start] 版本号从 " & LastVersionCode & " 降低到 " & VersionCode) Log("[Start] 版本号从 " & LastVersionCode & " 降低到 " & VersionCode)
Setup.Set("SystemLastVersionReg", VersionCode) Settings.Set("SystemLastVersionReg", VersionCode)
End Sub End Sub
#End Region #End Region
@@ -637,7 +586,7 @@ Public Class FormMain
Sub() Sub()
Log("[System] 正在强行停止任务") Log("[System] 正在强行停止任务")
For Each Task As LoaderBase In LoaderTaskbar.ToList() For Each Task As LoaderBase In LoaderTaskbar.ToList()
Task.Abort() Task.Interrupt()
Next Next
End Sub, "强行停止下载任务") End Sub, "强行停止下载任务")
End If End If
@@ -712,8 +661,8 @@ Public Class FormMain
Public IsSizeSaveable As Boolean = False Public IsSizeSaveable As Boolean = False
Private Sub FormMain_SizeChanged() Handles Me.SizeChanged, Me.Loaded Private Sub FormMain_SizeChanged() Handles Me.SizeChanged, Me.Loaded
If IsSizeSaveable Then If IsSizeSaveable Then
Setup.Set("WindowHeight", Height) Settings.Set("WindowHeight", Height)
Setup.Set("WindowWidth", Width) Settings.Set("WindowWidth", Width)
End If End If
RectForm.Rect = New Rect(0, 0, BorderForm.ActualWidth, BorderForm.ActualHeight) RectForm.Rect = New Rect(0, 0, BorderForm.ActualWidth, BorderForm.ActualHeight)
PanForm.Width = BorderForm.ActualWidth + 0.001 PanForm.Width = BorderForm.ActualWidth + 0.001
@@ -728,6 +677,131 @@ Public Class FormMain
WindowState = WindowState.Minimized WindowState = WindowState.Minimized
End Sub End Sub
'背景图片与标题栏
Public Shared Sub UpdateBackgroundAndTitleBar(Value) '从设置更新
If FrmMain Is Nothing OrElse Not FrmMain.IsLoaded Then Return
FrmMain.UpdateBackgroundAndTitleBar()
End Sub
Public Sub UpdateBackgroundAndTitleBar()
Log("[FormMain] 从设置更新背景图片与标题栏样式")
'背景图片透明度
ImgBack.Opacity = Settings.Get("UiBackgroundOpacity") / 1000
'背景图片模糊
Dim BlurRadius As Double = Settings.Get("UiBackgroundBlur") + 1
If BlurRadius = 1 Then
ImgBack.Effect = Nothing
Else
ImgBack.Effect = New Effects.BlurEffect With {.Radius = BlurRadius}
End If
ImgBack.Margin = New Thickness(-BlurRadius / 1.8)
'背景图片适应方式
Dim BackgroundType As Integer = Settings.Get("UiBackgroundSuit")
If ImgBack.Background IsNot Nothing Then
Dim Brush As ImageBrush = CType(ImgBack.Background, ImageBrush)
If BackgroundType = 0 Then
'智能:当图片较小时平铺,较大时适应
If Brush.ImageSource.Width < PanMain.ActualWidth / 2 AndAlso Brush.ImageSource.Height < PanMain.ActualHeight / 2 Then
BackgroundType = 4 '平铺
Else
BackgroundType = 2 '适应
End If
End If
Brush.Stretch = Stretch.UniformToFill
Brush.TileMode = TileMode.None
Brush.Viewport = New Rect(0, 0, 1, 1)
Brush.ViewportUnits = BrushMappingMode.RelativeToBoundingBox
Brush.AlignmentX = AlignmentX.Center
Brush.AlignmentY = AlignmentY.Center
Select Case BackgroundType
Case 1 '中
Brush.Stretch = Stretch.None
Case 3 '拉伸
Brush.Stretch = Stretch.Fill
Case 4 '平铺
Brush.Stretch = Stretch.None
Brush.TileMode = TileMode.Tile
Brush.Viewport = New Rect(0, 0, Brush.ImageSource.Width, Brush.ImageSource.Height)
Brush.ViewportUnits = BrushMappingMode.Absolute
Case 2 '适应
Case 5 '左上
Brush.AlignmentX = AlignmentX.Left
Brush.AlignmentY = AlignmentY.Top
Case 6 '右上
Brush.AlignmentX = AlignmentX.Right
Brush.AlignmentY = AlignmentY.Top
Case 7 '左下
Brush.AlignmentX = AlignmentX.Left
Brush.AlignmentY = AlignmentY.Bottom
Case 8 '右下
Brush.AlignmentX = AlignmentX.Right
Brush.AlignmentY = AlignmentY.Bottom
Case 9 '左
Brush.AlignmentX = AlignmentX.Left
Brush.AlignmentY = AlignmentY.Center
Case 10 '右
Brush.AlignmentX = AlignmentX.Right
Brush.AlignmentY = AlignmentY.Center
Case 11 '上
Brush.AlignmentX = AlignmentX.Center
Brush.AlignmentY = AlignmentY.Top
Case 12 '下
Brush.AlignmentX = AlignmentX.Center
Brush.AlignmentY = AlignmentY.Bottom
End Select
End If
'标题栏显示类型
Select Case Settings.Get("UiLogoType")
Case 0 '无
ShapeTitleLogo.Visibility = Visibility.Collapsed
LabTitleLogo.Visibility = Visibility.Collapsed
ImageTitleLogo.Visibility = Visibility.Collapsed
If Not IsNothing(FrmSetupUI) Then 'TODO: 和 FrmSetupUI 解耦
FrmSetupUI.CheckLogoLeft.Visibility = Visibility.Visible
FrmSetupUI.PanLogoText.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoChange.Visibility = Visibility.Collapsed
End If
Case 1 '默认
ShapeTitleLogo.Visibility = Visibility.Visible
LabTitleLogo.Visibility = Visibility.Collapsed
ImageTitleLogo.Visibility = Visibility.Collapsed
If Not IsNothing(FrmSetupUI) Then
FrmSetupUI.CheckLogoLeft.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoText.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoChange.Visibility = Visibility.Collapsed
End If
Case 2 '文本
ShapeTitleLogo.Visibility = Visibility.Collapsed
LabTitleLogo.Visibility = Visibility.Visible
ImageTitleLogo.Visibility = Visibility.Collapsed
If Not IsNothing(FrmSetupUI) Then
FrmSetupUI.CheckLogoLeft.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoText.Visibility = Visibility.Visible
FrmSetupUI.PanLogoChange.Visibility = Visibility.Collapsed
End If
Case 3 '图片
ShapeTitleLogo.Visibility = Visibility.Collapsed
LabTitleLogo.Visibility = Visibility.Collapsed
ImageTitleLogo.Visibility = Visibility.Visible
If Not IsNothing(FrmSetupUI) Then
FrmSetupUI.CheckLogoLeft.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoText.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoChange.Visibility = Visibility.Visible
End If
Try
ImageTitleLogo.Source = Path & "PCL\Logo.png"
Catch ex As Exception
ImageTitleLogo.Source = Nothing
Log(ex, "显示标题栏图片失败", LogLevel.Msgbox)
End Try
End Select
FrmSetupUI?.CardLogo.TriggerForceResize()
'标题栏文本
LabTitleLogo.Text = Settings.Get("UiLogoText")
'标题栏文本是否居左
PanTitleMain.ColumnDefinitions(0).Width = New GridLength(If(Settings.Get("UiLogoLeft") AndAlso Settings.Get("UiLogoType") = 0, 0, 1), GridUnitType.Star)
End Sub
#End Region #End Region
#Region "窗体事件" #Region "窗体事件"
@@ -819,13 +893,13 @@ Public Class FormMain
Log(ex, "切回窗口时出错", LogLevel.Feedback) Log(ex, "切回窗口时出错", LogLevel.Feedback)
End Try End Try
'读取剪贴板,自动加入联机房间 '读取剪贴板,自动加入联机房间
Return 'TODO: 联机复活赛
If PageLinkMain.LinkState <> PageLinkMain.LinkStates.Waiting Then Return '已启动联机 If PageLinkMain.LinkState <> PageLinkMain.LinkStates.Waiting Then Return '已启动联机
If PageCurrent = PageType.Link Then Return '已在联机界面 If PageCurrent = PageType.Link Then Return '已在联机界面
Dim Code = ClipboardGetText() : If Code Is Nothing Then Return '剪贴板无文本 Dim Code = ClipboardGetText() : If Code Is Nothing Then Return '剪贴板无文本
If Setup.Get("LinkLastAutoJoinInviteCode") = Code Then Return If Settings.Get("LinkLastAutoJoinInviteCode") = Code Then Return
' If PageLinkMain.ValidateCodeFormat(Code) IsNot Nothing Then Return '不是邀请码 If PageLinkMain.ValidateCodeFormat(Code) IsNot Nothing Then Return '不是邀请码
Return '联机关闭 直接return Settings.Set("LinkLastAutoJoinInviteCode", Code)
Setup.Set("LinkLastAutoJoinInviteCode", Code)
RunInThread( RunInThread(
Sub() Sub()
If MyMsgBox("嘿,是否使用复制的邀请码加入房间?", "加入联机房间", "加入", "取消") = 2 Then Return '防止弹窗阻碍主线程,所以必须放在工作线程 If MyMsgBox("嘿,是否使用复制的邀请码加入房间?", "加入联机房间", "加入", "取消") = 2 Then Return '防止弹窗阻碍主线程,所以必须放在工作线程
@@ -899,10 +973,10 @@ Public Class FormMain
"你可以在 版本设置 → 设置 → 服务器选项 中修改登录方式。", "第三方登录开启确认", "确定", "取消") = 2 Then "你可以在 版本设置 → 设置 → 服务器选项 中修改登录方式。", "第三方登录开启确认", "确定", "取消") = 2 Then
Return Return
End If End If
Setup.Set("VersionServerLogin", 4, Instance:=Target) Settings.Set("VersionServerLogin", 4, Instance:=Target)
Setup.Set("VersionServerAuthServer", "https://littleskin.cn/api/yggdrasil", Instance:=Target) Settings.Set("VersionServerAuthServer", "https://littleskin.cn/api/yggdrasil", Instance:=Target)
Setup.Set("VersionServerAuthRegister", "https://littleskin.cn/auth/register", Instance:=Target) Settings.Set("VersionServerAuthRegister", "https://littleskin.cn/auth/register", Instance:=Target)
Setup.Set("VersionServerAuthName", "LittleSkin 登录", Instance:=Target) Settings.Set("VersionServerAuthName", "LittleSkin 登录", Instance:=Target)
Else Else
'第三方 Authlib 服务器 '第三方 Authlib 服务器
If MyMsgBox($"是否要在版本 {Target.Name} 中开启第三方登录?" & vbCrLf & If MyMsgBox($"是否要在版本 {Target.Name} 中开启第三方登录?" & vbCrLf &
@@ -910,10 +984,10 @@ Public Class FormMain
"你可以在 版本设置 → 设置 → 服务器选项 中修改登录方式。", "第三方登录开启确认", "确定", "取消") = 2 Then "你可以在 版本设置 → 设置 → 服务器选项 中修改登录方式。", "第三方登录开启确认", "确定", "取消") = 2 Then
Return Return
End If End If
Setup.Set("VersionServerLogin", 4, Instance:=Target) Settings.Set("VersionServerLogin", 4, Instance:=Target)
Setup.Set("VersionServerAuthServer", AuthlibServer, Instance:=Target) Settings.Set("VersionServerAuthServer", AuthlibServer, Instance:=Target)
Setup.Set("VersionServerAuthRegister", AuthlibServer.Replace("api/yggdrasil", "auth/register"), Instance:=Target) Settings.Set("VersionServerAuthRegister", AuthlibServer.Replace("api/yggdrasil", "auth/register"), Instance:=Target)
Setup.Set("VersionServerAuthName", "", Instance:=Target) Settings.Set("VersionServerAuthName", "", Instance:=Target)
End If End If
If PageCurrent = PageType.InstanceSetup AndAlso PageCurrentSub = PageSubType.InstanceSetup Then If PageCurrent = PageType.InstanceSetup AndAlso PageCurrentSub = PageSubType.InstanceSetup Then
'正在服务器选项页,需要刷新设置项显示 '正在服务器选项页,需要刷新设置项显示
@@ -965,14 +1039,14 @@ Public Class FormMain
If FilePathList.Count > 1 Then If FilePathList.Count > 1 Then
'必须要求全部为 jar 文件 '必须要求全部为 jar 文件
For Each File In FilePathList For Each File In FilePathList
If Not {"jar", "litemod", "disabled", "old"}.Contains(File.AfterLast(".").ToLower) Then If Not {"jar", "litemod", "disabled", "old"}.Contains(File.AfterLast(".").Lower) Then
Hint("一次请只拖入一个文件!", HintType.Red) Hint("一次请只拖入一个文件!", HintType.Red)
Return Return
End If End If
Next Next
End If End If
'主页 '主页
Dim Extension As String = FilePath.AfterLast(".").ToLower Dim Extension As String = FilePath.AfterLast(".").Lower
If Extension = "xaml" Then If Extension = "xaml" Then
Log("[System] 文件后缀为 XAML,作为主页加载") Log("[System] 文件后缀为 XAML,作为主页加载")
If File.Exists(Path & "PCL\Custom.xaml") Then If File.Exists(Path & "PCL\Custom.xaml") Then
@@ -983,7 +1057,7 @@ Public Class FormMain
CopyFile(FilePath, Path & "PCL\Custom.xaml") CopyFile(FilePath, Path & "PCL\Custom.xaml")
RunInUi( RunInUi(
Sub() Sub()
Setup.Set("UiCustomType", 1) Settings.Set("UiCustomType", 1)
FrmLaunchRight.ForceRefresh() FrmLaunchRight.ForceRefresh()
Hint("已加载主页自定义文件!", HintType.Green) Hint("已加载主页自定义文件!", HintType.Green)
End Sub) End Sub)
@@ -1596,7 +1670,7 @@ Public Class FormMain
'关闭 Minecraft '关闭 Minecraft
Public Sub BtnExtraShutdown_Click() Handles BtnExtraShutdown.Click Public Sub BtnExtraShutdown_Click() Handles BtnExtraShutdown.Click
Try Try
If McLaunchLoaderReal IsNot Nothing Then McLaunchLoaderReal.Abort() If McLaunchLoaderReal IsNot Nothing Then McLaunchLoaderReal.Interrupt()
For Each Watcher In McWatcherList For Each Watcher In McWatcherList
Watcher.Kill() Watcher.Kill()
Next Next
@@ -8,7 +8,12 @@ Public Module ModAnimation
''' <summary> ''' <summary>
''' 动画速度。最大为 200。 ''' 动画速度。最大为 200。
''' </summary> ''' </summary>
Public AniSpeed As Double = 1 Public ReadOnly Property AniSpeed As Double
Get
Dim Setting = PCL.Settings.Get("SystemDebugAnim")
Return If(Setting >= 30, 200, MathClamp(Setting * 0.1 + 0.1, 0.1, 3))
End Get
End Property
''' <summary> ''' <summary>
''' 动画组列表。 ''' 动画组列表。
''' </summary> ''' </summary>
+298 -147
View File
@@ -14,25 +14,24 @@ Public Module ModBase
#Region "声明" #Region "声明"
'下列版本信息由更新器自动修改 '下列版本信息由更新器自动修改
Public Const VersionBaseName As String = "2.12.2" '不含分支前缀的显示用版本名 Public Const VersionBaseName As String = "2.12.6.2" '显示用版本名
Public Const VersionStandardCode As String = "2.12.2." & VersionBranchCode '标准格式的四段式版本号
Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换 Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换
#If BETA Then #If BETA Then
Public Const VersionCode As Integer = 379 'Release Public Const VersionCode As Integer = 391 '正式版
#Else #Else
Public Const VersionCode As Integer = 380 'Snapshot Public Const VersionCode As Integer = 390 '快照版
#End If #End If
'自动生成的版本信息 '自动生成的版本信息
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
#If RELEASE Then #If RELEASE Then
Public Const VersionBranchName As String = "Snapshot" Public Const VersionBranchName As String = "快照版"
Public Const VersionBranchCode As String = "0" Public Const VersionBranchCode As Integer = 0
#ElseIf BETA Then #ElseIf BETA Then
Public Const VersionBranchName As String = "Release" Public Const VersionBranchName As String = "正式版"
Public Const VersionBranchCode As String = "50" Public Const VersionBranchCode As Integer = 50
#Else #Else
Public Const VersionBranchName As String = "Debug" Public Const VersionBranchName As String = "开发版"
Public Const VersionBranchCode As String = "100" Public Const VersionBranchCode As Integer = 100
#End If #End If
''' <summary> ''' <summary>
@@ -56,10 +55,6 @@ Public Module ModBase
''' </summary> ''' </summary>
Public Lang As String = "zh_CN" Public Lang As String = "zh_CN"
''' <summary> ''' <summary>
''' 设置对象。
''' </summary>
Public Setup As New ModSetup
''' <summary>
''' 程序的打开计时。 ''' 程序的打开计时。
''' </summary> ''' </summary>
Public ApplicationStartTick As Long = GetTimeMs() Public ApplicationStartTick As Long = GetTimeMs()
@@ -86,11 +81,11 @@ Public Module ModBase
''' <summary> ''' <summary>
''' 系统盘盘符,以 \ 结尾。例如 “C:\”。 ''' 系统盘盘符,以 \ 结尾。例如 “C:\”。
''' </summary> ''' </summary>
Public OsDrive As String = Environment.GetLogicalDrives().Where(Function(p) Directory.Exists(p)).First.ToUpper.First & ":\" '#3799 Public OsDrive As String = Environment.GetLogicalDrives().Where(Function(p) Directory.Exists(p)).First.Upper.First & ":\" '#3799
''' <summary> ''' <summary>
''' 程序的缓存文件夹路径,以 \ 结尾。 ''' 程序的缓存文件夹路径,以 \ 结尾。
''' </summary> ''' </summary>
Public PathTemp As String = If(Setup.Get("SystemSystemCache") = "", IO.Path.GetTempPath() & "PCL\", Setup.Get("SystemSystemCache")).ToString.Replace("/", "\").TrimEnd("\") & "\" Public PathTemp As String = If(Settings.Get("SystemSystemCache") = "", IO.Path.GetTempPath() & "PCL\", Settings.Get("SystemSystemCache")).ToString.Replace("/", "\").TrimEnd("\") & "\"
''' <summary> ''' <summary>
''' AppData 中的 PCL 文件夹路径,以 \ 结尾。 ''' AppData 中的 PCL 文件夹路径,以 \ 结尾。
''' </summary> ''' </summary>
@@ -416,17 +411,13 @@ Public Module ModBase
Loading Loading
Finished Finished
Failed Failed
Aborted Interrupted
End Enum End Enum
''' <summary> ''' <summary>
''' 执行返回值。 ''' 执行返回值。
''' </summary> ''' </summary>
Public Enum ProcessReturnValues Public Enum ProcessReturnValues
''' <summary>
''' 执行成功,或进程被中断。
''' </summary>
Aborted = -1
''' <summary> ''' <summary>
''' 执行成功。 ''' 执行成功。
''' </summary> ''' </summary>
@@ -620,7 +611,8 @@ Public Module ModBase
Public Sub DeleteReg(Key As String, Optional ThrowException As Boolean = False) Public Sub DeleteReg(Key As String, Optional ThrowException As Boolean = False)
Try Try
Dim SubKey As Microsoft.Win32.RegistryKey = My.Computer.Registry.CurrentUser.OpenSubKey("Software\" & RegFolder, True) Dim SubKey As Microsoft.Win32.RegistryKey = My.Computer.Registry.CurrentUser.OpenSubKey("Software\" & RegFolder, True)
SubKey?.DeleteValue(Key) If SubKey?.GetValue(Key) Is Nothing Then Return
SubKey.DeleteValue(Key)
Catch ex As Exception Catch ex As Exception
Log(ex, "删除注册表出错:" & Key, If(ThrowException, LogLevel.Hint, LogLevel.Developer)) Log(ex, "删除注册表出错:" & Key, If(ThrowException, LogLevel.Hint, LogLevel.Developer))
If ThrowException Then Throw If ThrowException Then Throw
@@ -1071,25 +1063,25 @@ Public Module ModBase
''' 获取文件 MD5,若失败则返回空字符串。 ''' 获取文件 MD5,若失败则返回空字符串。
''' </summary> ''' </summary>
Public Function GetFileMD5(FilePath As String) As String Public Function GetFileMD5(FilePath As String) As String
Dim Retry As Boolean = False Dim Retried As Boolean = False
Re: Re:
Try Try
'获取 MD5 Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
Dim Result As New StringBuilder() Using h = MD5Cng.Create()
Dim File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) Dim Retval As Byte() = h.ComputeHash(File)
Dim MD5 As MD5 = New MD5CryptoServiceProvider() Dim Result As New StringBuilder(Retval.Length * 2)
Dim Retval As Byte() = MD5.ComputeHash(File) For i = 0 To Retval.Length - 1
File.Close() Result.Append(Retval(i).ToString("x2"))
For i = 0 To Retval.Length - 1 Next
Result.Append(Retval(i).ToString("x2")) Return Result.ToString
Next End Using
Return Result.ToString End Using
Catch ex As Exception Catch ex As Exception
If Retry OrElse TypeOf ex Is FileNotFoundException Then If Retried OrElse TypeOf ex Is FileNotFoundException Then
Log(ex, "获取文件 MD5 失败:" & FilePath) Log(ex, "获取文件 MD5 失败:" & FilePath)
Return "" Return ""
Else Else
Retry = True Retried = True
Log(ex, "获取文件 MD5 可重试失败:" & FilePath, LogLevel.Normal) Log(ex, "获取文件 MD5 可重试失败:" & FilePath, LogLevel.Normal)
Thread.Sleep(RandomInteger(200, 500)) Thread.Sleep(RandomInteger(200, 500))
GoTo Re GoTo Re
@@ -1100,27 +1092,25 @@ Re:
''' 获取文件 SHA512,若失败则返回空字符串。 ''' 获取文件 SHA512,若失败则返回空字符串。
''' </summary> ''' </summary>
Public Function GetFileSHA512(FilePath As String) As String Public Function GetFileSHA512(FilePath As String) As String
Dim Retry As Boolean = False Dim Retried As Boolean = False
Re: Re:
Try Try
''检测该文件是否在下载中,若在下载则放弃检测 Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
'If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return "" Using h = SHA512Cng.Create()
'获取 SHA512 Dim retval As Byte() = h.ComputeHash(File)
Dim file As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) Dim Result As New StringBuilder(retval.Length * 2)
Dim sha512 As SHA512 = New SHA512CryptoServiceProvider() For i As Integer = 0 To retval.Length - 1
Dim retval As Byte() = sha512.ComputeHash(file) Result.Append(retval(i).ToString("x2"))
file.Close() Next
Dim Result As New StringBuilder() Return Result.ToString
For i As Integer = 0 To retval.Length - 1 End Using
Result.Append(retval(i).ToString("x2")) End Using
Next
Return Result.ToString
Catch ex As Exception Catch ex As Exception
If Retry OrElse TypeOf ex Is FileNotFoundException Then If Retried OrElse TypeOf ex Is FileNotFoundException Then
Log(ex, "获取文件 SHA512 失败:" & FilePath) Log(ex, "获取文件 SHA512 失败:" & FilePath)
Return "" Return ""
Else Else
Retry = True Retried = True
Log(ex, "获取文件 SHA512 可重试失败:" & FilePath, LogLevel.Normal) Log(ex, "获取文件 SHA512 可重试失败:" & FilePath, LogLevel.Normal)
Thread.Sleep(RandomInteger(200, 500)) Thread.Sleep(RandomInteger(200, 500))
GoTo Re GoTo Re
@@ -1134,18 +1124,16 @@ Re:
Dim Retry As Boolean = False Dim Retry As Boolean = False
Re: Re:
Try Try
''检测该文件是否在下载中,若在下载则放弃检测 Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
'If IgnoreOnDownloading AndAlso NetManage.Files.ContainsKey(FilePath) AndAlso NetManage.Files(FilePath).State <= NetState.Merge Then Return "" Using h = SHA256Cng.Create()
'获取 SHA256 Dim retval As Byte() = h.ComputeHash(File)
Dim file As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) Dim Result As New StringBuilder(retval.Length * 2)
Dim sha256 As SHA256 = New SHA256CryptoServiceProvider() For i As Integer = 0 To retval.Length - 1
Dim retval As Byte() = sha256.ComputeHash(file) Result.Append(retval(i).ToString("x2"))
file.Close() Next
Dim Result As New StringBuilder() Return Result.ToString()
For i As Integer = 0 To retval.Length - 1 End Using
Result.Append(retval(i).ToString("x2")) End Using
Next
Return Result.ToString
Catch ex As Exception Catch ex As Exception
If Retry OrElse TypeOf ex Is FileNotFoundException Then If Retry OrElse TypeOf ex Is FileNotFoundException Then
Log(ex, "获取文件 SHA256 失败:" & FilePath) Log(ex, "获取文件 SHA256 失败:" & FilePath)
@@ -1165,16 +1153,16 @@ Re:
Dim Retry As Boolean = False Dim Retry As Boolean = False
Re: Re:
Try Try
'获取 SHA1 Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
Dim file As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) Using h = SHA1Cng.Create()
Dim sha1 As SHA1 = New SHA1CryptoServiceProvider() Dim retval As Byte() = h.ComputeHash(File)
Dim retval As Byte() = sha1.ComputeHash(file) Dim Result As New StringBuilder(retval.Length * 2)
file.Close() For i As Integer = 0 To retval.Length - 1
Dim Result As New StringBuilder() Result.Append(retval(i).ToString("x2"))
For i As Integer = 0 To retval.Length - 1 Next
Result.Append(retval(i).ToString("x2")) Return Result.ToString
Next End Using
Return Result.ToString End Using
Catch ex As Exception Catch ex As Exception
If Retry OrElse TypeOf ex Is FileNotFoundException Then If Retry OrElse TypeOf ex Is FileNotFoundException Then
Log(ex, "获取文件 SHA1 失败:" & FilePath) Log(ex, "获取文件 SHA1 失败:" & FilePath)
@@ -1257,11 +1245,11 @@ Re:
End If End If
If Not String.IsNullOrEmpty(Hash) Then If Not String.IsNullOrEmpty(Hash) Then
If Hash.Length < 35 Then 'MD5 If Hash.Length < 35 Then 'MD5
If Hash.ToLowerInvariant <> GetFileMD5(LocalPath) Then Return "文件 MD5 应为 " & Hash & ",实际为 " & GetFileMD5(LocalPath) If Hash.Lower <> GetFileMD5(LocalPath) Then Return "文件 MD5 应为 " & Hash & ",实际为 " & GetFileMD5(LocalPath)
ElseIf Hash.Length = 64 Then 'SHA256 ElseIf Hash.Length = 64 Then 'SHA256
If Hash.ToLowerInvariant <> GetFileSHA256(LocalPath) Then Return "文件 SHA256 应为 " & Hash & ",实际为 " & GetFileSHA256(LocalPath) If Hash.Lower <> GetFileSHA256(LocalPath) Then Return "文件 SHA256 应为 " & Hash & ",实际为 " & GetFileSHA256(LocalPath)
Else 'SHA1 (40) Else 'SHA1 (40)
If Hash.ToLowerInvariant <> GetFileSHA1(LocalPath) Then Return "文件 SHA1 应为 " & Hash & ",实际为 " & GetFileSHA1(LocalPath) If Hash.Lower <> GetFileSHA1(LocalPath) Then Return "文件 SHA1 应为 " & Hash & ",实际为 " & GetFileSHA1(LocalPath)
End If End If
End If End If
If IsJson Then If IsJson Then
@@ -1281,6 +1269,7 @@ Re:
End Function End Function
End Class End Class
'压缩文件
''' <summary> ''' <summary>
''' 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 jar 以 zip 方式解压。 ''' 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 jar 以 zip 方式解压。
''' 会尝试创建,但不会清空目标文件夹。 ''' 会尝试创建,但不会清空目标文件夹。
@@ -1291,7 +1280,7 @@ Re:
'解压 gz(gz 不需要考虑编码) '解压 gz(gz 不需要考虑编码)
If CompressFilePath.EndsWithF(".gz", True) Then If CompressFilePath.EndsWithF(".gz", True) Then
Using stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.Read, FileShare.Read), CompressionMode.Decompress) Using stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.Read, FileShare.Read), CompressionMode.Decompress)
Using decompressedFile As New FileStream(DestDirectory & GetFileNameFromPath(CompressFilePath).ToLower.Replace(".tar", "").Replace(".gz", ""), Using decompressedFile As New FileStream(DestDirectory & GetFileNameFromPath(CompressFilePath).Lower.Replace(".tar", "").Replace(".gz", ""),
FileMode.OpenOrCreate, FileAccess.Write) FileMode.OpenOrCreate, FileAccess.Write)
Dim data As Integer = stream.ReadByte() Dim data As Integer = stream.ReadByte()
While data <> -1 While data <> -1
@@ -1319,7 +1308,7 @@ Re:
End Using End Using
End Sub End Sub
Try Try
TryExtractZip(Encoding.UTF8) TryExtractZip(New UTF8Encoding(False, True))
Catch ex As Exception Catch ex As Exception
Log(ex, $"首次解压尝试失败,将更换编码并重试({CompressFilePath} → {DestDirectory})") Log(ex, $"首次解压尝试失败,将更换编码并重试({CompressFilePath} → {DestDirectory})")
Try Try
@@ -1329,6 +1318,25 @@ Re:
End Try End Try
End Try End Try
End Sub End Sub
''' <summary>
''' 将多个文件打包为一个压缩文件。
''' 这些文件会被直接放在压缩包根目录下。
''' </summary>
Public Sub CreateCompressedFile(OutputFullPath As String, SourceFiles As IEnumerable(Of String))
Dim DirectoryPath = IO.Path.GetDirectoryName(OutputFullPath)
If Not Directory.Exists(DirectoryPath) Then Directory.CreateDirectory(DirectoryPath)
Using ZipStream As New FileStream(OutputFullPath, FileMode.Create)
Using Archive As New ZipArchive(ZipStream, ZipArchiveMode.Create)
For Each FilePath In SourceFiles
If Not File.Exists(FilePath) Then Return
Using SourceStream As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read),
EntryStream As Stream = Archive.CreateEntry(IO.Path.GetFileName(FilePath)).Open()
SourceStream.CopyTo(EntryStream)
End Using
Next
End Using
End Using
End Sub
''' <summary> ''' <summary>
''' 删除文件夹,返回删除的文件个数。通过参数选择是否抛出异常。 ''' 删除文件夹,返回删除的文件个数。通过参数选择是否抛出异常。
@@ -1336,7 +1344,7 @@ Re:
Public Function DeleteDirectory(Path As String, Optional IgnoreIssue As Boolean = False) As Integer Public Function DeleteDirectory(Path As String, Optional IgnoreIssue As Boolean = False) As Integer
If Not Directory.Exists(Path) Then Return 0 If Not Directory.Exists(Path) Then Return 0
If Not Path.EndsWithF("\") Then Path &= "\" If Not Path.EndsWithF("\") Then Path &= "\"
If Path.EndsWith(":\") OrElse If Path.EndsWithF(":\") OrElse
Path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\" OrElse Path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\" OrElse
Path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) & "\" OrElse Path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) & "\" OrElse
Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) & "\" Then '#7030 Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) & "\" Then '#7030
@@ -1347,11 +1355,12 @@ Re:
Dim Files As String() Dim Files As String()
Try Try
Files = Directory.GetFiles(Path) Files = Directory.GetFiles(Path)
Catch ex As DirectoryNotFoundException '#4549 Catch ex As DirectoryNotFoundException '#4549,也可能已被其他线程删除
If Not Directory.Exists(Path) Then Return 0 '可能已被其他线程删除 If Directory.Exists(Path) Then
Log(ex, $"疑似为孤立符号链接,尝试直接删除({Path})", LogLevel.Developer) Log(ex, $"疑似为孤立符号链接,尝试直接删除({Path})", LogLevel.Developer)
Directory.Delete(Path) Directory.Delete(Path)
Return 0 End If
Return DeletedCount
End Try End Try
For Each FilePath As String In Files For Each FilePath As String In Files
Dim RetriedFile As Boolean = False Dim RetriedFile As Boolean = False
@@ -1359,6 +1368,8 @@ RetryFile:
Try Try
File.Delete(FilePath) File.Delete(FilePath)
DeletedCount += 1 DeletedCount += 1
Catch ex As DirectoryNotFoundException
Return DeletedCount
Catch ex As Exception Catch ex As Exception
If Not RetriedFile Then If Not RetriedFile Then
RetriedFile = True RetriedFile = True
@@ -1420,17 +1431,25 @@ RetryDir:
''' <summary> ''' <summary>
''' 若路径长度大于指定值,则将长路径转换为短路径。 ''' 若路径长度大于指定值,则将长路径转换为短路径。
''' 如果路径不存在,则返回原始路径。
''' </summary> ''' </summary>
Public Function ShortenPath(LongPath As String) As String Public Function ShortenPath(Raw As String) As String
If LongPath.Length <= 200 OrElse LongPath.StartsWithF("http", True) Then Return LongPath If Raw.Length <= 200 OrElse Raw.StartsWithF("http", True) Then Return Raw
If Not Directory.Exists(LongPath) AndAlso Not File.Exists(LongPath) Then Return LongPath If Not Directory.Exists(Raw) AndAlso Not File.Exists(Raw) Then Return Raw
Dim ShortPath As New StringBuilder(260) Dim PathToShorten As String, Ignored As String
GetShortPathName(LongPath.Replace("/", "\"), ShortPath, 260) '第一个参数也会在调用后被修改,使用 Replace 后不会影响原始字符串 If Not Directory.Exists(Raw) AndAlso Raw.EndsWithF(".jar", True) Then '只能缩短文件夹部分,必须保留 jar 文件名,否则会导致 Forge 1.20.1 无法通过文件名识别模块名
ShortenPath = ShortPath.ToString PathToShorten = GetPathFromFullPath(Raw)
If String.IsNullOrEmpty(ShortenPath) Then Return LongPath Ignored = GetFileNameFromPath(Raw)
Else
PathToShorten = Raw
Ignored = ""
End If
Dim ShortPathBuffer As New StringBuilder(260)
GetShortPathNameW(PathToShorten.Replace("/", "\"), ShortPathBuffer, 260)
Dim DirShortPath As String = ShortPathBuffer.ToString()
If String.IsNullOrEmpty(DirShortPath) Then Return Raw
Return If(String.IsNullOrEmpty(Ignored), DirShortPath, IO.Path.Combine(DirShortPath, Ignored))
End Function End Function
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (lpszLongPath As String, lpszShortPath As StringBuilder, cchBuffer As Integer) As Integer Private Declare Unicode Function GetShortPathNameW Lib "kernel32" Alias "GetShortPathNameW" (lpszLongPath As String, lpszShortPath As StringBuilder, cchBuffer As Integer) As Integer
#End Region #End Region
@@ -1497,7 +1516,7 @@ RetryDir:
Ex = Ex.InnerException Ex = Ex.InnerException
Loop Loop
DescList = DescList.Distinct.ToList DescList = DescList.Distinct.ToList
Dim Desc As String = Join(DescList, vbCrLf & "→ ") Dim Desc As String = DescList.Join(vbCrLf & "→ ")
'构造输出信息 '构造输出信息
Dim UsualReason As String = AnalyzeUsualReason(InnerEx, OuterEx, DescList) Dim UsualReason As String = AnalyzeUsualReason(InnerEx, OuterEx, DescList)
@@ -1505,7 +1524,7 @@ RetryDir:
Return UsualReason & "详细错误:" & DescList.First Return UsualReason & "详细错误:" & DescList.First
Else Else
DescList.Reverse() '让最深层错误在最左边 DescList.Reverse() '让最深层错误在最左边
Return Join(DescList, " ← ") Return DescList.Join(" ← ")
End If End If
End Function End Function
Private Function AnalyzeUsualReason(InnerEx As Exception, OuterEx As Exception, DescList As List(Of String)) As String Private Function AnalyzeUsualReason(InnerEx As Exception, OuterEx As Exception, DescList As List(Of String)) As String
@@ -1588,7 +1607,7 @@ RetryDir:
''' </summary> ''' </summary>
<Extension> Public Function Capitalize(word As String) As String <Extension> Public Function Capitalize(word As String) As String
If String.IsNullOrEmpty(word) Then Return word If String.IsNullOrEmpty(word) Then Return word
Return word.Substring(0, 1).ToUpperInvariant() & word.Substring(1).ToLowerInvariant() Return word.Substring(0, 1).Upper() & word.Substring(1).Lower()
End Function End Function
''' <summary> ''' <summary>
@@ -1608,7 +1627,24 @@ RetryDir:
''' <summary> ''' <summary>
''' 连接字符串。 ''' 连接字符串。
''' </summary> ''' </summary>
<Extension> Public Function Join(List As IEnumerable, Split As Char) As String
Dim Builder As New StringBuilder
Dim IsFirst As Boolean = True
For Each Element In List
If IsFirst Then
IsFirst = False
Else
Builder.Append(Split)
End If
If Element IsNot Nothing Then Builder.Append(Element)
Next
Return Builder.ToString
End Function
''' <summary>
''' 连接字符串。
''' </summary>
<Extension> Public Function Join(List As IEnumerable, Split As String) As String <Extension> Public Function Join(List As IEnumerable, Split As String) As String
If Split.IsSingle Then Return List.Join(Split(0))
Dim Builder As New StringBuilder Dim Builder As New StringBuilder
Dim IsFirst As Boolean = True Dim IsFirst As Boolean = True
For Each Element In List For Each Element In List
@@ -1626,7 +1662,7 @@ RetryDir:
''' 若原始字符串为空,则返回 {""}。 ''' 若原始字符串为空,则返回 {""}。
''' </summary> ''' </summary>
<Extension> Public Function Split(FullStr As String, SplitStr As String) As String() <Extension> Public Function Split(FullStr As String, SplitStr As String) As String()
If SplitStr.Length = 1 Then If SplitStr.IsSingle Then
Return FullStr.Split(SplitStr(0)) Return FullStr.Split(SplitStr(0))
Else Else
Return FullStr.Split({SplitStr}, StringSplitOptions.None) Return FullStr.Split({SplitStr}, StringSplitOptions.None)
@@ -1647,14 +1683,14 @@ RetryDir:
''' 获取字符串 MD5。 ''' 获取字符串 MD5。
''' </summary> ''' </summary>
Public Function GetStringMD5(Str As String) As String Public Function GetStringMD5(Str As String) As String
Dim md5Hasher As New MD5CryptoServiceProvider Using h = MD5Cng.Create()
Dim hashedDataBytes As Byte() Dim hashedDataBytes = h.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(Str))
hashedDataBytes = md5Hasher.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(Str)) Dim tmp As New StringBuilder(hashedDataBytes.Length * 2)
Dim tmp As New StringBuilder() For Each i As Byte In hashedDataBytes
For Each i As Byte In hashedDataBytes tmp.Append(i.ToString("x2"))
tmp.Append(i.ToString("x2")) Next
Next Return tmp.ToString()
Return tmp.ToString() End Using
End Function End Function
''' <summary> ''' <summary>
''' 检查字符串中的字符是否均为 ASCII 字符。 ''' 检查字符串中的字符是否均为 ASCII 字符。
@@ -1799,6 +1835,19 @@ RetryDir:
End Try End Try
End Function End Function
''' <summary>
''' 等效 ToLowerInvariant。
''' </summary>
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)> Public Function Lower(Str As String) As String
Return Str.ToLowerInvariant()
End Function
''' <summary>
''' 等效 ToUpperInvariant。
''' </summary>
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)> Public Function Upper(Str As String) As String
Return Str.ToUpperInvariant()
End Function
'转义 '转义
''' <summary> ''' <summary>
''' 为字符串进行 XML 转义。 ''' 为字符串进行 XML 转义。
@@ -1888,50 +1937,53 @@ RetryDir:
''' <param name="Source">被搜索的长内容。</param> ''' <param name="Source">被搜索的长内容。</param>
''' <param name="Query">用户输入的搜索文本。</param> ''' <param name="Query">用户输入的搜索文本。</param>
Private Function SearchSimilarity(Source As String, Query As String) As Double Private Function SearchSimilarity(Source As String, Query As String) As Double
If String.IsNullOrEmpty(Source) OrElse String.IsNullOrEmpty(Query) Then Return 0
Dim qp As Integer = 0, lenSum As Double = 0 Dim qp As Integer = 0, lenSum As Double = 0
Source = Source.ToLower.Replace(" ", "") Dim str As New StringBuilder(Source.Length)
Query = Query.ToLower.Replace(" ", "") str.Append(Source.Lower().Replace(" ", ""))
Dim sourceLength As Integer = Source.Length, queryLength As Integer = Query.Length '用于计算最后因数的长度缓存 Query = Query.Lower().Replace(" ", "")
Dim sourceLength As Integer = str.Length, queryLength As Integer = Query.Length '用于计算最后因数的长度缓存
If queryLength = 0 Then Return 0
Do While qp < queryLength Do While qp < queryLength
'对 qp 作为开始位置计算 '对 qp 作为开始位置计算
Dim sp As Integer = 0, lenMax As Integer = 0, spMax As Integer = 0 Dim sp As Integer = 0, lenMax As Integer = 0, spMax As Integer = 0
'查找以 qp 为头的最大子串 Dim currentSourceLength As Integer = str.Length
Do While sp < Source.Length Do While sp < currentSourceLength
'对每个 sp 作为开始位置计算最大子串
Dim len As Integer = 0 Dim len As Integer = 0
Do While (qp + len) < queryLength AndAlso (sp + len) < Source.Length AndAlso Source(sp + len) = Query(qp + len) While (qp + len) < queryLength AndAlso (sp + len) < currentSourceLength AndAlso str(sp + len) = Query(qp + len)
len += 1 len += 1
Loop End While
'存储 len '存储 len
If len > lenMax Then If len > lenMax Then
lenMax = len lenMax = len
spMax = sp spMax = sp
End If End If
'根据结果增加 sp '根据结果增加 sp
sp += Math.Max(1, len) sp += If(len > 0, len, 1)
Loop Loop
If lenMax > 0 Then If lenMax > 0 Then
Source = Source.Substring(0, spMax) & If(Source.Count > spMax + lenMax, Source.Substring(spMax + lenMax), String.Empty) '将源中的对应字段替换空 str.Remove(spMax, lenMax) '将源中的对应字段移除
'存储 lenSum '存储 lenSum
Dim IncWeight = (Math.Pow(1.4, 3 + lenMax) - 3.6) '根据长度加成 Dim IncWeight = (Math.Pow(1.4, 3 + lenMax) - 3.6) '根据长度加成
IncWeight *= 1 + 0.3 * Math.Max(0, 3 - Math.Abs(qp - spMax)) '根据位置加成 IncWeight *= 1 + 0.3 * Math.Max(0, 3 - Math.Abs(qp - spMax)) '根据位置加成
lenSum += IncWeight lenSum += IncWeight
End If End If
'根据结果增加 qp qp += If(lenMax > 0, lenMax, 1)
qp += Math.Max(1, lenMax)
Loop Loop
'计算结果:重复字段量 × 源长度影响比例 '计算结果:重复字段量 × 源长度影响比例
Return (lenSum / queryLength) * (3 / Math.Pow(sourceLength + 15, 0.5)) * If(queryLength <= 2, 3 - queryLength, 1) Return (lenSum / queryLength) * (3 / Math.Sqrt(sourceLength + 15)) * If(queryLength <= 2, 3 - queryLength, 1)
End Function End Function
''' <summary> ''' <summary>
''' 获取多段文本加权后的相似度。 ''' 获取多段文本加权后的相似度。
''' </summary> ''' </summary>
Private Function SearchSimilarityWeighted(Source As List(Of KeyValuePair(Of String, Double)), Query As String) As Double Private Function SearchSimilarityWeighted(Source As List(Of SearchSource), Query As String) As Double
Dim TotalWeight As Double = 0 Dim TotalWeight As Double = 0
Dim Sum As Double = 0 Dim Sum As Double = 0
For Each Pair In Source For Each Pair In Source
Sum += SearchSimilarity(Pair.Key, Query) * Pair.Value If Pair.Aliases.Any Then
TotalWeight += Pair.Value Sum += Pair.Aliases.Max(Function(a) SearchSimilarity(a, Query)) * Pair.Weight
End If
TotalWeight += Pair.Weight
Next Next
Return Sum / TotalWeight Return Sum / TotalWeight
End Function End Function
@@ -1944,9 +1996,10 @@ RetryDir:
''' </summary> ''' </summary>
Public Item As T Public Item As T
''' <summary> ''' <summary>
''' 该项目用于搜索的源。 ''' 该项目用于搜索的文本源。
''' 在搜索时,会对每个文本源单独加权,但单个文本源内的多个别名只取最高的一个的相似度。
''' </summary> ''' </summary>
Public SearchSource As List(Of KeyValuePair(Of String, Double)) Public SearchSource As List(Of SearchSource)
''' <summary> ''' <summary>
''' 相似度。 ''' 相似度。
''' </summary> ''' </summary>
@@ -1955,9 +2008,29 @@ RetryDir:
''' 是否完全匹配。 ''' 是否完全匹配。
''' </summary> ''' </summary>
Public AbsoluteRight As Boolean Public AbsoluteRight As Boolean
Public Overrides Function ToString() As String
Return Math.Round(Similarity, 3) & " - " & Item.ToString()
End Function
End Class
''' <summary>
''' 单个用于搜索的文本源。
''' </summary>
Public Class SearchSource
Public Aliases As String()
Public Weight As Double
Public Sub New(Aliases As String(), Optional Weight As Double = 1)
Me.Aliases = Aliases
Me.Weight = Weight
End Sub
Public Sub New(Text As String, Optional Weight As Double = 1)
Me.Aliases = {Text}
Me.Weight = Weight
End Sub
End Class End Class
''' <summary> ''' <summary>
''' 进行多段文本加权搜索,获取相似度较高的数项结果。 ''' 进行多段文本加权搜索,获取相似度较高的数项结果。
''' 在搜索时,会对每个文本源单独加权,但单个文本源内的多个别名只取最高的一个的相似度。
''' 这会修改 Entries 中每项的 Similarity 与 AbsoluteRight 字段。
''' </summary> ''' </summary>
''' <param name="MaxBlurCount">返回的最大模糊结果数。</param> ''' <param name="MaxBlurCount">返回的最大模糊结果数。</param>
''' <param name="MinBlurSimilarity">返回结果要求的最低相似度。</param> ''' <param name="MinBlurSimilarity">返回结果要求的最低相似度。</param>
@@ -1966,29 +2039,26 @@ RetryDir:
Dim ResultList As New List(Of SearchEntry(Of T)) Dim ResultList As New List(Of SearchEntry(Of T))
If Not Entries.Any() Then Return ResultList If Not Entries.Any() Then Return ResultList
'进行搜索,获取相似信息 '进行搜索,获取相似信息
Dim QueryParts = Query.Split({" "c}, StringSplitOptions.RemoveEmptyEntries)
Dim Candidates As New List(Of SearchEntry(Of T))
For Each Entry In Entries For Each Entry In Entries
Entry.Similarity = SearchSimilarityWeighted(Entry.SearchSource, Query) Entry.Similarity = SearchSimilarityWeighted(Entry.SearchSource, Query)
Entry.AbsoluteRight = Entry.AbsoluteRight =
Query.Split(" ").All( '对于按空格分割的每一段 QueryParts.All( '对于按空格分割的每一段
Function(QueryPart) Entry.SearchSource.Any( '若与任意一个搜索源完全匹配,则标记为完全匹配项 Function(QueryPart) Entry.SearchSource.Any( '若与任意一个搜索源完全匹配,则标记为完全匹配项
Function(Source) Source.Key.Replace(" ", "").ContainsF(QueryPart, True))) Function(Source) Source.Aliases.Any(
Function([Alias]) [Alias].Replace(" ", "").ContainsF(QueryPart, True))))
If Entry.AbsoluteRight OrElse Entry.Similarity >= MinBlurSimilarity Then Candidates.Add(Entry)
Next Next
'按照相似度进行排序 '按照相似度进行排序
Entries = Entries.SortByComparison( Candidates = Candidates.SortByComparison(Function(Left, Right) If(Left.AbsoluteRight <> Right.AbsoluteRight, Left.AbsoluteRight, Left.Similarity > Right.Similarity))
Function(Left, Right) As Boolean
If Left.AbsoluteRight Xor Right.AbsoluteRight Then
Return Left.AbsoluteRight
Else
Return Left.Similarity > Right.Similarity
End If
End Function)
'返回结果 '返回结果
Dim BlurCount As Integer = 0 Dim BlurCount As Integer = 0
For Each Entry In Entries For Each Entry In Candidates
If Entry.AbsoluteRight Then If Entry.AbsoluteRight Then
ResultList.Add(Entry) '完全匹配,直接加入 ResultList.Add(Entry) '完全匹配,直接加入
Else Else
If Entry.Similarity < MinBlurSimilarity OrElse BlurCount = MaxBlurCount Then Exit For '模糊结果边界条件 If BlurCount = MaxBlurCount Then Exit For
ResultList.Add(Entry) ResultList.Add(Entry)
BlurCount += 1 '模糊结果计数 BlurCount += 1 '模糊结果计数
End If End If
@@ -2167,7 +2237,7 @@ RetryDir:
''' </summary> ''' </summary>
<Extension> Public Function GetResultWithTimeout(Of T)(TargetTask As Task(Of T), TokenSource As CancellationTokenSource, TimeoutMs As Integer) As T <Extension> Public Function GetResultWithTimeout(Of T)(TargetTask As Task(Of T), TokenSource As CancellationTokenSource, TimeoutMs As Integer) As T
Dim DelayTask = Task.Delay(TimeoutMs) Dim DelayTask = Task.Delay(TimeoutMs)
If Task.WhenAny(TargetTask, DelayTask).GetAwaiter().GetResult() Is DelayTask Then If Task.WhenAny(TargetTask, DelayTask).ConfigureAwait(False).GetAwaiter().GetResult() Is DelayTask Then
TokenSource.Cancel() TokenSource.Cancel()
Throw New TimeoutException($"任务超时({TimeoutMs} ms)") Throw New TimeoutException($"任务超时({TimeoutMs} ms)")
End If End If
@@ -2178,7 +2248,7 @@ RetryDir:
''' </summary> ''' </summary>
<Extension> Public Sub GetResultWithTimeout(TargetTask As Task, TokenSource As CancellationTokenSource, TimeoutMs As Integer) <Extension> Public Sub GetResultWithTimeout(TargetTask As Task, TokenSource As CancellationTokenSource, TimeoutMs As Integer)
Dim DelayTask = Task.Delay(TimeoutMs) Dim DelayTask = Task.Delay(TimeoutMs)
If Task.WhenAny(TargetTask, DelayTask).GetAwaiter().GetResult() Is DelayTask Then If Task.WhenAny(TargetTask, DelayTask).ConfigureAwait(False).GetAwaiter().GetResult() Is DelayTask Then
TokenSource.Cancel() TokenSource.Cancel()
Throw New TimeoutException($"任务超时({TimeoutMs} ms)") Throw New TimeoutException($"任务超时({TimeoutMs} ms)")
End If End If
@@ -2296,6 +2366,22 @@ NextElement:
Return Arr?.Count > 0 Return Arr?.Count > 0
End Function End Function
''' <summary> ''' <summary>
''' 判断这是否是仅有一个元素的集合。
''' </summary>
<Extension> Public Function IsSingle(Of T)(Source As IEnumerable(Of T)) As Boolean
If Source Is Nothing Then
Return False
ElseIf TypeOf Source Is IList(Of T) Then
Return DirectCast(Source, IList(Of T)).Count = 1
Else
Using Enumerator = Source.GetEnumerator()
If Not Enumerator.MoveNext() Then Return False
If Enumerator.MoveNext() Then Return False
Return True
End Using
End If
End Function
''' <summary>
''' 对集合的每个元素执行指定操作。 ''' 对集合的每个元素执行指定操作。
''' </summary> ''' </summary>
<Extension> Public Function ForEach(Of T)(Collection As IEnumerable(Of T), Action As Action(Of T)) As IEnumerable(Of T) <Extension> Public Function ForEach(Of T)(Collection As IEnumerable(Of T), Action As Action(Of T)) As IEnumerable(Of T)
@@ -2525,11 +2611,63 @@ NextElement:
End If End If
End Sub End Sub
''' <summary>
''' 选择所有最大值对应的对象。
''' 若没有元素则返回空列表。
''' </summary>
<Extension> Public Function MaxByAll(Of T, C As IComparable(Of C))(Source As IEnumerable(Of T), Selector As Func(Of T, C)) As List(Of T)
Dim Results As New List(Of T)
Using Enumerator = Source.GetEnumerator()
If Not Enumerator.MoveNext() Then Return Results
Dim MaxItem As T = Enumerator.Current
Dim MaxValue As C = Selector(MaxItem)
Results.Add(MaxItem)
While Enumerator.MoveNext()
Dim CurrentItem = Enumerator.Current
Dim CurrentValue = Selector(CurrentItem)
Dim Comparison = CurrentValue.CompareTo(MaxValue)
If Comparison > 0 Then
MaxValue = CurrentValue
Results.Clear()
Results.Add(CurrentItem)
ElseIf Comparison = 0 Then
Results.Add(CurrentItem)
End If
End While
End Using
Return Results
End Function
''' <summary>
''' 选择所有最小值对应的对象。
''' 若没有元素则返回空列表。
''' </summary>
<Extension> Public Function MinByAll(Of T, C As IComparable(Of C))(List As IEnumerable(Of T), Selector As Func(Of T, C)) As List(Of T)
Dim Results As New List(Of T)
Using Enumerator = List.GetEnumerator()
If Not Enumerator.MoveNext() Then Return Results
Dim MinItem As T = Enumerator.Current
Dim MinValue As C = Selector(MinItem)
Results.Add(MinItem)
While Enumerator.MoveNext()
Dim CurrentItem = Enumerator.Current
Dim CurrentValue = Selector(CurrentItem)
Dim Comparison = CurrentValue.CompareTo(MinValue)
If Comparison < 0 Then
MinValue = CurrentValue
Results.Clear()
Results.Add(CurrentItem)
ElseIf Comparison = 0 Then
Results.Add(CurrentItem)
End If
End While
End Using
Return Results
End Function
''' <summary> ''' <summary>
''' 选择最大值对应的对象。 ''' 选择最大值对应的对象。
''' 若没有元素则返回 Nothing。 ''' 若没有元素则返回 Nothing。
''' </summary> ''' </summary>
<Extension> Public Function MaxOf(Of T, C As IComparable(Of C))(Source As IEnumerable(Of T), Selector As Func(Of T, C)) As T <Extension> Public Function MaxBy(Of T, C As IComparable(Of C))(Source As IEnumerable(Of T), Selector As Func(Of T, C)) As T
Using Enumerator = Source.GetEnumerator() Using Enumerator = Source.GetEnumerator()
If Not Enumerator.MoveNext() Then Return Nothing If Not Enumerator.MoveNext() Then Return Nothing
Dim MaxItem As T = Enumerator.Current Dim MaxItem As T = Enumerator.Current
@@ -2547,7 +2685,7 @@ NextElement:
''' 选择最小值对应的对象。 ''' 选择最小值对应的对象。
''' 若没有元素则返回 Nothing。 ''' 若没有元素则返回 Nothing。
''' </summary> ''' </summary>
<Extension> Public Function MinOf(Of T, C As IComparable(Of C))(List As IEnumerable(Of T), Selector As Func(Of T, C)) As T <Extension> Public Function MinBy(Of T, C As IComparable(Of C))(List As IEnumerable(Of T), Selector As Func(Of T, C)) As T
Using Enumerator = List.GetEnumerator() Using Enumerator = List.GetEnumerator()
If Not Enumerator.MoveNext() Then Return Nothing If Not Enumerator.MoveNext() Then Return Nothing
Dim MinItem As T = Enumerator.Current Dim MinItem As T = Enumerator.Current
@@ -2660,7 +2798,7 @@ NextElement:
Try Try
Location = Location.Replace("/", "\").Trim(" "c, """"c) Location = Location.Replace("/", "\").Trim(" "c, """"c)
Log("[System] 正在打开资源管理器:" & Location) Log("[System] 正在打开资源管理器:" & Location)
If Location.EndsWith("\") Then If Location.EndsWithF("\") Then
StartProcess(Location) StartProcess(Location)
Else Else
StartProcess("explorer", $"/select,""{Location}""") StartProcess("explorer", $"/select,""{Location}""")
@@ -2860,7 +2998,7 @@ Retry:
'类型检查 '类型检查
Using Reader As New XamlXmlReader(Stream) Using Reader As New XamlXmlReader(Stream)
While Reader.Read() While Reader.Read()
For Each BlackListType In {GetType(WebBrowser), GetType(Frame), GetType(MediaElement), GetType(ObjectDataProvider), GetType(XamlReader), GetType(Window), GetType(XmlDataProvider)} For Each BlackListType In {GetType(WebBrowser), GetType(Frame), GetType(MediaElement), GetType(ObjectDataProvider), GetType(XamlReader), GetType(Window), GetType(XmlDataProvider), GetType(SettingService)}
If Reader.Type IsNot Nothing AndAlso BlackListType.IsAssignableFrom(Reader.Type.UnderlyingType) Then Throw New UnauthorizedAccessException($"基于安全考虑,不允许使用 {BlackListType.Name} 类型。") If Reader.Type IsNot Nothing AndAlso BlackListType.IsAssignableFrom(Reader.Type.UnderlyingType) Then Throw New UnauthorizedAccessException($"基于安全考虑,不允许使用 {BlackListType.Name} 类型。")
If Reader.Value IsNot Nothing AndAlso Reader.Value = BlackListType.Name Then Throw New UnauthorizedAccessException($"基于安全考虑,不允许使用 {BlackListType.Name} 值。") If Reader.Value IsNot Nothing AndAlso Reader.Value = BlackListType.Name Then Throw New UnauthorizedAccessException($"基于安全考虑,不允许使用 {BlackListType.Name} 值。")
Next Next
@@ -2917,11 +3055,22 @@ Retry:
Return formattedText.Width Return formattedText.Width
End Function End Function
''' <summary>
''' 将布尔值转换为 Visibility。True 转换为 Visible,False 转换为 Collapsed。
''' </summary>
<Extension> Public Function ToVisibility(IsVisible As Boolean) As Visibility
Return If(IsVisible, Visibility.Visible, Visibility.Collapsed)
End Function
#End Region #End Region
#Region "Debug" #Region "Debug"
Public ModeDebug As Boolean = False Public ReadOnly Property ModeDebug As Boolean
Get
Return Settings.Get("SystemDebugMode")
End Get
End Property
'Log 'Log
Public Enum LogLevel Public Enum LogLevel
@@ -3194,9 +3343,11 @@ Retry:
'遥测 '遥测
Public Sub Telemetry([Event] As String, ParamArray Datas As String()) Public Sub Telemetry([Event] As String, ParamArray Datas As String())
If Not Setup.Get("SystemSystemTelemetry") Then Return '用户关闭了遥测 #If Not RELEASE And Not BETA Then
Return '开发版不上传遥测
#End If
If Not Settings.Get("SystemSystemTelemetry") Then Return '用户关闭了遥测
If Not ClsBaseUrl.StartsWithF("http") Then Return '开源版没有设置遥测地址 If Not ClsBaseUrl.StartsWithF("http") Then Return '开源版没有设置遥测地址
If VersionBranchName = "Debug" Then Return '开发版本不上传遥测
RunInNewThread( RunInNewThread(
Sub() Sub()
Try Try
@@ -3214,10 +3365,10 @@ Retry:
'获取当前的堆栈信息 '获取当前的堆栈信息
Public Function GetStackTrace() As String Public Function GetStackTrace() As String
Dim Stack As New StackTrace() Return (New StackTrace).GetFrames().Skip(1).
Return Join(Stack.GetFrames().Skip(1).Select(Function(f) f.GetMethod). Select(Function(f) f.GetMethod).
Select(Function(f) f.Name & "(" & Join(f.GetParameters.Select(Function(p) p.ToString).ToList, ", ") & ") - " & f.Module.ToString).ToList, Select(Function(f) $"{f.Name}({f.GetParameters.Select(Function(p) p.ToString).Join(", ")}) - {f.Module}").
vbCrLf).Replace(vbCrLf & vbCrLf, vbCrLf) Join(vbCrLf).Replace(vbCrLf & vbCrLf, vbCrLf)
End Function End Function
#End Region #End Region
@@ -88,7 +88,7 @@
Set(value As LoadState) Set(value As LoadState)
If _State = value Then Return If _State = value Then Return
Dim OldState = _State Dim OldState = _State
If value = LoadState.Finished AndAlso Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000)) If value = LoadState.Finished AndAlso Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000))
_State = value _State = value
If Not LogBlackList.Contains(Name) Then Log($"[Loader] 加载器 {Name} 状态改变:{GetStringFromEnum(value)}") If Not LogBlackList.Contains(Name) Then Log($"[Loader] 加载器 {Name} 状态改变:{GetStringFromEnum(value)}")
'实现 ILoadingTrigger 接口与 OnStateChanged 回调 '实现 ILoadingTrigger 接口与 OnStateChanged 回调
@@ -149,7 +149,7 @@
Case LoadState.Waiting Case LoadState.Waiting
Return 0 Return 0
Case LoadState.Loading Case LoadState.Loading
Return If(_Progress = -1, 0.02, _Progress) Return If(_Progress = -1, 0, _Progress)
Case Else Case Else
Return 1 Return 1
End Select End Select
@@ -170,7 +170,7 @@
'状态变化 '状态变化
Public MustOverride Sub Start(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = False) Public MustOverride Sub Start(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = False)
Public MustOverride Sub Abort() Public MustOverride Sub Interrupt()
Public MustOverride Sub Failed(Ex As Exception) Public MustOverride Sub Failed(Ex As Exception)
'等待结束 '等待结束
@@ -187,7 +187,7 @@
Loop Loop
If State = LoadState.Finished Then If State = LoadState.Finished Then
Return Return
ElseIf State = LoadState.Aborted Then ElseIf State = LoadState.Interrupted Then
Throw New ThreadInterruptedException("加载器执行已中断。") Throw New ThreadInterruptedException("加载器执行已中断。")
ElseIf IsNothing([Error]) Then ElseIf IsNothing([Error]) Then
Throw New Exception("未知错误!") Throw New Exception("未知错误!")
@@ -210,7 +210,7 @@
Loop Loop
If State = LoadState.Finished Then If State = LoadState.Finished Then
Return Return
ElseIf State = LoadState.Aborted Then ElseIf State = LoadState.Interrupted Then
Throw New ThreadInterruptedException("加载器执行已中断。") Throw New ThreadInterruptedException("加载器执行已中断。")
ElseIf IsNothing([Error]) Then ElseIf IsNothing([Error]) Then
Throw New Exception("未知错误!") Throw New Exception("未知错误!")
@@ -241,16 +241,16 @@
''' <summary> ''' <summary>
''' 当前执行线程是否应当中断。只应用在加载器的工作线程中判断,不可跨线程调用。 ''' 当前执行线程是否应当中断。只应用在加载器的工作线程中判断,不可跨线程调用。
''' </summary> ''' </summary>
Public ReadOnly Property IsAborted As Boolean Public ReadOnly Property IsInterrupted As Boolean
Get Get
Return IsAbortedWithThread(Thread.CurrentThread) Return IsInterruptedWithThread(Thread.CurrentThread)
End Get End Get
End Property End Property
''' <summary> ''' <summary>
''' 当前执行线程是否应当中断。需要手动提供加载器线程,用于需要跨线程检查的情况。 ''' 当前执行线程是否应当中断。需要手动提供加载器线程,用于需要跨线程检查的情况。
''' </summary> ''' </summary>
Public Function IsAbortedWithThread(Thread As Thread) As Boolean Public Function IsInterruptedWithThread(Thread As Thread) As Boolean
Return LastRunningThread Is Nothing OrElse Not ReferenceEquals(Thread, LastRunningThread) OrElse State = LoadState.Aborted Return LastRunningThread Is Nothing OrElse Not ReferenceEquals(Thread, LastRunningThread) OrElse State = LoadState.Interrupted
End Function End Function
''' <summary> ''' <summary>
''' 在输入相同时使用原有结果的超时,单位为毫秒。 ''' 在输入相同时使用原有结果的超时,单位为毫秒。
@@ -305,7 +305,7 @@
'确认是否开始加载 '确认是否开始加载
If ShouldStart(Input, IsForceRestart) Then If ShouldStart(Input, IsForceRestart) Then
'输入不同或失败,开始加载 '输入不同或失败,开始加载
If State = LoadState.Loading Then TriggerThreadAbort() If State = LoadState.Loading Then TriggerThreadInterrupt()
Me.Input = Input Me.Input = Input
SyncLock LockState SyncLock LockState
State = LoadState.Loading State = LoadState.Loading
@@ -321,7 +321,7 @@
IsForceRestarting = IsForceRestart IsForceRestarting = IsForceRestart
If ModeDebug AndAlso Not LogBlackList.Contains(Name) Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动") If ModeDebug AndAlso Not LogBlackList.Contains(Name) Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动")
LoadDelegate(Me) LoadDelegate(Me)
If IsAborted Then If IsInterrupted Then
Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId)})", LogLevel.Developer) Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId)})", LogLevel.Developer)
Return Return
End If End If
@@ -331,18 +331,18 @@
LastFinishedTime = GetTimeMs() '未中断,本次输出有效 LastFinishedTime = GetTimeMs() '未中断,本次输出有效
Catch ex As CancelledException Catch ex As CancelledException
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发取消中断,已完成 {Math.Round(Progress * 100)}%") If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发取消中断,已完成 {Math.Round(Progress * 100)}%")
If Not IsAborted Then State = LoadState.Aborted If Not IsInterrupted Then State = LoadState.Interrupted
Catch ex As ThreadInterruptedException Catch ex As ThreadInterruptedException
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发线程中断,已完成 {Math.Round(Progress * 100)}%") If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发线程中断,已完成 {Math.Round(Progress * 100)}%")
'如果线程是因为判断到 IsAborted 而提前中止,则代表已有新线程被重启,此时不应当改为 Aborted '如果线程是因为判断到 IsInterrupted 而提前中止,则代表已有新线程被重启,此时不应当改为 Interrupted
'如果线程是在没有 IsAborted 时手动引发了 ThreadInterruptedException,则代表没有重启线程,这通常代表用户手动取消,应当改为 Aborted '如果线程是在没有 IsInterrupted 时手动引发了 ThreadInterruptedException,则代表没有重启线程,这通常代表用户手动取消,应当改为 Interrupted
If Not IsAborted Then State = LoadState.Aborted If Not IsInterrupted Then State = LoadState.Interrupted
Catch ex As Exception Catch ex As Exception
Failed(ex) Failed(ex)
End Try End Try
End Sub) With {.Name = "L/" & Name, .Priority = ThreadPriority} End Sub) With {.Name = "L/" & Name, .Priority = ThreadPriority}
Try Try
LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsInterrupted
Catch ex As ThreadStateException '若遇到偶发的 “线程正在运行或被终止”,则等待后重试 Catch ex As ThreadStateException '若遇到偶发的 “线程正在运行或被终止”,则等待后重试
Thread.Sleep(500) Thread.Sleep(500)
LastRunningThread.Start() LastRunningThread.Start()
@@ -351,20 +351,20 @@
Public Overrides Sub Failed(ex As Exception) Public Overrides Sub Failed(ex As Exception)
[Error] = ex [Error] = ex
SyncLock LockState SyncLock LockState
If IsAborted OrElse State >= LoadState.Finished Then Return If IsInterrupted OrElse State >= LoadState.Finished Then Return
State = LoadState.Failed State = LoadState.Failed
End SyncLock End SyncLock
Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%", LogLevel.Developer) Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%", LogLevel.Developer)
TriggerThreadAbort() TriggerThreadInterrupt()
End Sub End Sub
Public Overrides Sub Abort() Public Overrides Sub Interrupt()
SyncLock LockState SyncLock LockState
If State <> LoadState.Loading Then Return If State <> LoadState.Loading Then Return
State = LoadState.Aborted State = LoadState.Interrupted
End SyncLock End SyncLock
TriggerThreadAbort() TriggerThreadInterrupt()
End Sub End Sub
Private Sub TriggerThreadAbort() Private Sub TriggerThreadInterrupt()
If LastRunningThread Is Nothing Then Return If LastRunningThread Is Nothing Then Return
If LastRunningThread.IsAlive Then If LastRunningThread.IsAlive Then
LastRunningThread.Interrupt() LastRunningThread.Interrupt()
@@ -451,11 +451,11 @@
End If End If
RunInThread(AddressOf Update) RunInThread(AddressOf Update)
End Sub End Sub
Public Overrides Sub Abort() Public Overrides Sub Interrupt()
'改变状态 '改变状态
SyncLock LockState SyncLock LockState
If State = LoadState.Loading OrElse State = LoadState.Waiting Then If State = LoadState.Loading OrElse State = LoadState.Waiting Then
State = LoadState.Aborted State = LoadState.Interrupted
Else Else
Return Return
End If End If
@@ -464,7 +464,7 @@
Sub() Sub()
'中断加载器 '中断加载器
For Each Loader In Loaders For Each Loader In Loaders
Loader.Abort() Loader.Interrupt()
Next Next
End Sub) End Sub)
End Sub End Sub
@@ -475,7 +475,7 @@
State = LoadState.Failed State = LoadState.Failed
End SyncLock End SyncLock
For Each Loader In Loaders For Each Loader In Loaders
Loader.Abort() Loader.Interrupt()
Next Next
FrmMain.BtnExtraDownload.ShowRefresh() FrmMain.BtnExtraDownload.ShowRefresh()
End Sub End Sub
@@ -493,9 +493,9 @@
Case LoadState.Finished Case LoadState.Finished
'正常结束,触发刷新 '正常结束,触发刷新
Update() Update()
Case LoadState.Aborted Case LoadState.Interrupted
'被中断,这个任务也中断 '被中断,这个任务也中断
Abort() Interrupt()
Case LoadState.Failed Case LoadState.Failed
'完蛋,出错了 '完蛋,出错了
Failed(New Exception(Loader.Name & "失败", Loader.Error)) Failed(New Exception(Loader.Name & "失败", Loader.Error))
@@ -505,7 +505,7 @@
''' 触发一次更新,以启动新加载器或完成。 ''' 触发一次更新,以启动新加载器或完成。
''' </summary> ''' </summary>
Private Sub Update() Private Sub Update()
If State = LoadState.Finished OrElse State = LoadState.Failed OrElse State = LoadState.Aborted Then Return If State = LoadState.Finished OrElse State = LoadState.Failed OrElse State = LoadState.Interrupted Then Return
Dim IsFinished As Boolean = True Dim IsFinished As Boolean = True
Dim Blocked As Boolean = False Dim Blocked As Boolean = False
Dim Input As Object = Me.Input Dim Input As Object = Me.Input
@@ -607,7 +607,7 @@ Restart:
'若单个任务已中止,或全部任务已完成,则刷新并移除 '若单个任务已中止,或全部任务已完成,则刷新并移除
For Each Task In LoaderTaskbar For Each Task In LoaderTaskbar
If LoaderTaskbar.All(Function(l) l.State <> LoadState.Loading) OrElse If LoaderTaskbar.All(Function(l) l.State <> LoadState.Loading) OrElse
(Task.State = LoadState.Waiting OrElse Task.State = LoadState.Aborted) Then (Task.State = LoadState.Waiting OrElse Task.State = LoadState.Interrupted) Then
FrmSpeedLeft?.TaskRefresh(Task) FrmSpeedLeft?.TaskRefresh(Task)
LoaderTaskbar.Remove(Task) LoaderTaskbar.Remove(Task)
Log($"[Taskbar] {Task.Name} 已移出任务列表") Log($"[Taskbar] {Task.Name} 已移出任务列表")
+180 -183
View File
@@ -1,5 +1,4 @@
Imports System.Net.Http.Headers Imports System.Net.Sockets
Imports System.Net.Sockets
Imports System.Runtime.CompilerServices Imports System.Runtime.CompilerServices
Imports System.Threading.Tasks Imports System.Threading.Tasks
@@ -161,7 +160,7 @@ RequestFinished:
NetRequestByLoader = ReadFile(Temp) NetRequestByLoader = ReadFile(Temp)
File.Delete(Temp) File.Delete(Temp)
Finally Finally
NewTask.Abort() NewTask.Interrupt()
End Try End Try
End Function End Function
@@ -183,10 +182,19 @@ RequestFinished:
Throw New Exception($"预处理下载文件路径失败({LocalPath})", ex) Throw New Exception($"预处理下载文件路径失败({LocalPath})", ex)
End Try End Try
'下载 '下载
Dim RetryCount As Integer = 0
Retry:
Try Try
File.WriteAllBytes(LocalPath, SendRequest(Url, HttpMethod.Get, SimulateBrowserHeaders:=SimulateBrowserHeaders)) File.WriteAllBytes(LocalPath, SendRequest(Url, HttpMethod.Get, SimulateBrowserHeaders:=SimulateBrowserHeaders))
Catch ex As ThreadInterruptedException
File.Delete(LocalPath)
Throw
Catch ex As Exception Catch ex As Exception
File.Delete(LocalPath) File.Delete(LocalPath)
If RetryCount < 2 Then
RetryCount += 1
GoTo Retry
End If
Throw New WebException($"通过网络请求直接下载小文件失败({LocalPath})", ex) Throw New WebException($"通过网络请求直接下载小文件失败({LocalPath})", ex)
End Try End Try
End Sub End Sub
@@ -209,7 +217,7 @@ RequestFinished:
Catch ex As Exception Catch ex As Exception
Throw New WebException($"多线程直接下载文件失败(第一下载源:" & Urls.First() & ")", ex) Throw New WebException($"多线程直接下载文件失败(第一下载源:" & Urls.First() & ")", ex)
Finally Finally
NewTask.Abort() NewTask.Interrupt()
End Try End Try
End Sub End Sub
@@ -239,7 +247,7 @@ RequestFinished:
End If End If
'写入 Headers '写入 Headers
For Each Header In If(Headers, New Dictionary(Of String, String)) For Each Header In If(Headers, New Dictionary(Of String, String))
If Header.Key.ToLower = "content-type" Then If Header.Key.Lower = "content-type" Then
Request.Content?.Headers.TryAddWithoutValidation(Header.Key, Header.Value) Request.Content?.Headers.TryAddWithoutValidation(Header.Key, Header.Value)
Else Else
Request.Headers.TryAddWithoutValidation(Header.Key, Header.Value) Request.Headers.TryAddWithoutValidation(Header.Key, Header.Value)
@@ -248,14 +256,13 @@ RequestFinished:
SecretHeadersSign(Url, Request, SimulateBrowserHeaders) SecretHeadersSign(Url, Request, SimulateBrowserHeaders)
'DNS 解析 'DNS 解析
CancelToken = New CancellationTokenSource(Timeout) CancelToken = New CancellationTokenSource(Timeout)
HostIp = DNSLookup(Request, CancelToken) HostIp = DNSLookup(Request, CancelToken.Token)
If HostIp IsNot Nothing AndAlso Not IPReliability.ContainsKey(HostIp) Then If HostIp IsNot Nothing AndAlso Not IPReliability.ContainsKey(HostIp) Then
IPReliability(HostIp) = -0.01 '预先降低一点,这样快速的重复请求会使用不同的 IP 以提高成功率 IPReliability(HostIp) = -0.01 '预先降低一点,这样快速的重复请求会使用不同的 IP 以提高成功率
End If End If
'发送请求 '发送请求
SyncLock RequestClientLock SyncLock RequestClientLock
'延迟初始化,以避免在程序启动前加载 CacheCow 导致 DLL 加载失败 If RequestClient Is Nothing Then '延迟初始化,以避免在程序启动前加载 CacheCow 导致 DLL 加载失败
If RequestClient Is Nothing Then
RequestClient = CacheCow.Client.ClientExtensions.CreateClient(New CacheCow.Client.FileCacheStore.FileStore(PathTemp & "Cache/Http/"), New HttpClientHandler With { RequestClient = CacheCow.Client.ClientExtensions.CreateClient(New CacheCow.Client.FileCacheStore.FileStore(PathTemp & "Cache/Http/"), New HttpClientHandler With {
.AutomaticDecompression = DecompressionMethods.Deflate Or DecompressionMethods.GZip, .AutomaticDecompression = DecompressionMethods.Deflate Or DecompressionMethods.GZip,
.UseCookies = False '不设为 False 就不能从 Header 手动传入 Cookies .UseCookies = False '不设为 False 就不能从 Header 手动传入 Cookies
@@ -263,11 +270,12 @@ RequestFinished:
End If End If
End SyncLock End SyncLock
Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout) Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
Dim ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
Dim ResponseBytes As Byte() Dim ResponseBytes As Byte()
Using Stream As New MemoryStream Using ResponseStream = Response.Content.ReadAsStreamAsync().GetResultWithTimeout(CancelToken, Timeout)
ResponseStream.CopyToAsync(Stream, 81920, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout) Using Stream As New MemoryStream
ResponseBytes = Stream.ToArray() ResponseStream.CopyToAsync(Stream, 81920, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
ResponseBytes = Stream.ToArray()
End Using
End Using End Using
'输出 '输出
If Response.IsSuccessStatusCode Then If Response.IsSuccessStatusCode Then
@@ -284,6 +292,9 @@ RequestFinished:
Throw Throw
Catch ex As ResponsedWebException Catch ex As ResponsedWebException
Throw Throw
Catch ex As FileNotFoundException
'由于 CacheCow 读取缓存失败,然后系统调用不存在的 System.Net.Http.Formatting.resources 抛出(#8150)
Throw New Exception($"网络请求时读取缓存失败", ex)
Catch ex As Exception Catch ex As Exception
RecordIPReliability(HostIp, -1) RecordIPReliability(HostIp, -1)
If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then 'CancellationToken 超时 If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then 'CancellationToken 超时
@@ -304,12 +315,13 @@ RequestFinished:
''' <summary> ''' <summary>
''' 进行 DNS 解析。它仅在选择的 IP 与系统默认的不一致时才对 URL 中的 Host 进行替换。 ''' 进行 DNS 解析。它仅在选择的 IP 与系统默认的不一致时才对 URL 中的 Host 进行替换。
''' 返回请求时应使用的 IP;若为 IPv6,则加上了方括号。 ''' 返回请求时应使用的 IP。若解析失败,则返回 Nothing。
''' 若解析失败,则返回 Nothing。
''' </summary> ''' </summary>
Private Function DNSLookup(Request As HttpRequestMessage, CancelToken As CancellationTokenSource) As String Private Function DNSLookup(Request As HttpRequestMessage, CancelToken As CancellationToken) As String
'若一分钟内已失败过,则不再重复尝试解析,以减少断网时的 Exception 数量
Dim Host = Request.RequestUri.Host Dim Host = Request.RequestUri.Host
'不对部分有严格 SNI 限制的域名进行 DNS 解析(#8295)
If {"mojang.com", "minecraft.net", "minecraftservices.com"}.Any(Function(h) Host.ContainsF(h, True)) Then Return Nothing
'若一分钟内已失败过,则不再重复尝试解析,以减少断网时的 Exception 数量
SyncLock DNSFailureRecord.SyncRoot SyncLock DNSFailureRecord.SyncRoot
If DNSFailureRecord.ContainsKey(Host) Then If DNSFailureRecord.ContainsKey(Host) Then
If Date.Now - DNSFailureRecord(Host) < New TimeSpan(0, 1, 0) Then If Date.Now - DNSFailureRecord(Host) < New TimeSpan(0, 1, 0) Then
@@ -320,43 +332,36 @@ RequestFinished:
End If End If
End SyncLock End SyncLock
'初步 DNS 解析 '初步 DNS 解析
Dim DnsTask As Task(Of IPAddress()) = Nothing Dim Candidates As IPAddress()
Try Try
DnsTask = Dns.GetHostAddressesAsync(Host) Dim AsyncResult = Dns.BeginGetHostAddresses(Host, Nothing, Nothing)
DnsTask.Wait(CancelToken.Token) If WaitHandle.WaitAny(New WaitHandle() {AsyncResult.AsyncWaitHandle, CancelToken.WaitHandle}) Then Throw New TimeoutException("DNS 解析超时")
Candidates = Dns.EndGetHostAddresses(AsyncResult).Distinct.ToArray
Catch ex As Exception Catch ex As Exception
Log(ex, $"DNS 解析失败({Host})") Log(ex, $"DNS 解析失败({Host})")
DNSFailureRecord(Host) = Date.Now DNSFailureRecord(Host) = Date.Now
Return Nothing Return Nothing
End Try End Try
Dim Candidates As IPAddress() = DnsTask.Result.ToArray
If Not Candidates.Any Then If Not Candidates.Any Then
Log($"[Net] DNS 解析无结果({Host})") Log($"[Net] DNS 解析无结果({Host})")
Return Nothing Return Nothing
End If End If
'若同时存在 IPv4 和 IPv6 地址,仅选择其中一类(因为 GFW 可能只屏蔽了 IPv4 或 IPv6) '若同时存在 IPv4 和 IPv6 地址,仅选择其中一类(因为 GFW 可能只屏蔽了 IPv4 或 IPv6)
Dim GetIPReliability = Function(Key) IPReliability.GetOrDefault(Key.ToString, 0) Dim Reliabilities = Candidates.ToDictionary(Function(i) i, Function(i) IPReliability.GetOrDefault(i.ToString, 0))
Dim IPv4Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetwork).ToArray Dim IPv4Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetwork).ToArray
Dim IPv6Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetworkV6).ToArray Dim IPv6Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetworkV6).ToArray
If IPv4Targets.Any AndAlso IPv6Targets.Any Then If IPv4Targets.Any AndAlso IPv6Targets.Any Then
Dim IPv4Reliability = IPv4Targets.Average(Function(i) GetIPReliability(i)) Dim IPv4Reliability = IPv4Targets.Max(Function(i) Reliabilities(i))
Dim IPv6Reliability = IPv6Targets.Average(Function(i) GetIPReliability(i)) Dim IPv6Reliability = IPv6Targets.Max(Function(i) Reliabilities(i))
If Host = "api.modrinth.com" Then IPv6Reliability -= 0.1 '让 Modrinth 优先使用 IPv4 地址(#6887) If Host = "api.modrinth.com" Then IPv6Reliability -= 0.1 '让 Modrinth 优先使用 IPv4 地址(#6887)
If ModeDebug Then Log($"[Net] DNS IPv4/IPv6 选择({Host}),IPv4 {IPv4Reliability:0.000},IPv6 {IPv6Reliability:0.000}")
Candidates = If(IPv4Reliability >= IPv6Reliability, IPv4Targets, IPv6Targets) Candidates = If(IPv4Reliability >= IPv6Reliability, IPv4Targets, IPv6Targets)
End If End If
'选择可靠度最高的 IP '选择可靠度最高的 IP
Dim MaxReliability As Double = Candidates.Max(Function(i) GetIPReliability(i)) Dim Target As IPAddress = Candidates.MaxBy(Function(i) Reliabilities(i))
Dim Target As IPAddress = Candidates.First(Function(i) GetIPReliability(i) = MaxReliability) Request.Headers.Host = Request.RequestUri.Authority
Dim TargetIp As String = If(Target.AddressFamily = AddressFamily.InterNetworkV6, $"[{Target}]", Target.ToString) Request.RequestUri = (New UriBuilder(Request.RequestUri) With {.Host = If(Target.AddressFamily = AddressFamily.InterNetworkV6, $"[{Target}]", Target.ToString)}).Uri
If Target IsNot Candidates.First Then Return Target.ToString
'优选结果与系统默认 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 End Function
Private DNSFailureRecord As New SafeDictionary(Of String, Date) Private DNSFailureRecord As New SafeDictionary(Of String, Date)
''' <summary> ''' <summary>
@@ -369,8 +374,10 @@ RequestFinished:
''' </summary> ''' </summary>
Private Sub RecordIPReliability(IP As String, Result As Double) Private Sub RecordIPReliability(IP As String, Result As Double)
If IP Is Nothing Then Return If IP Is Nothing Then Return
If Not IPReliability.ContainsKey(IP) Then IPReliability(IP) = 0 SyncLock IPReliability.SyncRoot
IPReliability(IP) = (IPReliability(IP) + Result) / 2 If Not IPReliability.ContainsKey(IP) Then IPReliability(IP) = 0
IPReliability(IP) = (IPReliability(IP) + Result) / 2
End SyncLock
End Sub End Sub
''' <summary> ''' <summary>
@@ -405,7 +412,11 @@ RequestFinished:
''' <summary> ''' <summary>
''' 最大线程数。 ''' 最大线程数。
''' </summary> ''' </summary>
Public NetTaskThreadLimit As Integer Public ReadOnly Property NetTaskThreadLimit As Integer
Get
Return Settings.Get("ToolDownloadThread") + 1
End Get
End Property
''' <summary> ''' <summary>
''' 速度下限。 ''' 速度下限。
''' </summary> ''' </summary>
@@ -413,17 +424,35 @@ RequestFinished:
''' <summary> ''' <summary>
''' 速度上限。若无限制则为 -1。 ''' 速度上限。若无限制则为 -1。
''' </summary> ''' </summary>
Public NetTaskSpeedLimitHigh As Long = -1 Public ReadOnly Property NetTaskSpeedLimitHigh As Long
Get
If _NetTaskSpeedLimitHigh Is Nothing Then
Dim Setting As Integer = Settings.Get("ToolDownloadSpeed")
If Setting <= 14 Then
_NetTaskSpeedLimitHigh = (Setting + 1) * 0.1 * 1024 * 1024L
ElseIf Setting <= 31 Then
_NetTaskSpeedLimitHigh = (Setting - 11) * 0.5 * 1024 * 1024L
ElseIf Setting <= 41 Then
_NetTaskSpeedLimitHigh = (Setting - 21) * 1024 * 1024L
Else
_NetTaskSpeedLimitHigh = -1
End If
End If
Return _NetTaskSpeedLimitHigh.Value
End Get
End Property
Private _NetTaskSpeedLimitHigh As Long? = Nothing
Public Sub UpdateNetTaskSpeedLimitHigh(Value As Integer)
_NetTaskSpeedLimitHigh = Nothing
End Sub
''' <summary> ''' <summary>
''' 基于限速,当前可以下载的剩余量。 ''' 基于限速,当前可以下载的剩余量。
''' </summary> ''' </summary>
Public NetTaskSpeedLimitLeft As Long = -1 Public NetTaskSpeedLimitLeft As Long = -1
Private ReadOnly NetTaskSpeedLimitLeftLock As New Object
''' <summary> ''' <summary>
''' 正在运行中的线程数。 ''' 正在运行中的线程数。
''' </summary> ''' </summary>
Public NetTaskThreadCount As Integer = 0 Public NetTaskThreadCount As Integer = 0
Private ReadOnly NetTaskThreadCountLock As New Object
''' <summary> ''' <summary>
''' 下载源。 ''' 下载源。
@@ -760,7 +789,6 @@ RequestFinished:
''' 文件的已下载大小。 ''' 文件的已下载大小。
''' </summary> ''' </summary>
Public DownloadDone As Long = 0 Public DownloadDone As Long = 0
Private ReadOnly LockDone As New Object
''' <summary> ''' <summary>
''' 文件的校验规则。 ''' 文件的校验规则。
''' </summary> ''' </summary>
@@ -840,14 +868,12 @@ RequestFinished:
''' </summary> ''' </summary>
Private ReadOnly Property ConnectAverage As Integer Private ReadOnly Property ConnectAverage As Integer
Get Get
SyncLock LockCount Dim CurrentConnectCount As Integer = ConnectCount '防止竞态条件
Return If(ConnectCount = 0, -1, ConnectTime / ConnectCount) Return If(CurrentConnectCount = 0, -1, ConnectTime / CurrentConnectCount)
End SyncLock
End Get End Get
End Property End Property
Private Const FilePieceLimit As Long = 256 * 1024 Private Const FilePieceLimit As Long = 256 * 1024
Public ReadOnly LockCount As New Object
Public ReadOnly LockState As New Object Public ReadOnly LockState As New Object
Public ReadOnly LockChain As New Object Public ReadOnly LockChain As New Object
Public ReadOnly LockSource As New Object Public ReadOnly LockSource As New Object
@@ -928,8 +954,8 @@ StartSingleThreadDownload:
Dim Source As NetSource = GetSource() Dim Source As NetSource = GetSource()
If Source Is Nothing Then Return Nothing If Source Is Nothing Then Return Nothing
Dim TargetUrl As String = Source.Url Dim TargetUrl As String = Source.Url
If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("bmclapi") OrElse TargetUrl.Contains("github.com") OrElse If TargetUrl.Contains("pcl2-server") OrElse TargetUrl.Contains("meloong.com") OrElse TargetUrl.Contains("bmclapi") OrElse TargetUrl.Contains("github.com") OrElse
TargetUrl.Contains("optifine.net") OrElse TargetUrl.Contains("modrinth") OrElse TargetUrl.Contains("momot.rs") Then Return Nothing TargetUrl.Contains("optifine.net") OrElse TargetUrl.Contains("momot.rs") Then Return Nothing
'寻找最大碎片 '寻找最大碎片
'FUTURE: 下载引擎重做,计算下载源平均链接时间和线程下载速度,按最高时间节省来开启多线程 'FUTURE: 下载引擎重做,计算下载源平均链接时间和线程下载速度,按最高时间节省来开启多线程
Dim FilePieceMax As NetThread = Threads Dim FilePieceMax As NetThread = Threads
@@ -962,9 +988,7 @@ StartThread:
End SyncLock End SyncLock
'开始线程 '开始线程
SyncLock NetTaskThreadCountLock Interlocked.Increment(NetTaskThreadCount)
NetTaskThreadCount += 1
End SyncLock
SyncLock LockSource SyncLock LockSource
If Not HasAvailableSource(False) Then SourcesOnce.First.SingleThread = ThreadInfo If Not HasAvailableSource(False) Then SourcesOnce.First.SingleThread = ThreadInfo
End SyncLock End SyncLock
@@ -986,7 +1010,7 @@ StartThread:
CancelToken As CancellationTokenSource = Nothing, HostIp As String = Nothing CancelToken As CancellationTokenSource = Nothing, HostIp As String = Nothing
'部分下载源真的特别慢,并且只需要一个请求,例如 Ping 为 20s,如果增长太慢,就会造成类似 2.5s 5s 7.5s 10s 12.5s... 的极大延迟 '部分下载源真的特别慢,并且只需要一个请求,例如 Ping 为 20s,如果增长太慢,就会造成类似 2.5s 5s 7.5s 10s 12.5s... 的极大延迟
'延迟过长会导致某些特别慢的链接迟迟不被掐死 '延迟过长会导致某些特别慢的链接迟迟不被掐死
Dim Timeout As Integer = Math.Min(Math.Max(ConnectAverage, 10000) * (1 + Th.Source.FailCount), 30000) Dim Timeout As Integer = Math.Min(Math.Max(ConnectAverage, 15000) * (1 + Th.Source.FailCount), 30000)
Th.State = NetState.Connecting Th.State = NetState.Connecting
Try Try
Dim HttpDataCount As Integer = 0 Dim HttpDataCount As Integer = 0
@@ -994,8 +1018,8 @@ StartThread:
HttpRequest = New HttpRequestMessage(HttpMethod.Get, Th.Source.Url) HttpRequest = New HttpRequestMessage(HttpMethod.Get, Th.Source.Url)
SecretHeadersSign(Th.Source.Url, HttpRequest, SimulateBrowserHeaders) SecretHeadersSign(Th.Source.Url, HttpRequest, SimulateBrowserHeaders)
CancelToken = New CancellationTokenSource(Timeout) CancelToken = New CancellationTokenSource(Timeout)
HostIp = DNSLookup(HttpRequest, CancelToken) 'DNS 预解析 HostIp = DNSLookup(HttpRequest, CancelToken.Token) 'DNS 预解析
If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New RangeHeaderValue(Th.DownloadStart, Nothing) If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New Headers.RangeHeaderValue(Th.DownloadStart, Nothing)
Dim ContentLength As Long = 0 Dim ContentLength As Long = 0
Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout) Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查 If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查
@@ -1032,7 +1056,7 @@ StartThread:
Dim DriveName As String = Drive.Name.First.ToString Dim DriveName As String = Drive.Name.First.ToString
Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ContentLength * 1.1, 0) + Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ContentLength * 1.1, 0) +
If(LocalPath.StartsWithF(DriveName), ContentLength + 5 * 1024 * 1024, 0) If(LocalPath.StartsWithF(DriveName), ContentLength + 5 * 1024 * 1024, 0)
If Drive.TotalFreeSpace < RequiredSpace Then If RequiredSpace > 0 AndAlso Drive.TotalFreeSpace < RequiredSpace Then
Throw New Exception(DriveName & " 盘空间不足,无法进行下载。" & vbCrLf & "需要至少 " & GetString(RequiredSpace) & " 空间,但当前仅剩余 " & GetString(Drive.TotalFreeSpace) & "。" & Throw New Exception(DriveName & " 盘空间不足,无法进行下载。" & vbCrLf & "需要至少 " & GetString(RequiredSpace) & " 空间,但当前仅剩余 " & GetString(Drive.TotalFreeSpace) & "。" &
If(PathTemp.StartsWithF(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", "")) If(PathTemp.StartsWithF(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", ""))
End If End If
@@ -1040,7 +1064,7 @@ StartThread:
End If End If
ElseIf FileSize < 0 Then ElseIf FileSize < 0 Then
Throw New Exception("非首线程运行时,尚未获取文件大小") Throw New Exception("非首线程运行时,尚未获取文件大小")
ElseIf Th.DownloadStart > 0 AndAlso ContentLength = FileSize Then ElseIf Th.DownloadStart > 0 AndAlso ContentLength >= FileSize Then
NotSupportRange: NotSupportRange:
SyncLock LockSource SyncLock LockSource
If SourcesOnce.Contains(Th.Source) Then GoTo SourceBreak If SourcesOnce.Contains(Th.Source) Then GoTo SourceBreak
@@ -1066,7 +1090,7 @@ NotSupportRange:
End If End If
'开始下载 '开始下载
ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult() ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
If Setup.Get("SystemDebugDelay") Then Threading.Thread.Sleep(RandomInteger(50, 3000)) If Settings.Get("SystemDebugDelay") Then Threading.Thread.Sleep(RandomInteger(50, 3000))
Dim ResponseBytes As Byte() = New Byte(16384) {} Dim ResponseBytes As Byte() = New Byte(16384) {}
HttpDataCount = ResponseStream.ReadAsync(ResponseBytes, 0, 16384, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout) HttpDataCount = ResponseStream.ReadAsync(ResponseBytes, 0, 16384, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout)
While (IsUnknownSize OrElse Th.DownloadUndone > 0) AndAlso '判断是否下载完成 While (IsUnknownSize OrElse Th.DownloadUndone > 0) AndAlso '判断是否下载完成
@@ -1076,11 +1100,9 @@ NotSupportRange:
Threading.Thread.Sleep(16) Threading.Thread.Sleep(16)
End While End While
Dim RealDataCount As Integer = If(IsUnknownSize, HttpDataCount, Math.Min(HttpDataCount, Th.DownloadUndone)) Dim RealDataCount As Integer = If(IsUnknownSize, HttpDataCount, Math.Min(HttpDataCount, Th.DownloadUndone))
SyncLock NetTaskSpeedLimitLeftLock If NetTaskSpeedLimitHigh > 0 Then Interlocked.Add(NetTaskSpeedLimitLeft, -RealDataCount)
If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft -= RealDataCount
End SyncLock
Dim DeltaTime = GetTimeMs() - Th.LastReceiveTime Dim DeltaTime = GetTimeMs() - Th.LastReceiveTime
If DeltaTime > 1000000 Then DeltaTime = 1 '避免时间刻反转导致出现极大值 If DeltaTime > 100000000 Then DeltaTime = 1 '避免时间刻反转导致出现极大值
If RealDataCount > 0 Then If RealDataCount > 0 Then
'有数据 '有数据
If Th.DownloadDone = 0 Then If Th.DownloadDone = 0 Then
@@ -1089,27 +1111,21 @@ NotSupportRange:
SyncLock LockState SyncLock LockState
If State < NetState.Downloading Then State = NetState.Downloading If State < NetState.Downloading Then State = NetState.Downloading
End SyncLock End SyncLock
SyncLock LockCount Interlocked.Increment(ConnectCount)
ConnectCount += 1 Interlocked.Add(ConnectTime, GetTimeMs() - Th.InitTime)
ConnectTime += GetTimeMs() - Th.InitTime
End SyncLock
End If End If
SyncLock LockCount Th.Source.FailCount = 0
Th.Source.FailCount = 0 For Each Task In Tasks
For Each Task In Tasks Task.FailCount = 0
Task.FailCount = 0 Next
Next Interlocked.Add(NetManager.DownloadDone, RealDataCount)
End SyncLock Interlocked.Add(DownloadDone, RealDataCount)
NetManager.DownloadDone += RealDataCount
SyncLock LockDone
DownloadDone += RealDataCount
End SyncLock
Th.DownloadDone += RealDataCount Th.DownloadDone += RealDataCount
ResultStream.Write(ResponseBytes, 0, RealDataCount) ResultStream.Write(ResponseBytes, 0, RealDataCount)
'已完成 '已完成
If Th.DownloadUndone = 0 AndAlso Not IsUnknownSize Then Exit While If Th.DownloadUndone = 0 AndAlso Not IsUnknownSize Then Exit While
'检查速度是否过慢 '检查速度是否过慢
If DeltaTime > 5000 AndAlso DeltaTime > RealDataCount AndAlso '数据包间隔大于 5s,且速度小于 1K/s If Th.LastReceiveTime > 0 AndAlso DeltaTime > 5000 AndAlso DeltaTime > RealDataCount AndAlso '数据包间隔大于 5s,且速度小于 1K/s
Th.Source.SingleThread Is Nothing Then '且并非单线程下载 Th.Source.SingleThread Is Nothing Then '且并非单线程下载
Throw New TimeoutException("由于速度过慢断开链接,下载 " & RealDataCount & " B,消耗 " & DeltaTime & " ms。") Throw New TimeoutException("由于速度过慢断开链接,下载 " & RealDataCount & " B,消耗 " & DeltaTime & " ms。")
End If End If
@@ -1147,9 +1163,7 @@ SourceBreak:
CancelToken?.Dispose() CancelToken?.Dispose()
If Not IsNoSplit Then ResultStream?.Dispose() If Not IsNoSplit Then ResultStream?.Dispose()
'改变计数 '改变计数
SyncLock NetTaskThreadCountLock Interlocked.Decrement(NetTaskThreadCount)
NetTaskThreadCount -= 1
End SyncLock
'合并 '合并
If ((FileSize >= 0 AndAlso DownloadDone >= FileSize) OrElse (FileSize = -1 AndAlso DownloadDone > 0)) AndAlso If ((FileSize >= 0 AndAlso DownloadDone >= FileSize) OrElse (FileSize = -1 AndAlso DownloadDone > 0)) AndAlso
State < NetState.Merging AndAlso Th.State <> NetState.Interrupted Then Merge(Th) State < NetState.Merging AndAlso Th.State <> NetState.Interrupted Then Merge(Th)
@@ -1157,12 +1171,10 @@ SourceBreak:
End Sub End Sub
Private Sub SourceFail(Th As NetThread, ex As Exception, IsMergeFailure As Boolean) Private Sub SourceFail(Th As NetThread, ex As Exception, IsMergeFailure As Boolean)
'状态变更 '状态变更
SyncLock LockCount Interlocked.Increment(Th.Source.FailCount)
Th.Source.FailCount += 1 For Each Task In Tasks
For Each Task In Tasks Interlocked.Increment(Task.FailCount)
Task.FailCount += 1 Next
Next
End SyncLock
Th.State = NetState.Interrupted Th.State = NetState.Interrupted
Th.Source.Ex = ex Th.Source.Ex = ex
'根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传) '根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传)
@@ -1170,7 +1182,7 @@ SourceBreak:
If IsMergeFailure OrElse IsRangeNotSupported OrElse If IsMergeFailure OrElse IsRangeNotSupported OrElse
ex.Message.Contains("(502)") OrElse ex.Message.Contains("(404)") OrElse ex.Message.Contains("(502)") OrElse ex.Message.Contains("(404)") OrElse
ex.Message.Contains("未能解析") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse ex.Message.Contains("未能解析") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse
((ex.Message.Contains("(403)") OrElse ex.Message.Contains("(429)")) AndAlso Not Th.Source.Url.ContainsF("bmclapi")) OrElse 'BMCLAPI 的部分源在高频率请求下会返回 403/429,所以不应因此禁用下载源 ((ex.Message.Contains("(403)") OrElse ex.Message.Contains("(429)")) AndAlso Not Th.Source.Url.Contains("bmclapi")) OrElse 'BMCLAPI 的部分源在高频率请求下会返回 403/429,所以不应因此禁用下载源
(Th.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 30) AndAlso DownloadDone < 1) OrElse Th.Source.FailCount > NetTaskThreadLimit + 2 Then (Th.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 30) AndAlso DownloadDone < 1) OrElse Th.Source.FailCount > NetTaskThreadLimit + 2 Then
'当一个下载源有多个线程在下载时,只选择其中一个线程进行后续处理 '当一个下载源有多个线程在下载时,只选择其中一个线程进行后续处理
Dim IsThisFail As Boolean = False Dim IsThisFail As Boolean = False
@@ -1241,10 +1253,8 @@ SourceBreak:
SyncLock LockChain SyncLock LockChain
Threads = Nothing Threads = Nothing
End SyncLock End SyncLock
NetManager.DownloadDone -= DownloadDone Interlocked.Add(NetManager.DownloadDone, -DownloadDone)
SyncLock LockDone DownloadDone = 0
DownloadDone = 0
End SyncLock
SpeedLastDone = 0 SpeedLastDone = 0
End Sub End Sub
@@ -1271,7 +1281,7 @@ Retry:
SyncLock LockChain SyncLock LockChain
'合并文件 '合并文件
If IsNoSplit Then If IsNoSplit Then
'仅有一个线程,从缓存中输出 '仅有一个线程,从内存中输出
If ModeDebug Then Log($"[Download] {LocalName}:下载结束,从内存输出文件") If ModeDebug Then Log($"[Download] {LocalName}:下载结束,从内存输出文件")
Cache.Position = 0 Cache.Position = 0
WriteFile(LocalPath, Cache) WriteFile(LocalPath, Cache)
@@ -1321,6 +1331,7 @@ Retry:
End SyncLock End SyncLock
Catch ex As Exception Catch ex As Exception
RetryCount += 1 RetryCount += 1
If State > NetState.Merging Then Return '通常是因为在合并时被中断了
Log(ex, $"合并文件出错,第 {RetryCount} 次尝试({LocalName})") Log(ex, $"合并文件出错,第 {RetryCount} 次尝试({LocalName})")
'重新尝试合并 '重新尝试合并
If RetryCount < 3 Then If RetryCount < 3 Then
@@ -1349,7 +1360,7 @@ Retry:
Log($"[Download] {LocalName}:已失败,当前状态 {State}") Log($"[Download] {LocalName}:已失败,当前状态 {State}")
State = NetState.Interrupted State = NetState.Interrupted
End SyncLock End SyncLock
AbortInternal() InterruptInternal()
For Each Task In Tasks For Each Task In Tasks
Task.OnFileFail(Me) Task.OnFileFail(Me)
Next Next
@@ -1357,9 +1368,9 @@ Retry:
''' <summary> ''' <summary>
''' 下载中断。 ''' 下载中断。
''' </summary> ''' </summary>
Public Sub Abort(AbortedTask As LoaderDownload) Public Sub Interrupt(InterruptedTask As LoaderDownload)
'从特定任务中移除,如果它还属于其他任务,则继续下载 '从特定任务中移除,如果它还属于其他任务,则继续下载
Tasks.Remove(AbortedTask) Tasks.Remove(InterruptedTask)
If Tasks.Any Then Return If Tasks.Any Then Return
'确认中断 '确认中断
SyncLock LockState SyncLock LockState
@@ -1367,14 +1378,12 @@ Retry:
Log($"[Download] {LocalName}:已中断,当前状态 {State}") Log($"[Download] {LocalName}:已中断,当前状态 {State}")
State = NetState.Interrupted State = NetState.Interrupted
End SyncLock End SyncLock
AbortInternal() InterruptInternal()
End Sub End Sub
Private Sub AbortInternal() Private Sub InterruptInternal()
On Error Resume Next On Error Resume Next
Reset() Reset()
SyncLock NetManager.LockRemain Interlocked.Decrement(NetManager.FileRemain)
NetManager.FileRemain -= 1
End SyncLock
End Sub End Sub
'状态改变接口 '状态改变接口
@@ -1386,9 +1395,7 @@ Retry:
If State >= NetState.Finished Then Return If State >= NetState.Finished Then Return
State = NetState.Finished State = NetState.Finished
End SyncLock End SyncLock
SyncLock NetManager.LockRemain Interlocked.Decrement(NetManager.FileRemain)
NetManager.FileRemain -= 1
End SyncLock
If PrintLog Then Log($"[Download] {LocalName}:已完成") If PrintLog Then Log($"[Download] {LocalName}:已完成")
For Each Task In Tasks For Each Task In Tasks
Task.OnFileFinish(Me) Task.OnFileFinish(Me)
@@ -1518,12 +1525,12 @@ FinishExCatch:
Next Next
If Not File.HasAvailableSource() Then Throw New ArgumentException("输入的下载链接不正确!") If Not File.HasAvailableSource() Then Throw New ArgumentException("输入的下载链接不正确!")
File.LocalPath = File.LocalPath.Replace("/", "\") File.LocalPath = File.LocalPath.Replace("/", "\")
If Not File.LocalPath.ToLower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确:" & File.LocalPath) If Not File.LocalPath.Lower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确:" & File.LocalPath)
If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径:" & File.LocalPath) If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径:" & File.LocalPath)
Directory.CreateDirectory(GetPathFromFullPath(File.LocalPath)) '创建目标文件夹 Directory.CreateDirectory(GetPathFromFullPath(File.LocalPath)) '创建目标文件夹
Next Next
'接入下载管理器 '接入下载管理器,获取新开始下载的文件列表
NetManager.Start(Me) Dim NewFiles = NetManager.Start(Me)
'==================================== '====================================
' 已存在文件查找 ' 已存在文件查找
@@ -1531,9 +1538,8 @@ FinishExCatch:
'整理允许进行查找的文件 '整理允许进行查找的文件
Dim FilesToCheck As New List(Of NetFile) Dim FilesToCheck As New List(Of NetFile)
Dim DisabledCopy As Boolean = Setup.Get("SystemDebugSkipCopy") '在设置中禁用了复制 For Each File In NewFiles
For Each File In Files If File.Check?.CanUseExistsFile Then
If Not DisabledCopy AndAlso File.Check?.CanUseExistsFile Then
FilesToCheck.Add(File) FilesToCheck.Add(File)
Else '不允许,直接开始下载 Else '不允许,直接开始下载
SyncLock LockState SyncLock LockState
@@ -1570,7 +1576,7 @@ FinishExCatch:
End Sub End Sub
Private Sub CheckExistingFiles(Files As List(Of NetFile), FolderList As List(Of String)) Private Sub CheckExistingFiles(Files As List(Of NetFile), FolderList As List(Of String))
Try Try
If ModeDebug Then Log($"[Download] 文件检查线程已启动,分配的文件数:{Files.Count}") If ModeDebug Then Log($"[Download] 文件检查开始,本线程负责的文件数:{Files.Count}")
'列出 MC 文件夹中的各个版本文件夹 '列出 MC 文件夹中的各个版本文件夹
Dim VersionFolders As New List(Of String) Dim VersionFolders As New List(Of String)
For Each McFolder In FolderList For Each McFolder In FolderList
@@ -1584,7 +1590,7 @@ FinishExCatch:
'处理每个文件 '处理每个文件
For Each File As NetFile In Files For Each File As NetFile In Files
Dim Target As String = CheckExistingFile(FolderList, VersionFolders, File) Dim Target As String = CheckExistingFile(FolderList, VersionFolders, File)
If File.State >= NetState.WaitingToDownload Then Return '中断 If File.State >= NetState.WaitingToDownload Then Continue For '中断
'已找到相同文件 '已找到相同文件
If Target IsNot Nothing Then If Target IsNot Nothing Then
File.IsCopy = True File.IsCopy = True
@@ -1594,6 +1600,8 @@ Retry:
If Target <> File.LocalPath Then If Target <> File.LocalPath Then
Log($"[Download] 复制已存在的文件:{Target} → {File.LocalPath}") Log($"[Download] 复制已存在的文件:{Target} → {File.LocalPath}")
CopyFile(Target, File.LocalPath) CopyFile(Target, File.LocalPath)
Else
If ModeDebug Then Log($"[Download] 需要下载的文件已存在,并通过校验:{Target}")
End If End If
File.Finish(False) File.Finish(False)
Continue For Continue For
@@ -1619,6 +1627,8 @@ Retry:
Private Function CheckExistingFile(FolderList As List(Of String), VersionFolders As List(Of String), File As NetFile) As String Private Function CheckExistingFile(FolderList As List(Of String), VersionFolders As List(Of String), File As NetFile) As String
'目标文件已存在 '目标文件已存在
If File.Check.Check(File.LocalPath) Is Nothing Then Return File.LocalPath If File.Check.Check(File.LocalPath) Is Nothing Then Return File.LocalPath
'在设置中禁用了复制
If Settings.Get("SystemDebugSkipCopy") Then Return Nothing
'没有可用的检查规则,只能开始下载 '没有可用的检查规则,只能开始下载
If File.Check.Hash Is Nothing AndAlso File.Check.ActualSize < 0 Then Return Nothing If File.Check.Hash Is Nothing AndAlso File.Check.ActualSize < 0 Then Return Nothing
'大致判断文件类别 '大致判断文件类别
@@ -1633,7 +1643,7 @@ Retry:
Return Nothing Return Nothing
End If End If
End If End If
Dim Type = TypeIndexes.MaxOf(Function(kv) kv.Item2).FolderName.TrimStart("\"c) Dim Type = TypeIndexes.MaxBy(Function(kv) kv.Item2).FolderName.TrimStart("\"c)
'根据类别进行查找 '根据类别进行查找
Static Sizes As New SafeDictionary(Of String, Long) Static Sizes As New SafeDictionary(Of String, Long)
Select Case Type Select Case Type
@@ -1647,7 +1657,7 @@ Retry:
'版本 jar 或 json:查找 MC 文件夹下的各个版本文件夹 '版本 jar 或 json:查找 MC 文件夹下的各个版本文件夹
For Each VersionFolder In VersionFolders For Each VersionFolder In VersionFolders
For Each Candidate In Directory.GetFiles(VersionFolder, For Each Candidate In Directory.GetFiles(VersionFolder,
"*." & GetFileNameFromPath(File.LocalPath).AfterLast(".").ToLower, SearchOption.TopDirectoryOnly) "*." & GetFileNameFromPath(File.LocalPath).AfterLast(".").Lower, SearchOption.TopDirectoryOnly)
'快速进行大小校验 '快速进行大小校验
If Not Sizes.ContainsKey(Candidate) Then Sizes(Candidate) = New FileInfo(Candidate).Length If Not Sizes.ContainsKey(Candidate) Then Sizes(Candidate) = New FileInfo(Candidate).Length
If File.Check.ActualSize <> Sizes(Candidate) Then Continue For If File.Check.ActualSize <> Sizes(Candidate) Then Continue For
@@ -1709,7 +1719,7 @@ Retry:
For Each File In Files For Each File In Files
If File.State <> NetState.Interrupted Then Continue For If File.State <> NetState.Interrupted Then Continue For
If File.Sources.All(Function(s) TypeOf s.Ex Is OperationCanceledException OrElse TypeOf s.Ex Is TimeoutException OrElse TypeOf s.Ex Is ThreadInterruptedException) Then Continue For If File.Sources.All(Function(s) TypeOf s.Ex Is OperationCanceledException OrElse TypeOf s.Ex Is TimeoutException OrElse TypeOf s.Ex Is ThreadInterruptedException) Then Continue For
Dim Detail As String = Join(File.Sources.Select(Function(s) $"{If(s.Ex Is Nothing, "无错误信息。", s.Ex.GetBrief())}({s.Url})"), vbCrLf) Dim Detail As String = File.Sources.Select(Function(s) $"{If(s.Ex Is Nothing, "无错误信息。", s.Ex.GetBrief())}({s.Url})").Join(vbCrLf)
[Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf & [Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf &
"各下载源的错误如下:" & vbCrLf & Detail, [Error]) "各下载源的错误如下:" & vbCrLf & Detail, [Error])
'上报 '上报
@@ -1723,24 +1733,24 @@ Retry:
End SyncLock End SyncLock
'中断所有文件 '中断所有文件
For Each TaskFile In Files For Each TaskFile In Files
TaskFile.Abort(Me) TaskFile.Interrupt(Me)
Next Next
'在退出同步锁后再进行日志输出 '在退出同步锁后再进行日志输出
Dim ErrOutput As New List(Of String) Dim ErrOutput As New List(Of String)
For Each Ex As Exception In ExList For Each Ex As Exception In ExList
ErrOutput.Add(Ex.GetDetail()) ErrOutput.Add(Ex.GetDetail())
Next Next
Log("[Download] " & Join(ErrOutput.Distinct.ToArray, vbCrLf)) Log("[Download] " & ErrOutput.Distinct.Join(vbCrLf))
End Sub End Sub
Public Overrides Sub Abort() Public Overrides Sub Interrupt()
SyncLock LockState SyncLock LockState
If State >= LoadState.Finished Then Return If State >= LoadState.Finished Then Return
State = LoadState.Aborted State = LoadState.Interrupted
End SyncLock End SyncLock
Log("[Download] " & Name & " 已取消!") Log("[Download] " & Name & " 已取消!")
'中断所有文件 '中断所有文件
For Each TaskFile In Files For Each TaskFile In Files
TaskFile.Abort(Me) TaskFile.Interrupt(Me)
Next Next
End Sub End Sub
@@ -1757,8 +1767,7 @@ Retry:
''' <summary> ''' <summary>
''' 需要下载的文件。为“本地地址 - 文件对象”键值对。 ''' 需要下载的文件。为“本地地址 - 文件对象”键值对。
''' </summary> ''' </summary>
Public Files As New Dictionary(Of String, NetFile) Public AllFiles As New SafeDictionary(Of String, NetFile)
Public ReadOnly LockFiles As New Object
''' <summary> ''' <summary>
''' 当前的所有下载任务。 ''' 当前的所有下载任务。
@@ -1768,25 +1777,12 @@ Retry:
''' <summary> ''' <summary>
''' 已下载完成的大小。 ''' 已下载完成的大小。
''' </summary> ''' </summary>
Public Property DownloadDone As Long Public DownloadDone As Long = 0
Get
Return _DownloadDone
End Get
Set(value As Long)
SyncLock LockDone
_DownloadDone = value
End SyncLock
End Set
End Property
Private _DownloadDone As Long = 0
Private ReadOnly LockDone As New Object
''' <summary> ''' <summary>
''' 尚未完成下载的文件数。 ''' 尚未完成下载的文件数。
''' </summary> ''' </summary>
Public FileRemain As Integer = 0 Public FileRemain As Integer = 0
Public ReadOnly LockRemain As New Object
'这些属性由 RefreshStat 刷新 '这些属性由 RefreshStat 刷新
''' <summary> ''' <summary>
@@ -1855,9 +1851,9 @@ Retry:
Thread.Sleep(20) Thread.Sleep(20)
'获取文件列表 '获取文件列表
Dim AllFiles As List(Of NetFile) Dim AllFiles As List(Of NetFile)
SyncLock LockFiles SyncLock Me.AllFiles.SyncRoot
If Id = 0 AndAlso FileRemain = 0 AndAlso Files.Any() Then Files.Clear() '若已完成,则清空 If Id = 0 AndAlso FileRemain = 0 AndAlso Me.AllFiles.Any() Then Me.AllFiles.Clear() '若已完成,则清空
AllFiles = Files.Values.ToList() AllFiles = Me.AllFiles.Values.ToList()
End SyncLock End SyncLock
Dim WaitingFiles As New List(Of NetFile) Dim WaitingFiles As New List(Of NetFile)
Dim OngoingFiles As New List(Of NetFile) Dim OngoingFiles As New List(Of NetFile)
@@ -1865,7 +1861,7 @@ Retry:
If File.Uuid Mod 2 = Id Then Continue For If File.Uuid Mod 2 = Id Then Continue For
If File.State = NetState.WaitingToDownload Then If File.State = NetState.WaitingToDownload Then
WaitingFiles.Add(File) WaitingFiles.Add(File)
ElseIf File.State < NetState.Merging Then ElseIf File.State < NetState.Merging AndAlso File.State >= NetState.WaitingToDownload Then
OngoingFiles.Add(File) OngoingFiles.Add(File)
End If End If
Next Next
@@ -1908,7 +1904,7 @@ Retry:
Dim NextTick As Long = GetTimeMs() Dim NextTick As Long = GetTimeMs()
While True While True
'增加限速余量 '增加限速余量
If NetTaskSpeedLimitHigh > 0 Then NetTaskSpeedLimitLeft = NetTaskSpeedLimitHigh / 10 If NetTaskSpeedLimitHigh > 0 Then Interlocked.Add(NetTaskSpeedLimitLeft, CLng(NetTaskSpeedLimitHigh / 10))
'刷新公开属性 '刷新公开属性
RefreshStat() RefreshStat()
'等待 100 ms '等待 100 ms
@@ -1931,7 +1927,7 @@ Retry:
''' <summary> ''' <summary>
''' 开始一个下载任务。 ''' 开始一个下载任务。
''' </summary> ''' </summary>
Public Sub Start(Task As LoaderDownload) Public Function Start(Task As LoaderDownload) As List(Of NetFile)
StartManager() StartManager()
'清理缓存 '清理缓存
SyncLock DownloadCacheLock '防止同时开启多个下载任务时重复清理 SyncLock DownloadCacheLock '防止同时开启多个下载任务时重复清理
@@ -1943,45 +1939,30 @@ Retry:
Catch ex As Exception Catch ex As Exception
Log(ex, "清理下载缓存失败") Log(ex, "清理下载缓存失败")
End Try End Try
IsDownloadCacheCleared = True
End If End If
IsDownloadCacheCleared = True
End SyncLock
'文件处理
SyncLock LockFiles
'添加每个文件
For i = 0 To Task.Files.Count - 1
Dim File = Task.Files(i)
If Files.ContainsKey(File.LocalPath) Then
'已有该文件
If Files(File.LocalPath).State >= NetState.Finished Then
'该文件已经下载过一次,且下载完成
'将已下载的文件替换成当前文件,重新下载
File.Tasks.Add(Task)
Files(File.LocalPath) = File
SyncLock LockRemain
FileRemain += 1
End SyncLock
If ModeDebug Then Log($"[Download] {File.LocalName}:重新加入下载列表,目标 {File.LocalPath}")
Else
'该文件正在下载中
'将当前文件替换成下载中的文件,即两个任务指向同一个文件
File = Files(File.LocalPath)
File.Tasks.Add(Task)
End If
Else
'没有该文件
File.Tasks.Add(Task)
Files.Add(File.LocalPath, File)
SyncLock LockRemain
FileRemain += 1
End SyncLock
If ModeDebug Then Log($"[Download] {File.LocalName}:已加入下载列表,目标 {File.LocalPath}")
End If
Task.Files(i) = File '回设
Next
End SyncLock End SyncLock
'添加每个文件
Dim NewFiles As New List(Of NetFile)
For i = 0 To Task.Files.Count - 1
Dim File As NetFile = Task.Files(i)
If AllFiles.ContainsKey(File.LocalPath) AndAlso AllFiles(File.LocalPath).State < NetState.Finished Then
'该文件正在被另一个任务下载
If ModeDebug Then Log($"[Download] {File.LocalName}:无需开始,该文件已在下载中,目标 {File.LocalPath}")
File = AllFiles(File.LocalPath) '将列表中的文件替换成下载中的文件,即两个任务指向同一个文件;抛弃现在的 File 对象
Task.Files(i) = File
Else
'常规情况(该文件可能已在其他任务中下载完成,但这并不影响)
If ModeDebug Then Log($"[Download] {File.LocalName}:开始,目标 {File.LocalPath}")
AllFiles(File.LocalPath) = File
NewFiles.Add(File)
Interlocked.Increment(FileRemain)
End If
File.Tasks.Add(Task)
Next
Tasks.Add(Task) Tasks.Add(Task)
End Sub Return NewFiles
End Function
End Class End Class
@@ -1989,13 +1970,9 @@ Retry:
''' 是否有正在进行中、需要在下载管理页面显示的下载任务? ''' 是否有正在进行中、需要在下载管理页面显示的下载任务?
''' </summary> ''' </summary>
Public Function HasDownloadingTask(Optional IgnoreCustomDownload As Boolean = False) As Boolean Public Function HasDownloadingTask(Optional IgnoreCustomDownload As Boolean = False) As Boolean
For Each Task In LoaderTaskbar.ToList() Return LoaderTaskbar.Any(
If (Task.Show AndAlso Task.State = LoadState.Loading) AndAlso Function(Task) Task.Show AndAlso Task.State = LoadState.Loading AndAlso
(Not IgnoreCustomDownload OrElse Not Task.Name.ToString.Contains("自定义下载")) Then (Not IgnoreCustomDownload OrElse Not Task.Name.ToString.Contains("自定义下载")))
Return True
End If
Next
Return False
End Function End Function
#End Region #End Region
@@ -2079,4 +2056,24 @@ Retry:
}.Any(Function(k) Detail.ContainsF(k, True)) }.Any(Function(k) Detail.ContainsF(k, True))
End Function End Function
''' <summary>
''' 设置是否应当在正版登录时校验 SSL 证书。
''' </summary>
Public Sub ShouldValidateSslCertificateOnLogin(Enabled As Boolean)
ServicePointManager.ServerCertificateValidationCallback =
Function(Sender, Certificate, Chain, Failure)
Dim Request As HttpWebRequest = TryCast(Sender, HttpWebRequest)
If Failure = Net.Security.SslPolicyErrors.None Then Return True '已通过验证
'基于 #3018 和 #5879,只在访问正版登录 API 时跳过证书验证
Log($"[System] 未通过 SSL 证书验证({Failure}),提供的证书为 {Certificate?.Subject},URL:{Request?.Address}", LogLevel.Debug)
If Request Is Nothing Then
Return Not Enabled
ElseIf Request.Address.Host.Contains("xboxlive") OrElse Request.Address.Host.Contains("minecraftservices") Then
Return Not Enabled '根据设置决定是否忽略错误
Else
Return False
End If
End Function
End Sub
End Module End Module
@@ -208,7 +208,7 @@ Public Class ValidateExceptSame
If Str Is Nothing Then Return ErrorMessage.Replace("%", "null") If Str Is Nothing Then Return ErrorMessage.Replace("%", "null")
For Each Ch As String In Excepts For Each Ch As String In Excepts
If IgnoreCase Then If IgnoreCase Then
If Str.ToLower = Ch.ToLower Then Return ErrorMessage.Replace("%", Ch) If Str.Lower = Ch.Lower Then Return ErrorMessage.Replace("%", Ch)
Else Else
If Str.Equals(Ch) Then Return ErrorMessage.Replace("%", Ch) '使用 = 不确定是否会忽略大小写 If Str.Equals(Ch) Then Return ErrorMessage.Replace("%", Ch) '使用 = 不确定是否会忽略大小写
End If End If
@@ -218,6 +218,27 @@ Public Class ValidateExceptSame
End Class End Class
''' <summary>
''' 必须为特定字符串。
''' </summary>
Public Class ValidateSame
Inherits Validate
Public Property Required As String
Public Property ErrorMessage As String
Public Property IgnoreCase As Boolean = False
Public Sub New()
End Sub
Public Sub New(Required As String, Optional ErrorMessage As String = "输入内容有误", Optional IgnoreCase As Boolean = False)
Me.Required = Required
Me.ErrorMessage = ErrorMessage
Me.IgnoreCase = IgnoreCase
End Sub
Public Overrides Function Validate(Str As String) As String
Return If(String.Compare(Str, Required, IgnoreCase) = 0, "", ErrorMessage)
End Function
End Class
''' <summary> ''' <summary>
''' 对文件夹名的粗略的特化检测。 ''' 对文件夹名的粗略的特化检测。
''' </summary> ''' </summary>
@@ -355,7 +376,7 @@ Public Class ValidateFolderPath
'检查开头 '检查开头
If Str.StartsWithF("\\Mac\") Then GoTo Fin If Str.StartsWithF("\\Mac\") Then GoTo Fin
For Each Drive As DriveInfo In My.Computer.FileSystem.Drives For Each Drive As DriveInfo In My.Computer.FileSystem.Drives
If Str.ToUpper = Drive.Name Then Return "" If Str.Upper = Drive.Name Then Return ""
If Str.StartsWithF(Drive.Name, True) Then GoTo Fin If Str.StartsWithF(Drive.Name, True) Then GoTo Fin
Next Next
Return "文件夹路径头存在错误!" Return "文件夹路径头存在错误!"
File diff suppressed because it is too large Load Diff
@@ -79,7 +79,7 @@
End Try End Try
Next Next
If LatestLog IsNot Nothing AndAlso LatestLog.Any Then If LatestLog IsNot Nothing AndAlso LatestLog.Any Then
Dim RawOutput As String = Join(LatestLog, vbCrLf) Dim RawOutput As String = LatestLog.Join(vbCrLf)
Log("[Crash] 以下为游戏输出的最后一段内容:" & vbCrLf & RawOutput) Log("[Crash] 以下为游戏输出的最后一段内容:" & vbCrLf & RawOutput)
WriteFile(TempFolder & "RawOutput.log", RawOutput) WriteFile(TempFolder & "RawOutput.log", RawOutput)
AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(TempFolder & "RawOutput.log", LatestLog.ToArray)) AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(TempFolder & "RawOutput.log", LatestLog.ToArray))
@@ -113,7 +113,7 @@ Extracted:
For Each TargetFile As FileInfo In New DirectoryInfo(TempFolder & "Temp\").EnumerateFiles.ToList() For Each TargetFile As FileInfo In New DirectoryInfo(TempFolder & "Temp\").EnumerateFiles.ToList()
Try Try
If Not TargetFile.Exists OrElse TargetFile.Length = 0 Then Continue For If Not TargetFile.Exists OrElse TargetFile.Length = 0 Then Continue For
Dim Ext As String = TargetFile.Extension.ToLower Dim Ext As String = TargetFile.Extension.Lower
If Ext = ".log" OrElse Ext = ".txt" Then If Ext = ".log" OrElse Ext = ".txt" Then
AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(TargetFile.FullName, ReadFile(TargetFile.FullName).Split(vbCrLf.ToCharArray))) AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(TargetFile.FullName, ReadFile(TargetFile.FullName).Split(vbCrLf.ToCharArray)))
Else Else
@@ -147,7 +147,7 @@ Extracted:
DirectFile = Nothing DirectFile = Nothing
Dim AllFiles As New List(Of KeyValuePair(Of AnalyzeFileType, KeyValuePair(Of String, String()))) Dim AllFiles As New List(Of KeyValuePair(Of AnalyzeFileType, KeyValuePair(Of String, String())))
For Each LogFile In AnalyzeRawFiles For Each LogFile In AnalyzeRawFiles
Dim MatchName As String = GetFileNameFromPath(LogFile.Key).ToLower Dim MatchName As String = GetFileNameFromPath(LogFile.Key).Lower
Dim TargetType As AnalyzeFileType Dim TargetType As AnalyzeFileType
If MatchName.StartsWithF("hs_err") Then If MatchName.StartsWithF("hs_err") Then
TargetType = AnalyzeFileType.HsErr TargetType = AnalyzeFileType.HsErr
@@ -229,7 +229,7 @@ Extracted:
'创建文件名词典 '创建文件名词典
Dim FileNameDict As New Dictionary(Of String, KeyValuePair(Of String, String())) Dim FileNameDict As New Dictionary(Of String, KeyValuePair(Of String, String()))
For Each SelectedFile In SelectedFiles For Each SelectedFile In SelectedFiles
FileNameDict(GetFileNameFromPath(SelectedFile.Key).ToLower) = SelectedFile FileNameDict(GetFileNameFromPath(SelectedFile.Key).Lower) = SelectedFile
OutputFiles.Add(SelectedFile.Key) OutputFiles.Add(SelectedFile.Key)
Log("[Crash] 输出报告:" & SelectedFile.Key & ",作为 Minecraft 或启动器日志") Log("[Crash] 输出报告:" & SelectedFile.Key & ",作为 Minecraft 或启动器日志")
Next Next
@@ -307,7 +307,7 @@ Extracted:
''' 输出字符串的前后某些行,并统一行尾为 vbLf (正则 \n)、删除空行和重复行。 ''' 输出字符串的前后某些行,并统一行尾为 vbLf (正则 \n)、删除空行和重复行。
''' </summary> ''' </summary>
Private Function GetHeadTailLines(Raw As String(), HeadLines As Integer, TailLines As Integer) As String Private Function GetHeadTailLines(Raw As String(), HeadLines As Integer, TailLines As Integer) As String
If Raw.Length <= HeadLines + TailLines Then Return Join(Raw.Distinct, vbLf) If Raw.Length <= HeadLines + TailLines Then Return Raw.Distinct.Join(vbLf)
Dim Lines As New List(Of String) Dim Lines As New List(Of String)
Dim RealHeadLines As Integer = 0, ViewedLines As Integer Dim RealHeadLines As Integer = 0, ViewedLines As Integer
For ViewedLines = 0 To Raw.Length - 1 For ViewedLines = 0 To Raw.Length - 1
@@ -448,7 +448,7 @@ Done:
Else Else
Log("[Crash] 步骤 3:分析崩溃原因完成,找到 " & CrashReasons.Count & " 条可能的原因") Log("[Crash] 步骤 3:分析崩溃原因完成,找到 " & CrashReasons.Count & " 条可能的原因")
For Each Reason In CrashReasons For Each Reason In CrashReasons
Log("[Crash] - " & GetStringFromEnum(Reason.Key) & If(Reason.Value.Any, "(" & Join(Reason.Value, ";") & ")", "")) Log("[Crash] - " & GetStringFromEnum(Reason.Key) & If(Reason.Value.Any, "(" & Reason.Value.Join(";"c) & ")", ""))
Next Next
End If End If
End Sub End Sub
@@ -464,7 +464,7 @@ Done:
Else Else
CrashReasons.Add(Reason, New List(Of String)(If(Additional, {}))) CrashReasons.Add(Reason, New List(Of String)(If(Additional, {})))
End If End If
Log("[Crash] 可能的崩溃原因:" & GetStringFromEnum(Reason) & If(Additional IsNot Nothing AndAlso Additional.Any, "(" & Join(Additional, ";") & ")", "")) Log("[Crash] 可能的崩溃原因:" & GetStringFromEnum(Reason) & If(Additional IsNot Nothing AndAlso Additional.Any, "(" & Additional.Join(";"c) & ")", ""))
End Sub End Sub
Private Sub AppendReason(Reason As CrashReason, Additional As String) Private Sub AppendReason(Reason As CrashReason, Additional As String)
AppendReason(Reason, If(String.IsNullOrEmpty(Additional), Nothing, New List(Of String) From {Additional})) AppendReason(Reason, If(String.IsNullOrEmpty(Additional), Nothing, New List(Of String) From {Additional}))
@@ -623,9 +623,9 @@ Done:
Dim IsMixin As Boolean = MixinAnalyze(LogMc) Dim IsMixin As Boolean = MixinAnalyze(LogMc)
'常规信息 '常规信息
If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf)) If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf))
If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+"), vbLf)) If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+").Join(vbLf))
If LogMc.Contains("A potential solution has been determined, this may resolve your problem:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined, this may resolve your problem:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+"), vbLf)) If LogMc.Contains("A potential solution has been determined, this may resolve your problem:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined, this may resolve your problem:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+").Join(vbLf))
If LogMc.Contains("确定了一种可能的解决方法,这样做可能会解决你的问题:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=确定了一种可能的解决方法,这样做可能会解决你的问题:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+"), vbLf)) If LogMc.Contains("确定了一种可能的解决方法,这样做可能会解决你的问题:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, RegexSearch(If(RegexSeek(LogMc, "(?<=确定了一种可能的解决方法,这样做可能会解决你的问题:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+").Join(vbLf))
If Not IsMixin AndAlso LogMc.Contains("due to errors, provided by ") Then '在 #3104 的情况下,这一句导致 OptiFabric 的 Mixin 失败错判为 Fabric Loader 加载失败 If Not IsMixin AndAlso LogMc.Contains("due to errors, provided by ") Then '在 #3104 的情况下,这一句导致 OptiFabric 的 Mixin 失败错判为 Fabric Loader 加载失败
AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray)))
End If End If
@@ -714,18 +714,18 @@ NextStack:
If {"com", "org", "net", "asm", "fml", "mod", "jar", "sun", "lib", "map", "gui", "dev", "nio", "api", "dsi", "top", "mcp", If {"com", "org", "net", "asm", "fml", "mod", "jar", "sun", "lib", "map", "gui", "dev", "nio", "api", "dsi", "top", "mcp",
"core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base", "fake", "oshi", "impl", "data", "pool", "task", "core", "init", "mods", "main", "file", "game", "load", "read", "done", "util", "tile", "item", "base", "fake", "oshi", "impl", "data", "pool", "task",
"forge", "setup", "block", "model", "mixin", "event", "unimi", "netty", "world", "lwjgl", "fakes", "forge", "setup", "block", "model", "mixin", "event", "unimi", "netty", "world", "lwjgl", "fakes",
"gitlab", "common", "server", "config", "mixins", "compat", "loader", "launch", "script", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events", "fabric", "gitlab", "common", "server", "config", "mixins", "compat", "loader", "launch", "script", "entity", "assist", "client", "plugin", "modapi", "mojang", "shader", "events", "github", "recipe", "render", "packet", "events",
"preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content", "systems", "modules", "service", "scripts", "network", "preinit", "preload", "machine", "reflect", "channel", "general", "handler", "content", "systems", "modules", "service", "scripts", "network",
"fastutil", "optifine", "internal", "platform", "override", "fabricmc", "neoforge", "external", "fastutil", "optifine", "internal", "platform", "override", "fabricmc", "neoforge", "external",
"injection", "listeners", "scheduler", "minecraft", "universal", "multipart", "neoforged", "microsoft", "injection", "listeners", "scheduler", "minecraft", "universal", "multipart", "neoforged", "microsoft",
"transformer", "transformers", "minecraftforge", "blockentity", "spongepowered", "electronwill", "concurrent" "transformer", "transformers", "minecraftforge", "blockentity", "spongepowered", "electronwill", "concurrent"
}.Contains(Word.ToLower) Then Continue For }.Contains(Word.Lower) Then Continue For
PossibleWords.Add(Word.Trim) PossibleWords.Add(Word.Trim)
Next Next
Next Next
PossibleWords = PossibleWords.Distinct.ToList PossibleWords = PossibleWords.Distinct.ToList
Log("[Crash] 从堆栈信息中找到 " & PossibleWords.Count & " 个可能的 Mod ID 关键词") Log("[Crash] 从堆栈信息中找到 " & PossibleWords.Count & " 个可能的 Mod ID 关键词")
If PossibleWords.Any Then Log("[Crash] - " & Join(PossibleWords, ", ")) If PossibleWords.Any Then Log("[Crash] - " & PossibleWords.Join(", "))
If PossibleWords.Count > 10 Then If PossibleWords.Count > 10 Then
Log("[Crash] 关键词过多,考虑匹配出错,不纳入考虑") Log("[Crash] 关键词过多,考虑匹配出错,不纳入考虑")
Return New List(Of String) Return New List(Of String)
@@ -773,8 +773,8 @@ NextStack:
Dim HintLines As New List(Of String) Dim HintLines As New List(Of String)
For Each KeyWord As String In Keywords For Each KeyWord As String In Keywords
For Each ModString As String In ModNameLines For Each ModString As String In ModNameLines
Dim RealModString As String = ModString.ToLower.Replace("_", "") Dim RealModString As String = ModString.Lower.Replace("_", "")
If Not RealModString.Contains(KeyWord.ToLower.Replace("_", "")) Then Continue For If Not RealModString.Contains(KeyWord.Lower.Replace("_", "")) Then Continue For
If RealModString.Contains("minecraft.jar") OrElse RealModString.Contains(" forge-") OrElse RealModString.Contains(" mixin-") Then Continue For If RealModString.Contains("minecraft.jar") OrElse RealModString.Contains(" forge-") OrElse RealModString.Contains(" mixin-") Then Continue For
HintLines.Add(ModString.Trim(vbCrLf.ToCharArray)) HintLines.Add(ModString.Trim(vbCrLf.ToCharArray))
Exit For Exit For
@@ -874,7 +874,7 @@ NextStack:
StartProcess(DirectFile.Value.Key) StartProcess(DirectFile.Value.Key)
Else Else
Dim FilePath As String = PathTemp & "Crash.txt" Dim FilePath As String = PathTemp & "Crash.txt"
WriteFile(FilePath, Join(DirectFile.Value.Value, vbCrLf)) WriteFile(FilePath, DirectFile.Value.Value.Join(vbCrLf))
StartProcess(FilePath) StartProcess(FilePath)
End If End If
End Sub)) End Sub))
@@ -974,35 +974,35 @@ NextStack:
End If End If
Case CrashReason.Mod缺少前置或MC版本错误 Case CrashReason.Mod缺少前置或MC版本错误
If Additional.Any Then If Additional.Any Then
Results.Add("由于未安装正确的前置 Mod,导致游戏退出。\n缺失的依赖项:\n - " & Join(Additional, "\n - ") & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Results.Add("由于未安装正确的前置 Mod,导致游戏退出。\n缺失的依赖项:\n - " & Additional.Join("\n - ") & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else Else
Results.Add("由于未安装正确的前置 Mod,导致游戏退出。\n请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") Results.Add("由于未安装正确的前置 Mod,导致游戏退出。\n请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If End If
Case CrashReason.堆栈分析发现关键字 Case CrashReason.堆栈分析发现关键字
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("你的游戏遇到了一些问题,PCL 为此找到了一个可疑的关键词:" & Additional.First & "。\n\n如果你知道某个关键词对应的 Mod,那么有可能就是它引起的错误,你也可以查看错误报告获取详情。\h") Results.Add("你的游戏遇到了一些问题,PCL 为此找到了一个可疑的关键词:" & Additional.First & "。\n\n如果你知道某个关键词对应的 Mod,那么有可能就是它引起的错误,你也可以查看错误报告获取详情。\h")
Else Else
Results.Add("你的游戏遇到了一些问题,PCL 为此找到了以下可疑的关键词:\n - " & Join(Additional, ", ") & "\n\n如果你知道某个关键词对应的 Mod,那么有可能就是它引起的错误,你也可以查看错误报告获取详情。\h") Results.Add("你的游戏遇到了一些问题,PCL 为此找到了以下可疑的关键词:\n - " & Additional.Join(", ") & "\n\n如果你知道某个关键词对应的 Mod,那么有可能就是它引起的错误,你也可以查看错误报告获取详情。\h")
End If End If
Case CrashReason.堆栈分析发现Mod名称, CrashReason.怀疑Mod导致游戏崩溃 Case CrashReason.堆栈分析发现Mod名称, CrashReason.怀疑Mod导致游戏崩溃
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("PCL 怀疑名为 " & Additional.First & " 的 Mod 导致了游戏出错,但不能完全确定。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h") Results.Add("PCL 怀疑名为 " & Additional.First & " 的 Mod 导致了游戏出错,但不能完全确定。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h")
Else Else
Results.Add("PCL 怀疑以下 Mod 导致了游戏出错,但不能完全确定:\n - " & Join(Additional, "\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h") Results.Add("PCL 怀疑以下 Mod 导致了游戏出错,但不能完全确定:\n - " & Additional.Join("\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h")
End If End If
Case CrashReason.确定Mod导致游戏崩溃 Case CrashReason.确定Mod导致游戏崩溃
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("名为 " & Additional.First & " 的 Mod 导致了游戏出错。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h") Results.Add("名为 " & Additional.First & " 的 Mod 导致了游戏出错。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h")
Else Else
Results.Add("以下 Mod 导致了游戏出错:\n - " & Join(Additional, "\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h") Results.Add("以下 Mod 导致了游戏出错:\n - " & Additional.Join("\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h")
End If End If
Case CrashReason.ModMixin失败 Case CrashReason.ModMixin失败
If Additional.Count = 0 Then If Additional.Count = 0 Then
Results.Add("部分 Mod 注入失败,导致游戏出错。\n这一般代表着部分 Mod 与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试逐步禁用 Mod,然后观察游戏是否还会崩溃,以此定位导致崩溃的 Mod。\n\e\h") Results.Add("部分 Mod 注入失败,导致游戏出错。\n这一般代表着部分 Mod 与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试逐步禁用 Mod,然后观察游戏是否还会崩溃,以此定位导致崩溃的 Mod。\n\e\h")
ElseIf Additional.Count = 1 Then ElseIf Additional.IsSingle Then
Results.Add("名为 " & Additional.First & " 的 Mod 注入失败,导致游戏出错。\n这一般代表着它与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h") Results.Add("名为 " & Additional.First & " 的 Mod 注入失败,导致游戏出错。\n这一般代表着它与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h")
Else Else
Results.Add("以下 Mod 导致了游戏出错:\n - " & Join(Additional, "\n - ") & "\n这一般代表着它们与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h") Results.Add("以下 Mod 导致了游戏出错:\n - " & Additional.Join("\n - ") & "\n这一般代表着它们与其他 Mod 或当前环境不兼容,或是它存在 Bug。\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h")
End If End If
Case CrashReason.Mod配置文件导致游戏崩溃 Case CrashReason.Mod配置文件导致游戏崩溃
If Additional(1) Is Nothing Then If Additional(1) Is Nothing Then
@@ -1011,25 +1011,25 @@ NextStack:
Results.Add("名为 " & Additional.First & " 的 Mod 导致了游戏出错:\n其配置文件 " & Additional(1) & " 存在异常,无法读取。") Results.Add("名为 " & Additional.First & " 的 Mod 导致了游戏出错:\n其配置文件 " & Additional(1) & " 存在异常,无法读取。")
End If End If
Case CrashReason.Mod初始化失败 Case CrashReason.Mod初始化失败
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("名为 " & Additional.First & " 的 Mod 初始化失败,导致游戏无法继续加载。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h") Results.Add("名为 " & Additional.First & " 的 Mod 初始化失败,导致游戏无法继续加载。\n你可以尝试禁用此 Mod,然后观察游戏是否还会崩溃。\n\e\h")
Else Else
Results.Add("以下 Mod 初始化失败,导致游戏出错:\n - " & Join(Additional, "\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h") Results.Add("以下 Mod 初始化失败,导致游戏出错:\n - " & Additional.Join("\n - ") & "\n\n你可以尝试依次禁用上述 Mod,然后观察游戏是否还会崩溃。\n\e\h")
End If End If
Case CrashReason.特定方块导致崩溃 Case CrashReason.特定方块导致崩溃
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("游戏似乎因为方块 " & Additional.First & " 出现了问题。\n\n你可以创建一个新世界,并观察游戏的运行情况:\n - 若正常运行,则是该方块导致出错,你或许需要使用一些方式删除此方块。\n - 若仍然出错,问题就可能来自其他原因……\h") Results.Add("游戏似乎因为方块 " & Additional.First & " 出现了问题。\n\n你可以创建一个新世界,并观察游戏的运行情况:\n - 若正常运行,则是该方块导致出错,你或许需要使用一些方式删除此方块。\n - 若仍然出错,问题就可能来自其他原因……\h")
Else Else
Results.Add("游戏似乎因为世界中的某些方块出现了问题。\n\n你可以创建一个新世界,并观察游戏的运行情况:\n - 若正常运行,则是某些方块导致出错,你或许需要删除该世界。\n - 若仍然出错,问题就可能来自其他原因……\h") Results.Add("游戏似乎因为世界中的某些方块出现了问题。\n\n你可以创建一个新世界,并观察游戏的运行情况:\n - 若正常运行,则是某些方块导致出错,你或许需要删除该世界。\n - 若仍然出错,问题就可能来自其他原因……\h")
End If End If
Case CrashReason.Mod重复安装 Case CrashReason.Mod重复安装
If Additional.Count >= 2 Then If Additional.Count >= 2 Then
Results.Add("你重复安装了多个相同的 Mod:\n - " & Join(Additional, "\n - ") & "\n\n每个 Mod 只能出现一次,请删除重复的 Mod,然后再启动游戏。") Results.Add("你重复安装了多个相同的 Mod:\n - " & Additional.Join("\n - ") & "\n\n每个 Mod 只能出现一次,请删除重复的 Mod,然后再启动游戏。")
Else Else
Results.Add("你可能重复安装了多个相同的 Mod,导致游戏出错。\n\n每个 Mod 只能出现一次,请删除重复的 Mod,然后再启动游戏。\e\h") Results.Add("你可能重复安装了多个相同的 Mod,导致游戏出错。\n\n每个 Mod 只能出现一次,请删除重复的 Mod,然后再启动游戏。\e\h")
End If End If
Case CrashReason.特定实体导致崩溃 Case CrashReason.特定实体导致崩溃
If Additional.Count = 1 Then If Additional.IsSingle Then
If Additional.First.Contains("minecraft:player") Then If Additional.First.Contains("minecraft:player") Then
If Additional.First.Contains(" ") Then If Additional.First.Contains(" ") Then
Results.Add($"游戏因为位于 {Additional.First.AfterFirst(" ")} 的玩家实体导致了崩溃。\h") Results.Add($"游戏因为位于 {Additional.First.AfterFirst(" ")} 的玩家实体导致了崩溃。\h")
@@ -1040,7 +1040,7 @@ NextStack:
Results.Add($"游戏因为实体 {Additional.First} 导致了崩溃。\h") Results.Add($"游戏因为实体 {Additional.First} 导致了崩溃。\h")
End If End If
Else Else
Results.Add($"游戏因为下列实体导致了崩溃:{Additional.Join("、")}\h") Results.Add($"游戏因为下列实体导致了崩溃:{Additional.Join("、"c)}\h")
End If End If
Case CrashReason.OptiFine与Forge不兼容 Case CrashReason.OptiFine与Forge不兼容
Results.Add("由于 OptiFine 与当前版本的 Forge 不兼容,导致了游戏崩溃。\n\n请前往 OptiFine 官网(https://optifine.net/downloads)查看 OptiFine 所兼容的 Forge 版本,并严格按照对应版本重新安装游戏。") Results.Add("由于 OptiFine 与当前版本的 Forge 不兼容,导致了游戏崩溃。\n\n请前往 OptiFine 官网(https://optifine.net/downloads)查看 OptiFine 所兼容的 Forge 版本,并严格按照对应版本重新安装游戏。")
@@ -1077,31 +1077,31 @@ NextStack:
Case CrashReason.Forge安装不完整 Case CrashReason.Forge安装不完整
Results.Add("由于安装的 Forge 文件丢失,导致游戏无法正常运行。\n请重新安装一次相同版本的 Forge,然后再启动游戏。\n在打包游戏时删除 libraries 文件夹可能导致此错误。\h") Results.Add("由于安装的 Forge 文件丢失,导致游戏无法正常运行。\n请重新安装一次相同版本的 Forge,然后再启动游戏。\n在打包游戏时删除 libraries 文件夹可能导致此错误。\h")
Case CrashReason.Fabric报错 Case CrashReason.Fabric报错
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("Fabric 提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Results.Add("Fabric 提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else Else
Results.Add("Fabric 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") Results.Add("Fabric 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If End If
Case CrashReason.Mod互不兼容 Case CrashReason.Mod互不兼容
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("你所安装的 Mod 不兼容:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Results.Add("你所安装的 Mod 不兼容:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else Else
Results.Add("你所安装的 Mod 不兼容,Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") Results.Add("你所安装的 Mod 不兼容,Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If End If
Case CrashReason.Mod加载器报错 Case CrashReason.Mod加载器报错
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("Mod 加载器提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Results.Add("Mod 加载器提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else Else
Results.Add("Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") Results.Add("Mod 加载器可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If End If
Case CrashReason.Fabric报错并给出解决方案 Case CrashReason.Fabric报错并给出解决方案
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("Fabric 提供了以下解决方案:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Results.Add("Fabric 提供了以下解决方案:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else Else
Results.Add("Fabric 可能已经提供了解决方案,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") Results.Add("Fabric 可能已经提供了解决方案,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
End If End If
Case CrashReason.Forge报错 Case CrashReason.Forge报错
If Additional.Count = 1 Then If Additional.IsSingle Then
Results.Add("Forge 提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。") Results.Add("Forge 提供了以下错误信息:\n" & Additional.First & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
Else Else
Results.Add("Forge 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h") Results.Add("Forge 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
@@ -1113,7 +1113,7 @@ NextStack:
End Select End Select
Next Next
Return Join(Results, "\n\n此外,"). Return Results.Join("\n\n此外,").
Replace("\n", vbCrLf). Replace("\n", vbCrLf).
Replace("\h", ""). Replace("\h", "").
Replace("\e", If(IsHandAnalyze, "", vbCrLf & "你可以查看错误报告了解错误具体是如何发生的。")). Replace("\e", If(IsHandAnalyze, "", vbCrLf & "你可以查看错误报告了解错误具体是如何发生的。")).
@@ -97,7 +97,7 @@
Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Instance) Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Instance)
If BackAssetsFile Is Nothing Then If BackAssetsFile Is Nothing Then
Log("[Download] 未找到版本 " & Instance.Name & " 的合适的资源索引下载地址,游戏 assets 可能缺失", LogLevel.Debug) Log("[Download] 未找到版本 " & Instance.Name & " 的合适的资源索引下载地址,游戏 assets 可能缺失", LogLevel.Debug)
Task.Abort() Task.Interrupt()
Throw New ThreadInterruptedException Throw New ThreadInterruptedException
End If End If
RealAddress = BackAssetsFile.LocalPath RealAddress = BackAssetsFile.LocalPath
@@ -107,7 +107,7 @@
'检查是否需要更新:每天只更新一次 '检查是否需要更新:每天只更新一次
If File.Exists(RealAddress) AndAlso Math.Abs((File.GetLastWriteTime(RealAddress).Date - Now.Date).TotalDays) < 1 Then If File.Exists(RealAddress) AndAlso Math.Abs((File.GetLastWriteTime(RealAddress).Date - Now.Date).TotalDays) < 1 Then
Log("[Download] 无需更新资源文件索引,取消") Log("[Download] 无需更新资源文件索引,取消")
Task.Abort() Task.Interrupt()
End If End If
End Sub)) End Sub))
LoadersAssetsUpdate.Add(New LoaderDownload("后台下载资源文件索引", New List(Of NetFile))) LoadersAssetsUpdate.Add(New LoaderDownload("后台下载资源文件索引", New List(Of NetFile)))
@@ -158,14 +158,14 @@
Public Property AllDrops As List(Of Integer) Public Property AllDrops As List(Of Integer)
Get Get
If _AllDrops Is Nothing Then If _AllDrops Is Nothing Then
_AllDrops = Setup.Get("CacheDrops").ToString. _AllDrops = Settings.Get("CacheDrops").ToString.
Split(",".ToCharArray, StringSplitOptions.RemoveEmptyEntries).Select(Function(d) CInt(Val(d))).ToList() Split(",".ToCharArray, StringSplitOptions.RemoveEmptyEntries).Select(Function(d) CInt(Val(d))).ToList()
End If End If
Return If(_AllDrops.Any, _AllDrops, Nothing) '不要将 _AllDrops 再设为 Nothing,以防止反复获取设置尝试初始化 Return If(_AllDrops.Any, _AllDrops, Nothing) '不要将 _AllDrops 再设为 Nothing,以防止反复获取设置尝试初始化
End Get End Get
Set(value As List(Of Integer)) Set(value As List(Of Integer))
_AllDrops = value _AllDrops = value
Setup.Set("CacheDrops", value.Join(",")) Settings.Set("CacheDrops", value.Join(","c))
End Set End Set
End Property End Property
Private _AllDrops As List(Of Integer) = Nothing Private _AllDrops As List(Of Integer) = Nothing
@@ -191,7 +191,7 @@
''' </summary> ''' </summary>
Public DlClientListLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Main", AddressOf DlClientListMain) Public DlClientListLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Main", AddressOf DlClientListMain)
Private Sub DlClientListMain(Loader As LoaderTask(Of String, DlClientListResult)) Private Sub DlClientListMain(Loader As LoaderTask(Of String, DlClientListResult))
Select Case Setup.Get("ToolDownloadVersion") Select Case Settings.Get("ToolDownloadVersion")
Case 0 Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From { DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 30), New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 30),
@@ -211,7 +211,9 @@
'提取所有 Drop 序数 '提取所有 Drop 序数
Dim Drops As New List(Of Integer) Dim Drops As New List(Of Integer)
For Each Version As JObject In Loader.Output.Value("versions") For Each Version As JObject In Loader.Output.Value("versions")
Drops.Add(McVersion.VersionToDrop(Version("id"))) Dim Drop As Integer = McVersion.VersionToDrop(Version("id"))
If Drop = 209 Then Continue For
Drops.Add(Drop)
Next Next
AllDrops = Drops.Distinct.OrderByDescending(Function(d) d).ToList() AllDrops = Drops.Distinct.OrderByDescending(Function(d) d).ToList()
End Sub End Sub
@@ -242,20 +244,20 @@
Dim Version As String Dim Version As String
'快照版 '快照版
Version = Json("latest")("snapshot") Version = Json("latest")("snapshot")
If Setup.Get("ToolUpdateSnapshot") AndAlso Not Setup.Get("ToolUpdateSnapshotLast") = "" AndAlso If Settings.Get("ToolUpdateSnapshot") AndAlso Not Settings.Get("ToolUpdateSnapshotLast") = "" AndAlso
Setup.Get("ToolUpdateSnapshotLast") <> Version AndAlso Not IsHinted Then Settings.Get("ToolUpdateSnapshotLast") <> Version AndAlso Not IsHinted Then
IsHinted = True IsHinted = True
McDownloadClientUpdateHint(Version, Json) McDownloadClientUpdateHint(Version, Json)
End If End If
Setup.Set("ToolUpdateSnapshotLast", If(Version, "Nothing")) Settings.Set("ToolUpdateSnapshotLast", If(Version, "Nothing"))
'正式版 '正式版
Version = Json("latest")("release") Version = Json("latest")("release")
If Setup.Get("ToolUpdateRelease") AndAlso Not Setup.Get("ToolUpdateReleaseLast") = "" AndAlso If Settings.Get("ToolUpdateRelease") AndAlso Not Settings.Get("ToolUpdateReleaseLast") = "" AndAlso
Setup.Get("ToolUpdateReleaseLast") <> Version AndAlso Not IsHinted Then Settings.Get("ToolUpdateReleaseLast") <> Version AndAlso Not IsHinted Then
IsHinted = True IsHinted = True
McDownloadClientUpdateHint(Version, Json) McDownloadClientUpdateHint(Version, Json)
End If End If
Setup.Set("ToolUpdateReleaseLast", Version) Settings.Set("ToolUpdateReleaseLast", Version)
Catch ex As Exception Catch ex As Exception
Throw New Exception("Minecraft 官方源版本列表解析失败", ex) Throw New Exception("Minecraft 官方源版本列表解析失败", ex)
End Try End Try
@@ -304,7 +306,7 @@
DlClientListLoader.WaitForExit(Id, IsForceRestart:=True) DlClientListLoader.WaitForExit(Id, IsForceRestart:=True)
Case LoadState.Loading Case LoadState.Loading
DlClientListLoader.WaitForExit(Id) DlClientListLoader.WaitForExit(Id)
Case LoadState.Failed, LoadState.Aborted, LoadState.Waiting Case LoadState.Failed, LoadState.Interrupted, LoadState.Waiting
DlClientListLoader.WaitForExit(Id, IsForceRestart:=True) DlClientListLoader.WaitForExit(Id, IsForceRestart:=True)
End Select End Select
'重新查找版本 '重新查找版本
@@ -383,7 +385,7 @@
''' </summary> ''' </summary>
Public DlOptiFineListLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Main", AddressOf DlOptiFineListMain) Public DlOptiFineListLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Main", AddressOf DlOptiFineListMain)
Private Sub DlOptiFineListMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult)) Private Sub DlOptiFineListMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
Select Case Setup.Get("ToolDownloadVersion") Select Case Settings.Get("ToolDownloadVersion")
Case 0 Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From { DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 30), New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 30),
@@ -423,7 +425,7 @@
Name(i) = Name(i).Replace("_", " ") Name(i) = Name(i).Replace("_", " ")
Dim Entry As New DlOptiFineListEntry With { Dim Entry As New DlOptiFineListEntry With {
.DisplayName = Name(i).Replace("HD U ", "").Replace(".0 ", " "), .DisplayName = Name(i).Replace("HD U ", "").Replace(".0 ", " "),
.ReleaseTime = Join({ReleaseTime(i).Split(".")(2), ReleaseTime(i).Split(".")(1), ReleaseTime(i).Split(".")(0)}, "/"), .ReleaseTime = {ReleaseTime(i).Split(".")(2), ReleaseTime(i).Split(".")(1), ReleaseTime(i).Split(".")(0)}.Join("/"c),
.IsPreview = Name(i).ContainsF("pre", True), .IsPreview = Name(i).ContainsF("pre", True),
.Inherit = Name(i).ToString.Split(" ")(0), .Inherit = Name(i).ToString.Split(" ")(0),
.FileName = If(Name(i).ContainsF("pre", True), "preview_", "") & "OptiFine_" & Name(i).Replace(" ", "_") & ".jar", .FileName = If(Name(i).ContainsF("pre", True), "preview_", "") & "OptiFine_" & Name(i).Replace(" ", "_") & ".jar",
@@ -489,7 +491,7 @@
''' </summary> ''' </summary>
Public DlForgeListLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Main", AddressOf DlForgeListMain) Public DlForgeListLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Main", AddressOf DlForgeListMain)
Private Sub DlForgeListMain(Loader As LoaderTask(Of Integer, DlForgeListResult)) Private Sub DlForgeListMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
Select Case Setup.Get("ToolDownloadVersion") Select Case Settings.Get("ToolDownloadVersion")
Case 0 Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From { DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 30), New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 30),
@@ -638,7 +640,7 @@
Public Sub DlForgeVersionMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry))) Public Sub DlForgeVersionMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
Dim DlForgeVersionOfficialLoader As New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Official", AddressOf DlForgeVersionOfficialMain) Dim DlForgeVersionOfficialLoader As New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Official", AddressOf DlForgeVersionOfficialMain)
Dim DlForgeVersionBmclapiLoader As New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Bmclapi", AddressOf DlForgeVersionBmclapiMain) Dim DlForgeVersionBmclapiLoader As New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Bmclapi", AddressOf DlForgeVersionBmclapiMain)
Select Case Setup.Get("ToolDownloadVersion") Select Case Settings.Get("ToolDownloadVersion")
Case 0 Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From { DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From {
New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 30), New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 30),
@@ -849,7 +851,7 @@
VersionName = ApiName.Replace("1.20.1-", "") VersionName = ApiName.Replace("1.20.1-", "")
Version = New Version("19." & VersionName) Version = New Version("19." & VersionName)
Inherit = "1.20.1" Inherit = "1.20.1"
ElseIf ApiName.StartsWith("0.") Then '0.25w14craftmine.3-beta ElseIf ApiName.StartsWithF("0.") Then '0.25w14craftmine.3-beta
VersionName = ApiName VersionName = ApiName
Dim Segments = ApiName.BeforeFirst("-").Split("."c) Dim Segments = ApiName.BeforeFirst("-").Split("."c)
Version = New Version(0, 0, Segments.Last) Version = New Version(0, 0, Segments.Last)
@@ -858,10 +860,11 @@
VersionName = ApiName VersionName = ApiName
Version = New Version(ApiName.BeforeFirst("-")) Version = New Version(ApiName.BeforeFirst("-"))
If Version.Major >= 24 Then If Version.Major >= 24 Then
Inherit = Version.ToString.Replace(".0", "") Inherit = $"{Version.Major}.{Version.Minor}.{Version.Build}"
Else Else
Inherit = "1." & Version.Major & If(Version.Minor > 0, "." & Version.Minor, "") Inherit = $"1.{Version.Major}.{Version.Minor}"
End If End If
If Inherit.EndsWithF(".0") Then Inherit = Left(Inherit, Inherit.Length - 2)
If VersionName.Contains("+") Then Inherit &= "-" & VersionName.AfterFirst("+") If VersionName.Contains("+") Then Inherit &= "-" & VersionName.AfterFirst("+")
End If End If
End Sub End Sub
@@ -872,7 +875,7 @@
''' </summary> ''' </summary>
Public DlNeoForgeListLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Main", AddressOf DlNeoForgeListMain) Public DlNeoForgeListLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Main", AddressOf DlNeoForgeListMain)
Private Sub DlNeoForgeListMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult)) Private Sub DlNeoForgeListMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
Select Case Setup.Get("ToolDownloadVersion") Select Case Settings.Get("ToolDownloadVersion")
Case 0 Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From { DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 30), New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 30),
@@ -997,7 +1000,7 @@
''' </summary> ''' </summary>
Public DlLiteLoaderListLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Main", AddressOf DlLiteLoaderListMain) Public DlLiteLoaderListLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Main", AddressOf DlLiteLoaderListMain)
Private Sub DlLiteLoaderListMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult)) Private Sub DlLiteLoaderListMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
Select Case Setup.Get("ToolDownloadVersion") Select Case Settings.Get("ToolDownloadVersion")
Case 0 Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From { DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 30), New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 30),
@@ -1031,7 +1034,7 @@
Versions.Add(New DlLiteLoaderListEntry With { Versions.Add(New DlLiteLoaderListEntry With {
.Inherit = Pair.Key, .Inherit = Pair.Key,
.IsLegacy = Pair.Key.Split(".")(1) < 8, .IsLegacy = Pair.Key.Split(".")(1) < 8,
.IsPreview = RealEntry("stream").ToString.ToLower = "snapshot", .IsPreview = RealEntry("stream").ToString.Lower = "snapshot",
.FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar", .FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar",
.MD5 = RealEntry("md5"), .MD5 = RealEntry("md5"),
.ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy'/'MM'/'dd HH':'mm"), .ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy'/'MM'/'dd HH':'mm"),
@@ -1059,7 +1062,7 @@
Versions.Add(New DlLiteLoaderListEntry With { Versions.Add(New DlLiteLoaderListEntry With {
.Inherit = Pair.Key, .Inherit = Pair.Key,
.IsLegacy = Pair.Key.Split(".")(1) < 8, .IsLegacy = Pair.Key.Split(".")(1) < 8,
.IsPreview = RealEntry("stream").ToString.ToLower = "snapshot", .IsPreview = RealEntry("stream").ToString.Lower = "snapshot",
.FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar", .FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar",
.MD5 = RealEntry("md5"), .MD5 = RealEntry("md5"),
.ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy'/'MM'/'dd HH':'mm"), .ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy'/'MM'/'dd HH':'mm"),
@@ -1096,7 +1099,7 @@
''' </summary> ''' </summary>
Public DlFabricListLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Main", AddressOf DlFabricListMain) Public DlFabricListLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Main", AddressOf DlFabricListMain)
Private Sub DlFabricListMain(Loader As LoaderTask(Of Integer, DlFabricListResult)) Private Sub DlFabricListMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
Select Case Setup.Get("ToolDownloadVersion") Select Case Settings.Get("ToolDownloadVersion")
Case 0 Case 0
DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From { DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From {
New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 30), New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 30),
@@ -1170,23 +1173,23 @@
Dim Urls As New List(Of KeyValuePair(Of String, Integer)) Dim Urls As New List(Of KeyValuePair(Of String, Integer))
Dim McimUrl As String = DlSourceModGet(Url) Dim McimUrl As String = DlSourceModGet(Url)
If McimUrl <> Url Then If McimUrl <> Url Then
Select Case Setup.Get("ToolDownloadMod") Select Case Settings.Get("ToolDownloadMod")
Case 0 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)(McimUrl, 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)(Url, 30))
Case 1 Case 1
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10)) '至少 10s,要不然有时候远端服务器来不及完成 Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10))) '至少 20s,要不然 Modrinth 返回不过来
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)) Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30)) Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
Case Else Case Else
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10)) Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10)))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30)) Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30)) Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30))
End Select End Select
Else Else
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 10)) Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10)))
Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30)) Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30))
End If End If
Dim Exs As String = "" Dim Exs As String = ""
@@ -1210,7 +1213,7 @@
''' </summary> ''' </summary>
Public ReadOnly Property DlSourcePreferMojang As Boolean Public ReadOnly Property DlSourcePreferMojang As Boolean
Get Get
Return Setup.Get("ToolDownloadSource") = 2 OrElse (Setup.Get("ToolDownloadSource") = 1 AndAlso DlPreferMojang) Return Settings.Get("ToolDownloadSource") = 2 OrElse (Settings.Get("ToolDownloadSource") = 1 AndAlso DlPreferMojang)
End Get End Get
End Property End Property
''' <summary> ''' <summary>
@@ -1224,7 +1227,7 @@
''' </summary> ''' </summary>
Public ReadOnly Property DlVersionListPreferMojang As Boolean Public ReadOnly Property DlVersionListPreferMojang As Boolean
Get Get
Return Setup.Get("ToolDownloadVersion") = 2 OrElse (Setup.Get("ToolDownloadVersion") = 1 AndAlso DlPreferMojang) Return Settings.Get("ToolDownloadVersion") = 2 OrElse (Settings.Get("ToolDownloadVersion") = 1 AndAlso DlPreferMojang)
End Get End Get
End Property End Property
''' <summary> ''' <summary>
@@ -1323,7 +1326,7 @@
If SubLoader.Key.State = LoadState.Finished Then If SubLoader.Key.State = LoadState.Finished Then
'检查加载器成功 '检查加载器成功
MainLoader.Output = SubLoader.Key.Output MainLoader.Output = SubLoader.Key.Output
DlSourceLoaderAbort(LoaderList) DlSourceLoaderInterrupt(LoaderList)
Return Return
ElseIf BeforeLoadersAllFailed Then ElseIf BeforeLoadersAllFailed Then
'此前的加载器全部失败,直接启动后续加载器 '此前的加载器全部失败,直接启动后续加载器
@@ -1355,7 +1358,7 @@
End If End If
Next Next
If ErrorInfo Is Nothing Then ErrorInfo = New TimeoutException("下载源连接超时") If ErrorInfo Is Nothing Then ErrorInfo = New TimeoutException("下载源连接超时")
DlSourceLoaderAbort(LoaderList) DlSourceLoaderInterrupt(LoaderList)
Throw ErrorInfo Throw ErrorInfo
End If End If
Exit For Exit For
@@ -1364,15 +1367,15 @@
Thread.Sleep(10) Thread.Sleep(10)
WaitCycle += 1 WaitCycle += 1
'检查父加载器中断 '检查父加载器中断
If MainLoader.IsAborted Then If MainLoader.IsInterrupted Then
DlSourceLoaderAbort(LoaderList) DlSourceLoaderInterrupt(LoaderList)
Return Return
End If End If
Loop Loop
End Sub End Sub
Private Sub DlSourceLoaderAbort(Of InputType, OutputType)(LoaderList As List(Of KeyValuePair(Of LoaderTask(Of InputType, OutputType), Integer))) Private Sub DlSourceLoaderInterrupt(Of InputType, OutputType)(LoaderList As List(Of KeyValuePair(Of LoaderTask(Of InputType, OutputType), Integer)))
For Each Loader In LoaderList For Each Loader In LoaderList
If Loader.Key.State = LoadState.Loading Then Loader.Key.Abort() If Loader.Key.State = LoadState.Loading Then Loader.Key.Interrupt()
Next Next
End Sub End Sub
@@ -95,10 +95,11 @@
Try Try
'确定文件存在 '确定文件存在
If Not File.Exists(PathJava) Then Throw New FileNotFoundException("未找到 java.exe 文件", PathJava) If Not File.Exists(PathJava) Then Throw New FileNotFoundException("未找到 java.exe 文件", PathJava)
If {"finalshell", "Paranoia File"}.Any(Function(n) PathJava.ContainsF(n, True)) Then Throw New Exception("不兼容该精简版 Java") '#2249、#8080
If File.Exists(PathFolder & "pdf-bookmark") Then Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326 If File.Exists(PathFolder & "pdf-bookmark") Then Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326
IsJre = Not File.Exists(PathFolder & "javac.exe") IsJre = Not File.Exists(PathFolder & "javac.exe")
'运行 -version '运行 -version
Output = StartProcessAndGetOutput(PathJava, "-version", 15000).ToLower Output = StartProcessAndGetOutput(PathJava, "-version", 15000).Lower
If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败") If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败")
If ModeDebug Then Log("[Java] Java 检查输出:" & PathJava & 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("/lib/ext exists") Then Throw New ApplicationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试")
@@ -123,8 +124,6 @@
If Version.Minor <= 4 OrElse Version.Minor >= 100 Then Throw New ApplicationException("分析详细信息失败,获取的版本为 " & Version.ToString) 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") If Not Is64Bit AndAlso Not Is32BitSystem Then Throw New Exception("该 Java 为 32 位版本,请安装 64 位的 Java")
'#2249:JRE 17 似乎会导致 Forge 安装失败,干脆禁用更多版本的 JRE
If IsJre AndAlso MajorVersion >= 16 Then Throw New Exception("由于高版本 JRE 对游戏的兼容性很差,因此不再允许使用。你可以使用对应版本的 JDK,而非 JRE!")
Catch ex As ApplicationException Catch ex As ApplicationException
Throw ex Throw ex
Catch ex As ThreadInterruptedException Catch ex As ThreadInterruptedException
@@ -166,13 +165,13 @@
Public Sub JavaListInit() Public Sub JavaListInit()
JavaList = New List(Of JavaEntry) JavaList = New List(Of JavaEntry)
Try Try
If Setup.Get("CacheJavaListVersion") < JavaListCacheVersion Then If Settings.Get("CacheJavaListVersion") < JavaListCacheVersion Then
'不使用缓存 '不使用缓存
Log("[Java] 要求 Java 列表缓存更新") Log("[Java] 要求 Java 列表缓存更新")
Setup.Set("CacheJavaListVersion", JavaListCacheVersion) Settings.Set("CacheJavaListVersion", JavaListCacheVersion)
Else Else
'使用缓存 '使用缓存
For Each JsonEntry In GetJson(Setup.Get("LaunchArgumentJavaAll")) For Each JsonEntry In GetJson(Settings.Get("LaunchArgumentJavaAll"))
JavaList.Add(JavaEntry.FromJson(JsonEntry)) JavaList.Add(JavaEntry.FromJson(JsonEntry))
Next Next
End If End If
@@ -185,7 +184,7 @@
End If End If
Catch ex As Exception Catch ex As Exception
Log(ex, "初始化 Java 列表失败", LogLevel.Feedback) Log(ex, "初始化 Java 列表失败", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaAll", "[]") Settings.Set("LaunchArgumentJavaAll", "[]")
End Try End Try
End Sub End Sub
@@ -233,7 +232,7 @@
'获取版本独立设置中指定的 Java '获取版本独立设置中指定的 Java
Dim VersionSelect As String = "" Dim VersionSelect As String = ""
If GameInstance IsNot Nothing Then If GameInstance IsNot Nothing Then
VersionSelect = Setup.Get("VersionArgumentJavaSelect", Instance:=GameInstance) VersionSelect = Settings.Get("VersionArgumentJavaSelect", Instance:=GameInstance)
If VersionSelect.StartsWithF("{") Then If VersionSelect.StartsWithF("{") Then
Try Try
UserJava = JavaEntry.FromJson(GetJson(VersionSelect)) UserJava = JavaEntry.FromJson(GetJson(VersionSelect))
@@ -242,22 +241,22 @@
Throw Throw
Catch ex As Exception Catch ex As Exception
UserJava = Nothing UserJava = Nothing
Setup.Reset("VersionArgumentJavaSelect", Instance:=GameInstance) Settings.Reset("VersionArgumentJavaSelect", Instance:=GameInstance)
Log(ex, "版本独立设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint) Log(ex, "版本独立设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint)
End Try End Try
End If End If
End If End If
'获取全局设置中指定的 Java '获取全局设置中指定的 Java
If UserJava Is Nothing AndAlso VersionSelect <> "" AndAlso Setup.Get("LaunchArgumentJavaSelect") <> "" Then If UserJava Is Nothing AndAlso VersionSelect <> "" AndAlso Settings.Get("LaunchArgumentJavaSelect") <> "" Then
Try Try
UserJava = JavaEntry.FromJson(GetJson(Setup.Get("LaunchArgumentJavaSelect"))) UserJava = JavaEntry.FromJson(GetJson(Settings.Get("LaunchArgumentJavaSelect")))
UserJava.Check() UserJava.Check()
Catch ex As ThreadInterruptedException Catch ex As ThreadInterruptedException
Throw Throw
Catch ex As Exception Catch ex As Exception
UserJava = Nothing UserJava = Nothing
Setup.Reset("LaunchArgumentJavaSelect") Settings.Reset("LaunchArgumentJavaSelect")
Log(ex, "全局设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint) Log(ex, "全局设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint)
End Try End Try
End If End If
@@ -276,7 +275,7 @@ RetryGet:
Select Case JavaSearchLoader.State Select Case JavaSearchLoader.State
Case LoadState.Failed Case LoadState.Failed
Throw JavaSearchLoader.Error Throw JavaSearchLoader.Error
Case LoadState.Aborted Case LoadState.Interrupted
Throw New ThreadInterruptedException("Java 搜索加载器已中断") Throw New ThreadInterruptedException("Java 搜索加载器已中断")
End Select End Select
@@ -331,7 +330,7 @@ RetryGet:
Requirement = "需要 Java " & If(Left = Right, Left, Left & " ~ " & Right) Requirement = "需要 Java " & If(Left = Right, Left, Left & " ~ " & Right)
End If End If
Dim JavaCurrent As String = UserJava.MajorVersion & If(ShowRevision, "." & UserJava.Version.MajorRevision & "." & UserJava.Version.MinorRevision, "") Dim JavaCurrent As String = UserJava.MajorVersion & If(ShowRevision, "." & UserJava.Version.MajorRevision & "." & UserJava.Version.MinorRevision, "")
If GameInstance IsNot Nothing AndAlso Setup.Get("VersionAdvanceJava", GameInstance) Then If GameInstance IsNot Nothing AndAlso Settings.Get("VersionAdvanceJava", GameInstance) Then
'直接跳过弹窗 '直接跳过弹窗
Log("[Java] 设置中指定了使用 Java " & JavaCurrent & ",但当前版本" & Requirement & ",这可能会导致游戏崩溃!", LogLevel.Debug) Log("[Java] 设置中指定了使用 Java " & JavaCurrent & ",但当前版本" & Requirement & ",这可能会导致游戏崩溃!", LogLevel.Debug)
AllowedJavaList = New List(Of JavaEntry) From {UserJava} AllowedJavaList = New List(Of JavaEntry) From {UserJava}
@@ -411,9 +410,9 @@ UserPass:
Public Function JavaIs64Bit(Optional GameInstance As McInstance = Nothing) As Boolean Public Function JavaIs64Bit(Optional GameInstance As McInstance = Nothing) As Boolean
Try Try
'检查强制指定 '检查强制指定
Dim UserSetup As String = Setup.Get("LaunchArgumentJavaSelect") Dim UserSetup As String = Settings.Get("LaunchArgumentJavaSelect")
If GameInstance IsNot Nothing Then If GameInstance IsNot Nothing Then
Dim UserSetupVersion As String = Setup.Get("VersionArgumentJavaSelect", Instance:=GameInstance) Dim UserSetupVersion As String = Settings.Get("VersionArgumentJavaSelect", Instance:=GameInstance)
If UserSetupVersion <> "使用全局设置" Then UserSetup = UserSetupVersion If UserSetupVersion <> "使用全局设置" Then UserSetup = UserSetupVersion
End If End If
If UserSetup <> "" Then If UserSetup <> "" Then
@@ -422,7 +421,7 @@ UserPass:
UserJava = JavaEntry.FromJson(GetJson(UserSetup)) UserJava = JavaEntry.FromJson(GetJson(UserSetup))
Catch ex As Exception Catch ex As Exception
Log(ex, "版本指定的 Java 信息已损坏,已重置版本设置中指定的 Java") Log(ex, "版本指定的 Java 信息已损坏,已重置版本设置中指定的 Java")
Setup.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=GameInstance) Settings.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=GameInstance)
GoTo NoUserJava GoTo NoUserJava
End Try End Try
For Each Java In JavaList For Each Java In JavaList
@@ -437,7 +436,7 @@ NoUserJava:
Return False Return False
Catch ex As Exception Catch ex As Exception
Log(ex, "检查 Java 类别时出错", LogLevel.Feedback) Log(ex, "检查 Java 类别时出错", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaSelect", "") Settings.Set("LaunchArgumentJavaSelect", "")
Return True Return True
End Try End Try
End Function End Function
@@ -518,17 +517,14 @@ NoUserJava:
If Disk.DriveType = DriveType.Network Then Continue For '跳过网络驱动器(#3705) If Disk.DriveType = DriveType.Network Then Continue For '跳过网络驱动器(#3705)
JavaSearchFolder(Disk.Name, JavaPreList, False) JavaSearchFolder(Disk.Name, JavaPreList, False)
Next Next
'查找 .jdks 文件夹中的 Java '查找用户文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.jdks\", JavaPreList, False, True) JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), JavaPreList, False)
'查找 APPDATA 文件夹中的 Java JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.jdks\", JavaPreList, False, IsFullSearch:=True)
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\", JavaPreList, False) JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.sdkman\candidates\java\", JavaPreList, False, IsFullSearch:=True)
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) & "\", JavaPreList, False)
'查找启动器目录中的 Java '查找启动器目录中的 Java
JavaSearchFolder(Path, JavaPreList, False, IsFullSearch:=True) JavaSearchFolder(Path, JavaPreList, False, IsFullSearch:=True)
'查找所选 Minecraft 文件夹中的 Java '查找所选 Minecraft 文件夹中的 Java
If Not String.IsNullOrWhiteSpace(McFolderSelected) AndAlso Path <> McFolderSelected Then If Not String.IsNullOrWhiteSpace(McFolderSelected) AndAlso Path <> McFolderSelected Then JavaSearchFolder(McFolderSelected, JavaPreList, False, IsFullSearch:=True)
JavaSearchFolder(McFolderSelected, JavaPreList, False, IsFullSearch:=True)
End If
'若不全为符号链接,则清除符号链接的地址 '若不全为符号链接,则清除符号链接的地址
Dim JavaWithoutReparse As New Dictionary(Of String, Boolean) Dim JavaWithoutReparse As New Dictionary(Of String, Boolean)
@@ -562,7 +558,7 @@ NoUserJava:
#Region "添加玩家手动导入的 Java" #Region "添加玩家手动导入的 Java"
Dim ImportedJava As String = Setup.Get("LaunchArgumentJavaAll") Dim ImportedJava As String = Settings.Get("LaunchArgumentJavaAll")
Try Try
For Each JavaJsonObject In GetJson(ImportedJava) For Each JavaJsonObject In GetJson(ImportedJava)
Dim Entry = JavaEntry.FromJson(JavaJsonObject) Dim Entry = JavaEntry.FromJson(JavaJsonObject)
@@ -570,14 +566,14 @@ NoUserJava:
Next Next
Catch ex As Exception Catch ex As Exception
Log(ex, "Java 列表已损坏", LogLevel.Feedback) Log(ex, "Java 列表已损坏", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaAll", "[]") Settings.Set("LaunchArgumentJavaAll", "[]")
End Try End Try
#End Region #End Region
'确保可用并获取详细信息,转入正式列表 '确保可用并获取详细信息,转入正式列表
Dim NewJavaList As New List(Of JavaEntry) Dim NewJavaList As New List(Of JavaEntry)
For Each Entry In JavaPreList.Distinct(Function(a, b) a.Key.ToLower = b.Key.ToLower) '#794 For Each Entry In JavaPreList.Distinct(Function(a, b) a.Key.Lower = b.Key.Lower) '#794
NewJavaList.Add(New JavaEntry(Entry.Key, Entry.Value)) NewJavaList.Add(New JavaEntry(Entry.Key, Entry.Value))
Next Next
NewJavaList = JavaCheckList(NewJavaList).SortByComparison(AddressOf JavaSorter) NewJavaList = JavaCheckList(NewJavaList).SortByComparison(AddressOf JavaSorter)
@@ -587,7 +583,7 @@ NoUserJava:
For Each Java In NewJavaList For Each Java In NewJavaList
AllList.Add(Java.ToJson) AllList.Add(Java.ToJson)
Next Next
Setup.Set("LaunchArgumentJavaAll", AllList.ToString(Newtonsoft.Json.Formatting.None)) Settings.Set("LaunchArgumentJavaAll", AllList.ToString(Newtonsoft.Json.Formatting.None))
JavaList = NewJavaList JavaList = NewJavaList
Catch ex As Exception Catch ex As Exception
@@ -596,7 +592,7 @@ NoUserJava:
End Try End Try
Log("[Java] Java 搜索完成,发现 " & JavaList.Count & " 个 Java") Log("[Java] Java 搜索完成,发现 " & JavaList.Count & " 个 Java")
If FrmSetupLaunch IsNot Nothing Then RunInUi(Sub() FrmSetupLaunch.RefreshJavaComboBox()) If FrmSetupLaunch IsNot Nothing Then RunInUi(Sub() FrmSetupLaunch.UpdateJavaComboBox())
If FrmInstanceSetup IsNot Nothing Then RunInUi(Sub() FrmInstanceSetup.RefreshJavaComboBox()) If FrmInstanceSetup IsNot Nothing Then RunInUi(Sub() FrmInstanceSetup.RefreshJavaComboBox())
End Sub End Sub
@@ -669,18 +665,18 @@ Wait:
If File.Exists(Path & "javaw.exe") Then Results(Path) = Source If File.Exists(Path & "javaw.exe") Then Results(Path) = Source
'查找其下的所有文件夹 '查找其下的所有文件夹
'不应使用网易的 Java:https://github.com/Meloong-Git/PCL/issues/1279#issuecomment-2761489121 '不应使用网易的 Java:https://github.com/Meloong-Git/PCL/issues/1279#issuecomment-2761489121
Dim Keywords = {"java", "jdk", "env", "环境", "run", "软件", "jre", "mc", "dragon", "bin", Static Keywords As String() = {
"soft", "cache", "temp", "corretto", "roaming", "users", "craft", "program", "世界", "net", "java", "jdk", "jre", "env", "环境", "run", "软件", "mc", "dragon", "well", "bin", "sdk", "candidate", "current",
"游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", "client", "整合", "software", "cache", "temp", "corretto", "roaming", "users", "craft", "program", "世界", "net",
"应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot", "游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", "client", "整合",
"runtime", "x86", "x64", "forge", "原版", "optifine", "官方", "启动", "hmcl", "mod", "高清", "应用", "运行", "前置", "mojang", "官启", "官方", "新建文件夹", "eclipse", "microsoft", "hotspot",
"download", "launch", "程序", "path", "version", "baka", "pcl", "zulu", "local", "packages", "runtime", "x86", "x64", "arm", "forge", "原版", "optifine", "官方", "启动", "hmcl", "mod", "forge", "fabric",
"4297127d64ec6", "1.", "启动", "jbr"} "download", "launch", "程序", "path", "version", "baka", "pcl", "zulu", "local", "packages", "4297127d64ec6", "1.", "启动", "jbr"}
For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories
If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接 If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接
Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).ToLower '用于搜索的字符串 Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).Lower '用于搜索的字符串
If IsFullSearch OrElse If IsFullSearch OrElse
OriginalPath.Name.ToLower = "users" OrElse Val(SearchEntry) > 0 OrElse Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then OriginalPath.Name.Lower = "users" OrElse Val(SearchEntry) > 0 OrElse Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then
JavaSearchFolder(FolderInfo, Results, Source) JavaSearchFolder(FolderInfo, Results, Source)
End If End If
Next Next
@@ -707,7 +703,7 @@ Wait:
}) })
AddHandler JavaDownloadLoader.OnStateChangedThread, AddHandler JavaDownloadLoader.OnStateChangedThread,
Sub(Raw As LoaderBase, NewState As LoadState, OldState As LoadState) Sub(Raw As LoaderBase, NewState As LoadState, OldState As LoadState)
If (NewState = LoadState.Failed OrElse NewState = LoadState.Aborted) AndAlso LastJavaBaseDir IsNot Nothing Then If (NewState = LoadState.Failed OrElse NewState = LoadState.Interrupted) AndAlso LastJavaBaseDir IsNot Nothing Then
Log($"[Java] 由于下载未完成,清理未下载完成的 Java 文件:{LastJavaBaseDir}", LogLevel.Debug) Log($"[Java] 由于下载未完成,清理未下载完成的 Java 文件:{LastJavaBaseDir}", LogLevel.Debug)
DeleteDirectory(LastJavaBaseDir) DeleteDirectory(LastJavaBaseDir)
ElseIf NewState = LoadState.Finished Then ElseIf NewState = LoadState.Finished Then
File diff suppressed because it is too large Load Diff
@@ -5,9 +5,24 @@ Public Module ModMinecraft
#Region "文件夹" #Region "文件夹"
''' <summary> ''' <summary>
''' 当前的 Minecraft 文件夹路径,以“\”结尾。 ''' 当前的 Minecraft 文件夹路径,以 \ 结尾。
''' </summary> ''' </summary>
Public McFolderSelected As String Public Property McFolderSelected As String
Get
If _McFolderSelected Is Nothing Then SetMcFolder(Settings.Get("LaunchFolderSelect")) '不能使用 McFolderSelected 触发 Set,这会被视为为 Get 设置返回值
Return _McFolderSelected
End Get
Set(Value As String)
SetMcFolder(Value)
End Set
End Property
Private Sub SetMcFolder(Value As String) '等同 McFolderSelected.Set
If _McFolderSelected = Value Then Return
_McFolderSelected = Value.Replace("$", Path)
Settings.Set("LaunchFolderSelect", Value.Replace(Path, "$"))
Log("[Minecraft] 当前选择的 Minecraft 文件夹:" & _McFolderSelected)
End Sub
Private _McFolderSelected As String
''' <summary> ''' <summary>
''' 当前的 Minecraft 文件夹列表。 ''' 当前的 Minecraft 文件夹列表。
''' </summary> ''' </summary>
@@ -22,15 +37,15 @@ Public Module ModMinecraft
Public Location As String Public Location As String
Public Type As Types Public Type As Types
Public Enum Types Public Enum Types
Original Vanilla
RenamedOriginal RenamedVanilla
Custom Custom
End Enum End Enum
Public Overrides Function Equals(obj As Object) As Boolean Public Overrides Function Equals(obj As Object) As Boolean
If Not (TypeOf obj Is McFolder) Then Return False If Not (TypeOf obj Is McFolder) Then Return False
Dim folder = DirectCast(obj, McFolder) Dim Folder = DirectCast(obj, McFolder)
Return Name = folder.Name AndAlso Location = folder.Location AndAlso Type = folder.Type Return Name = Folder.Name AndAlso Location = Folder.Location AndAlso Type = Folder.Type
End Function End Function
Public Overrides Function ToString() As String Public Overrides Function ToString() As String
Return Location Return Location
@@ -50,9 +65,9 @@ Public Module ModMinecraft
'扫描当前文件夹 '扫描当前文件夹
Try Try
If Directory.Exists(Path & "versions\") Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = Path, .Type = McFolder.Types.Original}) If Directory.Exists(Path & "versions\") Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = Path, .Type = McFolder.Types.Vanilla})
For Each Folder As DirectoryInfo In New DirectoryInfo(Path).GetDirectories For Each Folder As DirectoryInfo In New DirectoryInfo(Path).GetDirectories
If Directory.Exists(Folder.FullName & "versions\") OrElse Folder.Name = ".minecraft" Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = Folder.FullName & "\", .Type = McFolder.Types.Original}) If Directory.Exists(Folder.FullName & "versions\") OrElse Folder.Name = ".minecraft" Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = Folder.FullName & "\", .Type = McFolder.Types.Vanilla})
Next Next
Catch ex As Exception Catch ex As Exception
Log(ex, "扫描 PCL 所在文件夹中是否有 MC 文件夹失败") Log(ex, "扫描 PCL 所在文件夹中是否有 MC 文件夹失败")
@@ -62,7 +77,7 @@ Public Module ModMinecraft
Dim MojangPath As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\" Dim MojangPath As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\"
If (Not CacheMcFolderList.Any OrElse MojangPath <> CacheMcFolderList(0).Location) AndAlso '当前文件夹不是官启文件夹 If (Not CacheMcFolderList.Any OrElse MojangPath <> CacheMcFolderList(0).Location) AndAlso '当前文件夹不是官启文件夹
Directory.Exists(MojangPath & "versions\") Then '具有权限且存在 versions 文件夹 Directory.Exists(MojangPath & "versions\") Then '具有权限且存在 versions 文件夹
CacheMcFolderList.Add(New McFolder With {.Name = "官方启动器文件夹", .Location = MojangPath, .Type = McFolder.Types.Original}) CacheMcFolderList.Add(New McFolder With {.Name = "官方启动器文件夹", .Location = MojangPath, .Type = McFolder.Types.Vanilla})
End If End If
#End Region #End Region
@@ -70,54 +85,51 @@ Public Module ModMinecraft
#Region "读取自定义(Custom)文件夹,可能没有结果" #Region "读取自定义(Custom)文件夹,可能没有结果"
'格式:TMZ 12>C://xxx/xx/|Test>D://xxx/xx/|名称>路径 '格式:TMZ 12>C://xxx/xx/|Test>D://xxx/xx/|名称>路径
For Each Folder As String In Setup.Get("LaunchFolders").Split("|") For Each Folder As String In Settings.Get("LaunchFolders").ToString.Split({"|"c}, StringSplitOptions.RemoveEmptyEntries)
If Folder = "" Then Continue For If Folder = "" Then Continue For
If Not Folder.Contains(">") OrElse Not Folder.EndsWithF("\") Then If Not Folder.Contains(">") OrElse Not Folder.EndsWithF("\") Then
Hint("无效的 Minecraft 文件夹:" & Folder, HintType.Red) Hint("无效的 Minecraft 文件夹:" & Folder, HintType.Red)
Continue For Continue For
End If End If
Dim Name As String = Folder.Split(">")(0) Dim FolderName As String = Folder.BeforeFirst(">"), FolderPath As String = Folder.AfterFirst(">")
Dim Path As String = Folder.Split(">")(1)
Try Try
CheckPermissionWithException(Path) CheckPermissionWithException(FolderPath)
'若已有该文件夹,则直接重命名;没有则添加 '若已有该文件夹,则直接重命名;没有则添加
Dim Renamed As Boolean = False Dim Renamed As Boolean = False
For Each OriginalFolder As McFolder In CacheMcFolderList For Each OriginalFolder As McFolder In CacheMcFolderList
If OriginalFolder.Location = Path Then If OriginalFolder.Location = FolderPath Then
OriginalFolder.Name = Name OriginalFolder.Name = FolderName
OriginalFolder.Type = McFolder.Types.RenamedOriginal OriginalFolder.Type = McFolder.Types.RenamedVanilla
Renamed = True Renamed = True
End If End If
Next Next
If Not Renamed Then CacheMcFolderList.Add(New McFolder With {.Name = Name, .Location = Path, .Type = McFolder.Types.Custom}) If Not Renamed Then CacheMcFolderList.Add(New McFolder With {.Name = FolderName, .Location = FolderPath, .Type = McFolder.Types.Custom})
Catch ex As Exception Catch ex As Exception
MyMsgBox("失效的 Minecraft 文件夹:" & vbCrLf & Path & vbCrLf & vbCrLf & ex.GetBrief(), "Minecraft 文件夹失效", IsWarn:=True) MyMsgBox("失效的 Minecraft 文件夹:" & vbCrLf & FolderPath & vbCrLf & vbCrLf & ex.GetBrief(), "Minecraft 文件夹失效", IsWarn:=True)
Log(ex, $"无法访问 Minecraft 文件夹 {Path}") Log(ex, $"无法访问 Minecraft 文件夹 {FolderPath}")
End Try End Try
Next Next
'将自定义文件夹情况同步到设置 '将自定义文件夹情况同步到设置
Dim NewSetup As New List(Of String) Dim NewSetup As New List(Of String)
For Each Folder As McFolder In CacheMcFolderList For Each Folder As McFolder In CacheMcFolderList
If Not Folder.Type = McFolder.Types.Original Then NewSetup.Add(Folder.Name & ">" & Folder.Location) If Not Folder.Type = McFolder.Types.Vanilla Then NewSetup.Add(Folder.Name & ">" & Folder.Location)
Next Next
If Not NewSetup.Any() Then NewSetup.Add("") '防止 0 元素 Join 返回 Nothing If Not NewSetup.Any() Then NewSetup.Add("") '防止 0 元素 Join 返回 Nothing
Setup.Set("LaunchFolders", Join(NewSetup, "|")) Settings.Set("LaunchFolders", NewSetup.Join("|"c))
#End Region #End Region
'若没有可用文件夹,则创建 .minecraft '若没有可用文件夹,则创建 .minecraft
If Not CacheMcFolderList.Any() Then If Not CacheMcFolderList.Any() Then
Directory.CreateDirectory(Path & ".minecraft\versions\") Directory.CreateDirectory(Path & ".minecraft\versions\")
CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = Path & ".minecraft\", .Type = McFolder.Types.Original}) CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = Path & ".minecraft\", .Type = McFolder.Types.Vanilla})
End If End If
For Each Folder As McFolder In CacheMcFolderList For Each Folder As McFolder In CacheMcFolderList
#Region "更新 launcher_profiles.json"
McFolderLauncherProfilesJsonCreate(Folder.Location) McFolderLauncherProfilesJsonCreate(Folder.Location)
#End Region
Next Next
If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 2000)) If Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 2000))
'回设 '回设
McFolderList = CacheMcFolderList McFolderList = CacheMcFolderList
@@ -158,7 +170,7 @@ Public Module ModMinecraft
#Region "版本处理" #Region "版本处理"
Public Const McInstanceCacheVersion As Integer = 33 Public Const McInstanceCacheVersion As Integer = 35
Private _McInstanceSelected As McInstance Private _McInstanceSelected As McInstance
''' <summary> ''' <summary>
@@ -173,30 +185,34 @@ Public Module ModMinecraft
If ReferenceEquals(_McInstanceSelectedLast, value) Then Return If ReferenceEquals(_McInstanceSelectedLast, value) Then Return
_McInstanceSelected = value '由于有可能是 Nothing,导致无法初始化,才得这样弄一圈 _McInstanceSelected = value '由于有可能是 Nothing,导致无法初始化,才得这样弄一圈
_McInstanceSelectedLast = value _McInstanceSelectedLast = value
Settings.MakeInstanceDirty()
'更新 MC 文件夹所选取的 Minecraft 版本
Log("[Launch] 当前选择的 Minecraft 版本:" & If(value?.PathVersion, "无"))
WriteIni(McFolderSelected & "PCL.ini", "Version", If(value?.Name, ""))
If value Is Nothing Then Return If value Is Nothing Then Return
'重置缓存的下载文件夹 '重置缓存的下载文件夹
PageDownloadCompDetail.CachedFolder.Clear() PageDownloadCompDetail.CachedFolder.Clear()
'统一通行证重判 '统一通行证重判
If AniControlEnabled = 0 AndAlso If AniControlEnabled = 0 AndAlso
Setup.Get("VersionServerNide", Instance:=value) <> Setup.Get("CacheNideServer") AndAlso Settings.Get("VersionServerNide", Instance:=value) <> Settings.Get("CacheNideServer") AndAlso
Setup.Get("VersionServerLogin", Instance:=value) = 3 Then Settings.Get("VersionServerLogin", Instance:=value) = 3 Then
Setup.Set("CacheNideAccess", "") Settings.Set("CacheNideAccess", "")
Log("[Launch] 服务器改变,要求重新登录统一通行证") Log("[Launch] 服务器改变,要求重新登录统一通行证")
End If End If
If Setup.Get("VersionServerLogin", Instance:=value) = 3 Then If Settings.Get("VersionServerLogin", Instance:=value) = 3 Then
Setup.Set("CacheNideServer", Setup.Get("VersionServerNide", Instance:=value)) Settings.Set("CacheNideServer", Settings.Get("VersionServerNide", Instance:=value))
End If End If
'Authlib-Injector 重判 'Authlib-Injector 重判
If AniControlEnabled = 0 AndAlso If AniControlEnabled = 0 AndAlso
Setup.Get("VersionServerAuthServer", Instance:=value) <> Setup.Get("CacheAuthServerServer") AndAlso Settings.Get("VersionServerAuthServer", Instance:=value) <> Settings.Get("CacheAuthServerServer") AndAlso
Setup.Get("VersionServerLogin", Instance:=value) = 4 Then Settings.Get("VersionServerLogin", Instance:=value) = 4 Then
Setup.Set("CacheAuthAccess", "") Settings.Set("CacheAuthAccess", "")
Log("[Launch] 服务器改变,要求重新登录 Authlib-Injector") Log("[Launch] 服务器改变,要求重新登录 Authlib-Injector")
End If End If
If Setup.Get("VersionServerLogin", Instance:=value) = 4 Then If Settings.Get("VersionServerLogin", Instance:=value) = 4 Then
Setup.Set("CacheAuthServerServer", Setup.Get("VersionServerAuthServer", Instance:=value)) Settings.Set("CacheAuthServerServer", Settings.Get("VersionServerAuthServer", Instance:=value))
Setup.Set("CacheAuthServerName", Setup.Get("VersionServerAuthName", Instance:=value)) Settings.Set("CacheAuthServerName", Settings.Get("VersionServerAuthName", Instance:=value))
Setup.Set("CacheAuthServerRegister", Setup.Get("VersionServerAuthRegister", Instance:=value)) Settings.Set("CacheAuthServerRegister", Settings.Get("VersionServerAuthRegister", Instance:=value))
End If End If
End Set End Set
End Property End Property
@@ -212,15 +228,15 @@ Public Module ModMinecraft
''' </summary> ''' </summary>
Public ReadOnly Property PathIndie As String Public ReadOnly Property PathIndie As String
Get Get
If Setup.IsUnset("VersionArgumentIndieV2", Instance:=Me) Then If Not Settings.HasSaved("VersionArgumentIndieV2", Instance:=Me) Then
If Not IsLoaded Then Load() If Not IsLoaded Then Load()
'决定该版本是否应该被隔离 '决定该版本是否应该被隔离
Dim ShouldBeIndie = Dim ShouldBeIndie =
Function() As Boolean Function() As Boolean
'从老的版本独立设置中迁移:-1 未决定,0 使用全局设置,1 手动开启,2 手动关闭 '从老的版本独立设置中迁移:-1 未决定,0 使用全局设置,1 手动开启,2 手动关闭
If Not Setup.IsUnset("VersionArgumentIndie", Instance:=Me) AndAlso Setup.Get("VersionArgumentIndie", Instance:=Me) > 0 Then If Settings.HasSaved("VersionArgumentIndie", Instance:=Me) AndAlso Settings.Get("VersionArgumentIndie", Instance:=Me) > 0 Then
Log($"[Minecraft] 版本隔离初始化({Name}):从老的版本独立设置中迁移") Log($"[Minecraft] 版本隔离初始化({Name}):从老的版本独立设置中迁移")
Return Setup.Get("VersionArgumentIndie", Instance:=Me) = 1 Return Settings.Get("VersionArgumentIndie", Instance:=Me) = 1
End If End If
'若版本文件夹下包含 mods 或 saves 文件夹,则自动开启版本隔离 '若版本文件夹下包含 mods 或 saves 文件夹,则自动开启版本隔离
Dim ModFolder As New DirectoryInfo(PathVersion & "mods\") Dim ModFolder As New DirectoryInfo(PathVersion & "mods\")
@@ -231,8 +247,8 @@ Public Module ModMinecraft
End If End If
'根据全局的默认设置决定是否隔离 '根据全局的默认设置决定是否隔离
Dim IsRelease As Boolean = State <> McInstanceState.Fool AndAlso State <> McInstanceState.Old AndAlso State <> McInstanceState.Snapshot Dim IsRelease As Boolean = State <> McInstanceState.Fool AndAlso State <> McInstanceState.Old AndAlso State <> McInstanceState.Snapshot
Log($"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Setup.Get("LaunchArgumentIndieV2")})判断,State {GetStringFromEnum(State)},IsRelease {IsRelease},Modable {Modable}") Log($"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Settings.Get("LaunchArgumentIndieV2")})判断,State {GetStringFromEnum(State)},IsRelease {IsRelease},Modable {Modable}")
Select Case Setup.Get("LaunchArgumentIndieV2") Select Case Settings.Get("LaunchArgumentIndieV2")
Case 0 '关闭 Case 0 '关闭
Return False Return False
Case 1 '仅隔离可安装 Mod 的版本 Case 1 '仅隔离可安装 Mod 的版本
@@ -245,9 +261,9 @@ Public Module ModMinecraft
Return True Return True
End Select End Select
End Function End Function
Setup.Set("VersionArgumentIndieV2", ShouldBeIndie(), Instance:=Me) Settings.Set("VersionArgumentIndieV2", ShouldBeIndie(), Instance:=Me)
End If End If
Return If(Setup.Get("VersionArgumentIndieV2", Instance:=Me), PathVersion, McFolderSelected) Return If(Settings.Get("VersionArgumentIndieV2", Instance:=Me), PathVersion, McFolderSelected)
End Get End Get
End Property End Property
@@ -428,21 +444,7 @@ Public Module ModMinecraft
VersionSearchFinish: VersionSearchFinish:
'获取版本号 '获取版本号
_Version.VanillaName = _Version.VanillaName.Replace("_unobfuscated", "").Replace(" Unobfuscated", "") _Version.VanillaName = _Version.VanillaName.Replace("_unobfuscated", "").Replace(" Unobfuscated", "")
If _Version.VanillaName.StartsWithF("1.") Then _Version.Vanilla = McVersion.NameToVersion(_Version.VanillaName)
Dim Segments = _Version.VanillaName.Split(" _-.".ToCharArray)
_Version.Vanilla = New Version(
Val(If(Segments.Count >= 2, Segments(1), "0")),
0,
Val(If(Segments.Count >= 3, Segments(2), "0")))
ElseIf RegexCheck(_Version.VanillaName, "^[2-9][0-9]\.") Then
Dim Segments = _Version.VanillaName.Split(" _-.".ToCharArray)
_Version.Vanilla = New Version(
Val(Segments(0)),
Val(If(Segments.Count >= 2, Segments(1), "0")),
Val(If(Segments.Count >= 3, Segments(2), "0")))
Else
_Version.Vanilla = New Version(9999, 0, 0)
End If
Return _Version Return _Version
End Get End Get
Set(value As McVersion) Set(value As McVersion)
@@ -471,6 +473,7 @@ VersionSearchFinish:
If Not JsonCandidate.ContainsKey("type") Then Continue For If Not JsonCandidate.ContainsKey("type") Then Continue For
If Not JsonCandidate.ContainsKey("id") Then Continue For If Not JsonCandidate.ContainsKey("id") Then Continue For
Catch Catch
Continue For
End Try End Try
JsonPath = JsonCandidatePath JsonPath = JsonCandidatePath
Exit For Exit For
@@ -691,7 +694,7 @@ Recheck:
End Try End Try
'确认 Json 可用性 '确认 Json 可用性
Try Try
Dim JsonObjCheck = JsonObject If JsonObject("mainClass") Is Nothing Then Throw New Exception("版本 JSON 中没有 mainClass 项!") '这里也会触发 JsonObject 的 Get 事件
Catch ex As Exception Catch ex As Exception
Log(ex, "版本 JSON 可用性检查失败(" & PathVersion & ")") Log(ex, "版本 JSON 可用性检查失败(" & PathVersion & ")")
JsonText = "" JsonText = ""
@@ -744,7 +747,11 @@ Recheck:
Case Else '根据 API 进行筛选 Case Else '根据 API 进行筛选
Dim RealJson As String = If(JsonObject, JsonText).ToString Dim RealJson As String = If(JsonObject, JsonText).ToString
'愚人节与快照版本 '愚人节与快照版本
If If(JsonObject("type"), "").ToString = "fool" OrElse GetMcFoolName(Version.VanillaName) <> "" Then Dim FixedReleaseTime = ReleaseTime.ToUniversalTime().AddHours(2)
Dim JsonType = If(JsonObject("type"), "").ToString
If JsonType = "fool" OrElse
(FixedReleaseTime.Month = 4 AndAlso FixedReleaseTime.Day = 1 AndAlso JsonType = "snapshot") OrElse
GetMcFoolName(Version.VanillaName) <> "" Then
State = McInstanceState.Fool State = McInstanceState.Fool
ElseIf IsSnapshot() Then ElseIf IsSnapshot() Then
State = McInstanceState.Snapshot State = McInstanceState.Snapshot
@@ -816,8 +823,8 @@ ExitDataLoad:
If State = McInstanceState.Fool Then If State = McInstanceState.Fool Then
Info = GetMcFoolName(Version.VanillaName) Info = GetMcFoolName(Version.VanillaName)
ElseIf State <> McInstanceState.Error Then ElseIf State <> McInstanceState.Error Then
If Setup.Get("VersionServerLogin", Instance:=Me) = 3 Then Info += ", 统一通行证验证" If Settings.Get("VersionServerLogin", Instance:=Me) = 3 Then Info += ", 统一通行证验证"
If Setup.Get("VersionServerLogin", Instance:=Me) = 4 Then Info += ", Authlib 验证" If Settings.Get("VersionServerLogin", Instance:=Me) = 4 Then Info += ", Authlib 验证"
End If End If
End If End If
'确定版本收藏状态 '确定版本收藏状态
@@ -913,7 +920,7 @@ ExitDataLoad:
End If End If
'Logo 'Logo
Try Try
If Logo.EndsWith("PCL\Logo.png") Then If Logo.EndsWithF("PCL\Logo.png") Then
NewItem.Logo = PathVersion & "PCL\Logo.png" '修复老版本中,存储的自定义 Logo 使用完整路径,导致移动后无法加载的 Bug NewItem.Logo = PathVersion & "PCL\Logo.png" '修复老版本中,存储的自定义 Logo 使用完整路径,导致移动后无法加载的 Bug
Else Else
NewItem.Logo = Logo NewItem.Logo = Logo
@@ -967,7 +974,7 @@ ExitDataLoad:
Public VanillaName As String Public VanillaName As String
''' <summary> ''' <summary>
''' 可比较的三段式原版版本号。 ''' 可比较的三段式原版版本号。
''' 对老版本格式,例如 1.20.3,会被转换为 20.0.3。 ''' 对老版本格式,例如 1.20.1,会被转换为 20.0.1。
''' 若没有版本号,例如旧快照,则为 9999.0.0。 ''' 若没有版本号,例如旧快照,则为 9999.0.0。
''' </summary> ''' </summary>
Public Vanilla As Version Public Vanilla As Version
@@ -1011,7 +1018,7 @@ ExitDataLoad:
Get Get
If String.IsNullOrEmpty(OptiFine) OrElse OptiFine = "未知版本" Then Return 0 If String.IsNullOrEmpty(OptiFine) OrElse OptiFine = "未知版本" Then Return 0
'字母编号,如 G2 中的 G(7) '字母编号,如 G2 中的 G(7)
Dim Result As Integer = Asc(OptiFine.ToUpper.First) - Asc("A"c) + 1 Dim Result As Integer = Asc(OptiFine.Upper.First) - Asc("A"c) + 1
'末尾数字,如 C5 beta4 中的 5 '末尾数字,如 C5 beta4 中的 5
Result *= 100 Result *= 100
Result += Val(RegexSeek(Right(OptiFine, OptiFine.Length - 1), "[0-9]+")) Result += Val(RegexSeek(Right(OptiFine, OptiFine.Length - 1), "[0-9]+"))
@@ -1022,7 +1029,7 @@ ExitDataLoad:
If Val(Right(OptiFine, 1)) = 0 AndAlso Right(OptiFine, 1) <> "0" Then If Val(Right(OptiFine, 1)) = 0 AndAlso Right(OptiFine, 1) <> "0" Then
Result += 1 '为 pre 或 beta 结尾,视作 1 Result += 1 '为 pre 或 beta 结尾,视作 1
Else Else
Result += Val(RegexSeek(OptiFine.ToLower, "(?<=((pre)|(beta)))[0-9]+")) Result += Val(RegexSeek(OptiFine.Lower, "(?<=((pre)|(beta)))[0-9]+"))
End If End If
Else Else
Result += 99 Result += 99
@@ -1054,7 +1061,7 @@ ExitDataLoad:
''' </summary> ''' </summary>
Public Forge As String = "" Public Forge As String = ""
''' <summary> ''' <summary>
''' NeoForge 版本名,如 21.0.2-beta、47.1.79。 ''' NeoForge 版本名,如 47.1.79、21.0.2-beta、26.1.0.0-alpha.14+snapshot-11。
''' </summary> ''' </summary>
Public NeoForge As String = "" Public NeoForge As String = ""
''' <summary> ''' <summary>
@@ -1105,27 +1112,18 @@ ExitDataLoad:
Public Shared Function IsFormatFit(Version As String) As Boolean Public Shared Function IsFormatFit(Version As String) As Boolean
If Version Is Nothing Then Return False If Version Is Nothing Then Return False
If RegexCheck(Version, "^1\.\d") Then Return True If RegexCheck(Version, "^1\.\d") Then Return True
If Val(RegexSeek(Version, "^[2-9]\d\.\d+")) > 25 Then Return True If Val(RegexSeek(Version, "^[2-9]\d\.\d+")) >= 26 Then Return True
Return False Return False
End Function End Function
''' <summary> ''' <summary>
''' 尝试将版本字符串转换为 Drop 序数。 ''' 将版本名转换为 Drop 序数。
''' 若无法转换则返回 0。 ''' 若无法转换则返回 209。
''' </summary> ''' </summary>
Public Shared Function VersionToDrop(Version As String, Optional AllowSnapshot As Boolean = False) As Integer Public Shared Function VersionToDrop(VanillaName As String) As Integer
If Not AllowSnapshot AndAlso Version.Contains("-") Then Return 0 If VanillaName Is Nothing Then Return 209
If Version Is Nothing Then Return 0 Dim Version = NameToVersion(VanillaName)
Dim Segments = Version.BeforeFirst("-").Split(".") If Version.Major >= 1000 Then Return 209
If Segments.Length < 2 Then Return 0 Return Version.Major * 10 + Version.Minor
Dim Major As Integer = Val(Segments(0))
Dim Minor As Integer = Val(Segments(1))
If Major = 1 Then
Return Minor * 10
ElseIf Major < 25 Then
Return 0
Else
Return Major * 10 + Minor
End If
End Function End Function
''' <summary> ''' <summary>
''' 将 Drop 序数转换为版本字符串。 ''' 将 Drop 序数转换为版本字符串。
@@ -1133,10 +1131,36 @@ ExitDataLoad:
Public Shared Function DropToVersion(Drop As Integer) As String Public Shared Function DropToVersion(Drop As Integer) As String
If Drop >= 250 Then If Drop >= 250 Then
Return $"{Drop \ 10}.{Drop Mod 10}" Return $"{Drop \ 10}.{Drop Mod 10}"
ElseIf Drop = 209 Then
Log("[Minecraft] 尝试将旧快照版 Drop 序数转换为版本字符串,这不应该发生!" & vbCrLf & GetStackTrace(), LogLevel.Debug)
Return "1.20"
Else Else
Return $"1.{Drop \ 10}" Return $"1.{Drop \ 10}"
End If End If
End Function End Function
''' <summary>
''' 将版本名转换为可比较的三段式原版版本号。
''' 对老版本格式,例如 1.20.3,会被转换为 20.0.3。
''' 若没有版本号,例如旧快照,则为 9999.0.0。
''' </summary>
Public Shared Function NameToVersion(VanillaName As String) As Version
VanillaName = VanillaName.Replace("_unobfuscated", "").Replace(" Unobfuscated", "")
If VanillaName.StartsWithF("1.") Then
Dim Segments = VanillaName.Split(" _-.".ToCharArray)
Return New Version(
Val(If(Segments.Count >= 2, Segments(1), "0")),
0,
Val(If(Segments.Count >= 3, Segments(2), "0")))
ElseIf RegexCheck(VanillaName, "^[2-9][0-9]\.") Then
Dim Segments = VanillaName.Split(" _-.".ToCharArray)
Return New Version(
Val(Segments(0)),
Val(If(Segments.Count >= 2, Segments(1), "0")),
Val(If(Segments.Count >= 3, Segments(2), "0")))
Else
Return New Version(9999, 0, 0)
End If
End Function
End Class End Class
@@ -1144,7 +1168,7 @@ ExitDataLoad:
''' 根据版本名获取对应的愚人节版本描述。非愚人节版本会返回空字符串。 ''' 根据版本名获取对应的愚人节版本描述。非愚人节版本会返回空字符串。
''' </summary> ''' </summary>
Public Function GetMcFoolName(Name As String) As String Public Function GetMcFoolName(Name As String) As String
Name = Name.ToLower Name = Name.Lower
If Name.StartsWithF("2.0") Then If Name.StartsWithF("2.0") Then
Return "2013 | 这个秘密计划了两年的更新将游戏推向了一个新高度!" Return "2013 | 这个秘密计划了两年的更新将游戏推向了一个新高度!"
ElseIf Name = "15w14a" Then ElseIf Name = "15w14a" Then
@@ -1163,6 +1187,8 @@ ExitDataLoad:
Return "2024 | 毒马铃薯一直都被大家忽视和低估,于是我们超级加强了它!" Return "2024 | 毒马铃薯一直都被大家忽视和低估,于是我们超级加强了它!"
ElseIf Name = "25w14craftmine" Then ElseIf Name = "25w14craftmine" Then
Return "2025 | 你可以合成任何东西——包括合成你的世界!" Return "2025 | 你可以合成任何东西——包括合成你的世界!"
ElseIf Name = "26w14a" Then
Return "2026 | 为什么需要物品栏?让方块们跟着你走吧!"
Else Else
Return "" Return ""
End If End If
@@ -1215,7 +1241,7 @@ ExitDataLoad:
GoTo OnLoaded GoTo OnLoaded
End If End If
'有可用版本 '有可用版本
Dim FolderListCheck As Integer = GetHash(McInstanceCacheVersion & "#" & Join(FolderList.ToArray, "#")) Mod (Integer.MaxValue - 1) '根据文件夹名列表生成辨识码 Dim FolderListCheck As Integer = GetHash(McInstanceCacheVersion & "#" & FolderList.Join("#"c)) Mod (Integer.MaxValue - 1) '根据文件夹名列表生成辨识码
If Not McInstanceListForceRefresh AndAlso Val(ReadIni(PathMc & "PCL.ini", "InstanceCache")) = FolderListCheck Then If Not McInstanceListForceRefresh AndAlso Val(ReadIni(PathMc & "PCL.ini", "InstanceCache")) = FolderListCheck Then
'可以使用缓存 '可以使用缓存
Dim Result = InitMcInstanceListWithCache(PathMc) Dim Result = InitMcInstanceListWithCache(PathMc)
@@ -1236,7 +1262,7 @@ Reload:
'改变当前选择的版本 '改变当前选择的版本
OnLoaded: OnLoaded:
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
If McInstanceList.Any(Function(v) v.Key <> McInstanceCardType.Error) Then If McInstanceList.Any(Function(v) v.Key <> McInstanceCardType.Error) Then
'尝试读取已储存的选择 '尝试读取已储存的选择
Dim SavedSelection As String = ReadIni(PathMc & "PCL.ini", "Version") Dim SavedSelection As String = ReadIni(PathMc & "PCL.ini", "Version")
@@ -1246,7 +1272,6 @@ OnLoaded:
If Instance.Name = SavedSelection AndAlso Not Instance.State = McInstanceState.Error Then If Instance.Name = SavedSelection AndAlso Not Instance.State = McInstanceState.Error Then
'使用已储存的选择 '使用已储存的选择
McInstanceSelected = Instance McInstanceSelected = Instance
Setup.Set("LaunchVersionSelect", McInstanceSelected.Name)
Log("[Minecraft] 选择该文件夹储存的 Minecraft 版本:" & McInstanceSelected.PathVersion) Log("[Minecraft] 选择该文件夹储存的 Minecraft 版本:" & McInstanceSelected.PathVersion)
Return Return
End If End If
@@ -1256,18 +1281,16 @@ OnLoaded:
If Not McInstanceList.First.Value(0).State = McInstanceState.Error Then If Not McInstanceList.First.Value(0).State = McInstanceState.Error Then
'自动选择第一项 '自动选择第一项
McInstanceSelected = McInstanceList.First.Value(0) McInstanceSelected = McInstanceList.First.Value(0)
Setup.Set("LaunchVersionSelect", McInstanceSelected.Name)
Log("[Launch] 自动选择 Minecraft 版本:" & McInstanceSelected.PathVersion) Log("[Launch] 自动选择 Minecraft 版本:" & McInstanceSelected.PathVersion)
End If End If
Else Else
McInstanceSelected = Nothing McInstanceSelected = Nothing
Setup.Set("LaunchVersionSelect", "")
Log("[Minecraft] 未找到可用 Minecraft 版本") Log("[Minecraft] 未找到可用 Minecraft 版本")
End If End If
If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 3000)) If Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 3000))
Catch ex As ThreadInterruptedException Catch ex As ThreadInterruptedException
Catch ex As Exception Catch ex As Exception
If Loader.IsAborted Then Return '#5617 If Loader.IsInterrupted Then Return '#5617
WriteIni(PathMc & "PCL.ini", "InstanceCache", "") '要求下次重新加载 WriteIni(PathMc & "PCL.ini", "InstanceCache", "") '要求下次重新加载
Log(ex, "加载 .minecraft 版本列表失败", LogLevel.Feedback) Log(ex, "加载 .minecraft 版本列表失败", LogLevel.Feedback)
End Try End Try
@@ -1425,7 +1448,7 @@ OnLoaded:
'确认最新版本,若为快照则加入常用列表 '确认最新版本,若为快照则加入常用列表
Dim LargestInstance As McInstance = InstanceList. Dim LargestInstance As McInstance = InstanceList.
Where(Function(v) v.State = McInstanceState.Original OrElse v.State = McInstanceState.Snapshot). Where(Function(v) v.State = McInstanceState.Original OrElse v.State = McInstanceState.Snapshot).
MaxOf(Function(v) v.ReleaseTime) MaxBy(Function(v) v.ReleaseTime)
If LargestInstance IsNot Nothing AndAlso LargestInstance.State = McInstanceState.Snapshot Then If LargestInstance IsNot Nothing AndAlso LargestInstance.State = McInstanceState.Snapshot Then
InstanceUseful.Add(LargestInstance) InstanceUseful.Add(LargestInstance)
InstanceList.Remove(LargestInstance) InstanceList.Remove(LargestInstance)
@@ -1641,9 +1664,9 @@ OnLoaded:
Case "Mojang", "Ms" Case "Mojang", "Ms"
Url = "https://sessionserver.mojang.com/session/minecraft/profile/" Url = "https://sessionserver.mojang.com/session/minecraft/profile/"
Case "Nide" Case "Nide"
Url = "https://auth.mc-user.com:233/" & If(McInstanceSelected Is Nothing, Setup.Get("CacheNideServer"), Setup.Get("VersionServerNide", Instance:=McInstanceSelected)) & "/sessionserver/session/minecraft/profile/" Url = "https://auth.mc-user.com:233/" & If(McInstanceSelected Is Nothing, Settings.Get("CacheNideServer"), Settings.Get("VersionServerNide", Instance:=McInstanceSelected)) & "/sessionserver/session/minecraft/profile/"
Case "Auth" Case "Auth"
Url = If(McInstanceSelected Is Nothing, Setup.Get("CacheAuthServerServer"), Setup.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/sessionserver/session/minecraft/profile/" Url = If(McInstanceSelected Is Nothing, Settings.Get("CacheAuthServerServer"), Settings.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/sessionserver/session/minecraft/profile/"
Case Else Case Else
Throw New ArgumentException("皮肤地址种类无效:" & If(Type, "null")) Throw New ArgumentException("皮肤地址种类无效:" & If(Type, "null"))
End Select End Select
@@ -1664,7 +1687,7 @@ OnLoaded:
Throw New Exception("皮肤返回值中不包含皮肤数据项,可能是未设置自定义皮肤的用户", ex) Throw New Exception("皮肤返回值中不包含皮肤数据项,可能是未设置自定义皮肤的用户", ex)
End Try End Try
SkinString = Encoding.GetEncoding("utf-8").GetString(Convert.FromBase64String(SkinValue)) SkinString = Encoding.GetEncoding("utf-8").GetString(Convert.FromBase64String(SkinValue))
Dim SkinJson As JObject = GetJson(SkinString.ToLower) Dim SkinJson As JObject = GetJson(SkinString.Lower)
If SkinJson("textures") Is Nothing OrElse SkinJson("textures")("skin") Is Nothing OrElse SkinJson("textures")("skin")("url") Is Nothing Then If SkinJson("textures") Is Nothing OrElse SkinJson("textures")("skin") Is Nothing OrElse SkinJson("textures")("skin")("url") Is Nothing Then
Throw New Exception("用户未设置自定义皮肤") Throw New Exception("用户未设置自定义皮肤")
Else Else
@@ -1688,7 +1711,7 @@ OnLoaded:
If Not File.Exists(FileAddress) Then If Not File.Exists(FileAddress) Then
NetDownloadByClient(Address, FileAddress & ".PCLDownloading") NetDownloadByClient(Address, FileAddress & ".PCLDownloading")
File.Delete(FileAddress) File.Delete(FileAddress)
FileSystem.Rename(FileAddress & ".PCLDownloading", FileAddress) File.Move(FileAddress & ".PCLDownloading", FileAddress)
Log("[Minecraft] 皮肤下载成功:" & FileAddress) Log("[Minecraft] 皮肤下载成功:" & FileAddress)
End If End If
Return FileAddress Return FileAddress
@@ -1762,7 +1785,7 @@ OnLoaded:
If OriginalName Is Nothing Then Return Nothing If OriginalName Is Nothing Then Return Nothing
Dim Splited As New List(Of String)(OriginalName.Split(":")) Dim Splited As New List(Of String)(OriginalName.Split(":"))
Splited.RemoveAt(2) 'Java 的此格式下版本号固定为第三段,第四段可能包含架构、分包等其他信息 Splited.RemoveAt(2) 'Java 的此格式下版本号固定为第三段,第四段可能包含架构、分包等其他信息
Return Join(Splited, ":") Return Splited.Join(":"c)
End Get End Get
End Property End Property
''' <summary> ''' <summary>
@@ -2008,12 +2031,12 @@ OnLoaded:
Result.AddRange(McLibNetFilesFromTokens(McLibListGet(Instance, False))) Result.AddRange(McLibNetFilesFromTokens(McLibListGet(Instance, False)))
'统一通行证文件 '统一通行证文件
If Setup.Get("VersionServerLogin", Instance:=Instance) = 3 Then If Settings.Get("VersionServerLogin", Instance:=Instance) = 3 Then
Dim TargetFile As String = PathAppdata & "nide8auth.jar" Dim TargetFile As String = PathPure & "nide8auth.jar"
Try Try
'测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/ '测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/
Log("[Minecraft] 开始获取统一通行证下载信息") Log("[Minecraft] 开始获取统一通行证下载信息")
Dim DownloadInfo = GetJson(NetRequestByClientRetry("https://auth.mc-user.com:233/" & Setup.Get("VersionServerNide", Instance:=Instance), RequireJson:=True)) Dim DownloadInfo = GetJson(NetRequestByClientRetry("https://auth.mc-user.com:233/" & Settings.Get("VersionServerNide", Instance:=Instance), RequireJson:=True))
Result.Add(New NetFile( Result.Add(New NetFile(
Urls:={"https://login.mc-user.com:233/index/jar"}, Urls:={"https://login.mc-user.com:233/index/jar"},
LocalPath:=TargetFile, LocalPath:=TargetFile,
@@ -2028,7 +2051,7 @@ OnLoaded:
End If End If
'Authlib-Injector 文件 'Authlib-Injector 文件
If Setup.Get("VersionServerLogin", Instance:=Instance) = 4 Then If Settings.Get("VersionServerLogin", Instance:=Instance) = 4 Then
Dim TargetFile = PathPure & "authlib-injector.jar" Dim TargetFile = PathPure & "authlib-injector.jar"
Try Try
Log("[Minecraft] 开始获取 Authlib-Injector 下载信息") Log("[Minecraft] 开始获取 Authlib-Injector 下载信息")
@@ -2142,7 +2165,7 @@ OnLoaded:
''' 检查设置,是否应当忽略文件检查? ''' 检查设置,是否应当忽略文件检查?
''' </summary> ''' </summary>
Public Function ShouldIgnoreFileCheck(Instance As McInstance) Public Function ShouldIgnoreFileCheck(Instance As McInstance)
Return Setup.Get("VersionAdvanceAssetsV2", Instance:=Instance) OrElse (Setup.Get("VersionAdvanceAssets", Instance:=Instance) = 2) Return Settings.Get("VersionAdvanceAssetsV2", Instance:=Instance) OrElse (Settings.Get("VersionAdvanceAssets", Instance:=Instance) = 2)
End Function End Function
#End Region #End Region
@@ -2365,8 +2388,8 @@ OnLoaded:
If Left = "未知版本" AndAlso Right = "未知版本" Then Return 0 If Left = "未知版本" AndAlso Right = "未知版本" Then Return 0
If Left <> "未知版本" AndAlso Right = "未知版本" Then Return -1 If Left <> "未知版本" AndAlso Right = "未知版本" Then Return -1
End If End If
Left = Left.ToLowerInvariant Left = Left.Lower
Right = Right.ToLowerInvariant Right = Right.Lower
Dim Lefts = RegexSearch(Left.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+") Dim Lefts = RegexSearch(Left.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+")
Dim Rights = RegexSearch(Right.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+") Dim Rights = RegexSearch(Right.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+")
Dim i As Integer = 0 Dim i As Integer = 0
@@ -1,7 +1,7 @@
Imports System.IO.Compression Imports System.IO.Compression
Public Module ModMod Public Module ModMod
Private Const LocalModCacheVersion As Integer = 11 Private Const LocalModCacheVersion As Integer = 13
Public Class McMod Public Class McMod
@@ -79,7 +79,7 @@ Public Module ModMod
End Get End Get
Set(value As String) Set(value As String)
If _Name Is Nothing AndAlso value IsNot Nothing AndAlso Not value.Contains("modname") AndAlso If _Name Is Nothing AndAlso value IsNot Nothing AndAlso Not value.Contains("modname") AndAlso
value.ToLower <> "name" AndAlso value.Count > 1 AndAlso Val(value).ToString <> value Then value.Lower <> "name" AndAlso value.Count > 1 AndAlso Val(value).ToString <> value Then
_Name = value _Name = value
End If End If
End Set End Set
@@ -98,7 +98,7 @@ Public Module ModMod
If _Description Is Nothing AndAlso value IsNot Nothing AndAlso value.Count > 2 Then If _Description Is Nothing AndAlso value IsNot Nothing AndAlso value.Count > 2 Then
_Description = value.ToString.Trim(vbLf) _Description = value.ToString.Trim(vbLf)
'优化显示:若以 [a-zA-Z0-9] 结尾,加上小数点句号 '优化显示:若以 [a-zA-Z0-9] 结尾,加上小数点句号
If _Description.ToLower.LastIndexOfAny("qwertyuiopasdfghjklzxcvbnm0123456789") = _Description.Count - 1 Then _Description += "." If _Description.Lower.LastIndexOfAny("qwertyuiopasdfghjklzxcvbnm0123456789") = _Description.Count - 1 Then _Description += "."
End If End If
End Set End Set
End Property End Property
@@ -252,10 +252,10 @@ GotFabric:
End If End If
Loop Loop
End If End If
Value = Join(ValueLines, vbLf).Trim(vbLf).Replace(vbLf, vbCrLf) Value = ValueLines.Join(vbLf).Trim(vbLf).Replace(vbLf, vbCrLf)
ElseIf RawValue.ToLower = "true" OrElse RawValue.ToLower = "false" Then ElseIf RawValue.Lower = "true" OrElse RawValue.Lower = "false" Then
'布尔型 '布尔型
Value = (RawValue.ToLower = "true") Value = (RawValue.Lower = "true")
ElseIf Val(RawValue).ToString = RawValue Then ElseIf Val(RawValue).ToString = RawValue Then
'数字型 '数字型
Value = Val(RawValue) Value = Val(RawValue)
@@ -424,7 +424,7 @@ Finished:
''' </summary> ''' </summary>
Public ReadOnly Property CanUpdate As Boolean Public ReadOnly Property CanUpdate As Boolean
Get Get
Return Not Setup.Get("UiHiddenFunctionModUpdate") AndAlso Not Setup.Get("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance) AndAlso UpdateFile IsNot Nothing Return Not Settings.Get("UiHiddenFunctionModUpdate") AndAlso Not Settings.Get("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance) AndAlso UpdateFile IsNot Nothing
End Get End Get
End Property End Property
@@ -526,7 +526,7 @@ Finished:
''' 是否可能为前置 Mod。目前非常不准确。 ''' 是否可能为前置 Mod。目前非常不准确。
''' </summary> ''' </summary>
Public Function IsPresetMod() As Boolean Public Function IsPresetMod() As Boolean
Return DisplayName IsNot Nothing AndAlso (DisplayName.ToLower.Contains("core") OrElse DisplayName.ToLower.Contains("lib")) Return DisplayName IsNot Nothing AndAlso (DisplayName.Lower.Contains("core") OrElse DisplayName.Lower.Contains("lib"))
End Function End Function
''' <summary> ''' <summary>
@@ -534,7 +534,7 @@ Finished:
''' </summary> ''' </summary>
Public Shared Function IsModFile(Path As String) Public Shared Function IsModFile(Path As String)
If Path Is Nothing OrElse Not Path.Contains(".") Then Return False If Path Is Nothing OrElse Not Path.Contains(".") Then Return False
Path = Path.ToLower Path = Path.Lower
If Path.EndsWithF(".jar", True) OrElse Path.EndsWithF(".zip", True) OrElse Path.EndsWithF(".litemod", True) OrElse If Path.EndsWithF(".jar", True) OrElse Path.EndsWithF(".zip", True) OrElse Path.EndsWithF(".litemod", True) OrElse
Path.EndsWithF(".jar.disabled", True) OrElse Path.EndsWithF(".zip.disabled", True) OrElse Path.EndsWithF(".litemod.disabled", True) OrElse Path.EndsWithF(".jar.disabled", True) OrElse Path.EndsWithF(".zip.disabled", True) OrElse Path.EndsWithF(".litemod.disabled", True) OrElse
Path.EndsWithF(".jar.old", True) OrElse Path.EndsWithF(".zip.old", True) OrElse Path.EndsWithF(".litemod.old", True) Then Return True Path.EndsWithF(".jar.old", True) OrElse Path.EndsWithF(".zip.old", True) OrElse Path.EndsWithF(".litemod.old", True) Then Return True
@@ -555,7 +555,7 @@ Finished:
Try Try
RunInUiWait(Sub() If FrmInstanceMod IsNot Nothing Then FrmInstanceMod.Load.Text = "正在更新 Mod") RunInUiWait(Sub() If FrmInstanceMod IsNot Nothing Then FrmInstanceMod.Load.Text = "正在更新 Mod")
Do Until Not PageInstanceMod.UpdatingInstanceModFolders.Contains(Loader.Input) Do Until Not PageInstanceMod.UpdatingInstanceModFolders.Contains(Loader.Input)
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
Thread.Sleep(100) Thread.Sleep(100)
Loop Loop
Finally Finally
@@ -567,9 +567,9 @@ Finished:
'获取 Mod 文件夹下的可用文件列表 '获取 Mod 文件夹下的可用文件列表
Dim ModFileList As New List(Of FileInfo) Dim ModFileList As New List(Of FileInfo)
If Directory.Exists(Loader.Input) Then If Directory.Exists(Loader.Input) Then
Dim RawName As String = Loader.Input.ToLower Dim RawName As String = Loader.Input.Lower
For Each File As FileInfo In EnumerateFiles(Loader.Input) For Each File As FileInfo In EnumerateFiles(Loader.Input)
If File.DirectoryName.ToLower & "\" <> RawName Then If File.DirectoryName.Lower & "\" <> RawName Then
'仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod '仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod
If Not (PageInstanceLeft.Instance IsNot Nothing AndAlso PageInstanceLeft.Instance.Version.HasForge AndAlso If Not (PageInstanceLeft.Instance IsNot Nothing AndAlso PageInstanceLeft.Instance.Version.HasForge AndAlso
PageInstanceLeft.Instance.Version.Vanilla.Major < 13 AndAlso PageInstanceLeft.Instance.Version.Vanilla.Major < 13 AndAlso
@@ -602,7 +602,7 @@ Finished:
'加载 Mod 列表 '加载 Mod 列表
Dim ModList As New List(Of McMod) Dim ModList As New List(Of McMod)
For Each ModFile As FileInfo In ModFileList For Each ModFile As FileInfo In ModFileList
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
Dim ModEntry As New McMod(ModFile.FullName) Dim ModEntry As New McMod(ModFile.FullName)
Dim DumpMod As McMod = ModList.FirstOrDefault(Function(m) m.RawFileName = ModEntry.RawFileName) '存在两个文件,名称相同,但一个启用一个禁用 Dim DumpMod As McMod = ModList.FirstOrDefault(Function(m) m.RawFileName = ModEntry.RawFileName) '存在两个文件,名称相同,但一个启用一个禁用
If DumpMod IsNot Nothing Then If DumpMod IsNot Nothing Then
@@ -622,7 +622,7 @@ Finished:
ModList = ModList.OrderBy(Function(m) m.FileName).ToList ModList = ModList.OrderBy(Function(m) m.FileName).ToList
'回设 '回设
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
Loader.Output = ModList Loader.Output = ModList
'开始联网加载 '开始联网加载
@@ -641,7 +641,7 @@ Finished:
Dim Cache As JObject = Loader.Input.Value Dim Cache As JObject = Loader.Input.Value
'读取 Comp 缓存,获取需要更新的 Mod 列表 '读取 Comp 缓存,获取需要更新的 Mod 列表
For Each ModEntry As McMod In Loader.Input.Key For Each ModEntry As McMod In Loader.Input.Key
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
Dim CacheKey = ModEntry.ModrinthHash & PageInstanceLeft.Instance.Version.VanillaName & GetTargetModLoaders().Join("") Dim CacheKey = ModEntry.ModrinthHash & PageInstanceLeft.Instance.Version.VanillaName & GetTargetModLoaders().Join("")
If Cache.ContainsKey(CacheKey) Then If Cache.ContainsKey(CacheKey) Then
ModEntry.FromJson(Cache(CacheKey)) ModEntry.FromJson(Cache(CacheKey))
@@ -691,7 +691,7 @@ Finished:
Entry.CompFile.Version = File.Version '使用来自 Modrinth 的版本号 Entry.CompFile.Version = File.Version '使用来自 Modrinth 的版本号
End If End If
Next Next
If Loader.IsAbortedWithThread(CurrentTaskThread) Then Return If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return
Log($"[Mod] 需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息") Log($"[Mod] 需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息")
'步骤 3:获取工程信息 '步骤 3:获取工程信息
If Not ModrinthMapping.Any() Then Return If Not ModrinthMapping.Any() Then Return
@@ -707,7 +707,7 @@ Finished:
'步骤 4:获取更新信息 '步骤 4:获取更新信息
Dim ModrinthUpdate As JObject = DlModRequest("https://api.modrinth.com/v2/version_files/update", HttpMethod.Post, Dim ModrinthUpdate As JObject = DlModRequest("https://api.modrinth.com/v2/version_files/update", HttpMethod.Post,
$"{{""hashes"": [""{ModrinthMapping.SelectMany(Function(l) l.Value.Select(Function(m) m.ModrinthHash)).Join(""",""")}""], ""algorithm"": ""sha1"", $"{{""hashes"": [""{ModrinthMapping.SelectMany(Function(l) l.Value.Select(Function(m) m.ModrinthHash)).Join(""",""")}""], ""algorithm"": ""sha1"",
""loaders"": [""{ModLoaders.Join(""",""").ToLower}""],""game_versions"": [""{VanillaVersion}""]}}", "application/json") ""loaders"": [""{ModLoaders.Join(""",""").Lower}""],""game_versions"": [""{VanillaVersion}""]}}", "application/json")
For Each Entry In Mods For Each Entry In Mods
If Not ModrinthUpdate.ContainsKey(Entry.ModrinthHash) OrElse Entry.CompFile Is Nothing Then Continue For If Not ModrinthUpdate.ContainsKey(Entry.ModrinthHash) OrElse Entry.CompFile Is Nothing Then Continue For
Dim UpdateFile As New CompFile(ModrinthUpdate(Entry.ModrinthHash), CompType.Mod) Dim UpdateFile As New CompFile(ModrinthUpdate(Entry.ModrinthHash), CompType.Mod)
@@ -740,7 +740,7 @@ Finished:
Dim CurseForgeHashes As New List(Of UInteger) Dim CurseForgeHashes As New List(Of UInteger)
For Each Entry In Mods For Each Entry In Mods
CurseForgeHashes.Add(Entry.CurseForgeHash) CurseForgeHashes.Add(Entry.CurseForgeHash)
If Loader.IsAbortedWithThread(CurrentTaskThread) Then Return If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return
Next Next
Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432", HttpMethod.Post, Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432", HttpMethod.Post,
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches") $"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches")
@@ -761,7 +761,7 @@ Finished:
If Entry.CompFile Is Nothing OrElse Entry.CompFile.ReleaseDate < File.ReleaseDate Then Entry.CompFile = File If Entry.CompFile Is Nothing OrElse Entry.CompFile.ReleaseDate < File.ReleaseDate Then Entry.CompFile = File
Next Next
Next Next
If Loader.IsAbortedWithThread(CurrentTaskThread) Then Return If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return
Log($"[Mod] 需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息") Log($"[Mod] 需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息")
'步骤 3:获取工程信息 '步骤 3:获取工程信息
If Not CurseForgeMapping.Any() Then Return If Not CurseForgeMapping.Any() Then Return
@@ -781,7 +781,7 @@ Finished:
Entry.Comp = Project Entry.Comp = Project
Next Next
'查找或许版本更新的文件列表 '查找或许版本更新的文件列表
If ModLoaders.Count = 1 Then If ModLoaders.IsSingle Then
Dim NewestVersion As String = Nothing Dim NewestVersion As String = Nothing
Dim NewestFileIds As New List(Of Integer) Dim NewestFileIds As New List(Of Integer)
For Each IndexEntry In ProjectJson("latestFilesIndexes") For Each IndexEntry In ProjectJson("latestFilesIndexes")
@@ -844,7 +844,7 @@ Finished:
'等待线程结束 '等待线程结束
Do Until EndedThreadCount = 2 Do Until EndedThreadCount = 2
Thread.Sleep(10) Thread.Sleep(10)
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
Loop Loop
'保存缓存 '保存缓存
Mods = Mods.Where(Function(m) m.Comp IsNot Nothing).ToList() Mods = Mods.Where(Function(m) m.Comp IsNot Nothing).ToList()
@@ -856,7 +856,7 @@ Finished:
Next Next
WriteFile(PathTemp & "Cache\LocalMod.json", Cache.ToString(If(ModeDebug, Newtonsoft.Json.Formatting.Indented, Newtonsoft.Json.Formatting.None))) WriteFile(PathTemp & "Cache\LocalMod.json", Cache.ToString(If(ModeDebug, Newtonsoft.Json.Formatting.Indented, Newtonsoft.Json.Formatting.None)))
'刷新边栏 '刷新边栏
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
If FrmInstanceMod?.Filter = PageInstanceMod.FilterType.CanUpdate Then If FrmInstanceMod?.Filter = PageInstanceMod.FilterType.CanUpdate Then
RunInUi(Sub() FrmInstanceMod?.RefreshUI()) '同步 “可更新” 列表 (#4677) RunInUi(Sub() FrmInstanceMod?.RefreshUI()) '同步 “可更新” 列表 (#4677)
Else Else
@@ -200,7 +200,7 @@ Retry:
Dim NeoForgeVersion As String = Nothing Dim NeoForgeVersion As String = Nothing
Dim FabricVersion As String = Nothing Dim FabricVersion As String = Nothing
For Each Entry In If(Json("minecraft")("modLoaders"), {}) For Each Entry In If(Json("minecraft")("modLoaders"), {})
Dim Id As String = If(Entry("id"), "").ToString.ToLower Dim Id As String = If(Entry("id"), "").ToString.Lower
If Id.StartsWithF("forge-") Then If Id.StartsWithF("forge-") Then
'Forge 指定 'Forge 指定
If Id.Contains("recommended") Then Throw New Exception("该整合包版本过老,已不支持进行安装!") If Id.Contains("recommended") Then Throw New Exception("该整合包版本过老,已不支持进行安装!")
@@ -250,7 +250,7 @@ Retry:
'获取 Mod 下载信息 '获取 Mod 下载信息
ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息", ModDownloadLoaders.Add(New LoaderTask(Of Integer, JArray)("获取 Mod 下载信息",
Sub(Task As LoaderTask(Of Integer, JArray)) Sub(Task As LoaderTask(Of Integer, JArray))
Task.Output = DlModRequest("https://api.curseforge.com/v1/mods/files", HttpMethod.Post, "{""fileIds"": [" & Join(ModList, ",") & "]}", "application/json")("data") Task.Output = DlModRequest("https://api.curseforge.com/v1/mods/files", HttpMethod.Post, "{""fileIds"": [" & ModList.Join(",") & "]}", "application/json")("data")
'如果文件已被删除,则 API 会跳过那一项 '如果文件已被删除,则 API 会跳过那一项
If ModList.Count > Task.Output.Count Then Throw New Exception("整合包中的部分 Mod 版本已被 Mod 作者删除,所以没法继续安装了,请向整合包作者反馈该问题") If ModList.Count > Task.Output.Count Then Throw New Exception("整合包中的部分 Mod 版本已被 Mod 作者删除,所以没法继续安装了,请向整合包作者反馈该问题")
End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s End Sub) With {.ProgressWeight = ModList.Count / 10}) '每 10 Mod 需要 1s
@@ -369,7 +369,7 @@ Retry:
Dim NeoForgeVersion As String = Nothing Dim NeoForgeVersion As String = Nothing
Dim FabricVersion As String = Nothing Dim FabricVersion As String = Nothing
For Each Entry As JProperty In If(Json("dependencies"), {}) For Each Entry As JProperty In If(Json("dependencies"), {})
Select Case Entry.Name.ToLower Select Case Entry.Name.Lower
Case "minecraft" Case "minecraft"
MinecraftVersion = Entry.Value.ToString MinecraftVersion = Entry.Value.ToString
Case "forge" 'eg. 14.23.5.2859 / 1.19-41.1.0 Case "forge" 'eg. 14.23.5.2859 / 1.19-41.1.0
@@ -584,7 +584,7 @@ Retry:
If Not Line.Contains("=") Then Continue For If Not Line.Contains("=") Then Continue For
Lines.Add(Line.BeforeFirst("=") & ":" & Line.AfterFirst("=")) Lines.Add(Line.BeforeFirst("=") & ":" & Line.AfterFirst("="))
Next Next
WriteFile(MMCSetupFile, Join(Lines, vbCrLf)) WriteFile(MMCSetupFile, Lines.Join(vbCrLf))
'读取文件 '读取文件
If ReadIni(MMCSetupFile, "OverrideCommands", False) Then If ReadIni(MMCSetupFile, "OverrideCommands", False) Then
Dim PreLaunchCommand As String = ReadIni(MMCSetupFile, "PreLaunchCommand") Dim PreLaunchCommand As String = ReadIni(MMCSetupFile, "PreLaunchCommand")
@@ -621,7 +621,7 @@ Retry:
WriteIni(SetupFile, "VersionAdvanceJvm", JvmArgs) WriteIni(SetupFile, "VersionAdvanceJvm", JvmArgs)
Log("[ModPack] 迁移 MultiMC 版本独立设置:JVM 参数(覆盖):" & JvmArgs) Log("[ModPack] 迁移 MultiMC 版本独立设置:JVM 参数(覆盖):" & JvmArgs)
Else Else
JvmArgs += " " & Setup.Get("LaunchAdvanceJvm") JvmArgs += " " & Settings.Get("LaunchAdvanceJvm")
WriteIni(SetupFile, "VersionAdvanceJvm", JvmArgs) WriteIni(SetupFile, "VersionAdvanceJvm", JvmArgs)
Log("[ModPack] 迁移 MultiMC 版本独立设置:JVM 参数(追加):" & JvmArgs) Log("[ModPack] 迁移 MultiMC 版本独立设置:JVM 参数(追加):" & JvmArgs)
End If End If
@@ -636,9 +636,8 @@ Retry:
Dim Request As New McInstallRequest With {.NewInstanceName = InstanceName, .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\"} Dim Request As New McInstallRequest With {.NewInstanceName = InstanceName, .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\"}
For Each Component As JObject In PackJson("components") For Each Component As JObject In PackJson("components")
If Not Component.ContainsKey("uid") Then Continue For If Not Component.ContainsKey("uid") Then Continue For
Select Case Component("uid").ToString Dim UID As String = Component("uid").ToString
Case "org.lwjgl" Select Case UID
Log("[ModPack] 已跳过 LWJGL 项")
Case "net.minecraft" Case "net.minecraft"
Request.MinecraftName = Component("version") Request.MinecraftName = Component("version")
Case "net.minecraftforge" Case "net.minecraftforge"
@@ -647,9 +646,13 @@ Retry:
Request.NeoForgeVersion = Component("version") Request.NeoForgeVersion = Component("version")
Case "net.fabricmc.fabric-loader" Case "net.fabricmc.fabric-loader"
Request.FabricVersion = Component("version") Request.FabricVersion = Component("version")
Case Else
'Case "org.quiltmc.quilt-loader" 'eg. 1.0.0 'Case "org.quiltmc.quilt-loader" 'eg. 1.0.0
NotifyIncompatibleLoader(Component("uid")) Case Else
If UID.StartsWithF("org.lwjgl") Then '#8210
Log("[ModPack] 已跳过 LWJGL 项:" & UID)
Else
NotifyIncompatibleLoader(UID)
End If
End Select End Select
Next Next
'构造加载器 '构造加载器
@@ -33,13 +33,13 @@
HasRunningMinecraft = False HasRunningMinecraft = False
FrmMain.BtnExtraShutdown.ShowRefresh() FrmMain.BtnExtraShutdown.ShowRefresh()
'音乐播放 '音乐播放
If Setup.Get("UiMusicStop") Then If Settings.Get("UiMusicStop") Then
RunInUi(Sub() If MusicResume() Then Log("[Music] 已根据设置,在结束后开始音乐播放")) RunInUi(Sub() If MusicResume() Then Log("[Music] 已根据设置,在结束后开始音乐播放"))
ElseIf Setup.Get("UiMusicStart") Then ElseIf Settings.Get("UiMusicStart") Then
RunInUi(Sub() If MusicPause() Then Log("[Music] 已根据设置,在结束后暂停音乐播放")) RunInUi(Sub() If MusicPause() Then Log("[Music] 已根据设置,在结束后暂停音乐播放"))
End If End If
'启动器可见性 '启动器可见性
Select Case Setup.Get("LaunchArgumentVisible") Select Case Settings.Get("LaunchArgumentVisible")
Case 2 Case 2
'直接关闭 '直接关闭
If TriggerLauncherShutdown Then If TriggerLauncherShutdown Then
@@ -91,7 +91,7 @@
RunInNewThread( RunInNewThread(
Sub() Sub()
Try Try
Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse State = MinecraftState.Canceled OrElse Loader.State = LoadState.Aborted Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse State = MinecraftState.Canceled OrElse Loader.State = LoadState.Interrupted
TimerWindow() TimerWindow()
TimerLog() TimerLog()
'设置窗口标题 '设置窗口标题
@@ -277,7 +277,7 @@
WatcherLog($"Minecraft 窗口已加载:{MinecraftWindowName}({MinecraftWindowHandle.ToInt64})") WatcherLog($"Minecraft 窗口已加载:{MinecraftWindowName}({MinecraftWindowHandle.ToInt64})")
IsWindowFinished = True IsWindowFinished = True
'最大化 '最大化
If Setup.Get("LaunchArgumentWindowType") = 4 Then If Settings.Get("LaunchArgumentWindowType") = 4 Then
RunInNewThread( RunInNewThread(
Sub() Sub()
Try Try
+4 -4
View File
@@ -302,7 +302,7 @@ Public Class CustomEvent
Case EventType.修改设置, EventType.写入设置 Case EventType.修改设置, EventType.写入设置
If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 UiLauncherTransparent|400") If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 UiLauncherTransparent|400")
Setup.SetSafe(Args(0), Args(1), Instance:=McInstanceSelected) Settings.SetSafe(Args(0), Args(1), Instance:=McInstanceSelected)
If Args.Length = 2 Then Hint($"已写入设置:{Args(0)} → {Args(1)}", HintType.Green) If Args.Length = 2 Then Hint($"已写入设置:{Args(0)} → {Args(1)}", HintType.Green)
Case EventType.修改变量, EventType.写入变量 Case EventType.修改变量, EventType.写入变量
@@ -369,7 +369,7 @@ Public Class CustomEvent
End Try End Try
RelativeUrl = LocalTemp RelativeUrl = LocalTemp
End If End If
RelativeUrl = RelativeUrl.Replace("/", "\").ToLower.TrimStart("\") RelativeUrl = RelativeUrl.Replace("/", "\").Lower.TrimStart("\")
'确认实际路径 '确认实际路径
Dim Location As String, WorkingDir As String = Path & "PCL" Dim Location As String, WorkingDir As String = Path & "PCL"
@@ -408,12 +408,12 @@ Public Class CustomEvent
''' 弹出安全确认弹窗。返回是否继续执行。 ''' 弹出安全确认弹窗。返回是否继续执行。
''' </summary> ''' </summary>
Private Shared Function EventSafetyConfirm(Message As String) As Boolean Private Shared Function EventSafetyConfirm(Message As String) As Boolean
If Setup.Get("HintCustomCommand") Then Return True If Settings.Get("HintCustomCommand") Then Return True
Select Case MyMsgBox(Message & vbCrLf & "请在确认没有安全隐患后再继续。", "执行确认", "继续", "继续且今后不再要求确认", "取消") Select Case MyMsgBox(Message & vbCrLf & "请在确认没有安全隐患后再继续。", "执行确认", "继续", "继续且今后不再要求确认", "取消")
Case 1 Case 1
Return True Return True
Case 2 Case 2
Setup.Set("HintCustomCommand", True) Settings.Set("HintCustomCommand", True)
Return True Return True
Case Else Case Else
Return False Return False
+56 -41
View File
@@ -166,7 +166,7 @@ EndHint:
Public Text As String Public Text As String
''' <summary> ''' <summary>
''' 输入模式:文本框的文本。 ''' 输入模式:文本框的文本。
''' 选择模式:需要放进去的 List(Of MyListItem)。 ''' 选择模式:需要放进去的 IEnumberable(Of IMyRadio)。
''' 登录模式:登录步骤 1 中返回的 JSON。 ''' 登录模式:登录步骤 1 中返回的 JSON。
''' </summary> ''' </summary>
Public Content As Object Public Content As Object
@@ -308,7 +308,7 @@ EndHint:
''' <param name="Button1">显示的第一个按钮,默认为 “确定”。</param> ''' <param name="Button1">显示的第一个按钮,默认为 “确定”。</param>
''' <param name="Button2">显示的第二个按钮,默认为空。</param> ''' <param name="Button2">显示的第二个按钮,默认为空。</param>
''' <param name="IsWarn">是否为警告弹窗,若为 True,弹窗配色和背景会变为红色。</param> ''' <param name="IsWarn">是否为警告弹窗,若为 True,弹窗配色和背景会变为红色。</param>
Public Function MyMsgBoxSelect(Selections As List(Of IMyRadio), Optional Title As String = "提示", Optional Button1 As String = "确定", Optional Button2 As String = "", Optional IsWarn As Boolean = False) As Integer? Public Function MyMsgBoxSelect(Selections As IEnumerable(Of IMyRadio), Optional Title As String = "提示", Optional Button1 As String = "确定", Optional Button2 As String = "", Optional IsWarn As Boolean = False) As Integer?
'将弹窗列入队列 '将弹窗列入队列
Dim Converter As New MyMsgBoxConverter With {.Type = MyMsgBoxType.Select, .Button1 = Button1, .Button2 = Button2, .Content = Selections, .IsWarn = IsWarn, .Title = Title} Dim Converter As New MyMsgBoxConverter With {.Type = MyMsgBoxType.Select, .Button1 = Button1, .Button2 = Button2, .Content = Selections, .IsWarn = IsWarn, .Title = Title}
WaitingMyMsgBox.Add(Converter) WaitingMyMsgBox.Add(Converter)
@@ -512,7 +512,7 @@ EndHint:
EventData = If(JsonData("EventData"), "") EventData = If(JsonData("EventData"), "")
IsEvent = True IsEvent = True
Else Else
Dim XamlAddress As String = FilePath.ToLower.Replace(".json", ".xaml") Dim XamlAddress As String = FilePath.Lower.Replace(".json", ".xaml")
If File.Exists(XamlAddress) Then If File.Exists(XamlAddress) Then
XamlContent = ReadFile(XamlAddress) XamlContent = ReadFile(XamlAddress)
IsEvent = False IsEvent = False
@@ -579,7 +579,7 @@ EndHint:
'读取自定义文件 '读取自定义文件
If Directory.Exists(Path & "PCL\Help\") Then If Directory.Exists(Path & "PCL\Help\") Then
For Each File In EnumerateFiles(Path & "PCL\Help\") For Each File In EnumerateFiles(Path & "PCL\Help\")
Select Case File.Extension.ToLower Select Case File.Extension.Lower
Case ".helpignore" Case ".helpignore"
'加载忽略列表 '加载忽略列表
Log("[Help] 发现 .helpignore 文件:" & File.FullName) Log("[Help] 发现 .helpignore 文件:" & File.FullName)
@@ -598,7 +598,7 @@ EndHint:
'读取自带文件 '读取自带文件
For Each File In EnumerateFiles(PathTemp & "Help") For Each File In EnumerateFiles(PathTemp & "Help")
'跳过非 json 文件与以 . 开头的文件夹 '跳过非 json 文件与以 . 开头的文件夹
If File.Extension.ToLower <> ".json" OrElse File.Directory.FullName.Replace(PathTemp & "Help", "").Contains("\.") Then Continue For If File.Extension.Lower <> ".json" OrElse File.Directory.FullName.Replace(PathTemp & "Help", "").Contains("\.") Then Continue For
'检查忽略列表 '检查忽略列表
Dim RealPath As String = File.FullName.Replace(PathTemp & "Help\", "") Dim RealPath As String = File.FullName.Replace(PathTemp & "Help\", "")
For Each Ignore In IgnoreList For Each Ignore In IgnoreList
@@ -614,7 +614,7 @@ NextFile:
Catch ex As Exception Catch ex As Exception
Log(ex, "检查帮助文件夹失败", LogLevel.Msgbox) Log(ex, "检查帮助文件夹失败", LogLevel.Msgbox)
End Try End Try
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
'将文件实例化 '将文件实例化
Dim Dict As New List(Of HelpEntry) Dim Dict As New List(Of HelpEntry)
@@ -630,7 +630,7 @@ NextFile:
'回设 '回设
If Not Dict.Any() Then Throw New Exception("未找到可用的帮助;若不需要帮助页面,可以在 设置 → 个性化 → 功能隐藏 中将其隐藏") If Not Dict.Any() Then Throw New Exception("未找到可用的帮助;若不需要帮助页面,可以在 设置 → 个性化 → 功能隐藏 中将其隐藏")
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
Loader.Output = Dict Loader.Output = Dict
Catch ex As Exception Catch ex As Exception
@@ -643,12 +643,12 @@ NextFile:
''' 尝试解压内置帮助文件。 ''' 尝试解压内置帮助文件。
''' </summary> ''' </summary>
Public Sub HelpTryExtract() Public Sub HelpTryExtract()
If Setup.Get("SystemHelpVersion") <> VersionCode OrElse Not File.Exists(PathTemp & "Help\启动器\备份设置.xaml") Then If Settings.Get("SystemHelpVersion") <> VersionCode OrElse Not File.Exists(PathTemp & "Help\启动器\备份设置.xaml") Then
DeleteDirectory(PathTemp & "Help") DeleteDirectory(PathTemp & "Help")
Directory.CreateDirectory(PathTemp & "Help") Directory.CreateDirectory(PathTemp & "Help")
WriteFile(PathTemp & "Cache\Help.zip", GetResources("Help")) WriteFile(PathTemp & "Cache\Help.zip", GetResources("Help"))
ExtractCompressedFile(PathTemp & "Cache\Help.zip", PathTemp & "Help") ExtractCompressedFile(PathTemp & "Cache\Help.zip", PathTemp & "Help")
Setup.Set("SystemHelpVersion", VersionCode) Settings.Set("SystemHelpVersion", VersionCode)
Log("[Help] 已解压内置帮助文件,目前状态:" & File.Exists(PathTemp & "Help\启动器\备份设置.xaml"), LogLevel.Debug) Log("[Help] 已解压内置帮助文件,目前状态:" & File.Exists(PathTemp & "Help\启动器\备份设置.xaml"), LogLevel.Debug)
End If End If
End Sub End Sub
@@ -657,11 +657,19 @@ NextFile:
#Region "愚人节" #Region "愚人节"
Public IsAprilEnabled As Boolean = Date.Now.Month = 4 AndAlso Date.Now.Day = 1 Private _IsAprilEnabled As Boolean? = Nothing
Public ReadOnly Property IsAprilEnabled As Boolean
Get
If _IsAprilEnabled Is Nothing Then
_IsAprilEnabled =
Date.Now.Month = 4 AndAlso Date.Now.Day = 1 AndAlso
Settings.Get("AprilDoneYear") <> Date.Now.Year '成功后同年内则不再触发
End If
Return _IsAprilEnabled.Value
End Get
End Property
Public IsAprilGiveup As Boolean = False Public IsAprilGiveup As Boolean = False
Private AprilSpeed As New Vector(0, 0) Private AprilDifficultiedDistance As Integer = 0
Private AprilIdieCount As Integer = 0, AprilMousePosLast As New Point(0, 0)
Private AprilDistance As Integer = 0
Private Sub TimerFool() Private Sub TimerFool()
Try Try
If FrmLaunchLeft Is Nothing OrElse FrmLaunchLeft.AprilPosTrans Is Nothing OrElse FrmMain.lastMouseArg Is Nothing Then Return If FrmLaunchLeft Is Nothing OrElse FrmLaunchLeft.AprilPosTrans Is Nothing OrElse FrmMain.lastMouseArg Is Nothing Then Return
@@ -669,11 +677,13 @@ NextFile:
'计算是否空闲 '计算是否空闲
Dim MousePos = FrmMain.lastMouseArg.GetPosition(FrmMain) Dim MousePos = FrmMain.lastMouseArg.GetPosition(FrmMain)
If MousePos = AprilMousePosLast Then Static IdieCount As Integer = 0
AprilIdieCount += 1 Static MousePosLast As New Point(0, 0)
If MousePos = MousePosLast Then
IdieCount += 1
Else Else
AprilMousePosLast = MousePos MousePosLast = MousePos
AprilIdieCount = 0 IdieCount = 0
End If End If
'计算躲避移动 '计算躲避移动
Dim Direction As Vector Dim Direction As Vector
@@ -685,9 +695,11 @@ NextFile:
Direction = -Dir Direction = -Dir
Distance = New Vector(Math.Max(0, Math.Abs(Vec.X) - ButtonWidth), Math.Max(0, Math.Abs(Vec.Y) - ButtonHeight)).Length Distance = New Vector(Math.Max(0, Math.Abs(Vec.X) - ButtonWidth), Math.Max(0, Math.Abs(Vec.Y) - ButtonHeight)).Length
Dim BreathScale = Math.Sin(Timer150Count / 37.5 * Math.PI) Dim BreathScale = Math.Sin(Timer150Count / 37.5 * Math.PI)
Dim Acc = Math.Max(0, BreathScale * 0.25 - 0.65 - Math.Log((Distance + 0.4) / 200)) * Direction '加速度 Dim Difficulty As Double = 1 / (1 + (AprilDifficultiedDistance / 6000) ^ 2) + 0.25 '难度,初始为 1.25x,6000 距离为 0.75x,12000 为 0.5x,24000 为 0.256x,最低 0.25x
'计算回归移动 Dim Acc = Math.Max(0, -0.65 - Math.Log((Distance / Difficulty + 0.4) / 200)) * Direction * Difficulty '加速度
If AprilIdieCount >= 64 * 5 Then 'FrmMain.Title = CInt(AprilTotalDistance) & " - " & Difficulty
'5s 不动时回到起始点
If IdieCount >= 64 * 5 Then
Dim SafeDist As Vector = FrmMain.lastMouseArg.GetPosition(FrmMain.PanMain) - New Vector(ButtonWidth, FrmMain.PanMain.ActualHeight - ButtonHeight * 3) Dim SafeDist As Vector = FrmMain.lastMouseArg.GetPosition(FrmMain.PanMain) - New Vector(ButtonWidth, FrmMain.PanMain.ActualHeight - ButtonHeight * 3)
Dim Back As New Vector(FrmLaunchLeft.AprilPosTrans.X, FrmLaunchLeft.AprilPosTrans.Y) Dim Back As New Vector(FrmLaunchLeft.AprilPosTrans.X, FrmLaunchLeft.AprilPosTrans.Y)
If SafeDist.Length > 250 AndAlso Back.Length > 0.4 Then If SafeDist.Length > 250 AndAlso Back.Length > 0.4 Then
@@ -697,10 +709,11 @@ NextFile:
End If End If
End If End If
'回到边界 '回到边界
Static Speed As New Vector(0, 0)
Dim Relative As Point = FrmLaunchLeft.BtnLaunch.TranslatePoint(New Point(0, 0), FrmMain.PanForm) Dim Relative As Point = FrmLaunchLeft.BtnLaunch.TranslatePoint(New Point(0, 0), FrmMain.PanForm)
If Relative.X < -ButtonWidth * 2 Then If Relative.X < -ButtonWidth * 2 Then
FrmLaunchLeft.AprilPosTrans.X += FrmMain.PanForm.ActualWidth + ButtonWidth * 2 '离开左边界 FrmLaunchLeft.AprilPosTrans.X += FrmMain.PanForm.ActualWidth + ButtonWidth * 2 '离开左边界
AprilSpeed.X -= 80 Speed.X -= 80
If Relative.Y < 0 Then If Relative.Y < 0 Then
FrmLaunchLeft.AprilPosTrans.Y += ButtonHeight * 2.5 FrmLaunchLeft.AprilPosTrans.Y += ButtonHeight * 2.5
ElseIf Relative.Y > FrmMain.PanForm.ActualHeight - ButtonHeight * 2 Then ElseIf Relative.Y > FrmMain.PanForm.ActualHeight - ButtonHeight * 2 Then
@@ -708,7 +721,7 @@ NextFile:
End If End If
ElseIf Relative.X > FrmMain.PanForm.ActualWidth Then ElseIf Relative.X > FrmMain.PanForm.ActualWidth Then
FrmLaunchLeft.AprilPosTrans.X -= FrmMain.PanForm.ActualWidth + ButtonWidth * 2 '离开右边界 FrmLaunchLeft.AprilPosTrans.X -= FrmMain.PanForm.ActualWidth + ButtonWidth * 2 '离开右边界
AprilSpeed.X += 80 Speed.X += 80
If Relative.Y < 0 Then If Relative.Y < 0 Then
FrmLaunchLeft.AprilPosTrans.Y += ButtonHeight * 2.5 FrmLaunchLeft.AprilPosTrans.Y += ButtonHeight * 2.5
ElseIf Relative.Y > FrmMain.PanForm.ActualHeight - ButtonHeight * 2 Then ElseIf Relative.Y > FrmMain.PanForm.ActualHeight - ButtonHeight * 2 Then
@@ -716,7 +729,7 @@ NextFile:
End If End If
ElseIf Relative.Y < -ButtonHeight * 2 Then ElseIf Relative.Y < -ButtonHeight * 2 Then
FrmLaunchLeft.AprilPosTrans.Y += FrmMain.PanForm.ActualHeight + ButtonHeight * 2 '离开上边界 FrmLaunchLeft.AprilPosTrans.Y += FrmMain.PanForm.ActualHeight + ButtonHeight * 2 '离开上边界
AprilSpeed.Y -= 25 Speed.Y -= 25
If Relative.X < 0 Then If Relative.X < 0 Then
FrmLaunchLeft.AprilPosTrans.X += ButtonWidth * 2 FrmLaunchLeft.AprilPosTrans.X += ButtonWidth * 2
ElseIf Relative.X > FrmMain.PanForm.ActualWidth - ButtonWidth * 2 Then ElseIf Relative.X > FrmMain.PanForm.ActualWidth - ButtonWidth * 2 Then
@@ -724,7 +737,7 @@ NextFile:
End If End If
ElseIf Relative.Y > FrmMain.PanForm.ActualHeight Then ElseIf Relative.Y > FrmMain.PanForm.ActualHeight Then
FrmLaunchLeft.AprilPosTrans.Y -= FrmMain.PanForm.ActualHeight + ButtonHeight * 2 '离开下边界 FrmLaunchLeft.AprilPosTrans.Y -= FrmMain.PanForm.ActualHeight + ButtonHeight * 2 '离开下边界
AprilSpeed.Y += 25 Speed.Y += 25
If Relative.X < 0 Then If Relative.X < 0 Then
FrmLaunchLeft.AprilPosTrans.X += ButtonWidth * 2 FrmLaunchLeft.AprilPosTrans.X += ButtonWidth * 2
ElseIf Relative.X > FrmMain.PanForm.ActualWidth - ButtonWidth * 2 Then ElseIf Relative.X > FrmMain.PanForm.ActualWidth - ButtonWidth * 2 Then
@@ -732,29 +745,31 @@ NextFile:
End If End If
End If End If
'移动 '移动
AprilSpeed = AprilSpeed * 0.8 + Acc Speed = Speed * 0.8 + Acc
Dim SpeedValue = Math.Min(60, AprilSpeed.Length) Dim SpeedValue = Math.Min(60, Speed.Length)
If SpeedValue < 0.01 Then Return If SpeedValue < 0.01 Then Return
AprilSpeed.Normalize() Speed.Normalize()
AprilSpeed *= SpeedValue Speed *= SpeedValue
AprilDistance += SpeedValue AprilDifficultiedDistance += SpeedValue
FrmLaunchLeft.AprilPosTrans.X += AprilSpeed.X FrmLaunchLeft.AprilPosTrans.X += Speed.X
FrmLaunchLeft.AprilPosTrans.Y += AprilSpeed.Y FrmLaunchLeft.AprilPosTrans.Y += Speed.Y
'大小改变 '大小改变
FrmLaunchLeft.AprilScaleTrans.ScaleX = MathClamp(1 - (Math.Abs(Direction.X) - Math.Abs(Direction.Y)) * (SpeedValue / 160), 0.2, 1.8) FrmLaunchLeft.AprilScaleTrans.ScaleX = MathClamp(1 - (Math.Abs(Direction.X) - Math.Abs(Direction.Y)) * (SpeedValue / 160), 0.2, 1.8)
FrmLaunchLeft.AprilScaleTrans.ScaleY = MathClamp(1 - (Math.Abs(Direction.Y) - Math.Abs(Direction.X)) * (SpeedValue / 100), 0.2, 1.8) FrmLaunchLeft.AprilScaleTrans.ScaleY = MathClamp(1 - (Math.Abs(Direction.Y) - Math.Abs(Direction.X)) * (SpeedValue / 100), 0.2, 1.8)
'放弃提示 '放弃提示
If AprilDistance > 4000 Then Static GiveUpDistance As Double = -1500
AprilDistance = -4000 GiveUpDistance += SpeedValue
If GiveUpDistance > 2500 Then
GiveUpDistance = 0
Select Case RandomInteger(0, 3) Select Case RandomInteger(0, 3)
Case 0 Case 0
Hint("放弃吧!只需要点一下右下角的小白旗……") Hint("放弃吧!只需要点一下右下角的小白旗……", HintType.Red)
Case 1 Case 1
Hint("看到右下角的那面小白旗了吗?") Hint("看到右下角的那面小白旗了吗?", HintType.Red)
Case 2 Case 2
Hint("这里建议点一下右下角的小白旗投降呢.jpg") Hint("这里建议点一下右下角的小白旗投降呢.jpg", HintType.Red)
Case 3 Case 3
Hint("右下角的小白旗永远等着你……") Hint("右下角的小白旗永远等着你……", HintType.Red)
End Select End Select
End If End If
@@ -843,7 +858,7 @@ NextFile:
Text = Text.Replace("{version_path}", Replacer(McInstanceSelected.PathVersion)) : Text = Text.Replace("{verpath}", Replacer(McInstanceSelected.PathVersion)) Text = Text.Replace("{version_path}", Replacer(McInstanceSelected.PathVersion)) : Text = Text.Replace("{verpath}", Replacer(McInstanceSelected.PathVersion))
Text = Text.Replace("{version_indie}", Replacer(McInstanceSelected.PathIndie)) : Text = Text.Replace("{verindie}", Replacer(McInstanceSelected.PathIndie)) Text = Text.Replace("{version_indie}", Replacer(McInstanceSelected.PathIndie)) : Text = Text.Replace("{verindie}", Replacer(McInstanceSelected.PathIndie))
Text = Text.Replace("{name}", Replacer(McInstanceSelected.Name)) Text = Text.Replace("{name}", Replacer(McInstanceSelected.Name))
If {"unknown", "old", "pending"}.Contains(McInstanceSelected.Version.VanillaName.ToLower) Then If {"unknown", "old", "pending"}.Contains(McInstanceSelected.Version.VanillaName.Lower) Then
Text = Text.Replace("{version}", Replacer(McInstanceSelected.Name)) Text = Text.Replace("{version}", Replacer(McInstanceSelected.Name))
Else Else
Text = Text.Replace("{version}", Replacer(McInstanceSelected.Version.VanillaName)) Text = Text.Replace("{version}", Replacer(McInstanceSelected.Version.VanillaName))
@@ -857,7 +872,7 @@ NextFile:
'登录信息 '登录信息
If McLoginLoader.State = LoadState.Finished Then If McLoginLoader.State = LoadState.Finished Then
Text = Text.Replace("{user}", Replacer(McLoginLoader.Output.Name)) Text = Text.Replace("{user}", Replacer(McLoginLoader.Output.Name))
Text = Text.Replace("{uuid}", Replacer(McLoginLoader.Output.Uuid?.ToLower)) Text = Text.Replace("{uuid}", Replacer(McLoginLoader.Output.Uuid?.Lower))
Select Case McLoginLoader.Input.Type Select Case McLoginLoader.Input.Type
Case McLoginType.Legacy Case McLoginType.Legacy
Text = Text.Replace("{login}", Replacer("离线")) Text = Text.Replace("{login}", Replacer("离线"))
@@ -876,7 +891,7 @@ NextFile:
'高级 '高级
Text = Text.RegexReplaceEach("\{hint\}", Function() Replacer(PageOtherTest.GetRandomHint())) Text = Text.RegexReplaceEach("\{hint\}", Function() Replacer(PageOtherTest.GetRandomHint()))
Text = Text.RegexReplaceEach("\{cave\}", Function() Replacer(PageOtherTest.GetRandomCave())) Text = Text.RegexReplaceEach("\{cave\}", Function() Replacer(PageOtherTest.GetRandomCave()))
Text = Text.RegexReplaceEach("\{setup:([a-zA-Z0-9]+)\}", Function(m) Replacer(Setup.GetSafe(m.Groups(1).Value, McInstanceSelected))) Text = Text.RegexReplaceEach("\{setup:([a-zA-Z0-9]+)\}", Function(m) Replacer(Settings.GetSafe(m.Groups(1).Value, McInstanceSelected)))
Text = Text.RegexReplaceEach("\{varible:([^:\}]+)(?::([^\}]+))?\}", Function(m) Replacer(ReadReg("CustomEvent" & m.Groups(1).Value, m.Groups(2).Value))) Text = Text.RegexReplaceEach("\{varible:([^:\}]+)(?::([^\}]+))?\}", Function(m) Replacer(ReadReg("CustomEvent" & m.Groups(1).Value, m.Groups(2).Value)))
Text = Text.RegexReplaceEach("\{variable:([^:\}]+)(?::([^\}]+))?\}", Function(m) Replacer(ReadReg("CustomEvent" & m.Groups(1).Value, m.Groups(2).Value))) Text = Text.RegexReplaceEach("\{variable:([^:\}]+)(?::([^\}]+))?\}", Function(m) Replacer(ReadReg("CustomEvent" & m.Groups(1).Value, m.Groups(2).Value)))
Return Text Return Text
@@ -971,7 +986,7 @@ NextFile:
Timer150Count = 0 Timer150Count = 0
Try Try
#Region "每 7.5s 执行一次的代码" #Region "每 7.5s 执行一次的代码"
If FrmMain.BtnExtraApril_ShowCheck AndAlso AprilDistance <> 0 Then FrmMain.BtnExtraApril.Ribble() If FrmMain.BtnExtraApril_ShowCheck AndAlso AprilDifficultiedDistance <> 0 Then FrmMain.BtnExtraApril.Ribble()
'以未知原因窗口被丢到一边去的修复(Top、Left = -25600),还有 #745 '以未知原因窗口被丢到一边去的修复(Top、Left = -25600),还有 #745
RunInUi( RunInUi(
Sub() Sub()
+13 -10
View File
@@ -24,13 +24,13 @@
Directory.CreateDirectory(Path & "PCL\Musics\") Directory.CreateDirectory(Path & "PCL\Musics\")
For Each File In EnumerateFiles(Path & "PCL\Musics\") For Each File In EnumerateFiles(Path & "PCL\Musics\")
'文件夹可能会被加入 .ini 文件夹配置文件、一些乱七八糟的 .jpg 文件啥的 '文件夹可能会被加入 .ini 文件夹配置文件、一些乱七八糟的 .jpg 文件啥的
Dim Ext As String = File.Extension.ToLower Dim Ext As String = File.Extension.Lower
If {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(Ext) Then Continue For If {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(Ext) Then Continue For
MusicAllList.Add(File.FullName) MusicAllList.Add(File.FullName)
Next Next
End If End If
'打乱顺序播放 '打乱顺序播放
MusicWaitingList = If(Setup.Get("UiMusicRandom"), New List(Of String)(MusicAllList).Shuffle().ToList, New List(Of String)(MusicAllList)) MusicWaitingList = If(Settings.Get("UiMusicRandom"), New List(Of String)(MusicAllList).Shuffle().ToList, New List(Of String)(MusicAllList))
If PreventFirst IsNot Nothing AndAlso MusicWaitingList.FirstOrDefault = PreventFirst Then If PreventFirst IsNot Nothing AndAlso MusicWaitingList.FirstOrDefault = PreventFirst Then
'若需要避免成为第一项的为第一项,则将它放在最后 '若需要避免成为第一项的为第一项,则将它放在最后
MusicWaitingList.RemoveAt(0) MusicWaitingList.RemoveAt(0)
@@ -129,7 +129,7 @@
''' 播放下一曲,并显示提示文本。 ''' 播放下一曲,并显示提示文本。
''' </summary> ''' </summary>
Public Sub MusicControlNext() Public Sub MusicControlNext()
If MusicAllList.Count = 1 Then If MusicAllList.IsSingle Then
MusicStartPlay(MusicCurrent) MusicStartPlay(MusicCurrent)
Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Green) Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Green)
Else Else
@@ -280,18 +280,23 @@
CurrentWave = New NAudio.Wave.WaveOutEvent() CurrentWave = New NAudio.Wave.WaveOutEvent()
MusicNAudio = CurrentWave MusicNAudio = CurrentWave
CurrentWave.DeviceNumber = -1 CurrentWave.DeviceNumber = -1
Reader = New NAudio.Wave.AudioFileReader(MusicCurrent) Try
Reader = New NAudio.Wave.AudioFileReader(MusicCurrent)
Catch ex As Exception
Log(ex, "使用 AudioFileReader 加载音频文件失败,换用 MediaFoundationReader 重试", LogLevel.Developer)
Reader = New NAudio.Wave.MediaFoundationReader(MusicCurrent)
End Try
CurrentWave.Init(Reader) CurrentWave.Init(Reader)
CurrentWave.Play() CurrentWave.Play()
'第一次打开的暂停 '第一次打开的暂停
If IsFirstLoad AndAlso Not Setup.Get("UiMusicAuto") Then CurrentWave.Pause() If IsFirstLoad AndAlso Not Settings.Get("UiMusicAuto") Then CurrentWave.Pause()
MusicRefreshUI() MusicRefreshUI()
'停止条件:播放完毕或变化 '停止条件:播放完毕或变化
Dim PreviousVolume = 0 Dim PreviousVolume = 0
While CurrentWave.Equals(MusicNAudio) AndAlso Not CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped While CurrentWave.Equals(MusicNAudio) AndAlso Not CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped
If Setup.Get("UiMusicVolume") <> PreviousVolume Then If Settings.Get("UiMusicVolume") <> PreviousVolume Then
'更新音量 '更新音量
PreviousVolume = Setup.Get("UiMusicVolume") PreviousVolume = Settings.Get("UiMusicVolume")
CurrentWave.Volume = PreviousVolume / 1000 CurrentWave.Volume = PreviousVolume / 1000
End If End If
'更新进度条 '更新进度条
@@ -311,9 +316,7 @@
Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Red) Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Red)
Thread.Sleep(1000000000) Thread.Sleep(1000000000)
End If End If
If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then If Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 不支持播放音频属性在中途发生变化的音乐", HintType.Red)
ElseIf Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse
ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4) ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4)
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Red) Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Red)
Else Else
+3 -12
View File
@@ -62,15 +62,6 @@ Friend Module ModSecret
Return "0000-0000-0000-0000" Return "0000-0000-0000-0000"
End Function End Function
Friend Sub SecretLaunchJvmArgs(ByRef DataList As List(Of String))
Dim DataJvmCustom As String = Setup.Get("VersionAdvanceJvm", Instance:=McInstanceSelected)
DataList.Insert(0, ArgumentReplace(If(DataJvmCustom = "", Setup.Get("LaunchAdvanceJvm"), DataJvmCustom))) '可变 JVM 参数
McLaunchLog("当前剩余内存:" & Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024 / 1024 * 10) / 10 & "G")
DataList.Add("-Xmn" & Math.Floor(PageInstanceSetup.GetRam(McInstanceSelected) * 1024 * 0.15) & "m")
DataList.Add("-Xmx" & Math.Floor(PageInstanceSetup.GetRam(McInstanceSelected) * 1024) & "m")
If Not DataList.Any(Function(d) d.Contains("-Dlog4j2.formatMsgNoLookups=true")) Then DataList.Add("-Dlog4j2.formatMsgNoLookups=true")
End Sub
#End Region #End Region
#Region "网络鉴权" #Region "网络鉴权"
@@ -87,9 +78,9 @@ Friend Module ModSecret
If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then
Req.Headers.Add("User-Agent", "LogStatistic") '#4951 Req.Headers.Add("User-Agent", "LogStatistic") '#4951
ElseIf SimulateBrowserHeaders Then ElseIf SimulateBrowserHeaders Then
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36") Req.Headers.Add("User-Agent", $"PCL2/{VersionBaseName}.{VersionBranchCode} Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36")
Else Else
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode}") Req.Headers.Add("User-Agent", $"PCL2/{VersionBaseName}.{VersionBranchCode}")
End If End If
End If End If
If Not SimulateBrowserHeaders Then Req.Headers.Add("Referer", $"http://{VersionCode}.open.pcl2.server/") If Not SimulateBrowserHeaders Then Req.Headers.Add("Referer", $"http://{VersionCode}.open.pcl2.server/")
@@ -229,7 +220,7 @@ Friend Module ModSecret
FrmMain.PanTitle.Background = Brush FrmMain.PanTitle.Background = Brush
FrmMain.PanTitle.Background.Freeze() FrmMain.PanTitle.Background.Freeze()
'主页面背景 '主页面背景
If Setup.Get("UiBackgroundColorful") Then If Settings.Get("UiBackgroundColorful") Then
Brush = New LinearGradientBrush With {.EndPoint = New Point(0.1, 1), .StartPoint = New Point(0.9, 0)} Brush = New LinearGradientBrush With {.EndPoint = New Point(0.1, 1), .StartPoint = New Point(0.9, 0)}
Brush.GradientStops.Add(New GradientStop With {.Offset = -0.1, .Color = New MyColor().FromHSL2(ColorHue - 15, ColorSat * 0.8, 91)}) Brush.GradientStops.Add(New GradientStop With {.Offset = -0.1, .Color = New MyColor().FromHSL2(ColorHue - 15, ColorSat * 0.8, 91)})
Brush.GradientStops.Add(New GradientStop With {.Offset = 0.4, .Color = New MyColor().FromHSL2(ColorHue, ColorSat * 0.8, 91)}) Brush.GradientStops.Add(New GradientStop With {.Offset = 0.4, .Color = New MyColor().FromHSL2(ColorHue, ColorSat * 0.8, 91)})
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*” ' 方法是按如下所示使用“*”
<Assembly: AssemblyVersion("2.12.2.0")> <Assembly: AssemblyVersion("2.12.6.2")>
<Assembly: AssemblyFileVersion("2.12.2.0")> <Assembly: AssemblyFileVersion("2.12.6.2")>
<Assembly: NeutralResourcesLanguage("")> <Assembly: NeutralResourcesLanguage("")>
+10
View File
@@ -150,6 +150,16 @@ Namespace My.Resources
End Get End Get
End Property End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property LUA() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("LUA", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary> '''<summary>
''' 查找 System.Byte[] 类型的本地化资源。 ''' 查找 System.Byte[] 类型的本地化资源。
'''</summary> '''</summary>
@@ -145,8 +145,11 @@
<data name="libwebp64" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="libwebp64" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\libwebp64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>..\Resources\libwebp64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="LUA" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\lwjgl-unsafe-agent.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ModData" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="ModData" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ModData.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>..\Resources\moddata.zip;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="NAudio" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="NAudio" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
@@ -94,36 +94,36 @@
End If End If
'打开详情页 '打开详情页
Dim TargetType As CompType Dim TargetType As CompType
Dim TargetVersion As String = Nothing Dim TargetInstance As String = Nothing
Dim TargetLoader As CompModLoaderType = CompModLoaderType.Any Dim TargetLoader As CompModLoaderType = CompModLoaderType.Any
If FrmMain.PageCurrent.Page = FormMain.PageType.Download Then If FrmMain.PageCurrent.Page = FormMain.PageType.Download Then
'从下载页进入 '从下载页进入
Select Case FrmMain.PageCurrentSub Select Case FrmMain.PageCurrentSub
Case FormMain.PageSubType.DownloadMod Case FormMain.PageSubType.DownloadMod
TargetType = CompType.Mod TargetType = CompType.Mod
TargetVersion = FrmDownloadMod.Content.Loader.Input.GameVersion TargetInstance = FrmDownloadMod.Content.Loader.Input.GameVersion
TargetLoader = FrmDownloadMod.Content.Loader.Input.ModLoader TargetLoader = FrmDownloadMod.Content.Loader.Input.ModLoader
Case FormMain.PageSubType.DownloadPack Case FormMain.PageSubType.DownloadPack
TargetType = CompType.ModPack TargetType = CompType.ModPack
TargetVersion = FrmDownloadPack.Content.Loader.Input.GameVersion TargetInstance = FrmDownloadPack.Content.Loader.Input.GameVersion
Case FormMain.PageSubType.DownloadDataPack Case FormMain.PageSubType.DownloadDataPack
TargetType = CompType.DataPack TargetType = CompType.DataPack
TargetVersion = FrmDownloadDataPack.Content.Loader.Input.GameVersion TargetInstance = FrmDownloadDataPack.Content.Loader.Input.GameVersion
Case FormMain.PageSubType.DownloadResourcePack Case FormMain.PageSubType.DownloadResourcePack
TargetType = CompType.ResourcePack TargetType = CompType.ResourcePack
TargetVersion = FrmDownloadResourcePack.Content.Loader.Input.GameVersion TargetInstance = FrmDownloadResourcePack.Content.Loader.Input.GameVersion
Case FormMain.PageSubType.DownloadShader Case FormMain.PageSubType.DownloadShader
TargetType = CompType.Shader TargetType = CompType.Shader
TargetVersion = FrmDownloadShader.Content.Loader.Input.GameVersion TargetInstance = FrmDownloadShader.Content.Loader.Input.GameVersion
End Select End Select
Else Else
'从详情页进入(查看前置) '从详情页进入(查看前置)
TargetType = CompType.Any '允许任意类别 TargetType = CompType.Any '允许任意类别
TargetVersion = FrmMain.PageCurrent.Additional(2) TargetInstance = FrmMain.PageCurrent.Additional(2)
TargetLoader = FrmMain.PageCurrent.Additional(3) TargetLoader = FrmMain.PageCurrent.Additional(3)
End If End If
FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail, FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
.Additional = {sender.Tag, New List(Of String), TargetVersion, TargetLoader, TargetType}}) .Additional = {sender.Tag, New List(Of String), TargetInstance, TargetLoader, TargetType}})
End Sub End Sub
'鼠标点击判定 '鼠标点击判定
@@ -32,20 +32,21 @@
<local:MyComboBoxItem Content="Modrinth" Tag="2" /> <local:MyComboBoxItem Content="Modrinth" Tag="2" />
</local:MyComboBox> </local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" /> <TextBlock VerticalAlignment="Center" Grid.Row="2" HorizontalAlignment="Left" Text="版本" Margin="0,0,18,0" />
<local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" IsEditable="True" MaxDropDownHeight="320"> <local:MyComboBox x:Name="TextSearchVersion" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" IsEditable="True">
<local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" /> <local:MyComboBoxItem Content="全部 (也可自行输入)" IsSelected="True" />
<local:MyComboBoxItem Content="26.1" />
<local:MyComboBoxItem Content="1.21.11" /> <local:MyComboBoxItem Content="1.21.11" />
<local:MyComboBoxItem Content="1.21.8" />
<local:MyComboBoxItem Content="1.21.4" />
<local:MyComboBoxItem Content="1.21.1" /> <local:MyComboBoxItem Content="1.21.1" />
<local:MyComboBoxItem Content="1.20.6" />
<local:MyComboBoxItem Content="1.20.1" /> <local:MyComboBoxItem Content="1.20.1" />
<local:MyComboBoxItem Content="1.19.4" /> <local:MyComboBoxItem Content="1.19.2" />
<local:MyComboBoxItem Content="1.18.2" /> <local:MyComboBoxItem Content="1.18.2" />
<local:MyComboBoxItem Content="1.16.5" /> <local:MyComboBoxItem Content="1.16.5" />
<local:MyComboBoxItem Content="1.12.2" /> <local:MyComboBoxItem Content="1.12.2" />
<local:MyComboBoxItem Content="1.8.9" />
<local:MyComboBoxItem Content="1.7.10" /> <local:MyComboBoxItem Content="1.7.10" />
</local:MyComboBox> </local:MyComboBox>
<local:MyComboBox x:Name="ComboSearchLoader" Visibility="Collapsed" Grid.Row="2" Grid.Column="2" MaxDropDownHeight="320" Margin="10,0,0,0"> <local:MyComboBox x:Name="ComboSearchLoader" Visibility="Collapsed" Grid.Row="2" Grid.Column="2" Margin="10,0,0,0">
<local:MyComboBoxItem Content="任意 Mod 加载器" IsSelected="True" Tag="0" /> <local:MyComboBoxItem Content="任意 Mod 加载器" IsSelected="True" Tag="0" />
<local:MyComboBoxItem Content="Forge" Tag="1" /> <local:MyComboBoxItem Content="Forge" Tag="1" />
<local:MyComboBoxItem Content="NeoForge" Tag="6" /> <local:MyComboBoxItem Content="NeoForge" Tag="6" />
@@ -53,7 +54,7 @@
<local:MyComboBoxItem Content="Quilt" Tag="5" /> <local:MyComboBoxItem Content="Quilt" Tag="5" />
</local:MyComboBox> </local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Column="4" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" /> <TextBlock VerticalAlignment="Center" Grid.Column="4" Grid.Row="2" HorizontalAlignment="Left" Text="类型" Margin="0,0,18,0" />
<local:MyComboBox x:Name="ComboSearchTag" Grid.Column="5" Grid.Row="2" MaxDropDownHeight="320" /> <local:MyComboBox x:Name="ComboSearchTag" Grid.Column="5" Grid.Row="2" />
</Grid> </Grid>
<Grid Margin="0,4,0,6" Height="35"> <Grid Margin="0,4,0,6" Height="35">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -87,7 +88,7 @@
</local:MyCard> </local:MyCard>
</StackPanel> </StackPanel>
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50"> <local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False" Margin="40,50">
<local:MyLoading Text="正在获取XXX列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" /> <local:MyLoading Text="正在获取XXX列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" ShowProgress="True" />
</local:MyCard> </local:MyCard>
</StackPanel> </StackPanel>
</local:MyScrollViewer> </local:MyScrollViewer>
@@ -127,7 +127,7 @@ Public Class PageComp
.GameVersion = GameVersion .GameVersion = GameVersion
.Tag = ComboSearchTag.SelectedItem.Tag .Tag = ComboSearchTag.SelectedItem.Tag
.ModLoader = If(PageType = CompType.Mod, Val(ComboSearchLoader.SelectedItem.Tag), CompModLoaderType.Any) .ModLoader = If(PageType = CompType.Mod, Val(ComboSearchLoader.SelectedItem.Tag), CompModLoaderType.Any)
.Source = CType(Val(ComboSearchSource.SelectedItem.Tag), CompSourceType) .Sources = CType(Val(ComboSearchSource.SelectedItem.Tag), CompSourceType)
End With End With
Return Request Return Request
End Function End Function
@@ -20,6 +20,7 @@
</StackPanel> </StackPanel>
</local:MyCard> </local:MyCard>
<StackPanel Grid.Row="1" Grid.RowSpan="2" Name="PanMain" Grid.IsSharedSizeScope="True"> <StackPanel Grid.Row="1" Grid.RowSpan="2" Name="PanMain" Grid.IsSharedSizeScope="True">
<local:MyHint x:Name="HintAlternative" Theme="Blue" Margin="0,0,0,15" />
<local:MyCard Margin="0,0,0,15" x:Name="CardFilter"> <local:MyCard Margin="0,0,0,15" x:Name="CardFilter">
<StackPanel x:Name="PanFilter" Margin="10,10,0,10" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left" /> <StackPanel x:Name="PanFilter" Margin="10,10,0,10" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left" />
</local:MyCard> </local:MyCard>
@@ -8,7 +8,7 @@
Sub(Task) Sub(Task)
LoadTargetFromAdditional() LoadTargetFromAdditional()
Dim Result = CompFilesGet(Project.Id, Project.FromCurseForge) Dim Result = CompFilesGet(Project.Id, Project.FromCurseForge)
If Task.IsAborted Then Return If Task.IsInterrupted Then Return
Task.Output = Result Task.Output = Result
End Sub) End Sub)
@@ -21,14 +21,15 @@
Project = FrmMain.PageCurrent.Additional(0) Project = FrmMain.PageCurrent.Additional(0)
TargetInstance = FrmMain.PageCurrent.Additional(2) TargetInstance = FrmMain.PageCurrent.Additional(2)
TargetLoader = FrmMain.PageCurrent.Additional(3) TargetLoader = FrmMain.PageCurrent.Additional(3)
PageType = FrmMain.PageCurrent.Additional(4) TargetType = FrmMain.PageCurrent.Additional(4)
End Sub End Sub
Private Project As CompProject Private Project As CompProject
Private TargetInstance As String, TargetLoader As CompModLoaderType Private TargetInstance As String, TargetLoader As CompModLoaderType
''' <summary> ''' <summary>
''' 当前页面应展示的内容类别。可能为 Any。 ''' 当前页面应展示的内容类别。
''' 若当前页面是在查看前置时进入,则也可能为 Any。
''' </summary> ''' </summary>
Private PageType As CompType Private TargetType As CompType
'自动重试 '自动重试
Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
Select Case CompFileLoader.State Select Case CompFileLoader.State
@@ -74,13 +75,13 @@
'筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表) '筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表)
Private Function GetResults() As List(Of CompFile) Private Function GetResults() As List(Of CompFile)
Dim Results As List(Of CompFile) = CompFileLoader.Output Dim Results As List(Of CompFile) = CompFileLoader.Output
Select Case PageType Select Case TargetType
Case CompType.Any Case CompType.Any
Results = Results.Where(Function(r) r.Type <> CompType.Plugin).ToList Results = Results.Where(Function(r) r.Type <> CompType.Plugin).ToList
Case CompType.Shader, CompType.ResourcePack Case CompType.Shader, CompType.ResourcePack
'不筛选光影和资源包,否则原版光影会因为是资源包格式而被过滤(#6473) '不筛选光影和资源包,否则原版光影会因为是资源包格式而被过滤(#6473)
Case Else Case Else
Results = Results.Where(Function(r) r.Type = PageType).ToList Results = Results.Where(Function(r) r.Type = TargetType).ToList
End Select End Select
Return Results Return Results
End Function End Function
@@ -171,7 +172,7 @@ GroupDone:
Version.Type = CompType.Mod AndAlso '是 Mod Version.Type = CompType.Mod AndAlso '是 Mod
McVersion.IsFormatFit(VerName) Then '不是 “快照版本” 之类的 McVersion.IsFormatFit(VerName) Then '不是 “快照版本” 之类的
For Each Loader In Version.ModLoaders For Each Loader In Version.ModLoaders
If Loader = CompModLoaderType.Quilt AndAlso Setup.Get("ToolDownloadIgnoreQuilt") Then Continue For If Loader = CompModLoaderType.Quilt AndAlso Settings.Get("ToolDownloadIgnoreQuilt") Then Continue For
If SupportedLoaders.Contains(Loader) Then Loaders.Add(Loader.ToString & " ") If SupportedLoaders.Contains(Loader) Then Loaders.Add(Loader.ToString & " ")
Next Next
End If End If
@@ -204,7 +205,7 @@ GroupDone:
If Not Pair.Value.Any() Then Continue For If Not Pair.Value.Any() Then Continue For
If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For
'增加卡片 '增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(PageType = CompType.ModPack, 9, 8)} '9 是安装,8 是另存为 Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(TargetType = CompType.ModPack, 9, 8)} '9 是安装,8 是另存为
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} 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.Children.Add(NewStack)
NewCard.SwapControl = NewStack NewCard.SwapControl = NewStack
@@ -213,7 +214,7 @@ GroupDone:
If Pair.Key = TargetCardName OrElse If Pair.Key = TargetCardName OrElse
(FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761 (FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then 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 是另存为 MyCard.StackInstall(NewStack, If(TargetType = CompType.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为
Else Else
NewCard.IsSwapped = True NewCard.IsSwapped = True
End If End If
@@ -226,19 +227,28 @@ GroupDone:
If PanResults.Children.Count = 1 Then If PanResults.Children.Count = 1 Then
CType(PanResults.Children(0), MyCard).IsSwapped = False CType(PanResults.Children(0), MyCard).IsSwapped = False
End If End If
'替代提示
If Project.Types = CompType.ModOrDataPack AndAlso (TargetType = CompType.Mod OrElse TargetType = CompType.DataPack) Then
HintAlternative.Visibility = Visibility.Visible
HintAlternative.Text = If(TargetType = CompType.Mod,
"以下是该项目的 Mod 版本。点击这里查看其数据包版本。", "以下是该项目的数据包版本。点击这里查看其 Mod 版本。")
Else
HintAlternative.Visibility = Visibility.Collapsed
End If
Catch ex As Exception Catch ex As Exception
Log(ex, "可视化工程下载列表出错", LogLevel.Feedback) Log(ex, "可视化工程下载列表出错", LogLevel.Feedback)
End Try End Try
End Sub End Sub
Private Function GetGroupedVersionName(Name As String, GroupedByDrop As Boolean, FoldOld As Boolean) As String Private Function GetGroupedVersionName(Name As String, GroupedByDrop As Boolean, FoldOld As Boolean) As String
Dim Drop = McVersion.VersionToDrop(Name)
If Name Is Nothing Then If Name Is Nothing Then
Return "其他" Return "其他"
ElseIf Name.Contains("w") Then ElseIf Name.Contains("w") OrElse Drop = 209 Then
Return "快照版" Return "快照版"
ElseIf Not McVersion.IsFormatFit(Name) OrElse (FoldOld AndAlso McVersion.VersionToDrop(Name, True) < 120) Then ElseIf Not McVersion.IsFormatFit(Name) OrElse (FoldOld AndAlso Drop < 120) Then
Return "远古版" Return "远古版"
ElseIf GroupedByDrop Then ElseIf GroupedByDrop Then
Return McVersion.DropToVersion(McVersion.VersionToDrop(Name, True)) Return McVersion.DropToVersion(Drop)
Else Else
Return Name Return Name
End If End If
@@ -303,7 +313,7 @@ GroupDone:
Select Case MyLoader.State Select Case MyLoader.State
Case LoadState.Failed Case LoadState.Failed
Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetBrief(), HintType.Red) Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetBrief(), HintType.Red)
Case LoadState.Aborted Case LoadState.Interrupted
Hint(MyLoader.Name & "已取消!", HintType.Blue) Hint(MyLoader.Name & "已取消!", HintType.Blue)
Case LoadState.Loading Case LoadState.Loading
Return '不重新加载版本列表 Return '不重新加载版本列表
@@ -359,8 +369,38 @@ GroupDone:
If Not Instance.IsLoaded Then Instance.Load() If Not Instance.IsLoaded Then Instance.Load()
'只对 Mod 和数据包进行版本检测 '只对 Mod 和数据包进行版本检测
If File.Type = CompType.Mod OrElse File.Type = CompType.DataPack Then If File.Type = CompType.Mod OrElse File.Type = CompType.DataPack Then
If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso If Not File.GameVersions.Any( '判断是否有任何一个版本匹配
Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v = Instance.Version.VanillaName) Then Return False Function(FileVersion)
Dim FileIsSnapshot As Boolean = FileVersion.Contains("预览版") OrElse Not FileVersion.Contains(".")
Dim InstanceIsSnapshot As Boolean = Instance.Version.VanillaName.Contains("snapshot") OrElse Not Instance.Version.VanillaName.Contains(".")
If FileIsSnapshot <> InstanceIsSnapshot Then
'只有一种是预览版
Return False
ElseIf Not FileIsSnapshot AndAlso Not InstanceIsSnapshot Then
'都不是预览版
Return FileVersion = Instance.Version.VanillaName
Else
'都是预览版
Dim FileIsNewFormat As Boolean = FileVersion.Contains(".") AndAlso Val(FileVersion.BeforeFirst(".")) > 1
Dim InstanceIsNewFormat As Boolean = Instance.Version.Drop > 250
If FileIsNewFormat <> InstanceIsNewFormat Then
'只有一种是新格式快照
Return False
ElseIf FileIsNewFormat AndAlso InstanceIsNewFormat Then
'都是新格式快照
Return FileVersion.BeforeFirst(" ") = Instance.Version.VanillaName.BeforeFirst("-")
Else
'都是旧格式快照
If FileVersion.Contains("w") AndAlso Instance.Version.VanillaName.Contains("w") Then
'都是 w 快照
Return FileVersion = Instance.Version.VanillaName
Else
'不全是 w 快照
Return True '只能假定相同,无法判断
End If
End If
End If
End Function) Then Return False
End If End If
'加载器 '加载器
If Not AllowedLoaders.Any() Then Return True '无要求 If Not AllowedLoaders.Any() Then Return True '无要求
@@ -412,7 +452,7 @@ GroupDone:
Else Else
Dim ChineseName As String = Project.TranslatedName.BeforeFirst(" (").BeforeFirst(" - "). Dim ChineseName As String = Project.TranslatedName.BeforeFirst(" (").BeforeFirst(" - ").
Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":") Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":")
Select Case Setup.Get("ToolDownloadTranslateV2") Select Case Settings.Get("ToolDownloadTranslateV2")
Case 0 Case 0
FileName = $"【{ChineseName}】{File.FileName}" FileName = $"【{ChineseName}】{File.FileName}"
Case 1 Case 1
@@ -433,8 +473,8 @@ GroupDone:
Target = SelectSaveFile("选择保存位置", FileName, Target = SelectSaveFile("选择保存位置", FileName,
Desc & "文件|" & Desc & "文件|" &
If(File.Type = CompType.Mod, If(File.Type = CompType.Mod,
If(File.FileName.EndsWith(".litemod"), "*.litemod", "*.jar"), If(File.FileName.EndsWithF(".litemod"), "*.litemod", "*.jar"),
If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder) If(File.FileName.EndsWithF(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
If Not Target.Contains("\") Then Return If Not Target.Contains("\") Then Return
'构造步骤加载器 '构造步骤加载器
Dim LoaderName As String = Desc & "下载:" & IO.Path.GetFileNameWithoutExtension(Target) & " " Dim LoaderName As String = Desc & "下载:" & IO.Path.GetFileNameWithoutExtension(Target) & " "
@@ -464,4 +504,11 @@ GroupDone:
ClipboardSet(CompItem.LabTitle.Text & CompItem.LabTitleRaw.Text) ClipboardSet(CompItem.LabTitle.Text & CompItem.LabTitleRaw.Text)
End Sub End Sub
'Mod / 数据包 互相跳转
Private Sub HintAlternative_Click() Handles HintAlternative.Click
TargetType = If(TargetType = CompType.Mod, CompType.DataPack, CompType.Mod)
FrmMain.PageCurrent.Additional(4) = TargetType '加载器会从这里重新拿数据
PageLoaderRestart(IsForceRestart:=True)
End Sub
End Class End Class
@@ -2,60 +2,8 @@
Public Module ModDownloadLib Public Module ModDownloadLib
''' <summary>
''' 如果 OptiFine 与 Forge 同时开始安装,就会导致 Forge 安装失败。
''' </summary>
Private InstallSyncLock As New Object
''' <summary>
''' 如果 OptiFine 与 Forge 同时复制原版 Jar,就会导致复制文件时冲突。
''' </summary>
Private VanillaSyncLock As New Object
#Region "Minecraft 下载" #Region "Minecraft 下载"
''' <summary>
''' 下载某个 Minecraft 版本,这会创造一个单独的下载任务,失败会跳过执行并要求反馈。
''' 返回正在下载的任务,若跳过或失败,则返回 Nothing。
''' </summary>
''' <param name="Id">所下载的 Minecraft 的版本名。</param>
''' <param name="JsonUrl">Json 文件的 Mojang 官方地址。</param>
Public Function McDownloadClient(Behaviour As NetPreDownloadBehaviour, Id As String, Optional JsonUrl As String = Nothing) As LoaderCombo(Of String)
Try
Dim VersionFolder As String = McFolderSelected & "versions\" & Id & "\"
'重复任务检查
For Each OngoingLoader In LoaderTaskbar.ToList()
If OngoingLoader.Name <> $"Minecraft {Id} 下载" Then Continue For
If Behaviour = NetPreDownloadBehaviour.ExitWhileExistsOrDownloading Then Return OngoingLoader
Hint("该版本正在下载中!", HintType.Red)
Return OngoingLoader
Next
'已有版本检查
If Behaviour <> NetPreDownloadBehaviour.IgnoreCheck AndAlso File.Exists(VersionFolder & Id & ".json") AndAlso File.Exists(VersionFolder & Id & ".jar") Then
If Behaviour = NetPreDownloadBehaviour.ExitWhileExistsOrDownloading Then Return Nothing
If MyMsgBox("版本 " & Id & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 json 与 jar 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
File.Delete(VersionFolder & Id & ".jar")
File.Delete(VersionFolder & Id & ".json")
Else
Return Nothing
End If
End If
'启动
Dim Loader As New LoaderCombo(Of String)("Minecraft " & Id & " 下载", McDownloadClientLoader(Id, JsonUrl)) With {.OnStateChanged = AddressOf McInstallState}
Loader.Start(VersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
Return Loader
Catch ex As Exception
Log(ex, "开始 Minecraft 下载失败", LogLevel.Feedback)
Return Nothing
End Try
End Function
''' <summary> ''' <summary>
''' 获取下载某个 Minecraft 版本的加载器列表。 ''' 获取下载某个 Minecraft 版本的加载器列表。
''' 它必须安装到 McFolderSelected,但是可以自定义版本名(不过自定义的版本名不会修改 Json 中的 id 项)。 ''' 它必须安装到 McFolderSelected,但是可以自定义版本名(不过自定义的版本名不会修改 Json 中的 id 项)。
@@ -235,11 +183,11 @@ Public Module ModDownloadLib
Dim Instance As New McInstance(VersionFolder) Dim Instance As New McInstance(VersionFolder)
If Instance.JsonObject("downloads") Is Nothing OrElse Instance.JsonObject("downloads")("server") Is Nothing OrElse Instance.JsonObject("downloads")("server")("url") Is Nothing Then If Instance.JsonObject("downloads") Is Nothing OrElse Instance.JsonObject("downloads")("server") Is Nothing OrElse Instance.JsonObject("downloads")("server")("url") Is Nothing Then
File.Delete(VersionFolder & Id & ".json") File.Delete(VersionFolder & Id & ".json")
If Not New DirectoryInfo(VersionFolder).GetFileSystemInfos.Any() Then Directory.Delete(VersionFolder) If Not New DirectoryInfo(VersionFolder).GetFileSystemInfos.Any() Then DeleteDirectory(VersionFolder)
Task.Output = New List(Of NetFile) Task.Output = New List(Of NetFile)
Hint($"Mojang 没有给 Minecraft {Id} 提供官方服务端下载,没法下,撤退!", HintType.Red) Hint($"Mojang 没有给 Minecraft {Id} 提供官方服务端下载,没法下,撤退!", HintType.Red)
Thread.Sleep(2000) '等玩家把上一个提示看完 Thread.Sleep(2000) '等玩家把上一个提示看完
Task.Abort() Task.Interrupt()
Return Return
End If End If
Dim JarUrl As String = Instance.JsonObject("downloads")("server")("url") Dim JarUrl As String = Instance.JsonObject("downloads")("server")("url")
@@ -254,7 +202,7 @@ echo 你可以在 PCL 的 [设置 → 启动选项] 中查看已安装的 java
echo ------------------------------ echo ------------------------------
echo 如果提示 ""You need to agree to the EULA in order to run the server"",请打开 eula.txt,按说明阅读并同意 Minecraft EULA 后,将该文件最后一行中的 eula=false 改为 eula=true。 echo 如果提示 ""You need to agree to the EULA in order to run the server"",请打开 eula.txt,按说明阅读并同意 Minecraft EULA 后,将该文件最后一行中的 eula=false 改为 eula=true。
echo ------------------------------ echo ------------------------------
""java"" -server -XX:+UseG1GC -Xmx4096M -Xms1024M -XX:+UseCompressedOops -jar {Id}-server.jar nogui ""java"" -server -XX:+UseG1GC -Xmx6144M -Xms1024M -jar {Id}-server.jar nogui
echo ---------------------- echo ----------------------
echo 服务端已停止。 echo 服务端已停止。
pause" pause"
@@ -327,7 +275,7 @@ pause"
''' <param name="InstanceJson">在 version_manifest.json 中的对应项。</param> ''' <param name="InstanceJson">在 version_manifest.json 中的对应项。</param>
Public Sub McUpdateLogShow(InstanceJson As JToken) Public Sub McUpdateLogShow(InstanceJson As JToken)
Dim WikiName As String Dim WikiName As String
Dim Id As String = InstanceJson("id").ToString.ToLower Dim Id As String = InstanceJson("id").ToString.Lower
If Id = "3d shareware v1.34" Then If Id = "3d shareware v1.34" Then
WikiName = "3D_Shareware_v1.34" WikiName = "3D_Shareware_v1.34"
ElseIf Id = "2.0" Then ElseIf Id = "2.0" Then
@@ -420,22 +368,22 @@ pause"
Dim JavaLoader = GetJavaDownloadLoader() Dim JavaLoader = GetJavaDownloadLoader()
Try Try
JavaLoader.Start(17, IsForceRestart:=True) JavaLoader.Start(17, IsForceRestart:=True)
Do While JavaLoader.State = LoadState.Loading AndAlso Not Task.IsAborted Do While JavaLoader.State = LoadState.Loading AndAlso Not Task.IsInterrupted
Thread.Sleep(10) Thread.Sleep(10)
Loop Loop
Finally Finally
JavaLoader.Abort() '确保取消时中止 Java 下载 JavaLoader.Interrupt() '确保取消时中止 Java 下载
End Try End Try
'检查下载结果 '检查下载结果
Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 0)) Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 0))
If Task.IsAborted Then Return If Task.IsInterrupted Then Return
If Java Is Nothing Then Throw New Exception("由于未找到 Java,已取消安装。") If Java Is Nothing Then Throw New Exception("由于未找到 Java,已取消安装。")
End If End If
End SyncLock End SyncLock
'添加 Java Wrapper 作为主 Jar '添加 Java Wrapper 作为主 Jar
Dim Arguments As String Dim Arguments As String
If UseJavaWrapper AndAlso Not Setup.Get("LaunchAdvanceDisableJLW") Then If UseJavaWrapper AndAlso Not Settings.Get("LaunchAdvanceDisableJLW") Then
Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" -jar ""{ExtractJavaWrapper()}"" optifine.Installer" Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" -jar ""{ExtractPatch("JavaWrapper")}"" optifine.Installer"
Else Else
Arguments = $"-Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" optifine.Installer" Arguments = $"-Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" optifine.Installer"
End If End If
@@ -478,7 +426,7 @@ pause"
Log(ex, "读取 OptiFine 安装器信息失败") Log(ex, "读取 OptiFine 安装器信息失败")
End Try End Try
Try Try
If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then If Task.State = LoadState.Interrupted AndAlso Not process.HasExited Then
Log("[Installer] 由于任务取消,已中止 OptiFine 安装") Log("[Installer] 由于任务取消,已中止 OptiFine 安装")
process.Kill() process.Kill()
End If End If
@@ -502,7 +450,7 @@ pause"
Log(ex, "读取 OptiFine 安装器错误信息失败") Log(ex, "读取 OptiFine 安装器错误信息失败")
End Try End Try
Try Try
If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then If Task.State = LoadState.Interrupted AndAlso Not process.HasExited Then
Log("[Installer] 由于任务取消,已中止 OptiFine 安装") Log("[Installer] 由于任务取消,已中止 OptiFine 安装")
process.Kill() process.Kill()
End If End If
@@ -529,11 +477,11 @@ pause"
''' <summary> ''' <summary>
''' 获取下载某个 OptiFine 版本的加载器列表。 ''' 获取下载某个 OptiFine 版本的加载器列表。
''' 这不会补全所需的支持库文件,需要后续手动补全支持库。
''' </summary> ''' </summary>
Private Function McDownloadOptiFineLoader(DownloadInfo As DlOptiFineListEntry, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase) Private Function McDownloadOptiFineLoader(DownloadInfo As DlOptiFineListEntry, McFolder As String, ClientDownloadLoader As LoaderCombo(Of String), ClientFolder As String) As List(Of LoaderBase)
'参数初始化 '参数初始化
McFolder = If(McFolder, McFolderSelected)
Dim IsCustomFolder As Boolean = McFolder <> McFolderSelected Dim IsCustomFolder As Boolean = McFolder <> McFolderSelected
Dim Id As String = DownloadInfo.InstanceName Dim Id As String = DownloadInfo.InstanceName
Dim VersionFolder As String = McFolder & "versions\" & Id & "\" Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
@@ -546,12 +494,6 @@ pause"
'获取下载地址 '获取下载地址
Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("获取 OptiFine 主文件下载地址", Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("获取 OptiFine 主文件下载地址",
Sub(Task As LoaderTask(Of String, List(Of NetFile))) Sub(Task As LoaderTask(Of String, List(Of NetFile)))
'启动依赖版本的下载
If ClientDownloadLoader Is Nothing Then
If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, DownloadInfo.Inherit)
End If
Task.Progress = 0.1
Dim Sources As New List(Of String) Dim Sources As New List(Of String)
'BMCLAPI 源 'BMCLAPI 源
Dim BmclapiInherit As String = DownloadInfo.Inherit Dim BmclapiInherit As String = DownloadInfo.Inherit
@@ -564,8 +506,8 @@ pause"
'官方源 '官方源
Dim PageData As String Dim PageData As String
Try Try
PageData = NetRequestByClient("https://optifine.net/adloadx?f=" & DownloadInfo.FileName, PageData = NetRequestByClientRetry("https://optifine.net/adloadx?f=" & DownloadInfo.FileName,
Encoding:=New UTF8Encoding(False), Timeout:=15000, Accept:="text/html", SimulateBrowserHeaders:=True) Encoding:=New UTF8Encoding(False), Accept:="text/html", SimulateBrowserHeaders:=True)
Task.Progress = 0.8 Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0)) Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
Log("[Download] OptiFine " & DownloadInfo.DisplayName & " 官方下载地址:" & Sources.Last) Log("[Download] OptiFine " & DownloadInfo.DisplayName & " 官方下载地址:" & Sources.Last)
@@ -579,16 +521,15 @@ pause"
Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("等待原版下载", Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("等待原版下载",
Sub(Task As LoaderTask(Of List(Of NetFile), Boolean)) Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
'等待原版文件下载完成 '等待原版文件下载完成
If ClientDownloadLoader Is Nothing Then Return
Dim TargetLoaders As List(Of LoaderBase) = Dim TargetLoaders As List(Of LoaderBase) =
ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName). ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
Where(Function(l) l.State <> LoadState.Finished).ToList Where(Function(l) l.State <> LoadState.Finished).ToList
If TargetLoaders.Any Then Log("[Download] OptiFine 安装正在等待原版文件下载完成") If TargetLoaders.Any Then Log("[Download] OptiFine 安装正在等待原版文件下载完成")
Do While TargetLoaders.Any AndAlso Not Task.IsAborted Do While TargetLoaders.Any AndAlso Not Task.IsInterrupted
TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
Thread.Sleep(50) Thread.Sleep(50)
Loop Loop
If Task.IsAborted Then Return If Task.IsInterrupted Then Return
'拷贝原版文件 '拷贝原版文件
If Not IsCustomFolder Then Return If Not IsCustomFolder Then Return
SyncLock VanillaSyncLock SyncLock VanillaSyncLock
@@ -699,13 +640,6 @@ Retry:
End Sub) With {.ProgressWeight = 1}) End Sub) With {.ProgressWeight = 1})
End If End If
'下载支持库
If FixLibrary Then
Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 OptiFine 支持库文件",
Sub(Task) Task.Output = McLibNetFilesFromInstance(New McInstance(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
Loaders.Add(New LoaderDownload("下载 OptiFine 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 4})
End If
Return Loaders Return Loaders
End Function End Function
''' <summary> ''' <summary>
@@ -728,8 +662,8 @@ Retry:
'官方源 '官方源
Dim PageData As String Dim PageData As String
Try Try
PageData = NetRequestByClient("https://optifine.net/adloadx?f=" & DownloadInfo.FileName, PageData = NetRequestByClientRetry("https://optifine.net/adloadx?f=" & DownloadInfo.FileName,
Encoding:=New UTF8Encoding(False), Timeout:=15000, Accept:="text/html", SimulateBrowserHeaders:=True) Encoding:=New UTF8Encoding(False), Accept:="text/html", SimulateBrowserHeaders:=True)
Task.Progress = 0.8 Task.Progress = 0.8
Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0)) Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
Log("[Download] OptiFine " & DownloadInfo.DisplayName & " 官方下载地址:" & Sources.Last) Log("[Download] OptiFine " & DownloadInfo.DisplayName & " 官方下载地址:" & Sources.Last)
@@ -818,41 +752,6 @@ Retry:
#Region "LiteLoader 下载" #Region "LiteLoader 下载"
Public Sub McDownloadLiteLoader(DownloadInfo As DlLiteLoaderListEntry)
Try
Dim Id As String = DownloadInfo.Inherit
Dim Target As String = PathTemp & "Download\" & Id & "-Liteloader.jar"
Dim InstanceName As String = DownloadInfo.Inherit & "-LiteLoader"
Dim VersionFolder As String = McFolderSelected & "versions\" & InstanceName & "\"
'重复任务检查
For Each OngoingLoader In LoaderTaskbar.ToList()
If OngoingLoader.Name <> $"LiteLoader {Id} 下载" Then Continue For
Hint("该版本正在下载中!", HintType.Red)
Return
Next
'已有版本检查
If File.Exists(VersionFolder & InstanceName & ".json") Then
If MyMsgBox("版本 " & InstanceName & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 json 和 jar 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
File.Delete(VersionFolder & InstanceName & ".jar")
File.Delete(VersionFolder & InstanceName & ".json")
Else
Return
End If
End If
'启动
Dim Loader As New LoaderCombo(Of String)("LiteLoader " & Id & " 下载", McDownloadLiteLoaderLoader(DownloadInfo)) With {.OnStateChanged = AddressOf McInstallState}
Loader.Start(VersionFolder)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
FrmMain.BtnExtraDownload.Ribble()
Catch ex As Exception
Log(ex, "开始 LiteLoader 下载失败", LogLevel.Feedback)
End Try
End Sub
Private Sub McDownloadLiteLoaderSave(DownloadInfo As DlLiteLoaderListEntry) Private Sub McDownloadLiteLoaderSave(DownloadInfo As DlLiteLoaderListEntry)
Try Try
Dim Id As String = DownloadInfo.Inherit Dim Id As String = DownloadInfo.Inherit
@@ -905,11 +804,11 @@ Retry:
''' <summary> ''' <summary>
''' 获取下载某个 LiteLoader 版本的加载器列表。 ''' 获取下载某个 LiteLoader 版本的加载器列表。
''' 这不会补全所需的支持库文件,需要后续手动补全支持库。
''' </summary> ''' </summary>
Private Function McDownloadLiteLoaderLoader(DownloadInfo As DlLiteLoaderListEntry, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase) Private Function McDownloadLiteLoaderLoader(DownloadInfo As DlLiteLoaderListEntry, McFolder As String) As List(Of LoaderBase)
'参数初始化 '参数初始化
McFolder = If(McFolder, McFolderSelected)
Dim IsCustomFolder As Boolean = McFolder <> McFolderSelected Dim IsCustomFolder As Boolean = McFolder <> McFolderSelected
Dim Id As String = DownloadInfo.Inherit Dim Id As String = DownloadInfo.Inherit
Dim Target As String = PathTemp & "Download\" & Id & "-Liteloader.jar" Dim Target As String = PathTemp & "Download\" & Id & "-Liteloader.jar"
@@ -917,14 +816,6 @@ Retry:
Dim VersionFolder As String = McFolder & "versions\" & VersionName & "\" Dim VersionFolder As String = McFolder & "versions\" & VersionName & "\"
Dim Loaders As New List(Of LoaderBase) Dim Loaders As New List(Of LoaderBase)
'启动依赖版本的下载
If ClientDownloadLoader Is Nothing Then
Loaders.Add(New LoaderTask(Of String, String)("启动 LiteLoader 依赖版本下载",
Sub()
If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, DownloadInfo.Inherit)
End Sub) With {.ProgressWeight = 0.2, .Show = False, .Block = False})
End If
'安装 '安装
Loaders.Add(New LoaderTask(Of String, String)("安装 LiteLoader", Loaders.Add(New LoaderTask(Of String, String)("安装 LiteLoader",
Sub(Task As LoaderTask(Of String, String)) Sub(Task As LoaderTask(Of String, String))
@@ -950,12 +841,6 @@ Retry:
Throw New Exception("安装新 LiteLoader 版本失败", ex) Throw New Exception("安装新 LiteLoader 版本失败", ex)
End Try End Try
End Sub) With {.ProgressWeight = 1}) End Sub) With {.ProgressWeight = 1})
'下载支持库
If FixLibrary Then
Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 LiteLoader 支持库文件",
Sub(Task) Task.Output = McLibNetFilesFromInstance(New McInstance(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
Loaders.Add(New LoaderDownload("下载 LiteLoader 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 6})
End If
Return Loaders Return Loaders
End Function End Function
@@ -1095,22 +980,22 @@ Retry:
Dim JavaLoader = GetJavaDownloadLoader() Dim JavaLoader = GetJavaDownloadLoader()
Try Try
JavaLoader.Start(17, IsForceRestart:=True) JavaLoader.Start(17, IsForceRestart:=True)
Do While JavaLoader.State = LoadState.Loading AndAlso Not Task.IsAborted Do While JavaLoader.State = LoadState.Loading AndAlso Not Task.IsInterrupted
Thread.Sleep(10) Thread.Sleep(10)
Loop Loop
Finally Finally
JavaLoader.Abort() '确保取消时中止 Java 下载 JavaLoader.Interrupt() '确保取消时中止 Java 下载
End Try End Try
'检查下载结果 '检查下载结果
Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 60)) Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 60))
If Task.IsAborted Then Return If Task.IsInterrupted Then Return
If Java Is Nothing Then Throw New Exception("由于未找到 Java,已取消安装。") If Java Is Nothing Then Throw New Exception("由于未找到 Java,已取消安装。")
End If End If
End SyncLock End SyncLock
'添加 Java Wrapper 作为主 Jar '添加 Java Wrapper 作为主 Jar
Dim Arguments As String Dim Arguments As String
If UseJavaWrapper AndAlso Not Setup.Get("LaunchAdvanceDisableJLW") Then If UseJavaWrapper AndAlso Not Settings.Get("LaunchAdvanceDisableJLW") Then
Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{ExtractJavaWrapper()}"" com.bangbang93.ForgeInstaller ""{McFolder}" Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{ExtractPatch("JavaWrapper")}"" com.bangbang93.ForgeInstaller ""{McFolder}"
Else Else
Arguments = $"-cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" com.bangbang93.ForgeInstaller ""{McFolder}" Arguments = $"-cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" com.bangbang93.ForgeInstaller ""{McFolder}"
End If End If
@@ -1146,7 +1031,7 @@ Retry:
Log(ex, $"读取 {LoaderName} 安装器信息失败") Log(ex, $"读取 {LoaderName} 安装器信息失败")
End Try End Try
Try Try
If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then If Task.State = LoadState.Interrupted AndAlso Not process.HasExited Then
Log($"[Installer] 由于任务取消,已中止 {LoaderName} 安装") Log($"[Installer] 由于任务取消,已中止 {LoaderName} 安装")
process.Kill() process.Kill()
End If End If
@@ -1169,7 +1054,7 @@ Retry:
Log(ex, $"读取 {LoaderName} 安装器错误信息失败") Log(ex, $"读取 {LoaderName} 安装器错误信息失败")
End Try End Try
Try Try
If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then If Task.State = LoadState.Interrupted AndAlso Not process.HasExited Then
Log($"[Installer] 由于任务取消,已中止 {LoaderName} 安装") Log($"[Installer] 由于任务取消,已中止 {LoaderName} 安装")
process.Kill() process.Kill()
End If End If
@@ -1190,7 +1075,7 @@ Retry:
process.Dispose() process.Dispose()
'检查是否安装成功:最后 5 行中是否有 true(true 可能在倒数数行,见 #832) '检查是否安装成功:最后 5 行中是否有 true(true 可能在倒数数行,见 #832)
If LastResults.Reverse().Take(5).Any(Function(l) l = "true") Then Return If LastResults.Reverse().Take(5).Any(Function(l) l = "true") Then Return
Log(Join(LastResults, vbCrLf)) Log(LastResults.Join(vbCrLf))
Dim LastLines As String = "" Dim LastLines As String = ""
For i As Integer = Math.Max(0, LastResults.Count - 5) To LastResults.Count - 1 '最后 5 行 For i As Integer = Math.Max(0, LastResults.Count - 5) To LastResults.Count - 1 '最后 5 行
LastLines &= vbCrLf & LastResults(i) LastLines &= vbCrLf & LastResults(i)
@@ -1245,7 +1130,7 @@ Retry:
''' <summary> ''' <summary>
''' 获取下载某个 Forgelike 版本的加载器列表。 ''' 获取下载某个 Forgelike 版本的加载器列表。
''' </summary> ''' </summary>
Private Function McDownloadForgelikeLoader(IsNeoForge As Boolean, LoaderVersion As String, NewInstanceName As String, Inherit As String, Optional Info As DlForgelikeEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing) As List(Of LoaderBase) Private Function McDownloadForgelikeLoader(IsNeoForge As Boolean, LoaderVersion As String, NewInstanceName As String, Inherit As String, Info As DlForgelikeEntry, McFolder As String, ClientDownloadLoader As LoaderCombo(Of String), ClientFolder As String) As List(Of LoaderBase)
'参数初始化 '参数初始化
McFolder = If(McFolder, McFolderSelected) McFolder = If(McFolder, McFolderSelected)
@@ -1291,11 +1176,6 @@ Retry:
'下载 Forgelike 主文件 '下载 Forgelike 主文件
Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"准备下载 {LoaderName}", Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"准备下载 {LoaderName}",
Sub(Task As LoaderTask(Of String, List(Of NetFile))) Sub(Task As LoaderTask(Of String, List(Of NetFile)))
'启动依赖版本的下载
If ClientDownloadLoader Is Nothing Then
If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, Inherit)
End If
'添加主文件下载 '添加主文件下载
Dim Files As New List(Of NetFile) Dim Files As New List(Of NetFile)
If Info.IsNeoForge Then If Info.IsNeoForge Then
@@ -1353,8 +1233,8 @@ Retry:
Task.Progress = 0.8 Task.Progress = 0.8
'去除其中的原始 Forgelike 项 '去除其中的原始 Forgelike 项
For i = 0 To Libs.Count - 1 For i = 0 To Libs.Count - 1
If Libs(i).LocalPath.EndsWithF($"{LoaderName.ToLower}-{Inherit}-{LoaderVersion}.jar") OrElse If Libs(i).LocalPath.EndsWithF($"{LoaderName.Lower}-{Inherit}-{LoaderVersion}.jar") OrElse
Libs(i).LocalPath.EndsWithF($"{LoaderName.ToLower}-{Inherit}-{LoaderVersion}-client.jar") Then Libs(i).LocalPath.EndsWithF($"{LoaderName.Lower}-{Inherit}-{LoaderVersion}-client.jar") Then
Log($"[Download] 已从待下载 {LoaderName} 支持库中移除:" & Libs(i).LocalPath, LogLevel.Debug) Log($"[Download] 已从待下载 {LoaderName} 支持库中移除:" & Libs(i).LocalPath, LogLevel.Debug)
Libs.RemoveAt(i) Libs.RemoveAt(i)
Exit For Exit For
@@ -1385,16 +1265,15 @@ Retry:
#End Region #End Region
#Region "原版文件" #Region "原版文件"
'等待原版文件下载完成 '等待原版文件下载完成
If ClientDownloadLoader Is Nothing Then Return
Dim TargetLoaders As List(Of LoaderBase) = Dim TargetLoaders As List(Of LoaderBase) =
ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName). ClientDownloadLoader.GetLoaderList.Where(Function(l) l.Name = McDownloadClientLibName OrElse l.Name = McDownloadClientJsonName).
Where(Function(l) l.State <> LoadState.Finished).ToList() Where(Function(l) l.State <> LoadState.Finished).ToList()
If TargetLoaders.Any Then Log($"[Download] {LoaderName} 安装正在等待原版文件下载完成") If TargetLoaders.Any Then Log($"[Download] {LoaderName} 安装正在等待原版文件下载完成")
Do While TargetLoaders.Any AndAlso Not Task.IsAborted Do While TargetLoaders.Any AndAlso Not Task.IsInterrupted
TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList
Thread.Sleep(50) Thread.Sleep(50)
Loop Loop
If Task.IsAborted Then Return If Task.IsInterrupted Then Return
'拷贝原版文件 '拷贝原版文件
If Not IsCustomFolder Then Return If Not IsCustomFolder Then Return
SyncLock VanillaSyncLock SyncLock VanillaSyncLock
@@ -1541,7 +1420,7 @@ Retry:
Public Sub ForgeDownloadListItemPreload(Stack As StackPanel, Entries As List(Of DlForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) Public Sub ForgeDownloadListItemPreload(Stack As StackPanel, Entries As List(Of DlForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
'如果只有一个版本,则不特别列出 '如果只有一个版本,则不特别列出
If Entries.Count = 1 Then Return If Entries.IsSingle Then Return
'获取推荐版本与最新版本 '获取推荐版本与最新版本
Dim FreshVersion As DlForgeVersionEntry = Nothing Dim FreshVersion As DlForgeVersionEntry = Nothing
If Entries.Any Then If Entries.Any Then
@@ -1662,7 +1541,7 @@ Retry:
Next Next
If RecommendedList.Count < 5 Then Throw New Exception("获取的推荐版本数过少(" & Result & ")") If RecommendedList.Count < 5 Then Throw New Exception("获取的推荐版本数过少(" & Result & ")")
'保存 '保存
Dim CacheJson As String = "{" & Join(RecommendedList, ",") & "}" Dim CacheJson As String = "{" & RecommendedList.Join(",") & "}"
WriteFile(PathTemp & "Cache\ForgeRecommendedList.json", CacheJson) WriteFile(PathTemp & "Cache\ForgeRecommendedList.json", CacheJson)
Log("[Download] 刷新 Forge 推荐版本缓存成功") Log("[Download] 刷新 Forge 推荐版本缓存成功")
Catch ex As Exception Catch ex As Exception
@@ -1698,7 +1577,7 @@ Retry:
Public Sub NeoForgeDownloadListItemPreload(Stack As StackPanel, Entries As List(Of DlNeoForgeListEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) Public Sub NeoForgeDownloadListItemPreload(Stack As StackPanel, Entries As List(Of DlNeoForgeListEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
'如果只有一个版本,则不特别列出 '如果只有一个版本,则不特别列出
If Entries.Count = 1 Then Return If Entries.IsSingle Then Return
'获取最新稳定版和测试版 '获取最新稳定版和测试版
Dim FreshStableVersion As DlNeoForgeListEntry = Nothing Dim FreshStableVersion As DlNeoForgeListEntry = Nothing
Dim FreshBetaVersion As DlNeoForgeListEntry = Nothing Dim FreshBetaVersion As DlNeoForgeListEntry = Nothing
@@ -1832,11 +1711,11 @@ Retry:
''' <summary> ''' <summary>
''' 获取下载某个 Fabric 版本的加载器列表。 ''' 获取下载某个 Fabric 版本的加载器列表。
''' 这不会补全所需的支持库文件,需要后续手动补全支持库。
''' </summary> ''' </summary>
Private Function McDownloadFabricLoader(FabricVersion As String, MinecraftName As String, Optional McFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase) Private Function McDownloadFabricLoader(FabricVersion As String, MinecraftName As String, McFolder As String) As List(Of LoaderBase)
'参数初始化 '参数初始化
McFolder = If(McFolder, McFolderSelected)
Dim IsCustomFolder As Boolean = McFolder <> McFolderSelected Dim IsCustomFolder As Boolean = McFolder <> McFolderSelected
Dim Id As String = "fabric-loader-" & FabricVersion & "-" & MinecraftName Dim Id As String = "fabric-loader-" & FabricVersion & "-" & MinecraftName
Dim VersionFolder As String = McFolder & "versions\" & Id & "\" Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
@@ -1846,26 +1725,13 @@ Retry:
MinecraftName = MinecraftName.Replace("∞", "infinite") '放在 ID 后面避免影响版本文件夹名称 MinecraftName = MinecraftName.Replace("∞", "infinite") '放在 ID 后面避免影响版本文件夹名称
Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("获取 Fabric 主文件下载地址", Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("获取 Fabric 主文件下载地址",
Sub(Task As LoaderTask(Of String, List(Of NetFile))) Sub(Task As LoaderTask(Of String, List(Of NetFile)))
'启动依赖版本的下载
If FixLibrary Then
McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, MinecraftName)
End If
Task.Progress = 0.5
'构造文件请求
Task.Output = New List(Of NetFile) From {New NetFile({ Task.Output = New List(Of NetFile) From {New NetFile({
"https://bmclapi2.bangbang93.com/fabric-meta/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json", "https://bmclapi2.bangbang93.com/fabric-meta/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json",
"https://meta.fabricmc.net/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json" "https://meta.fabricmc.net/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json"
}, VersionFolder & Id & ".json", New FileChecker(IsJson:=True))} }, VersionFolder & Id & ".json", New FileChecker(IsJson:=True))} '构造文件请求
End Sub) With {.ProgressWeight = 0.5}) End Sub) With {.ProgressWeight = 0.5})
Loaders.Add(New LoaderDownload("下载 Fabric 主文件", New List(Of NetFile)) With {.ProgressWeight = 2.5}) Loaders.Add(New LoaderDownload("下载 Fabric 主文件", New List(Of NetFile)) With {.ProgressWeight = 2.5})
'下载支持库
If FixLibrary Then
Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 Fabric 支持库文件",
Sub(Task) Task.Output = McLibNetFilesFromInstance(New McInstance(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
Loaders.Add(New LoaderDownload("下载 Fabric 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 8})
End If
Return Loaders Return Loaders
End Function End Function
@@ -1901,7 +1767,7 @@ Retry:
Return New MyVirtualizingElement(Of MyListItem)( Return New MyVirtualizingElement(Of MyListItem)(
Function() Function()
Dim NewItem As New MyListItem With { Dim NewItem As New MyListItem With {
.Title = Entry.DisplayName.ToLower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v"), .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .Title = Entry.DisplayName.Lower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v"), .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry,
.Info = Entry.StatusDescription & ",发布于 " & Entry.ReleaseDate.ToString("yyyy'/'MM'/'dd HH':'mm"), .Info = Entry.StatusDescription & ",发布于 " & Entry.ReleaseDate.ToString("yyyy'/'MM'/'dd HH':'mm"),
.Logo = PathImage & "Blocks/OptiFabric.png" .Logo = PathImage & "Blocks/OptiFabric.png"
} }
@@ -1999,7 +1865,7 @@ Retry:
Hint(Loader.Name & "成功!", HintType.Green) Hint(Loader.Name & "成功!", HintType.Green)
Case LoadState.Failed Case LoadState.Failed
Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red) Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red)
Case LoadState.Aborted Case LoadState.Interrupted
Hint(Loader.Name & "已取消!", HintType.Blue) Hint(Loader.Name & "已取消!", HintType.Blue)
End Select End Select
End Sub End Sub
@@ -2011,9 +1877,10 @@ Retry:
Case LoadState.Finished Case LoadState.Finished
WriteIni(McFolderSelected & "PCL.ini", "InstanceCache", "") '清空缓存(合并安装会先生成文件夹,这会在刷新时误判为可以使用缓存) WriteIni(McFolderSelected & "PCL.ini", "InstanceCache", "") '清空缓存(合并安装会先生成文件夹,这会在刷新时误判为可以使用缓存)
Hint(Loader.Name & "成功!", HintType.Green) Hint(Loader.Name & "成功!", HintType.Green)
'TODO: 自动选择安装成功的版本
Case LoadState.Failed Case LoadState.Failed
Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red) MyMsgBox(Loader.Error.GetDetail, Loader.Name & "失败", IsWarn:=True)
Case LoadState.Aborted Case LoadState.Interrupted
Hint(Loader.Name & "已取消!", HintType.Blue) Hint(Loader.Name & "已取消!", HintType.Blue)
Case LoadState.Loading Case LoadState.Loading
Return '不重新加载版本列表 Return '不重新加载版本列表
@@ -2024,7 +1891,7 @@ Retry:
Public Sub McInstallFailedClearFolder(Loader) Public Sub McInstallFailedClearFolder(Loader)
Try Try
Thread.Sleep(1000) '防止存在尚未完全释放的文件,导致清理失败(例如整合包安装) Thread.Sleep(1000) '防止存在尚未完全释放的文件,导致清理失败(例如整合包安装)
If Loader.State = LoadState.Failed OrElse Loader.State = LoadState.Aborted Then If Loader.State = LoadState.Failed OrElse Loader.State = LoadState.Interrupted Then
'删除版本文件夹 '删除版本文件夹
If Directory.Exists(Loader.Input & "saves\") OrElse Directory.Exists(Loader.Input & "versions\") Then If Directory.Exists(Loader.Input & "saves\") OrElse Directory.Exists(Loader.Input & "versions\") Then
Log("[Download] 由于版本已被独立启动,不清理版本文件夹:" & Loader.Input, LogLevel.Developer) Log("[Download] 由于版本已被独立启动,不清理版本文件夹:" & Loader.Input, LogLevel.Developer)
@@ -2102,7 +1969,11 @@ Retry:
Dim OptiFineAsMod As Boolean = Request.OptiFineEntry IsNot Nothing AndAlso Modable '选择了 OptiFine 与任意 Mod 加载器 Dim OptiFineAsMod As Boolean = Request.OptiFineEntry IsNot Nothing AndAlso Modable '选择了 OptiFine 与任意 Mod 加载器
If OptiFineAsMod Then If OptiFineAsMod Then
Log("[Download] OptiFine 将作为 Mod 进行下载") Log("[Download] OptiFine 将作为 Mod 进行下载")
OptiFineFolder = ModsTempFolder If Request.LiteLoaderEntry IsNot Nothing Then
OptiFineFolder = ModsTempFolder & Request.MinecraftName & "\" '#8147
Else
OptiFineFolder = ModsTempFolder
End If
End If End If
'记录日志 '记录日志
@@ -2140,7 +2011,7 @@ Retry:
LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.DisplayName, McDownloadOptiFineSaveLoader(Request.OptiFineEntry, OptiFineFolder & Request.OptiFineEntry.FileName)) With {.Show = False, .ProgressWeight = 16, LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.DisplayName, McDownloadOptiFineSaveLoader(Request.OptiFineEntry, OptiFineFolder & Request.OptiFineEntry.FileName)) With {.Show = False, .ProgressWeight = 16,
.Block = Request.ForgeVersion Is Nothing AndAlso Request.NeoForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing}) .Block = Request.ForgeVersion Is Nothing AndAlso Request.NeoForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
Else Else
LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.DisplayName, McDownloadOptiFineLoader(Request.OptiFineEntry, TempMcFolder, ClientLoader, Request.VersionFolder, False)) With {.Show = False, .ProgressWeight = 24, LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.DisplayName, McDownloadOptiFineLoader(Request.OptiFineEntry, TempMcFolder, ClientLoader, Request.VersionFolder)) With {.Show = False, .ProgressWeight = 24,
.Block = Request.ForgeVersion Is Nothing AndAlso Request.NeoForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing}) .Block = Request.ForgeVersion Is Nothing AndAlso Request.NeoForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
End If End If
End If End If
@@ -2156,12 +2027,12 @@ Retry:
End If End If
'LiteLoader 'LiteLoader
If Request.LiteLoaderEntry IsNot Nothing Then If Request.LiteLoaderEntry IsNot Nothing Then
LoaderList.Add(New LoaderCombo(Of String)("下载 LiteLoader " & Request.MinecraftName, McDownloadLiteLoaderLoader(Request.LiteLoaderEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 1, LoaderList.Add(New LoaderCombo(Of String)("下载 LiteLoader " & Request.MinecraftName, McDownloadLiteLoaderLoader(Request.LiteLoaderEntry, TempMcFolder)) With {.Show = False, .ProgressWeight = 1,
.Block = Request.FabricVersion Is Nothing}) .Block = Request.FabricVersion Is Nothing})
End If End If
'Fabric 'Fabric
If Request.FabricVersion IsNot Nothing Then If Request.FabricVersion IsNot Nothing Then
LoaderList.Add(New LoaderCombo(Of String)("下载 Fabric " & Request.FabricVersion, McDownloadFabricLoader(Request.FabricVersion, Request.MinecraftName, TempMcFolder, False)) With {.Show = False, .ProgressWeight = 2, LoaderList.Add(New LoaderCombo(Of String)("下载 Fabric " & Request.FabricVersion, McDownloadFabricLoader(Request.FabricVersion, Request.MinecraftName, TempMcFolder)) With {.Show = False, .ProgressWeight = 2,
.Block = True}) .Block = True})
End If End If
'合并安装 '合并安装
@@ -2313,7 +2184,7 @@ Retry:
SplitArguments.Add(RawArguments(i)) SplitArguments.Add(RawArguments(i))
End If End If
Next Next
Dim RealArguments As String = Join(SplitArguments.Distinct.ToList, " ") Dim RealArguments As String = SplitArguments.Distinct.Join(" ")
'合并 '合并
'相关讨论见 #2801 '相关讨论见 #2801
OutputJson = MinecraftJson OutputJson = MinecraftJson
@@ -2368,4 +2239,48 @@ Retry:
#End Region #End Region
''' <summary>
''' 如果 OptiFine 与 Forge 同时开始安装,就会导致 Forge 安装失败。
''' </summary>
Private InstallSyncLock As New Object
''' <summary>
''' 如果 OptiFine 与 Forge 同时复制原版 JAR,就会导致复制文件时冲突。
''' </summary>
Private VanillaSyncLock As New Object
''' <summary>
''' 释放补丁文件并返回完整文件路径。
''' </summary>
''' <param name="Patch">"LUA" 或 "JavaWrapper"。</param>
Public Function ExtractPatch(Patch As String) As String
Dim PatchPath As String = $"{PathPure}{Patch}.jar"
Log($"[Java] 选定的 {Patch} 路径:{PatchPath}")
Static Lock As New Object
SyncLock Lock '避免 OptiFine 和 Forge 安装时同时释放导致冲突
Try
WriteFile(PatchPath, GetResources(Patch))
Catch ex As Exception
If File.Exists(PatchPath) Then
'因为未知原因可能变为只读文件(#4243)
Log(ex, $"{Patch} 文件释放失败,但文件已存在,将在删除后尝试重新生成", LogLevel.Developer)
Try
File.Delete(PatchPath)
WriteFile(PatchPath, GetResources(Patch))
Catch ex2 As Exception
Log(ex2, $"{Patch} 文件重新释放失败,将尝试更换文件名重新生成", LogLevel.Developer)
PatchPath = $"{PathPure}{Patch}2.jar"
Try
WriteFile(PatchPath, GetResources(Patch))
Catch ex3 As Exception
Throw New FileNotFoundException($"释放 {Patch} 最终尝试失败", ex3)
End Try
End Try
Else
Throw New FileNotFoundException($"释放 {Patch} 失败", ex)
End If
End Try
End SyncLock
Return PatchPath
End Function
End Module End Module
@@ -161,7 +161,7 @@
Private VanillaIcon As String Private VanillaIcon As String
Private ReadOnly Property VanillaDrop As Integer Private ReadOnly Property VanillaDrop As Integer
Get Get
Return McVersion.VersionToDrop(VanillaName, True) Return McVersion.VersionToDrop(VanillaName)
End Get End Get
End Property End Property
@@ -322,7 +322,7 @@
Else Else
BtnOptiFabricClear.Visibility = Visibility.Visible BtnOptiFabricClear.Visibility = Visibility.Visible
ImgOptiFabric.Visibility = Visibility.Visible ImgOptiFabric.Visibility = Visibility.Visible
LabOptiFabric.Text = SelectedOptiFabric.DisplayName.ToLower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v") LabOptiFabric.Text = SelectedOptiFabric.DisplayName.Lower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v")
LabOptiFabric.Foreground = ColorGray1 LabOptiFabric.Foreground = ColorGray1
End If End If
End If End If
@@ -456,22 +456,22 @@
Case "snapshot" Case "snapshot"
Type = "预览版" Type = "预览版"
'Mojang 误分类 'Mojang 误分类
If Version("id").ToString.StartsWith("1.") AndAlso If Version("id").ToString.StartsWithF("1.") AndAlso
Not Version("id").ToString.ToLower.Contains("combat") AndAlso Not Version("id").ToString.Lower.Contains("combat") AndAlso
Not Version("id").ToString.ToLower.Contains("rc") AndAlso Not Version("id").ToString.Lower.Contains("rc") AndAlso
Not Version("id").ToString.ToLower.Contains("experimental") AndAlso Not Version("id").ToString.Lower.Contains("experimental") AndAlso
Not Version("id").ToString.ToLower.Contains("pre") Then Not Version("id").ToString.Lower.Contains("pre") Then
Type = "正式版" Type = "正式版"
Version("type") = "release" Version("type") = "release"
End If End If
'愚人节版本 '愚人节版本
Select Case Version("id").ToString.ToLower Select Case Version("id").ToString.Lower
Case "20w14infinite", "20w14∞" Case "20w14infinite", "20w14∞"
Type = "愚人节版" Type = "愚人节版"
Version("id") = "20w14∞" Version("id") = "20w14∞"
Version("type") = "special" Version("type") = "special"
Version.Add("lore", GetMcFoolName(Version("id"))) Version.Add("lore", GetMcFoolName(Version("id")))
Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime", "23w13a_or_b", "24w14potato", "25w14craftmine" Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime", "23w13a_or_b", "24w14potato", "25w14craftmine", "26w14a"
Type = "愚人节版" Type = "愚人节版"
Version("type") = "special" Version("type") = "special"
Version.Add("lore", GetMcFoolName(Version("id"))) Version.Add("lore", GetMcFoolName(Version("id")))
@@ -566,7 +566,7 @@
Dim HasAny As Boolean = False Dim HasAny As Boolean = False
Dim HasRequiredVersion As Boolean = False Dim HasRequiredVersion As Boolean = False
For Each OptiFineVersion As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value For Each OptiFineVersion As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
If Not OptiFineVersion.DisplayName.StartsWith(VanillaName & " ") Then Continue For '不是同一个大版本 If Not OptiFineVersion.DisplayName.StartsWithF(VanillaName & " ") Then Continue For '不是同一个大版本
HasAny = True HasAny = True
If SelectedForge Is Nothing Then Return Nothing '未选择 Forge If SelectedForge Is Nothing Then Return Nothing '未选择 Forge
If IsOptiFineSuitForForge(OptiFineVersion, SelectedForge) Then Return Nothing '该版本可用 If IsOptiFineSuitForForge(OptiFineVersion, SelectedForge) Then Return Nothing '该版本可用
@@ -609,7 +609,7 @@
Dim Versions As New List(Of DlOptiFineListEntry) Dim Versions As New List(Of DlOptiFineListEntry)
For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(Version, SelectedForge) Then Continue For If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(Version, SelectedForge) Then Continue For
If Version.DisplayName.StartsWith(VanillaName & " ") Then Versions.Add(Version) If Version.DisplayName.StartsWithF(VanillaName & " ") Then Versions.Add(Version)
Next Next
If Not Versions.Any() Then Return If Not Versions.Any() Then Return
'排序 '排序
@@ -915,16 +915,17 @@
Dim FabricApiName = FabricApi.DisplayName Dim FabricApiName = FabricApi.DisplayName
Try Try
If FabricApiName Is Nothing OrElse VanillaName Is Nothing Then Return False If FabricApiName Is Nothing OrElse VanillaName Is Nothing Then Return False
FabricApiName = FabricApiName.ToLower : VanillaName = VanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").ToLower FabricApiName = FabricApiName.Lower
If FabricApiName.StartsWith("[" & VanillaName & "]") Then Return True Dim TargetName = VanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").Lower
If FabricApiName.StartsWithF("[" & TargetName & "]") Then Return True
If Not FabricApiName.Contains("/") OrElse Not FabricApiName.Contains("]") Then Return False If Not FabricApiName.Contains("/") OrElse Not FabricApiName.Contains("]") Then Return False
'直接的判断(例如 1.18.1/22w03a) '直接的判断(例如 1.18.1/22w03a)
For Each Part As String In FabricApiName.BeforeFirst("]").TrimStart("[").Split("/") For Each Part As String In FabricApiName.BeforeFirst("]").TrimStart("[").Split("/")
If Part = VanillaName Then Return True If Part = TargetName Then Return True
Next Next
'将版本名分割语素(例如 1.16.4/5) '将版本名分割语素(例如 1.16.4/5)
Dim Lefts = RegexSearch(FabricApiName.BeforeFirst("]"), "[a-z/]+|[0-9/]+") Dim Lefts = RegexSearch(FabricApiName.BeforeFirst("]"), "[a-z/]+|[0-9/]+")
Dim Rights = RegexSearch(VanillaName.BeforeFirst("]"), "[a-z/]+|[0-9/]+") Dim Rights = RegexSearch(TargetName.BeforeFirst("]"), "[a-z/]+|[0-9/]+")
'对每段进行判断 '对每段进行判断
Dim i As Integer = 0 Dim i As Integer = 0
While True While True
@@ -980,7 +981,7 @@
Dim Versions As New List(Of CompFile) Dim Versions As New List(Of CompFile)
For Each Version In DlFabricApiLoader.Output For Each Version In DlFabricApiLoader.Output
If IsFabricApiCompatible(Version) Then If IsFabricApiCompatible(Version) Then
If Not Version.DisplayName.StartsWith("[") Then If Not Version.DisplayName.StartsWithF("[") Then
Log("[Download] 已特判修改 Fabric API 显示名:" & Version.DisplayName, LogLevel.Debug) Log("[Download] 已特判修改 Fabric API 显示名:" & Version.DisplayName, LogLevel.Debug)
Version.DisplayName = "[" & VanillaName & "] " & Version.DisplayName Version.DisplayName = "[" & VanillaName & "] " & Version.DisplayName
End If End If
@@ -1122,7 +1123,7 @@
Private Sub BtnStart_Click() Handles BtnStart.Click Private Sub BtnStart_Click() Handles BtnStart.Click
'确认版本隔离 '确认版本隔离
If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
(Setup.Get("LaunchArgumentIndieV2") = 0 OrElse Setup.Get("LaunchArgumentIndieV2") = 2) Then (Settings.Get("LaunchArgumentIndieV2") = 0 OrElse Settings.Get("LaunchArgumentIndieV2") = 2) Then
If MyMsgBox("你尚未开启版本隔离,多个 MC 版本会共用同一个 Mod 文件夹。" & vbCrLf & If MyMsgBox("你尚未开启版本隔离,多个 MC 版本会共用同一个 Mod 文件夹。" & vbCrLf &
"因此,游戏可能会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf & "因此,游戏可能会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
"推荐先在 设置 → 启动选项 → 默认版本隔离 中开启版本隔离!", "版本隔离提示", "取消下载", "继续") = 1 Then "推荐先在 设置 → 启动选项 → 默认版本隔离 中开启版本隔离!", "版本隔离提示", "取消下载", "继续") = 1 Then
@@ -313,8 +313,8 @@ Public Class MyLocalModItem
Shortened = True Shortened = True
Next Next
If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then
CurrentName = Join(CurrentSegs, "-") CurrentName = CurrentSegs.Join("-")
NewestName = Join(NewestSegs, "-") NewestName = NewestSegs.Join("-")
Entry._Version = CurrentName '使用网络信息作为显示的版本号 Entry._Version = CurrentName '使用网络信息作为显示的版本号
End If End If
Return $"当前版本:{CurrentName}({GetTimeSpanString(Entry.CompFile.ReleaseDate - Date.Now, False)}){vbCrLf}最新版本:{NewestName}({GetTimeSpanString(Entry.UpdateFile.ReleaseDate - Date.Now, False)})" Return $"当前版本:{CurrentName}({GetTimeSpanString(Entry.CompFile.ReleaseDate - Date.Now, False)}){vbCrLf}最新版本:{NewestName}({GetTimeSpanString(Entry.UpdateFile.ReleaseDate - Date.Now, False)})"
@@ -323,7 +323,7 @@ Public Class MyLocalModItem
'懒加载 '懒加载
Public Sub New() Public Sub New()
InitializeComponent() InitializeComponent()
OnFirstEnterScrollViewerViewport(AddressOf FirstEnterScrollViewerViewport) LazyLoadBehavior.OnFirstEnterScrollViewerViewport(Me, AddressOf FirstEnterScrollViewerViewport)
End Sub End Sub
Private HasEnteredViewport As Boolean = False Private HasEnteredViewport As Boolean = False
Private Sub FirstEnterScrollViewerViewport() Private Sub FirstEnterScrollViewerViewport()
@@ -347,7 +347,7 @@ Public Class MyLocalModItem
DescFileName = GetFileNameFromPath(Entry.Path) DescFileName = GetFileNameFromPath(Entry.Path)
End If End If
Dim NewDescription As String Dim NewDescription As String
If Setup.Get("ToolModLocalNameStyle") = 1 Then If Settings.Get("ToolModLocalNameStyle") = 1 Then
'标题显示文件名,详情显示译名 '标题显示文件名,详情显示译名
'标题 '标题
Title = DescFileName Title = DescFileName
@@ -357,7 +357,7 @@ Public Class MyLocalModItem
NewDescription = Entry.DisplayName NewDescription = Entry.DisplayName
Else Else
Dim Titles = Entry.Comp.GetControlTitle(False) Dim Titles = Entry.Comp.GetControlTitle(False)
NewDescription = Titles.Key & Titles.Value NewDescription = Titles.Title & Titles.SubTitle
End If End If
NewDescription = NewDescription.Replace(" | ", " / ") NewDescription = NewDescription.Replace(" | ", " / ")
If Entry.Version IsNot Nothing Then NewDescription &= $" ({Entry.Version})" If Entry.Version IsNot Nothing Then NewDescription &= $" ({Entry.Version})"
@@ -369,8 +369,8 @@ Public Class MyLocalModItem
SubTitle = If(Entry.Version Is Nothing, "", " | " & Entry.Version) SubTitle = If(Entry.Version Is Nothing, "", " | " & Entry.Version)
Else Else
Dim Titles = Entry.Comp.GetControlTitle(False) Dim Titles = Entry.Comp.GetControlTitle(False)
Title = Titles.Key Title = Titles.Title
SubTitle = Titles.Value & If(Entry.Version Is Nothing, "", " | " & Entry.Version) SubTitle = Titles.SubTitle & If(Entry.Version Is Nothing, "", " | " & Entry.Version)
End If End If
'描述 '描述
NewDescription = DescFileName NewDescription = DescFileName
@@ -94,7 +94,7 @@
<local:ExportOption <local:ExportOption
Title="整合包重要数据" Title="整合包重要数据"
Description="脚本文件、内置资源包、数据包等" Description="脚本文件、内置资源包、数据包等"
Rules="addons/|multiblocked/|modpack-update-checker/|global_packs/|global_resource_packs/|global_data_packs/|optional_data_packs/|moonlight-global-datapacks/|maps/|icon.png|mods-resourcepacks/|matmos/|resource_assorts/|resource_assorts.json|patchouli_books/|datapacks/|kubejs*/|!kubejs*/probe/|!kubejs*/exported/|!kubejs*/jsconfig.json|!kubejs*/README.txt|openloader/|worldshape/|resources/|scripts/|structures/|fontfiles/|oresources/|packmenu/|craftpresence/|pointblanks/|template*/|!template*/playerdata/|!template*/stats/" Rules="hotai/|bansoukou/|addons/|multiblocked/|modpack-update-checker/|global_packs/|global_resource_packs/|global_data_packs/|optional_data_packs/|moonlight-global-datapacks/|maps/|icon.png|mods-resourcepacks/|matmos/|resource_assorts/|resource_assorts.json|patchouli_books/|datapacks/|kubejs*/|!kubejs*/probe/|!kubejs*/exported/|!kubejs*/jsconfig.json|!kubejs*/README.txt|openloader/|worldshape/|resources/|scripts/|structures/|fontfiles/|oresources/|packmenu/|craftpresence/|pointblanks/|template*/|!template*/playerdata/|!template*/stats/"
DefaultChecked="True" /> DefaultChecked="True" />
</local:MyCheckBox.Tag> </local:MyCheckBox.Tag>
</local:MyCheckBox> </local:MyCheckBox>
@@ -23,7 +23,7 @@ Public Class PageInstanceExport
AniControlEnabled += 1 AniControlEnabled += 1
If CurrentInstance <> PageInstanceLeft.Instance.PathVersion Then RefreshAll() '切换到了另一个版本,重置页面 If CurrentInstance <> PageInstanceLeft.Instance.PathVersion Then RefreshAll() '切换到了另一个版本,重置页面
CustomEventService.SetEventData(BtnAdvancedHelp, CustomEventService.SetEventData(BtnAdvancedHelp,
If(VersionBranchName = "Release", "指南/整合包制作 - Public.json", "指南/整合包制作 - Snapshot.json")) If(VersionBranchCode = 50, "指南/整合包制作 - Public.json", "指南/整合包制作 - Snapshot.json"))
AniControlEnabled -= 1 AniControlEnabled -= 1
End Sub End Sub
Public Sub RefreshAll() Implements IRefreshable.Refresh Public Sub RefreshAll() Implements IRefreshable.Refresh
@@ -305,9 +305,9 @@ Public Class PageInstanceExport
'保存配置文件 '保存配置文件
Private Sub ExportConfig() Handles BtnAdvancedExport.Click Private Sub ExportConfig() Handles BtnAdvancedExport.Click
Try Try
Dim ConfigPath As String = SelectSaveFile("选择文件位置", "export_config.txt", "整合包导出配置(*.txt)|*.txt", Setup.Get("CacheExportConfig")) Dim ConfigPath As String = SelectSaveFile("选择文件位置", "export_config.txt", "整合包导出配置(*.txt)|*.txt", Settings.Get("CacheExportConfig"))
If String.IsNullOrEmpty(ConfigPath) Then Return If String.IsNullOrEmpty(ConfigPath) Then Return
Setup.Set("CacheExportConfig", ConfigPath) Settings.Set("CacheExportConfig", ConfigPath)
Dim ConfigLines As New List(Of String) Dim ConfigLines As New List(Of String)
'ini 段 'ini 段
ConfigLines.Add("Name:" & TextExportName.Text) ConfigLines.Add("Name:" & TextExportName.Text)
@@ -351,9 +351,9 @@ Public Class PageInstanceExport
'读取配置文件 '读取配置文件
Private Sub ImportConfig() Handles BtnAdvancedImport.Click Private Sub ImportConfig() Handles BtnAdvancedImport.Click
Try Try
Dim ConfigPath As String = SelectFile("整合包导出配置(*.txt)|*.txt", "选择配置文件", Setup.Get("CacheExportConfig")) Dim ConfigPath As String = SelectFile("整合包导出配置(*.txt)|*.txt", "选择配置文件", Settings.Get("CacheExportConfig"))
If String.IsNullOrEmpty(ConfigPath) Then Return If String.IsNullOrEmpty(ConfigPath) Then Return
Setup.Set("CacheExportConfig", ConfigPath) Settings.Set("CacheExportConfig", ConfigPath)
Dim Segments As String() = ReadFile(ConfigPath).Split(Sperator) Dim Segments As String() = ReadFile(ConfigPath).Split(Sperator)
'ini 段 'ini 段
Dim Ini As New Dictionary(Of String, String) Dim Ini As New Dictionary(Of String, String)
@@ -367,8 +367,8 @@ Public Class PageInstanceExport
TextExportVersion.Text = Ini.GetOrDefault("Version", "") TextExportVersion.Text = Ini.GetOrDefault("Version", "")
CheckOptionsPcl.Checked = Ini.GetOrDefault("IncludeLauncher", True) CheckOptionsPcl.Checked = Ini.GetOrDefault("IncludeLauncher", True)
CheckOptionsPclCustom.Checked = Ini.GetOrDefault("IncludeLauncherCustom", True) CheckOptionsPclCustom.Checked = Ini.GetOrDefault("IncludeLauncherCustom", True)
CheckAdvancedModrinth.Checked = Ini.GetOrDefault("ModrinthUploadMode", False)
CheckAdvancedInclude.Checked = Ini.GetOrDefault("DontCheckHostedAssets", False) CheckAdvancedInclude.Checked = Ini.GetOrDefault("DontCheckHostedAssets", False)
If Not CheckAdvancedInclude.Checked Then CheckAdvancedModrinth.Checked = Ini.GetOrDefault("ModrinthUploadMode", False) '#7979,加个特判
ConfigPackPath = Ini.GetOrDefault("PackPath", Nothing) ConfigPackPath = Ini.GetOrDefault("PackPath", Nothing)
'导出内容段 '导出内容段
RulesOverrides = Segments(1).Replace(vbCr, vbLf).Replace(vbLf & vbLf, vbLf).Split(vbLf).ToList RulesOverrides = Segments(1).Replace(vbCr, vbLf).Replace(vbLf & vbLf, vbLf).Split(vbLf).ToList
@@ -485,7 +485,7 @@ Public Class PageInstanceExport
'检查规则 '检查规则
Dim ShouldKeep As Boolean = False Dim ShouldKeep As Boolean = False
For Each Rule In AllRules For Each Rule In AllRules
Dim Revert = Rule.StartsWith("!") Dim Revert = Rule.StartsWithF("!")
If RelativePath Like Rule.TrimStart("!") Then ShouldKeep = Not Revert If RelativePath Like Rule.TrimStart("!") Then ShouldKeep = Not Revert
Next Next
If Not ShouldKeep Then Continue For If Not ShouldKeep Then Continue For
@@ -493,7 +493,7 @@ Public Class PageInstanceExport
CopyFile(Entry.FullName, TargetPath) CopyFile(Entry.FullName, TargetPath)
'若为压缩包,考虑联网获取路径 '若为压缩包,考虑联网获取路径
If CheckHostedAssets AndAlso If CheckHostedAssets AndAlso
{".zip", ".rar", ".jar", ".disabled", ".old"}.Contains(Entry.Extension.ToLower) AndAlso {".zip", ".rar", ".jar", ".disabled", ".old"}.Contains(Entry.Extension.Lower) AndAlso
{"mods", "packs", "openloader", "resource"}.Any(Function(s) RelativePath.Contains(s)) Then {"mods", "packs", "openloader", "resource"}.Any(Function(s) RelativePath.Contains(s)) Then
Dim ModFile As New McMod(TargetPath) Dim ModFile As New McMod(TargetPath)
Dim Unused = ModFile.ModrinthHash '提前计算 Hash Dim Unused = ModFile.ModrinthHash '提前计算 Hash
@@ -617,7 +617,7 @@ Public Class PageInstanceExport
'等待线程结束 '等待线程结束
Do Until EndedThreadCount = 2 Do Until EndedThreadCount = 2
If Loader.IsAborted Then Return If Loader.IsInterrupted Then Return
Thread.Sleep(10) Thread.Sleep(10)
Loop Loop
@@ -676,7 +676,7 @@ Public Class PageInstanceExport
'首次压缩整合包 '首次压缩整合包
ZipFile.CreateFromDirectory(CacheFolder & "modpack\", CacheFolder & "modpack.mrpack") ZipFile.CreateFromDirectory(CacheFolder & "modpack\", CacheFolder & "modpack.mrpack")
Loader.Progress = 0.5 Loader.Progress = 0.5
Directory.Delete(CacheFolder & "modpack\", True) DeleteDirectory(CacheFolder & "modpack\")
Loader.Progress = 0.6 Loader.Progress = 0.6
'二次压缩整合包 '二次压缩整合包
ZipFile.CreateFromDirectory(CacheFolder, PackPath) ZipFile.CreateFromDirectory(CacheFolder, PackPath)
@@ -686,7 +686,7 @@ Public Class PageInstanceExport
ZipFile.CreateFromDirectory(CacheFolder & "modpack\", PackPath) ZipFile.CreateFromDirectory(CacheFolder & "modpack\", PackPath)
Loader.Progress = 0.8 Loader.Progress = 0.8
End If End If
Directory.Delete(CacheFolder, True) DeleteDirectory(CacheFolder, True)
OpenExplorer(PackPath) OpenExplorer(PackPath)
End Sub) With {.ProgressWeight = 6}) End Sub) With {.ProgressWeight = 6})
@@ -305,7 +305,7 @@
''' 返回输入的文件是否为一个 Mod 文件,仅用于判断拖拽行为。 ''' 返回输入的文件是否为一个 Mod 文件,仅用于判断拖拽行为。
''' </summary> ''' </summary>
Public Shared Function InstallMods(FilePathList As IEnumerable(Of String)) As Boolean Public Shared Function InstallMods(FilePathList As IEnumerable(Of String)) As Boolean
Dim Extension As String = FilePathList.First.AfterLast(".").ToLower Dim Extension As String = FilePathList.First.AfterLast(".").Lower
'检查文件扩展名 '检查文件扩展名
If Not {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then Return False If Not {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then Return False
Log("[System] 文件为 jar/litemod 格式,尝试作为 Mod 安装") Log("[System] 文件为 jar/litemod 格式,尝试作为 Mod 安装")
@@ -322,7 +322,7 @@
Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!") Hint("若要安装 Mod,请先选择一个可以安装 Mod 的版本!")
ElseIf Not (FrmMain.PageCurrent = FormMain.PageType.InstanceSetup AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.InstanceMod) Then ElseIf Not (FrmMain.PageCurrent = FormMain.PageType.InstanceSetup AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.InstanceMod) Then
'未处于 Mod 管理页面 '未处于 Mod 管理页面
If MyMsgBox($"是否要将这{If(FilePathList.Count = 1, "个", "些")}文件作为 Mod 安装到 {Instance.Name}?", "Mod 安装确认", "确定", "取消") = 1 Then GoTo Install If MyMsgBox($"是否要将这{If(FilePathList.IsSingle, "个", "些")}文件作为 Mod 安装到 {Instance.Name}?", "Mod 安装确认", "确定", "取消") = 1 Then GoTo Install
Else Else
'处于 Mod 管理页面 '处于 Mod 管理页面
Install: Install:
@@ -332,7 +332,7 @@ Install:
If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227 If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227
CopyFile(ModFile, Instance.PathIndie & "mods\" & NewFileName) CopyFile(ModFile, Instance.PathIndie & "mods\" & NewFileName)
Next Next
If FilePathList.Count = 1 Then If FilePathList.IsSingle Then
Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Green) Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Green)
Else Else
Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Green) Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Green)
@@ -503,7 +503,7 @@ Install:
End If End If
End If End If
File.Delete(NewPath) File.Delete(NewPath)
FileSystem.Rename(ModEntity.Path, NewPath) File.Move(ModEntity.Path, NewPath)
Catch ex As FileNotFoundException Catch ex As FileNotFoundException
Log(ex, $"未找到需要重命名的 Mod({If(ModEntity.Path, "null")})", LogLevel.Feedback) Log(ex, $"未找到需要重命名的 Mod({If(ModEntity.Path, "null")})", LogLevel.Feedback)
ReloadModList(True) ReloadModList(True)
@@ -556,9 +556,9 @@ Install:
Public Shared UpdatingInstanceModFolders As New List(Of String) Public Shared UpdatingInstanceModFolders As New List(Of String)
Public Sub UpdateMods(ModList As IEnumerable(Of McMod)) Public Sub UpdateMods(ModList As IEnumerable(Of McMod))
'更新前警告 '更新前警告
If Not Setup.Get("HintUpdateMod") OrElse ModList.Count >= 15 Then If Not Settings.Get("HintUpdateMod") OrElse ModList.Count >= 15 Then
If MyMsgBox($"新版本 Mod 可能不兼容旧存档或者其他 Mod,这可能导致游戏崩溃,甚至永久损坏存档!{vbCrLf}如果你在游玩整合包,请千万不要自行更新 Mod!{vbCrLf}{vbCrLf}在更新前,请先备份存档,并检查 Mod 的更新日志。{vbCrLf}如果更新后出现问题,你也可以在回收站找回更新前的 Mod。", "Mod 更新警告", "我已了解风险,继续更新", "取消", IsWarn:=True) = 1 Then If MyMsgBox($"新版本 Mod 可能不兼容旧存档或者其他 Mod,这可能导致游戏崩溃,甚至永久损坏存档!{vbCrLf}如果你在游玩整合包,请千万不要自行更新 Mod!{vbCrLf}{vbCrLf}在更新前,请先备份存档,并检查 Mod 的更新日志。{vbCrLf}如果更新后出现问题,你也可以在回收站找回更新前的 Mod。", "Mod 更新警告", "我已了解风险,继续更新", "取消", IsWarn:=True) = 1 Then
Setup.Set("HintUpdateMod", True) Settings.Set("HintUpdateMod", True)
Else Else
Return Return
End If End If
@@ -592,8 +592,8 @@ Install:
Shortened = True Shortened = True
Loop Loop
If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then If Shortened AndAlso CurrentSegs.Any() AndAlso NewestSegs.Any() Then
CurrentReplaceName = Join(CurrentSegs, "-") CurrentReplaceName = CurrentSegs.Join("-")
NewestReplaceName = Join(NewestSegs, "-") NewestReplaceName = NewestSegs.Join("-")
End If End If
'添加到下载列表 '添加到下载列表
Dim TempAddress As String = PathTemp & "mods\" & Entry.FileName.Replace(CurrentReplaceName, NewestReplaceName) '需要下载到 mods 文件夹,以便重复文件检查时识别 Dim TempAddress As String = PathTemp & "mods\" & Entry.FileName.Replace(CurrentReplaceName, NewestReplaceName) '需要下载到 mods 文件夹,以便重复文件检查时识别
@@ -649,7 +649,7 @@ Install:
End Select End Select
Case LoadState.Failed Case LoadState.Failed
Hint("Mod 更新失败:" & Loader.Error.GetBrief(), HintType.Red) Hint("Mod 更新失败:" & Loader.Error.GetBrief(), HintType.Red)
Case LoadState.Aborted Case LoadState.Interrupted
Hint("Mod 更新已中止!", HintType.Blue) Hint("Mod 更新已中止!", HintType.Blue)
Case Else Case Else
Return Return
@@ -737,13 +737,13 @@ Install:
'显示结果提示 '显示结果提示
If Not IsSuccessful Then Return If Not IsSuccessful Then Return
If IsShiftPressed Then If IsShiftPressed Then
If ModList.Count = 1 Then If ModList.IsSingle Then
Hint($"已彻底删除 {ModList.Single.FileName}!", HintType.Green) Hint($"已彻底删除 {ModList.Single.FileName}!", HintType.Green)
Else Else
Hint($"已彻底删除 {ModList.Count} 个文件!", HintType.Green) Hint($"已彻底删除 {ModList.Count} 个文件!", HintType.Green)
End If End If
Else Else
If ModList.Count = 1 Then If ModList.IsSingle Then
Hint($"已将 {ModList.Single.FileName} 删除到回收站!", HintType.Green) Hint($"已将 {ModList.Single.FileName} 删除到回收站!", HintType.Green)
Else Else
Hint($"已将 {ModList.Count} 个文件删除到回收站!", HintType.Green) Hint($"已将 {ModList.Count} 个文件删除到回收站!", HintType.Green)
@@ -797,8 +797,8 @@ Install:
Dim ModOriginalName As String = ModEntry.DisplayName.Replace(" ", "+") Dim ModOriginalName As String = ModEntry.DisplayName.Replace(" ", "+")
Dim ModSearchName As String = ModOriginalName.Substring(0, 1) Dim ModSearchName As String = ModOriginalName.Substring(0, 1)
For i = 1 To ModOriginalName.Count - 1 For i = 1 To ModOriginalName.Count - 1
Dim IsLastLower As Boolean = ModOriginalName(i - 1).ToString.ToLower.Equals(ModOriginalName(i - 1).ToString) Dim IsLastLower As Boolean = ModOriginalName(i - 1).ToString.Lower.Equals(ModOriginalName(i - 1).ToString)
Dim IsCurrentLower As Boolean = ModOriginalName(i).ToString.ToLower.Equals(ModOriginalName(i).ToString) Dim IsCurrentLower As Boolean = ModOriginalName(i).ToString.Lower.Equals(ModOriginalName(i).ToString)
If IsLastLower AndAlso Not IsCurrentLower Then If IsLastLower AndAlso Not IsCurrentLower Then
'上一个字母为小写,这一个字母为大写 '上一个字母为小写,这一个字母为大写
ModSearchName += "+" ModSearchName += "+"
@@ -807,7 +807,7 @@ Install:
Next Next
ModSearchName = ModSearchName.Replace("++", "+").Replace("pti+Fine", "ptiFine") ModSearchName = ModSearchName.Replace("++", "+").Replace("pti+Fine", "ptiFine")
'百科搜索链接 '百科搜索链接
If MyMsgBox(Join(ContentLines, vbCrLf), ModEntry.DisplayName, "百科搜索", "返回") = 1 Then If MyMsgBox(ContentLines.Join(vbCrLf), ModEntry.DisplayName, "百科搜索", "返回") = 1 Then
OpenWebsite("https://www.mcmod.cn/s?key=" & ModSearchName & "&site=all&filter=0") OpenWebsite("https://www.mcmod.cn/s?key=" & ModSearchName & "&site=all&filter=0")
End If End If
End If End If
@@ -850,22 +850,22 @@ Install:
'构造请求 '构造请求
Dim QueryList As New List(Of SearchEntry(Of McMod)) Dim QueryList As New List(Of SearchEntry(Of McMod))
For Each Entry As McMod In McModLoader.Output For Each Entry As McMod In McModLoader.Output
Dim SearchSource As New List(Of KeyValuePair(Of String, Double)) Dim SearchSources As New List(Of SearchSource)
SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.DisplayName, 1)) SearchSources.Add(New SearchSource(Entry.DisplayName, 1))
SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.FileName, 1)) SearchSources.Add(New SearchSource(Entry.FileName, 1))
If Entry.Version IsNot Nothing Then If Entry.Version IsNot Nothing Then
SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Version, 0.2)) SearchSources.Add(New SearchSource(Entry.Version, 0.2))
End If End If
If Entry.Description IsNot Nothing AndAlso Entry.Description <> "" Then If Entry.Description IsNot Nothing AndAlso Entry.Description <> "" Then
SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Description, 0.4)) SearchSources.Add(New SearchSource(Entry.Description, 0.4))
End If End If
If Entry.Comp IsNot Nothing Then If Entry.Comp IsNot Nothing Then
If Entry.Comp.RawName <> Entry.DisplayName Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.RawName, 1)) If Entry.Comp.RawName <> Entry.DisplayName Then SearchSources.Add(New SearchSource(Entry.Comp.RawName, 1))
If Entry.Comp.TranslatedName <> Entry.Comp.RawName Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.TranslatedName, 1)) If Entry.Comp.TranslatedName <> Entry.Comp.RawName Then SearchSources.Add(New SearchSource(Entry.Comp.TranslatedName, 1))
If Entry.Comp.Description <> Entry.Description Then SearchSource.Add(New KeyValuePair(Of String, Double)(Entry.Comp.Description, 0.4)) If Entry.Comp.Description <> Entry.Description Then SearchSources.Add(New SearchSource(Entry.Comp.Description, 0.4))
SearchSource.Add(New KeyValuePair(Of String, Double)(String.Join("", Entry.Comp.Tags), 0.2)) SearchSources.Add(New SearchSource(String.Join("", Entry.Comp.Tags), 0.2))
End If End If
QueryList.Add(New SearchEntry(Of McMod) With {.Item = Entry, .SearchSource = SearchSource}) QueryList.Add(New SearchEntry(Of McMod) With {.Item = Entry, .SearchSource = SearchSources})
Next Next
'进行搜索 '进行搜索
SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=6, MinBlurSimilarity:=0.35).Select(Function(r) r.Item).ToList SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=6, MinBlurSimilarity:=0.35).Select(Function(r) r.Item).ToList
@@ -9,7 +9,7 @@
End Sub End Sub
Public Sub BtnDownload_Loaded() Handles BtnDownload.Loaded Public Sub BtnDownload_Loaded() Handles BtnDownload.Loaded
Dim NewVisibility = If((Setup.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow) OrElse If(FrmSelectRight Is Nothing, False, FrmSelectRight.ShowHidden), Visibility.Collapsed, Visibility.Visible) Dim NewVisibility = If((Settings.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow) OrElse If(FrmSelectRight Is Nothing, False, FrmSelectRight.ShowHidden), Visibility.Collapsed, Visibility.Visible)
If BtnDownload.Visibility <> NewVisibility Then If BtnDownload.Visibility <> NewVisibility Then
BtnDownload.Visibility = NewVisibility BtnDownload.Visibility = NewVisibility
PanMain.TriggerForceResize() PanMain.TriggerForceResize()
@@ -39,7 +39,7 @@
Dim LogoCustom As Boolean = ReadIni(PageInstanceLeft.Instance.PathVersion & "PCL\Setup.ini", "LogoCustom", "False") Dim LogoCustom As Boolean = ReadIni(PageInstanceLeft.Instance.PathVersion & "PCL\Setup.ini", "LogoCustom", "False")
If LogoCustom Then If LogoCustom Then
For Each Selection As MyComboBoxItem In ComboDisplayLogo.Items For Each Selection As MyComboBoxItem In ComboDisplayLogo.Items
If Selection.Tag = Logo OrElse (Selection.Tag = "PCL\Logo.png" AndAlso Logo.EndsWith("PCL\Logo.png")) Then If Selection.Tag = Logo OrElse (Selection.Tag = "PCL\Logo.png" AndAlso Logo.EndsWithF("PCL\Logo.png")) Then
ComboDisplayLogo.SelectedItem = Selection ComboDisplayLogo.SelectedItem = Selection
Exit For Exit For
End If End If
@@ -71,12 +71,12 @@
Else Else
'改为隐藏 '改为隐藏
Try Try
If Not Setup.Get("HintHide") Then If Not Settings.Get("HintHide") Then
If MyMsgBox("确认要从版本列表中隐藏该版本吗?隐藏该版本后,它将不再出现于 PCL 显示的版本列表中。" & vbCrLf & "此后,在版本列表页面按下 F11 才可以查看被隐藏的版本。", "隐藏版本提示",, "取消") <> 1 Then If MyMsgBox("确认要从版本列表中隐藏该版本吗?隐藏该版本后,它将不再出现于 PCL 显示的版本列表中。" & vbCrLf & "此后,在版本列表页面按下 F11 才可以查看被隐藏的版本。", "隐藏版本提示",, "取消") <> 1 Then
ComboDisplayType.SelectedIndex = 0 ComboDisplayType.SelectedIndex = 0
Return Return
End If End If
Setup.Set("HintHide", True) Settings.Set("HintHide", True)
End If End If
WriteIni(PageInstanceLeft.Instance.PathVersion & "PCL\Setup.ini", "DisplayType", McInstanceCardType.Hidden) WriteIni(PageInstanceLeft.Instance.PathVersion & "PCL\Setup.ini", "DisplayType", McInstanceCardType.Hidden)
WriteIni(McFolderSelected & "PCL.ini", "InstanceCache", "") '要求刷新缓存 WriteIni(McFolderSelected & "PCL.ini", "InstanceCache", "") '要求刷新缓存
@@ -115,7 +115,7 @@
'获取临时中间名,以防止仅修改大小写的重命名失败 '获取临时中间名,以防止仅修改大小写的重命名失败
Dim TempName As String = NewName & "_temp" Dim TempName As String = NewName & "_temp"
Dim TempPath As String = McFolderSelected & "versions\" & TempName & "\" Dim TempPath As String = McFolderSelected & "versions\" & TempName & "\"
Dim OnlyChangedCase As Boolean = NewName.ToLower = OldName.ToLower Dim OnlyChangedCase As Boolean = NewName.Lower = OldName.Lower
'重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储 '重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储
Dim JsonObject As JObject Dim JsonObject As JObject
Dim OldJsonPath As String = PageInstanceLeft.Instance.GetJsonPath() Dim OldJsonPath As String = PageInstanceLeft.Instance.GetJsonPath()
@@ -126,8 +126,8 @@
JsonObject = PageInstanceLeft.Instance.JsonObject JsonObject = PageInstanceLeft.Instance.JsonObject
End Try End Try
'重命名主文件夹 '重命名主文件夹
My.Computer.FileSystem.RenameDirectory(OldPath, TempName) Directory.Move(OldPath, TempPath)
My.Computer.FileSystem.RenameDirectory(TempPath, NewName) Directory.Move(TempPath, NewPath)
'清理 ini 缓存 '清理 ini 缓存
IniClearCache(PageInstanceLeft.Instance.PathIndie & "options.txt") IniClearCache(PageInstanceLeft.Instance.PathIndie & "options.txt")
IniClearCache(PageInstanceLeft.Instance.PathVersion & "PCL\Setup.ini") IniClearCache(PageInstanceLeft.Instance.PathVersion & "PCL\Setup.ini")
@@ -135,20 +135,20 @@
'不能进行遍历重命名,否则在版本名很短的时候容易误伤其他文件(#6443) '不能进行遍历重命名,否则在版本名很短的时候容易误伤其他文件(#6443)
If Directory.Exists($"{NewPath}{OldName}-natives") Then If Directory.Exists($"{NewPath}{OldName}-natives") Then
If OnlyChangedCase Then If OnlyChangedCase Then
My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives", $"{OldName}natives_temp") Directory.Move($"{NewPath}{OldName}-natives", $"{NewPath}{OldName}natives_temp")
My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives_temp", $"{NewName}-natives") Directory.Move($"{NewPath}{OldName}-natives_temp", $"{NewPath}{NewName}-natives")
Else Else
DeleteDirectory($"{NewPath}{NewName}-natives") DeleteDirectory($"{NewPath}{NewName}-natives")
My.Computer.FileSystem.RenameDirectory($"{NewPath}{OldName}-natives", $"{NewName}-natives") Directory.Move($"{NewPath}{OldName}-natives", $"{NewPath}{NewName}-natives")
End If End If
End If End If
If File.Exists($"{NewPath}{OldName}.jar") Then If File.Exists($"{NewPath}{OldName}.jar") Then
If OnlyChangedCase Then If OnlyChangedCase Then
My.Computer.FileSystem.RenameFile($"{NewPath}{OldName}.jar", $"{OldName}_temp.jar") File.Move($"{NewPath}{OldName}.jar", $"{NewPath}{OldName}_temp.jar")
My.Computer.FileSystem.RenameFile($"{NewPath}{OldName}_temp.jar", $"{NewName}.jar") File.Move($"{NewPath}{OldName}_temp.jar", $"{NewPath}{NewName}.jar")
Else Else
File.Delete($"{NewPath}{NewName}.jar") File.Delete($"{NewPath}{NewName}.jar")
My.Computer.FileSystem.RenameFile($"{NewPath}{OldName}.jar", $"{NewName}.jar") File.Move($"{NewPath}{OldName}.jar", $"{NewPath}{NewName}.jar")
End If End If
End If End If
'替换版本设置文件中的路径 '替换版本设置文件中的路径
@@ -267,7 +267,7 @@
End If End If
'生成脚本 '生成脚本
If McLaunchStart(New McLaunchOptions With {.SaveBatch = SavePath, .Instance = PageInstanceLeft.Instance}) Then If McLaunchStart(New McLaunchOptions With {.SaveBatch = SavePath, .Instance = PageInstanceLeft.Instance}) Then
If Setup.Get("LoginType") = McLoginType.Legacy Then If Settings.Get("LoginType") = McLoginType.Legacy Then
Hint("正在导出启动脚本……") Hint("正在导出启动脚本……")
Else Else
Hint("正在导出启动脚本……(注意,使用脚本启动可能会导致登录失效!)") Hint("正在导出启动脚本……(注意,使用脚本启动可能会导致登录失效!)")
@@ -301,7 +301,7 @@
Hint(Loader.Name & "成功!", HintType.Green) Hint(Loader.Name & "成功!", HintType.Green)
Case LoadState.Failed Case LoadState.Failed
Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red) Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red)
Case LoadState.Aborted Case LoadState.Interrupted
Hint(Loader.Name & "已取消!", HintType.Blue) Hint(Loader.Name & "已取消!", HintType.Blue)
End Select End Select
End Sub End Sub
@@ -48,7 +48,7 @@
</local:MyTextBox.ValidateRules> </local:MyTextBox.ValidateRules>
</local:MyTextBox> </local:MyTextBox>
<TextBlock VerticalAlignment="Center" Grid.Row="6" HorizontalAlignment="Left" Text="游戏 Java" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" Grid.Row="6" HorizontalAlignment="Left" Text="游戏 Java" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboArgumentJava" Grid.ColumnSpan="2" Grid.Row="6" Grid.Column="1" MaxDropDownHeight="240" <local:MyComboBox x:Name="ComboArgumentJava" Grid.ColumnSpan="2" Grid.Row="6" Grid.Column="1"
ToolTip="若将 Java 放在游戏文件夹或 PCL 文件夹,在进行自动选择时 PCL 会尽量优先选择它"> ToolTip="若将 Java 放在游戏文件夹或 PCL 文件夹,在进行自动选择时 PCL 会尽量优先选择它">
<ComboBoxItem Content="加载中……" IsSelected="True" /> <ComboBoxItem Content="加载中……" IsSelected="True" />
<!--<local:MyComboBoxItem Content="Java 8 (1.8.0_171),64 位:C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" IsSelected="True" ToolTip="C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe" />--> <!--<local:MyComboBoxItem Content="Java 8 (1.8.0_171),64 位:C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" IsSelected="True" ToolTip="C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe" />-->
@@ -56,7 +56,7 @@
</Grid> </Grid>
</StackPanel> </StackPanel>
</local:MyCard> </local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="游戏内存"> <local:MyCard Margin="0,0,0,15" Title="内存分配">
<StackPanel Margin="25,40,25,15"> <StackPanel Margin="25,40,25,15">
<local:MyHint x:Name="LabRamWarn" Text="32 位 Java 只能分配最多 1 GB 的内存。强烈建议换用 64 位的 Java!" Theme="Yellow" Margin="0,0,0,12" /> <local:MyHint x:Name="LabRamWarn" Text="32 位 Java 只能分配最多 1 GB 的内存。强烈建议换用 64 位的 Java!" Theme="Yellow" Margin="0,0,0,12" />
<Grid Margin="0,0,0,3"> <Grid Margin="0,0,0,3">
@@ -204,6 +204,8 @@
<RowDefinition Height="9" /> <RowDefinition Height="9" />
<RowDefinition Height="28" /> <RowDefinition Height="28" />
<RowDefinition Height="9" /> <RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="31" /> <RowDefinition Height="31" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -213,12 +215,26 @@
Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" /> 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;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置" /> <local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" /> <TextBlock VerticalAlignment="Center" Grid.Row="4" HorizontalAlignment="Left" Text="内存管理" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3" <local:MyComboBox local:SettingService.Key="VersionAdvanceGC" Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="1">
<local:MyComboBoxItem Content="跟随全局设置" />
<local:MyComboBoxItem Content="尽量使用 ZGC"
ToolTipService.BetweenShowDelay="0" ToolTip="在 Java 21+ 使用分代 ZGC,20~15 使用非分代的 ZGC,14- 使用 G1GC。&#xa;ZGC 的内存占用比 G1GC 更高,不过在回收内存时不会导致卡顿。&#xa;覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
<local:MyComboBoxItem Content="尽量使用分代 ZGC"
ToolTipService.BetweenShowDelay="0" ToolTip="在 Java 21+ 使用分代 ZGC,20- 使用 G1GC。&#xa;ZGC 的内存占用比 G1GC 更高,不过在回收内存时不会导致卡顿。&#xa;覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
<local:MyComboBoxItem Content="标准 G1GC"
ToolTipService.BetweenShowDelay="0" ToolTip="总是使用 G1GC,附带 Mojang 官方的优化参数。&#xa;G1GC 的内存占用比 ZGC 更低,但在回收内存时会导致突然的卡顿。&#xa;覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
<local:MyComboBoxItem Content="调优 G1GC" local:SettingService.Value="5"
ToolTipService.BetweenShowDelay="0" ToolTip="总是使用 G1GC,附带 PCL 调优过的优化参数。&#xa;G1GC 的内存占用比 ZGC 更低,但在回收内存时会导致突然的卡顿。&#xa;覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
<local:MyComboBoxItem Content="不指定(可自定义)" local:SettingService.Value="4"
ToolTipService.BetweenShowDelay="0" ToolTip="不自动添加 GC 参数。&#xa;仅当选择此项时,你可以在 “Java 虚拟机参数” 设置中手动添加 GC 参数。" />
</local:MyComboBox>
<TextBlock Grid.Row="6" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="6" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3"
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。&#xa;&#xa;在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" /> ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。&#xa;&#xa;在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="VersionAdvanceRunWait" Visibility="Collapsed" <local:MyCheckBox Grid.Row="7" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="VersionAdvanceRunWait" Visibility="Collapsed"
Text="等待命令执行完成后再继续启动" Margin="0,5,0,0" /> Text="等待命令执行完成后再继续启动" Margin="0,5,0,0" />
<StackPanel Margin="0,12,0,4" Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Left"> <StackPanel Margin="0,12,0,4" Grid.Row="8" Grid.ColumnSpan="2" HorizontalAlignment="Left">
<local:MyCheckBox Height="28" Text="禁止更新 Mod" x:Name="CheckAdvanceDisableModUpdate" Tag="VersionAdvanceDisableModUpdate" <local:MyCheckBox Height="28" Text="禁止更新 Mod" x:Name="CheckAdvanceDisableModUpdate" Tag="VersionAdvanceDisableModUpdate"
ToolTip="禁止为此版本更新 Mod,以防止整合包玩家误操作" ToolTip="禁止为此版本更新 Mod,以防止整合包玩家误操作"
ToolTipService.Placement="Right" /> ToolTipService.Placement="Right" />
@@ -230,7 +246,10 @@
ToolTip="完全不更改 assets;不校验 libraries、第三方登录库与版本主 jar 文件是否被修改。&#xa;如果你没有修改相关文件,请勿勾选此项。" /> ToolTip="完全不更改 assets;不校验 libraries、第三方登录库与版本主 jar 文件是否被修改。&#xa;如果你没有修改相关文件,请勿勾选此项。" />
<local:MyCheckBox Height="28" Text="禁用 Java Launch Wrapper" x:Name="CheckAdvanceDisableJLW" Tag="VersionAdvanceDisableJLW" <local:MyCheckBox Height="28" Text="禁用 Java Launch Wrapper" x:Name="CheckAdvanceDisableJLW" Tag="VersionAdvanceDisableJLW"
ToolTipService.Placement="Right" ToolTipService.Placement="Right"
ToolTip="PCL 会使用 Java Launch Wrapper 来修复老版本 Java 在中文路径下无法启动的问题。&#xa;如果这被反作弊拦截,或遇到其他问题,也可以将其关闭。" /> ToolTip="是否使用 Java Launch Wrapper 修复 Java 18- 在中文路径下可能无法正常启动的问题。&#xa;详见:https://github.com/00ll00/java_launch_wrapper" />
<local:MyCheckBox Height="28" Text="禁用 LWJGL Unsafe Agent" local:SettingService.Key="VersionAdvanceDisableLUA"
ToolTipService.Placement="Right"
ToolTip="是否使用 LWJGL Unsafe Agent 修复 Java 25+ 的一个性能问题。&#xa;详见:https://github.com/HMCL-dev/lwjgl-unsafe-agent" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</local:MyCard> </local:MyCard>
@@ -27,41 +27,44 @@
Try Try
'启动参数 '启动参数
TextArgumentTitle.Text = Setup.Get("VersionArgumentTitle", Instance:=PageInstanceLeft.Instance) TextArgumentTitle.Text = Settings.Get("VersionArgumentTitle", Instance:=PageInstanceLeft.Instance)
TextArgumentInfo.Text = Setup.Get("VersionArgumentInfo", Instance:=PageInstanceLeft.Instance) TextArgumentInfo.Text = Settings.Get("VersionArgumentInfo", Instance:=PageInstanceLeft.Instance)
Dim _unused = PageInstanceLeft.Instance.PathIndie '触发自动判定 Dim _unused = PageInstanceLeft.Instance.PathIndie '触发自动判定
ComboArgumentIndieV2.SelectedIndex = If(Setup.Get("VersionArgumentIndieV2", Instance:=PageInstanceLeft.Instance), 0, 1) ComboArgumentIndieV2.SelectedIndex = If(Settings.Get("VersionArgumentIndieV2", Instance:=PageInstanceLeft.Instance), 0, 1)
RefreshJavaComboBox() RefreshJavaComboBox()
'游戏内存 '游戏内存
CType(FindName("RadioRamType" & Setup.Load("VersionRamType", Instance:=PageInstanceLeft.Instance)), MyRadioBox).Checked = True CType(FindName("RadioRamType" & Settings.Get("VersionRamType", Instance:=PageInstanceLeft.Instance)), MyRadioBox).Checked = True
SliderRamCustom.Value = Setup.Get("VersionRamCustom", Instance:=PageInstanceLeft.Instance) OnVersionRamTypeChanged(Settings.Get("VersionRamType", Instance:=PageInstanceLeft.Instance))
ComboRamOptimize.SelectedIndex = Setup.Get("VersionRamOptimize", Instance:=PageInstanceLeft.Instance) SliderRamCustom.Value = Settings.Get("VersionRamCustom", Instance:=PageInstanceLeft.Instance)
ComboRamOptimize.SelectedIndex = Settings.Get("VersionRamOptimize", Instance:=PageInstanceLeft.Instance)
'服务器 '服务器
TextServerEnter.Text = Setup.Get("VersionServerEnter", Instance:=PageInstanceLeft.Instance) TextServerEnter.Text = Settings.Get("VersionServerEnter", Instance:=PageInstanceLeft.Instance)
ComboServerLogin.SelectedIndex = Setup.Get("VersionServerLogin", Instance:=PageInstanceLeft.Instance) ComboServerLogin.SelectedIndex = Settings.Get("VersionServerLogin", Instance:=PageInstanceLeft.Instance)
ComboServerLoginLast = ComboServerLogin.SelectedIndex ComboServerLoginLast = ComboServerLogin.SelectedIndex
ServerLogin(ComboServerLogin.SelectedIndex) ServerLogin(ComboServerLogin.SelectedIndex)
TextServerNide.Text = Setup.Get("VersionServerNide", Instance:=PageInstanceLeft.Instance) TextServerNide.Text = Settings.Get("VersionServerNide", Instance:=PageInstanceLeft.Instance)
TextServerAuthServer.Text = Setup.Get("VersionServerAuthServer", Instance:=PageInstanceLeft.Instance) TextServerAuthServer.Text = Settings.Get("VersionServerAuthServer", Instance:=PageInstanceLeft.Instance)
TextServerAuthName.Text = Setup.Get("VersionServerAuthName", Instance:=PageInstanceLeft.Instance) TextServerAuthName.Text = Settings.Get("VersionServerAuthName", Instance:=PageInstanceLeft.Instance)
TextServerAuthRegister.Text = Setup.Get("VersionServerAuthRegister", Instance:=PageInstanceLeft.Instance) TextServerAuthRegister.Text = Settings.Get("VersionServerAuthRegister", Instance:=PageInstanceLeft.Instance)
'高级设置 '高级设置
TextAdvanceJvm.Text = Setup.Get("VersionAdvanceJvm", Instance:=PageInstanceLeft.Instance) TextAdvanceJvm.Text = Settings.Get("VersionAdvanceJvm", Instance:=PageInstanceLeft.Instance)
TextAdvanceGame.Text = Setup.Get("VersionAdvanceGame", Instance:=PageInstanceLeft.Instance) TextAdvanceGame.Text = Settings.Get("VersionAdvanceGame", Instance:=PageInstanceLeft.Instance)
TextAdvanceRun.Text = Setup.Get("VersionAdvanceRun", Instance:=PageInstanceLeft.Instance) TextAdvanceRun.Text = Settings.Get("VersionAdvanceRun", Instance:=PageInstanceLeft.Instance)
CheckAdvanceRunWait.Checked = Setup.Get("VersionAdvanceRunWait", Instance:=PageInstanceLeft.Instance) CheckAdvanceRunWait.Checked = Settings.Get("VersionAdvanceRunWait", Instance:=PageInstanceLeft.Instance)
If Setup.Get("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) = 2 Then If Settings.Get("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) = 2 Then
Log("[Setup] 已迁移老版本的关闭文件校验设置") Log("[Setup] 已迁移老版本的关闭文件校验设置")
Setup.Reset("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance)
Setup.Set("VersionAdvanceAssetsV2", True, Instance:=PageInstanceLeft.Instance) Settings.Set("VersionAdvanceAssetsV2", True, Instance:=PageInstanceLeft.Instance)
End If End If
CheckAdvanceAssetsV2.Checked = Setup.Get("VersionAdvanceAssetsV2", Instance:=PageInstanceLeft.Instance) CheckAdvanceAssetsV2.Checked = Settings.Get("VersionAdvanceAssetsV2", Instance:=PageInstanceLeft.Instance)
CheckAdvanceJava.Checked = Setup.Get("VersionAdvanceJava", Instance:=PageInstanceLeft.Instance) CheckAdvanceJava.Checked = Settings.Get("VersionAdvanceJava", Instance:=PageInstanceLeft.Instance)
CheckAdvanceDisableJLW.Checked = Setup.Get("VersionAdvanceDisableJLW", Instance:=PageInstanceLeft.Instance) CheckAdvanceDisableJLW.Checked = Settings.Get("VersionAdvanceDisableJLW", Instance:=PageInstanceLeft.Instance)
CheckAdvanceDisableModUpdate.Checked = Setup.Get("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance) CheckAdvanceDisableModUpdate.Checked = Settings.Get("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance)
SettingService.RefreshSettings(Me)
Catch ex As Exception Catch ex As Exception
Log(ex, "重载版本独立设置时出错", LogLevel.Feedback) Log(ex, "重载版本独立设置时出错", LogLevel.Feedback)
@@ -72,31 +75,32 @@
Public Sub Reset() Public Sub Reset()
Try Try
Setup.Reset("VersionServerEnter", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionServerEnter", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionServerLogin", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionServerLogin", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionServerNide", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionServerNide", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionServerAuthServer", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionServerAuthServer", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionServerAuthRegister", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionServerAuthRegister", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionServerAuthName", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionServerAuthName", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionArgumentTitle", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionArgumentTitle", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionArgumentInfo", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionArgumentInfo", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionArgumentIndieV2", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionArgumentIndieV2", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionRamType", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionRamType", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionRamCustom", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionRamCustom", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionRamOptimize", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionRamOptimize", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceJvm", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceJvm", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceGame", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceGame", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceAssetsV2", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceAssetsV2", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceJava", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceJava", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceRun", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceRun", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceRunWait", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceRunWait", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceDisableJLW", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceDisableJLW", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance) Settings.Reset("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance)
Settings.Reset("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance)
Setup.Reset("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance)
JavaSearchLoader.Start(IsForceRestart:=True) JavaSearchLoader.Start(IsForceRestart:=True)
SettingService.ResetSettings(Me)
Log("[Setup] 已初始化版本独立设置") Log("[Setup] 已初始化版本独立设置")
Hint("已初始化版本独立设置!", HintType.Green, False) Hint("已初始化版本独立设置!", HintType.Green, False)
Catch ex As Exception Catch ex As Exception
@@ -108,31 +112,36 @@
'将控件改变路由到设置改变 '将控件改变路由到设置改变
Private Shared Sub RadioBoxChange(sender As MyRadioBox, e As Object) Handles RadioRamType0.Check, RadioRamType1.Check, RadioRamType2.Check Private Shared Sub RadioBoxChange(sender As MyRadioBox, e As Object) Handles RadioRamType0.Check, RadioRamType1.Check, RadioRamType2.Check
If AniControlEnabled = 0 Then Setup.Set(sender.Tag.ToString.Split("/")(0), Val(sender.Tag.ToString.Split("/")(1)), Instance:=PageInstanceLeft.Instance) If AniControlEnabled = 0 Then Settings.Set(sender.Tag.ToString.Split("/")(0), Val(sender.Tag.ToString.Split("/")(1)), Instance:=PageInstanceLeft.Instance)
End Sub End Sub
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextServerEnter.ValidatedTextChanged, TextArgumentInfo.ValidatedTextChanged, TextAdvanceGame.ValidatedTextChanged, TextAdvanceJvm.ValidatedTextChanged, TextServerNide.ValidatedTextChanged, TextServerAuthName.ValidatedTextChanged, TextServerAuthRegister.ValidatedTextChanged, TextServerAuthServer.ValidatedTextChanged, TextArgumentTitle.ValidatedTextChanged, TextAdvanceRun.ValidatedTextChanged Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextServerEnter.ValidatedTextChanged, TextArgumentInfo.ValidatedTextChanged, TextAdvanceGame.ValidatedTextChanged, TextAdvanceJvm.ValidatedTextChanged, TextServerNide.ValidatedTextChanged, TextServerAuthName.ValidatedTextChanged, TextServerAuthRegister.ValidatedTextChanged, TextServerAuthServer.ValidatedTextChanged, TextArgumentTitle.ValidatedTextChanged, TextAdvanceRun.ValidatedTextChanged
If AniControlEnabled = 0 Then If AniControlEnabled = 0 Then
'#3194,不能删减 / '#3194,不能删减 /
'Dim HandledText As String = sender.Text 'Dim HandledText As String = sender.Text
'If sender.Tag = "VersionServerAuthServer" OrElse sender.Tag = "VersionServerAuthRegister" Then HandledText = HandledText.TrimEnd("/") 'If sender.Tag = "VersionServerAuthServer" OrElse sender.Tag = "VersionServerAuthRegister" Then HandledText = HandledText.TrimEnd("/")
Setup.Set(sender.Tag, sender.Text, Instance:=PageInstanceLeft.Instance) Settings.Set(sender.Tag, sender.Text, Instance:=PageInstanceLeft.Instance)
End If End If
End Sub End Sub
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value, Instance:=PageInstanceLeft.Instance) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Value, Instance:=PageInstanceLeft.Instance)
End Sub End Sub
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboRamOptimize.SelectionChanged Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboRamOptimize.SelectionChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex, Instance:=PageInstanceLeft.Instance) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.SelectedIndex, Instance:=PageInstanceLeft.Instance)
End Sub End Sub
Private Shared Sub CheckBoxLikeComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndieV2.SelectionChanged Private Shared Sub CheckBoxLikeComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndieV2.SelectionChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex = 0, Instance:=PageInstanceLeft.Instance) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.SelectedIndex = 0, Instance:=PageInstanceLeft.Instance)
End Sub End Sub
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckAdvanceRunWait.Change, CheckAdvanceAssetsV2.Change, CheckAdvanceJava.Change, CheckAdvanceDisableJLW.Change, CheckAdvanceDisableModUpdate.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, Instance:=PageInstanceLeft.Instance) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Checked, Instance:=PageInstanceLeft.Instance)
End Sub End Sub
#Region "游戏内存" #Region "游戏内存"
Public Shared Sub OnVersionRamTypeChanged(Type As Integer)
If FrmInstanceSetup Is Nothing Then Return
FrmInstanceSetup.RamType(Type)
End Sub
Public Sub RamType(Type As Integer) Public Sub RamType(Type As Integer)
If SliderRamCustom Is Nothing Then Return If SliderRamCustom Is Nothing Then Return
SliderRamCustom.IsEnabled = (Type = 1) SliderRamCustom.IsEnabled = (Type = 1)
@@ -271,7 +280,7 @@
''' </summary> ''' </summary>
Public Shared Function GetRam(Instance As McInstance, Optional Is32BitJava As Boolean? = Nothing) As Double Public Shared Function GetRam(Instance As McInstance, Optional Is32BitJava As Boolean? = Nothing) As Double
'跟随全局设置 '跟随全局设置
If Setup.Get("VersionRamType", Instance:=Instance) = 2 Then If Settings.Get("VersionRamType", Instance:=Instance) = 2 Then
Return PageSetupLaunch.GetRam(Instance, True, Is32BitJava) Return PageSetupLaunch.GetRam(Instance, True, Is32BitJava)
End If End If
@@ -281,7 +290,7 @@
'使用当前版本的设置 '使用当前版本的设置
Dim RamGive As Double Dim RamGive As Double
If Setup.Get("VersionRamType", Instance:=Instance) = 0 Then If Settings.Get("VersionRamType", Instance:=Instance) = 0 Then
'自动配置 '自动配置
Dim RamAvailable As Double = Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024 / 1024 * 10) / 10 Dim RamAvailable As Double = Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024 / 1024 * 10) / 10
'确定需求的内存值 '确定需求的内存值
@@ -293,7 +302,7 @@
If Instance IsNot Nothing AndAlso Instance.Modable Then If Instance IsNot Nothing AndAlso Instance.Modable Then
'可安装 Mod 的版本 '可安装 Mod 的版本
Dim ModDir As New DirectoryInfo(Instance.PathIndie & "mods\") Dim ModDir As New DirectoryInfo(Instance.PathIndie & "mods\")
Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Length, 0) Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Count(Function(f) {".jar", ".zip", ".litemod"}.Contains(f.Extension.Lower)), 0)
RamMininum = 0.5 + ModCount / 150 RamMininum = 0.5 + ModCount / 150
RamTarget1 = 1.5 + ModCount / 90 RamTarget1 = 1.5 + ModCount / 90
RamTarget2 = 2.7 + ModCount / 50 RamTarget2 = 2.7 + ModCount / 50
@@ -337,7 +346,7 @@ PreFin:
RamGive = Math.Round(Math.Max(RamGive, RamMininum), 1) RamGive = Math.Round(Math.Max(RamGive, RamMininum), 1)
Else Else
'手动配置 '手动配置
Dim Value As Integer = Setup.Get("VersionRamCustom", Instance:=Instance) Dim Value As Integer = Settings.Get("VersionRamCustom", Instance:=Instance)
If Value <= 12 Then If Value <= 12 Then
RamGive = Value * 0.1 + 0.3 RamGive = Value * 0.1 + 0.3
ElseIf Value <= 25 Then ElseIf Value <= 25 Then
@@ -357,6 +366,16 @@ PreFin:
#Region "服务器" #Region "服务器"
'当第三方登录更改时,清空版本列表缓存以更新版本分类
'TODO: 这会不会导致拖拽改变第三方登录的时候版本列表缓存没有更新?
Public Shared Sub OnVersionServerLoginChanged(Type As Integer)
If FrmInstanceSetup Is Nothing Then Return
WriteIni(McFolderSelected & "PCL.ini", "InstanceCache", "")
If PageInstanceLeft.Instance Is Nothing Then Return
PageInstanceLeft.Instance = New McInstance(PageInstanceLeft.Instance.Name).Load()
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
End Sub
'自动替换标点 '自动替换标点
Private Sub TextServerEnter_Change() Handles TextServerEnter.TextChanged Private Sub TextServerEnter_Change() Handles TextServerEnter.TextChanged
Dim NewText = TextServerEnter.Text.Replace(":", ":").Replace("。", ".") Dim NewText = TextServerEnter.Text.Replace(":", ":").Replace("。", ".")
@@ -423,7 +442,7 @@ PreFin:
ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "自动选择合适的 Java", .Tag = "自动选择"}) ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "自动选择合适的 Java", .Tag = "自动选择"})
'更新列表 '更新列表
Dim SelectedItem As MyComboBoxItem = Nothing Dim SelectedItem As MyComboBoxItem = Nothing
Dim SelectedBySetup As String = Setup.Get("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance) Dim SelectedBySetup As String = Settings.Get("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance)
Try Try
For Each Java In JavaList.Clone().OrderByDescending(Function(v) v.MajorVersion) For Each Java In JavaList.Clone().OrderByDescending(Function(v) v.MajorVersion)
Dim ListItem = New MyComboBoxItem With {.Content = Java.ToString, .ToolTip = Java.PathFolder, .Tag = Java} Dim ListItem = New MyComboBoxItem With {.Content = Java.ToString, .ToolTip = Java.PathFolder, .Tag = Java}
@@ -434,7 +453,7 @@ PreFin:
If JavaEntry.FromJson(GetJson(SelectedBySetup)).PathFolder = Java.PathFolder Then SelectedItem = ListItem If JavaEntry.FromJson(GetJson(SelectedBySetup)).PathFolder = Java.PathFolder Then SelectedItem = ListItem
Next Next
Catch ex As Exception Catch ex As Exception
Setup.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=PageInstanceLeft.Instance) Settings.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=PageInstanceLeft.Instance)
Log(ex, "更新版本设置 Java 下拉框失败", LogLevel.Feedback) Log(ex, "更新版本设置 Java 下拉框失败", LogLevel.Feedback)
End Try End Try
'更新选择项 '更新选择项
@@ -469,15 +488,15 @@ PreFin:
Dim SelectedJava = ComboArgumentJava.SelectedItem.Tag Dim SelectedJava = ComboArgumentJava.SelectedItem.Tag
If "使用全局设置".Equals(SelectedJava) Then If "使用全局设置".Equals(SelectedJava) Then
'选择 “自动” '选择 “自动”
Setup.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=PageInstanceLeft.Instance) Settings.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=PageInstanceLeft.Instance)
Log("[Java] 修改版本 Java 选择设置:跟随全局设置") Log("[Java] 修改版本 Java 选择设置:跟随全局设置")
ElseIf "自动选择".Equals(SelectedJava) Then ElseIf "自动选择".Equals(SelectedJava) Then
'选择 “自动” '选择 “自动”
Setup.Set("VersionArgumentJavaSelect", "", Instance:=PageInstanceLeft.Instance) Settings.Set("VersionArgumentJavaSelect", "", Instance:=PageInstanceLeft.Instance)
Log("[Java] 修改版本 Java 选择设置:自动选择") Log("[Java] 修改版本 Java 选择设置:自动选择")
Else Else
'选择指定项 '选择指定项
Setup.Set("VersionArgumentJavaSelect", CType(SelectedJava.ToJson(), JObject).ToString(Newtonsoft.Json.Formatting.None), Instance:=PageInstanceLeft.Instance) Settings.Set("VersionArgumentJavaSelect", CType(SelectedJava.ToJson(), JObject).ToString(Newtonsoft.Json.Formatting.None), Instance:=PageInstanceLeft.Instance)
Log("[Java] 修改版本 Java 选择设置:" & SelectedJava.ToString) Log("[Java] 修改版本 Java 选择设置:" & SelectedJava.ToString)
End If End If
RefreshRam(True) RefreshRam(True)
@@ -55,7 +55,7 @@
Dim FileAddress As String = SelectSaveFile("选取保存皮肤的位置", GetFileNameFromPath(Address), "皮肤图片文件(*.png)|*.png") Dim FileAddress As String = SelectSaveFile("选取保存皮肤的位置", GetFileNameFromPath(Address), "皮肤图片文件(*.png)|*.png")
If FileAddress.Contains("\") Then If FileAddress.Contains("\") Then
File.Delete(FileAddress) File.Delete(FileAddress)
If Address.StartsWith(PathImage) Then If Address.StartsWithF(PathImage) Then
Dim Image As New MyBitmap(Address) Dim Image As New MyBitmap(Address)
Image.Save(FileAddress) Image.Save(FileAddress)
Else Else
@@ -79,7 +79,7 @@
'检查文件存在 '检查文件存在
Address = Loader.Output Address = Loader.Output
If String.IsNullOrEmpty(Address) Then Throw New Exception("皮肤加载器 " & Loader.Name & " 没有输出") If String.IsNullOrEmpty(Address) Then Throw New Exception("皮肤加载器 " & Loader.Name & " 没有输出")
If Not Address.StartsWith(PathImage) AndAlso Not File.Exists(Address) Then Throw New FileNotFoundException("皮肤文件未找到", Address) If Not Address.StartsWithF(PathImage) AndAlso Not File.Exists(Address) Then Throw New FileNotFoundException("皮肤文件未找到", Address)
'加载 '加载
Dim Image As MyBitmap Dim Image As MyBitmap
Try Try
@@ -142,7 +142,7 @@
End If End If
Next Next
If FrmLaunchLeft IsNot Nothing AndAlso HasLoaderRunning Then If FrmLaunchLeft IsNot Nothing AndAlso HasLoaderRunning Then
'由于 Abort 不是实时的,暂时不会释放文件,会导致删除报错,故只能取消执行 '由于 Interrupt 不是实时的,暂时不会释放文件,会导致删除报错,故只能取消执行
Hint("有正在获取中的皮肤,请稍后再试!", HintType.Blue) Hint("有正在获取中的皮肤,请稍后再试!", HintType.Blue)
Else Else
RunInThread( RunInThread(
@@ -177,8 +177,8 @@
Sub() Sub()
Try Try
'更新缓存 '更新缓存
WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Setup.Get("CacheMsV2Uuid"), SkinAddress) WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Settings.Get("CacheMsV2Uuid"), SkinAddress)
Log($"[Skin] 已写入皮肤地址缓存 {Setup.Get("CacheMsV2Uuid")} -> {SkinAddress}") Log($"[Skin] 已写入皮肤地址缓存 {Settings.Get("CacheMsV2Uuid")} -> {SkinAddress}")
'刷新控件 '刷新控件
For Each SkinLoader In {PageLaunchLeft.SkinMs, PageLaunchLeft.SkinLegacy} For Each SkinLoader In {PageLaunchLeft.SkinMs, PageLaunchLeft.SkinLegacy}
SkinLoader.WaitForExit(IsForceRestart:=True) SkinLoader.WaitForExit(IsForceRestart:=True)
@@ -27,17 +27,10 @@
If File.Exists(Path & "modpack.mrpack") Then PackInstallPath = Path & "modpack.mrpack" If File.Exists(Path & "modpack.mrpack") Then PackInstallPath = Path & "modpack.mrpack"
If PackInstallPath IsNot Nothing Then If PackInstallPath IsNot Nothing Then
Log("[Launch] 需自动安装整合包:" & PackInstallPath, LogLevel.Debug) Log("[Launch] 需自动安装整合包:" & PackInstallPath, LogLevel.Debug)
Setup.Set("LaunchFolderSelect", "$.minecraft\") PageSelectLeft.CreateMcFolderInCurrentPath()
If Not Directory.Exists(Path & ".minecraft\") Then
Directory.CreateDirectory(Path & ".minecraft\")
Directory.CreateDirectory(Path & ".minecraft\versions\")
McFolderLauncherProfilesJsonCreate(Path & ".minecraft\")
End If
PageSelectLeft.AddFolder(Path & ".minecraft\", GetFolderNameFromPath(Path), False)
McFolderListLoader.WaitForExit() McFolderListLoader.WaitForExit()
End If End If
'确认 Minecraft 文件夹存在 '确认 Minecraft 文件夹存在
McFolderSelected = Setup.Get("LaunchFolderSelect").ToString.Replace("$", Path)
If McFolderSelected = "" OrElse Not Directory.Exists(McFolderSelected) Then If McFolderSelected = "" OrElse Not Directory.Exists(McFolderSelected) Then
'无效的文件夹 '无效的文件夹
If McFolderSelected = "" Then If McFolderSelected = "" Then
@@ -46,10 +39,9 @@
Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" & McFolderSelected, LogLevel.Debug) Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" & McFolderSelected, LogLevel.Debug)
End If End If
McFolderListLoader.WaitForExit(IsForceRestart:=True) McFolderListLoader.WaitForExit(IsForceRestart:=True)
Setup.Set("LaunchFolderSelect", McFolderList(0).Location.Replace(Path, "$")) McFolderSelected = McFolderList.First.Location
End If End If
Log("[Launch] Minecraft 文件夹:" & McFolderSelected) If Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
If Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
'自动整合包安装 '自动整合包安装
If PackInstallPath IsNot Nothing Then If PackInstallPath IsNot Nothing Then
Try Try
@@ -67,7 +59,7 @@
End Try End Try
End If End If
'确认 Minecraft 版本存在 '确认 Minecraft 版本存在
Dim Selection As String = Setup.Get("LaunchVersionSelect") Dim Selection As String = ReadIni(McFolderSelected & "PCL.ini", "Version")
Dim Instance As McInstance = If(Selection = "", Nothing, New McInstance(Selection)) Dim Instance As McInstance = If(Selection = "", Nothing, New McInstance(Selection))
If Instance Is Nothing OrElse Not Instance.PathVersion.StartsWithF(McFolderSelected) OrElse Not Instance.Check() Then If Instance Is Nothing OrElse Not Instance.PathVersion.StartsWithF(McFolderSelected) OrElse Not Instance.Check() Then
'无效的版本 '无效的版本
@@ -75,11 +67,9 @@
If Not McInstanceListLoader.State = LoadState.Finished Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True) If Not McInstanceListLoader.State = LoadState.Finished Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
If Not McInstanceList.Any() OrElse McInstanceList.First.Value(0).Logo.Contains("RedstoneBlock") Then If Not McInstanceList.Any() OrElse McInstanceList.First.Value(0).Logo.Contains("RedstoneBlock") Then
Instance = Nothing Instance = Nothing
Setup.Set("LaunchVersionSelect", "")
Log("[Launch] 无可用 Minecraft 版本") Log("[Launch] 无可用 Minecraft 版本")
Else Else
Instance = McInstanceList.First.Value(0) Instance = McInstanceList.First.Value(0)
Setup.Set("LaunchVersionSelect", Instance.Name)
Log("[Launch] 自动选择 Minecraft 版本:" & Instance.PathVersion) Log("[Launch] 自动选择 Minecraft 版本:" & Instance.PathVersion)
End If End If
End If End If
@@ -94,7 +84,7 @@
End Sub, "Version Check", ThreadPriority.AboveNormal) End Sub, "Version Check", ThreadPriority.AboveNormal)
'改变页面 '改变页面
Dim LoginType As McLoginType = Setup.Get("LoginType") Dim LoginType As McLoginType = Settings.Get("LoginType")
If LoginType = McLoginType.Legacy OrElse LoginType = McLoginType.Ms Then CType(FindName("RadioLoginType" & LoginType), MyRadioButton).Checked = True If LoginType = McLoginType.Legacy OrElse LoginType = McLoginType.Ms Then CType(FindName("RadioLoginType" & LoginType), MyRadioButton).Checked = True
RefreshPage(False, False) RefreshPage(False, False)
@@ -108,7 +98,7 @@
''' </summary> ''' </summary>
Public Sub PageChangeToLaunching() Public Sub PageChangeToLaunching()
'修改登陆方式 '修改登陆方式
Select Case Setup.Get("LoginType") Select Case Settings.Get("LoginType")
Case McLoginType.Legacy Case McLoginType.Legacy
LabLaunchingMethod.Text = "离线登录" LabLaunchingMethod.Text = "离线登录"
Case McLoginType.Ms Case McLoginType.Ms
@@ -279,37 +269,37 @@
Dim Type As PageType Dim Type As PageType
Dim LoginPageType As Integer Dim LoginPageType As Integer
If McInstanceSelected IsNot Nothing Then If McInstanceSelected IsNot Nothing Then
LoginPageType = Setup.Get("VersionServerLogin", Instance:=McInstanceSelected) LoginPageType = Settings.Get("VersionServerLogin", Instance:=McInstanceSelected)
'缓存当前版本的页面种类,下一次打开 McInstanceSelected 为空时才能加载出正确的页面 '缓存当前版本的页面种类,下一次打开 McInstanceSelected 为空时才能加载出正确的页面
Setup.Set("LoginPageType", LoginPageType) Settings.Set("LoginPageType", LoginPageType)
Else Else
LoginPageType = Setup.Get("LoginPageType") LoginPageType = Settings.Get("LoginPageType")
End If End If
Select Case LoginPageType Select Case LoginPageType
Case 0 '正版或离线 Case 0 '正版或离线
UnknownType: UnknownType:
If RadioLoginType5.Checked Then If RadioLoginType5.Checked Then
If Setup.Get("CacheMsV2Access") = "" Then If Settings.Get("CacheMsV2Access") = "" Then
Type = PageType.Ms Type = PageType.Ms
Else Else
Type = PageType.MsSkin Type = PageType.MsSkin
End If End If
Setup.Set("LoginType", McLoginType.Ms) Settings.Set("LoginType", McLoginType.Ms)
Else Else
Type = PageType.Legacy Type = PageType.Legacy
Setup.Set("LoginType", McLoginType.Legacy) Settings.Set("LoginType", McLoginType.Legacy)
End If End If
PanType.Visibility = Visibility.Visible PanType.Visibility = Visibility.Visible
PanTypeOne.Visibility = Visibility.Collapsed PanTypeOne.Visibility = Visibility.Collapsed
RadioLoginType5.Visibility = Visibility.Visible RadioLoginType5.Visibility = Visibility.Visible
RadioLoginType0.Visibility = Visibility.Visible RadioLoginType0.Visibility = Visibility.Visible
Case 1 '仅正版 Case 1 '仅正版
If Setup.Get("CacheMsV2Access") = "" Then If Settings.Get("CacheMsV2Access") = "" Then
Type = PageType.Ms Type = PageType.Ms
Else Else
Type = PageType.MsSkin Type = PageType.MsSkin
End If End If
Setup.Set("LoginType", McLoginType.Ms) Settings.Set("LoginType", McLoginType.Ms)
PanType.Visibility = Visibility.Collapsed PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonShield) PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonShield)
@@ -318,33 +308,33 @@ UnknownType:
RadioLoginType0.Visibility = Visibility.Collapsed RadioLoginType0.Visibility = Visibility.Collapsed
Case 2 '仅离线 Case 2 '仅离线
Type = PageType.Legacy Type = PageType.Legacy
Setup.Set("LoginType", McLoginType.Legacy) Settings.Set("LoginType", McLoginType.Legacy)
PanType.Visibility = Visibility.Collapsed PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonOffline) PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonOffline)
LabTypeOne.Text = "离线登录" LabTypeOne.Text = "离线登录"
Case 3 '统一通行证 Case 3 '统一通行证
If Setup.Get("CacheNideAccess") = "" Then If Settings.Get("CacheNideAccess") = "" Then
Type = PageType.Nide Type = PageType.Nide
Else Else
Type = PageType.NideSkin Type = PageType.NideSkin
End If End If
Setup.Set("LoginType", McLoginType.Nide) Settings.Set("LoginType", McLoginType.Nide)
PanType.Visibility = Visibility.Collapsed PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonCard) PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonCard)
LabTypeOne.Text = "统一通行证登录" LabTypeOne.Text = "统一通行证登录"
Case 4 'Authlib-Injector Case 4 'Authlib-Injector
If Setup.Get("CacheAuthAccess") = "" Then If Settings.Get("CacheAuthAccess") = "" Then
Type = PageType.Auth Type = PageType.Auth
Else Else
Type = PageType.AuthSkin Type = PageType.AuthSkin
End If End If
Setup.Set("LoginType", McLoginType.Auth) Settings.Set("LoginType", McLoginType.Auth)
PanType.Visibility = Visibility.Collapsed PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonCard) PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonCard)
LabTypeOne.Text = If(McInstanceSelected Is Nothing, Setup.Get("CacheAuthServerName"), Setup.Get("VersionServerAuthName", Instance:=McInstanceSelected)) LabTypeOne.Text = If(McInstanceSelected Is Nothing, Settings.Get("CacheAuthServerName"), Settings.Get("VersionServerAuthName", Instance:=McInstanceSelected))
If LabTypeOne.Text = "" Then LabTypeOne.Text = "第三方登录" If LabTypeOne.Text = "" Then LabTypeOne.Text = "第三方登录"
Case Else Case Else
Log("[Control] 未知的登录页面:" & LoginPageType, LogLevel.Hint) Log("[Control] 未知的登录页面:" & LoginPageType, LogLevel.Hint)
@@ -353,7 +343,7 @@ UnknownType:
'刷新页面 '刷新页面
If PageCurrent = Type Then Return If PageCurrent = Type Then Return
PageChange(Type, Anim).Reload(KeepInput) PageChange(Type, Anim).Reload(KeepInput)
Dim Control As MyRadioButton = FindName("RadioLoginType" & Setup.Get("LoginType")) Dim Control As MyRadioButton = FindName("RadioLoginType" & Settings.Get("LoginType"))
If Control IsNot Nothing Then Control.Checked = True If Control IsNot Nothing Then Control.Checked = True
End Sub End Sub
Private Sub RadioLoginType_Change(sender As Object, raiseByMouse As Boolean) Handles RadioLoginType0.Check, RadioLoginType5.Check Private Sub RadioLoginType_Change(sender As Object, raiseByMouse As Boolean) Handles RadioLoginType0.Check, RadioLoginType5.Check
@@ -368,7 +358,7 @@ UnknownType:
Public Shared SkinMs As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Ms", AddressOf SkinMsLoad, AddressOf SkinMsInput, ThreadPriority.AboveNormal) Public Shared SkinMs As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Ms", AddressOf SkinMsLoad, AddressOf SkinMsInput, ThreadPriority.AboveNormal)
Private Shared Function SkinMsInput() As EqualableList(Of String) Private Shared Function SkinMsInput() As EqualableList(Of String)
'获取名称 '获取名称
Return New EqualableList(Of String) From {Setup.Get("CacheMsV2Name"), Setup.Get("CacheMsV2Uuid")} Return New EqualableList(Of String) From {Settings.Get("CacheMsV2Name"), Settings.Get("CacheMsV2Uuid")}
End Function End Function
Private Shared Sub SkinMsLoad(Data As LoaderTask(Of EqualableList(Of String), String)) Private Shared Sub SkinMsLoad(Data As LoaderTask(Of EqualableList(Of String), String))
'清空已有皮肤 '清空已有皮肤
@@ -384,9 +374,9 @@ UnknownType:
End If End If
Try Try
Dim Result As String = McSkinGetAddress(Uuid, "Ms") Dim Result As String = McSkinGetAddress(Uuid, "Ms")
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Result = McSkinDownload(Result) Result = McSkinDownload(Result)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Data.Output = Result Data.Output = Result
Catch ex As ThreadInterruptedException Catch ex As ThreadInterruptedException
Data.Output = "" Data.Output = ""
@@ -407,7 +397,7 @@ Finish:
'刷新显示 '刷新显示
If FrmLoginMsSkin IsNot Nothing Then If FrmLoginMsSkin IsNot Nothing Then
RunInUi(AddressOf FrmLoginMsSkin.Skin.Load) RunInUi(AddressOf FrmLoginMsSkin.Skin.Load)
ElseIf Not Data.IsAborted Then '如果已经中断,Input 也被清空,就不会再次刷新 ElseIf Not Data.IsInterrupted Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染 Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If End If
End Sub End Sub
@@ -416,18 +406,18 @@ Finish:
Public Shared SkinLegacy As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Legacy", AddressOf SkinLegacyLoad, AddressOf SkinLegacyInput, ThreadPriority.AboveNormal) Public Shared SkinLegacy As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Legacy", AddressOf SkinLegacyLoad, AddressOf SkinLegacyInput, ThreadPriority.AboveNormal)
Private Shared Function SkinLegacyInput() As EqualableList(Of String) Private Shared Function SkinLegacyInput() As EqualableList(Of String)
'根据类型判断输入 '根据类型判断输入
Dim Type As Integer = Setup.Get("LaunchSkinType") Dim Type As Integer = Settings.Get("LaunchSkinType")
Select Case Type Select Case Type
Case 0 Case 0
If FrmLoginLegacy IsNot Nothing AndAlso FrmLoginLegacy.IsReloaded Then If FrmLoginLegacy IsNot Nothing AndAlso FrmLoginLegacy.IsReloaded Then
Return New EqualableList(Of String) From {0, If(FrmLoginLegacy.ComboName.Text.Trim, "")} Return New EqualableList(Of String) From {0, If(FrmLoginLegacy.ComboName.Text.Trim, "")}
ElseIf Setup.Get("LoginLegacyName") = "" Then ElseIf Settings.Get("LoginLegacyName") = "" Then
Return New EqualableList(Of String) From {0, ""} Return New EqualableList(Of String) From {0, ""}
Else Else
Return New EqualableList(Of String) From {0, If(Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨"), "")} Return New EqualableList(Of String) From {0, If(Settings.Get("LoginLegacyName").ToString.BeforeFirst("¨"), "")}
End If End If
Case 3 Case 3
Return New EqualableList(Of String) From {3, Setup.Get("LaunchSkinID")} Return New EqualableList(Of String) From {3, Settings.Get("LaunchSkinID")}
Case Else Case Else
Return New EqualableList(Of String) From {Type} Return New EqualableList(Of String) From {Type}
End Select End Select
@@ -451,11 +441,11 @@ UseDefault:
Data.Output = PathImage & "Skins/Steve.png" Data.Output = PathImage & "Skins/Steve.png"
Else Else
Dim Result As String = McLoginMojangUuid(ID, True) Dim Result As String = McLoginMojangUuid(ID, True)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & ID) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & ID)
Result = McSkinGetAddress(Result, "Mojang") Result = McSkinGetAddress(Result, "Mojang")
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & ID) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & ID)
Result = McSkinDownload(Result) Result = McSkinDownload(Result)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & ID) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & ID)
Data.Output = Result Data.Output = Result
End If End If
Catch ex As ThreadInterruptedException Catch ex As ThreadInterruptedException
@@ -473,7 +463,7 @@ UseDefault:
Case 4 '自定义 Case 4 '自定义
If Not File.Exists(PathAppdata & "CustomSkin.png") Then If Not File.Exists(PathAppdata & "CustomSkin.png") Then
Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL 将使用默认的 Steve 皮肤!") Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL 将使用默认的 Steve 皮肤!")
Setup.Set("LaunchSkinType", 1) Settings.Set("LaunchSkinType", 1)
GoTo UseDefault GoTo UseDefault
End If End If
Data.Output = PathAppdata & "CustomSkin.png" Data.Output = PathAppdata & "CustomSkin.png"
@@ -481,7 +471,7 @@ UseDefault:
'刷新显示 '刷新显示
If FrmLoginLegacy IsNot Nothing Then If FrmLoginLegacy IsNot Nothing Then
RunInUi(AddressOf FrmLoginLegacy.Skin.Load) RunInUi(AddressOf FrmLoginLegacy.Skin.Load)
ElseIf Not Data.IsAborted Then '如果已经中断,Input 也被清空,就不会再次刷新 ElseIf Not Data.IsInterrupted Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染 Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If End If
End Sub End Sub
@@ -490,7 +480,7 @@ UseDefault:
Public Shared SkinNide As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Nide", AddressOf SkinNideLoad, AddressOf SkinNideInput, ThreadPriority.AboveNormal) Public Shared SkinNide As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Nide", AddressOf SkinNideLoad, AddressOf SkinNideInput, ThreadPriority.AboveNormal)
Private Shared Function SkinNideInput() As EqualableList(Of String) Private Shared Function SkinNideInput() As EqualableList(Of String)
'获取名称 '获取名称
Return New EqualableList(Of String) From {Setup.Get("CacheNideName"), Setup.Get("CacheNideUuid")} Return New EqualableList(Of String) From {Settings.Get("CacheNideName"), Settings.Get("CacheNideUuid")}
End Function End Function
Private Shared Sub SkinNideLoad(Data As LoaderTask(Of EqualableList(Of String), String)) Private Shared Sub SkinNideLoad(Data As LoaderTask(Of EqualableList(Of String), String))
'清空已有皮肤 '清空已有皮肤
@@ -506,9 +496,9 @@ UseDefault:
End If End If
Try Try
Dim Result As String = McSkinGetAddress(Uuid, "Nide") Dim Result As String = McSkinGetAddress(Uuid, "Nide")
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Result = McSkinDownload(Result) Result = McSkinDownload(Result)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Data.Output = Result Data.Output = Result
Catch ex As ThreadInterruptedException Catch ex As ThreadInterruptedException
Data.Output = "" Data.Output = ""
@@ -529,7 +519,7 @@ Finish:
'刷新显示 '刷新显示
If FrmLoginNideSkin IsNot Nothing Then If FrmLoginNideSkin IsNot Nothing Then
RunInUi(AddressOf FrmLoginNideSkin.Skin.Load) RunInUi(AddressOf FrmLoginNideSkin.Skin.Load)
ElseIf Not Data.IsAborted Then '如果已经中断,Input 也被清空,就不会再次刷新 ElseIf Not Data.IsInterrupted Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染 Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If End If
End Sub End Sub
@@ -538,7 +528,7 @@ Finish:
Public Shared SkinAuth As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Auth", AddressOf SkinAuthLoad, AddressOf SkinAuthInput, ThreadPriority.AboveNormal) Public Shared SkinAuth As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Auth", AddressOf SkinAuthLoad, AddressOf SkinAuthInput, ThreadPriority.AboveNormal)
Private Shared Function SkinAuthInput() As EqualableList(Of String) Private Shared Function SkinAuthInput() As EqualableList(Of String)
'获取名称 '获取名称
Return New EqualableList(Of String) From {Setup.Get("CacheAuthName"), Setup.Get("CacheAuthUuid")} Return New EqualableList(Of String) From {Settings.Get("CacheAuthName"), Settings.Get("CacheAuthUuid")}
End Function End Function
Private Shared Sub SkinAuthLoad(Data As LoaderTask(Of EqualableList(Of String), String)) Private Shared Sub SkinAuthLoad(Data As LoaderTask(Of EqualableList(Of String), String))
'清空已有皮肤 '清空已有皮肤
@@ -554,9 +544,9 @@ Finish:
End If End If
Try Try
Dim Result As String = McSkinGetAddress(UUID, "Auth") Dim Result As String = McSkinGetAddress(UUID, "Auth")
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Result = McSkinDownload(Result) Result = McSkinDownload(Result)
If Data.IsAborted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName) If Data.IsInterrupted Then Throw New ThreadInterruptedException("当前任务已取消:" & UserName)
Data.Output = Result Data.Output = Result
Catch ex As ThreadInterruptedException Catch ex As ThreadInterruptedException
Data.Output = "" Data.Output = ""
@@ -577,7 +567,7 @@ Finish:
'刷新显示 '刷新显示
If FrmLoginAuthSkin IsNot Nothing Then If FrmLoginAuthSkin IsNot Nothing Then
RunInUi(AddressOf FrmLoginAuthSkin.Skin.Load) RunInUi(AddressOf FrmLoginAuthSkin.Skin.Load)
ElseIf Not Data.IsAborted Then '如果已经中断,Input 也被清空,就不会再次刷新 ElseIf Not Data.IsInterrupted Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染 Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If End If
End Sub End Sub
@@ -601,6 +591,7 @@ Finish:
If IsAprilEnabled AndAlso Not IsAprilGiveup Then If IsAprilEnabled AndAlso Not IsAprilGiveup Then
ThemeUnlock(12, False, "隐藏主题 滑稽彩 已解锁!") ThemeUnlock(12, False, "隐藏主题 滑稽彩 已解锁!")
IsAprilGiveup = True IsAprilGiveup = True
Settings.Set("AprilDoneYear", Date.Now.Year)
FrmLaunchLeft.AprilScaleTrans.ScaleX = 1 FrmLaunchLeft.AprilScaleTrans.ScaleX = 1
FrmLaunchLeft.AprilScaleTrans.ScaleY = 1 FrmLaunchLeft.AprilScaleTrans.ScaleY = 1
FrmLaunchLeft.AprilPosTrans.X = 0 FrmLaunchLeft.AprilPosTrans.X = 0
@@ -624,7 +615,7 @@ Finish:
CurrentState = 0 CurrentState = 0
Else Else
If McInstanceSelected Is Nothing Then If McInstanceSelected Is Nothing Then
If Setup.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow Then If Settings.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow Then
CurrentState = 1 CurrentState = 1
Else Else
CurrentState = 2 CurrentState = 2
@@ -670,7 +661,7 @@ Finish:
End Select End Select
ExitRefresh: ExitRefresh:
'功能隐藏 '功能隐藏
FrmLaunchLeft.BtnVersion.Visibility = If(Not PageSetupUI.HiddenForceShow AndAlso Setup.Get("UiHiddenFunctionSelect"), Visibility.Collapsed, Visibility.Visible) FrmLaunchLeft.BtnVersion.Visibility = If(Not PageSetupUI.HiddenForceShow AndAlso Settings.Get("UiHiddenFunctionSelect"), Visibility.Collapsed, Visibility.Visible)
If CurrentState = 3 Then If CurrentState = 3 Then
FrmLaunchLeft.BtnMore.Visibility = FrmLaunchLeft.BtnVersion.Visibility FrmLaunchLeft.BtnMore.Visibility = FrmLaunchLeft.BtnVersion.Visibility
End If End If
@@ -678,7 +669,7 @@ ExitRefresh:
'取消按钮 '取消按钮
Private Sub BtnCancel_Click() Handles BtnCancel.Click Private Sub BtnCancel_Click() Handles BtnCancel.Click
If McLaunchLoaderReal IsNot Nothing Then If McLaunchLoaderReal IsNot Nothing Then
McLaunchLoaderReal.Abort() McLaunchLoaderReal.Interrupt()
McLaunchLog("已取消启动") McLaunchLog("已取消启动")
Try Try
If McLaunchWatcher IsNot Nothing Then If McLaunchWatcher IsNot Nothing Then
@@ -703,7 +694,7 @@ ExitRefresh:
''' </summary> ''' </summary>
Public Sub LaunchingRefresh() Public Sub LaunchingRefresh()
Try Try
If McLaunchLoaderReal.State = LoadState.Aborted Then Return If McLaunchLoaderReal.State = LoadState.Interrupted Then Return
'阶段状态获取 '阶段状态获取
Dim IsLaunched As Boolean = False '是否已经启动游戏,只是在等待窗口 Dim IsLaunched As Boolean = False '是否已经启动游戏,只是在等待窗口
Try Try
@@ -42,17 +42,17 @@ Public Class PageLaunchRight
End Sub End Sub
Private Sub RefreshReal() Private Sub RefreshReal()
Dim Content As String = Nothing, Url As String = Nothing Dim Content As String = Nothing, Url As String = Nothing
Select Case Setup.Get("UiCustomType") Select Case Settings.Get("UiCustomType")
Case 1 Case 1
'加载本地文件 '加载本地文件
Log("[Page] 主页自定义数据来源:本地文件") Log("[Page] 主页自定义数据来源:本地文件")
Content = ReadFile(Path & "PCL\Custom.xaml") 'ReadFile 会进行存在检测 Content = ReadFile(Path & "PCL\Custom.xaml") 'ReadFile 会进行存在检测
Case 2 Case 2
'联网下载 '联网下载
Url = Setup.Get("UiCustomNet") Url = Settings.Get("UiCustomNet")
Case 3 Case 3
'预设 '预设
Select Case Setup.Get("UiCustomPreset") Select Case Settings.Get("UiCustomPreset")
Case 0 Case 0
Log("[Page] 主页预设:你知道吗") Log("[Page] 主页预设:你知道吗")
Content = " Content = "
@@ -88,7 +88,7 @@ Public Class PageLaunchRight
Url = "https://pcl-bmcl.milu.ink/" Url = "https://pcl-bmcl.milu.ink/"
Case 7 Case 7
Log("[Page] 主页预设:主页市场") Log("[Page] 主页预设:主页市场")
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/JingHai-Lingyun/Custom.xaml" Url = "https://pclhomeplazaoss.lingyunawa.top:26994/p/Homepages/Homepage.Market/Custom.xaml"
Case 8 Case 8
Log("[Page] 主页预设:更新日志") Log("[Page] 主页预设:更新日志")
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Joker2184/UpdateHomepage.xaml" Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Joker2184/UpdateHomepage.xaml"
@@ -100,7 +100,7 @@ Public Class PageLaunchRight
Url = "https://files.mcimirror.top/PCL" Url = "https://files.mcimirror.top/PCL"
Case 11 Case 11
Log("[Page] 主页预设:杂志主页") Log("[Page] 主页预设:杂志主页")
Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Ext1nguisher/Custom.xaml" Url = "http://118.195.192.193:26995/d/magazine-homepage-pcl/Custom.xaml"
Case 12 Case 12
Log("[Page] 主页预设:PCL GitHub 仪表盘") Log("[Page] 主页预设:PCL GitHub 仪表盘")
Url = "https://ddf.pcl-community.org/Custom.xaml" Url = "https://ddf.pcl-community.org/Custom.xaml"
@@ -117,7 +117,7 @@ Public Class PageLaunchRight
End Select End Select
'联网下载 '联网下载
If Not String.IsNullOrWhiteSpace(Url) Then If Not String.IsNullOrWhiteSpace(Url) Then
If Url = Setup.Get("CacheSavedPageUrl") AndAlso File.Exists(PathTemp & "Cache\Custom.xaml") Then If Url = Settings.Get("CacheSavedPageUrl") AndAlso File.Exists(PathTemp & "Cache\Custom.xaml") Then
'缓存可用 '缓存可用
Log("[Page] 主页自定义数据来源:联网缓存文件") Log("[Page] 主页自定义数据来源:联网缓存文件")
Content = ReadFile(PathTemp & "Cache\Custom.xaml") Content = ReadFile(PathTemp & "Cache\Custom.xaml")
@@ -128,7 +128,7 @@ Public Class PageLaunchRight
Log("[Page] 主页自定义数据来源:联网全新下载") Log("[Page] 主页自定义数据来源:联网全新下载")
Hint("正在加载主页……") Hint("正在加载主页……")
RunInUiWait(Sub() LoadContent(Nothing)) '在加载结束前清空页面 RunInUiWait(Sub() LoadContent(Nothing)) '在加载结束前清空页面
Setup.Set("CacheSavedPageVersion", "") Settings.Set("CacheSavedPageVersion", "")
OnlineLoader.Start(New Tuple(Of String, Boolean)(Url, True)) '下载完成后将会再次触发更新 OnlineLoader.Start(New Tuple(Of String, Boolean)(Url, True)) '下载完成后将会再次触发更新
Return Return
End If End If
@@ -152,7 +152,7 @@ Public Class PageLaunchRight
VersionAddress = Address.Replace(".xaml", ".xaml.ini") VersionAddress = Address.Replace(".xaml", ".xaml.ini")
Else Else
VersionAddress = Address.BeforeFirst("?") VersionAddress = Address.BeforeFirst("?")
If Not VersionAddress.EndsWith("/") Then VersionAddress += "/" If Not VersionAddress.EndsWithF("/") Then VersionAddress += "/"
VersionAddress += "version" VersionAddress += "version"
If Address.Contains("?") Then VersionAddress += "?" & Address.AfterFirst("?") If Address.Contains("?") Then VersionAddress += "?" & Address.AfterFirst("?")
End If End If
@@ -161,7 +161,7 @@ Public Class PageLaunchRight
Try Try
Version = NetRequestByClientRetry(VersionAddress) Version = NetRequestByClientRetry(VersionAddress)
If Version.Length > 1000 Then Throw New Exception($"获取的主页版本过长({Version.Length} 字符)") If Version.Length > 1000 Then Throw New Exception($"获取的主页版本过长({Version.Length} 字符)")
Dim CurrentVersion As String = Setup.Get("CacheSavedPageVersion") Dim CurrentVersion As String = Settings.Get("CacheSavedPageVersion")
If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then
Log($"[Page] 当前缓存的主页已为最新,当前版本:{Version},检查源:{VersionAddress}") Log($"[Page] 当前缓存的主页已为最新,当前版本:{Version},检查源:{VersionAddress}")
Return Return
@@ -174,8 +174,8 @@ Public Class PageLaunchRight
'实际下载 '实际下载
Dim FileContent As String = NetRequestByClientRetry(Address) Dim FileContent As String = NetRequestByClientRetry(Address)
Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}") Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}")
Setup.Set("CacheSavedPageUrl", Address) Settings.Set("CacheSavedPageUrl", Address)
Setup.Set("CacheSavedPageVersion", Version) Settings.Set("CacheSavedPageVersion", Version)
WriteFile(PathTemp & "Cache\Custom.xaml", FileContent) WriteFile(PathTemp & "Cache\Custom.xaml", FileContent)
'若内容变更则要求刷新 '若内容变更则要求刷新
If LoadedContentHash <> FileContent.GetHashCode() AndAlso ShouldRefresh Then Refresh() If LoadedContentHash <> FileContent.GetHashCode() AndAlso ShouldRefresh Then Refresh()
@@ -206,8 +206,8 @@ Public Class PageLaunchRight
Private Sub ClearCache() Private Sub ClearCache()
LoadedContentHash = -1 LoadedContentHash = -1
OnlineLoader.Input = New Tuple(Of String, Boolean)("", True) OnlineLoader.Input = New Tuple(Of String, Boolean)("", True)
Setup.Set("CacheSavedPageUrl", "") Settings.Set("CacheSavedPageUrl", "")
Setup.Set("CacheSavedPageVersion", "") Settings.Set("CacheSavedPageVersion", "")
Log("[Page] 已清空主页缓存") Log("[Page] 已清空主页缓存")
End Sub End Sub
@@ -251,7 +251,7 @@ Public Class PageLaunchRight
''' 加载主页失败时调用。 ''' 加载主页失败时调用。
''' </summary> ''' </summary>
Private Sub OnLoadContentFailed(ex As Exception) Private Sub OnLoadContentFailed(ex As Exception)
If ModeDebug OrElse Setup.Get("UiCustomType") = 1 Then If ModeDebug OrElse Settings.Get("UiCustomType") = 1 Then
Log(ex, "加载主页失败") Log(ex, "加载主页失败")
If MyMsgBox(If(TypeOf ex Is UnauthorizedAccessException, ex.Message, $"主页内容编写有误,请根据下列错误信息进行检查:{vbCrLf}{ex.GetBrief}"), If MyMsgBox(If(TypeOf ex Is UnauthorizedAccessException, ex.Message, $"主页内容编写有误,请根据下列错误信息进行检查:{vbCrLf}{ex.GetBrief}"),
"加载主页失败", "重试", "取消") = 1 Then ForceRefresh() "加载主页失败", "重试", "取消") = 1 Then ForceRefresh()
@@ -5,20 +5,20 @@
''' </summary> ''' </summary>
Public Sub Reload(KeepInput As Boolean) Public Sub Reload(KeepInput As Boolean)
'记住密码 '记住密码
CheckRemember.Checked = Setup.Get("LoginRemember") CheckRemember.Checked = Settings.Get("LoginRemember")
If KeepInput AndAlso Not IsFirstLoad Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西 If KeepInput AndAlso Not IsFirstLoad Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西
'保留输入,只刷新下拉框列表 '保留输入,只刷新下拉框列表
Dim Input As String = ComboName.Text Dim Input As String = ComboName.Text
ComboName.ItemsSource = If(Setup.Get("LoginAuthEmail") = "", Nothing, Setup.Get("LoginAuthEmail").ToString.Split("¨")) ComboName.ItemsSource = If(Settings.Get("LoginAuthEmail") = "", Nothing, Settings.Get("LoginAuthEmail").ToString.Split("¨"))
ComboName.Text = Input ComboName.Text = Input
Else Else
'不保留输入,刷新列表后自动选择第一项 '不保留输入,刷新列表后自动选择第一项
If Setup.Get("LoginAuthEmail") = "" Then If Settings.Get("LoginAuthEmail") = "" Then
ComboName.ItemsSource = Nothing ComboName.ItemsSource = Nothing
Else Else
ComboName.ItemsSource = Setup.Get("LoginAuthEmail").ToString.Split("¨") ComboName.ItemsSource = Settings.Get("LoginAuthEmail").ToString.Split("¨")
ComboName.Text = Setup.Get("LoginAuthEmail").ToString.BeforeFirst("¨") ComboName.Text = Settings.Get("LoginAuthEmail").ToString.BeforeFirst("¨")
If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginAuthPass").ToString.BeforeFirst("¨").Trim If Settings.Get("LoginRemember") Then TextPass.Password = Settings.Get("LoginAuthPass").ToString.BeforeFirst("¨").Trim
End If End If
End If End If
IsFirstLoad = False IsFirstLoad = False
@@ -27,7 +27,7 @@
''' 获取当前页面的登录信息。 ''' 获取当前页面的登录信息。
''' </summary> ''' </summary>
Public Shared Function GetLoginData() As McLoginServer Public Shared Function GetLoginData() As McLoginServer
Dim Server As String = If(IsNothing(McInstanceSelected), Setup.Get("CacheAuthServerServer"), Setup.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/authserver" Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get("CacheAuthServerServer"), Settings.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/authserver"
If FrmLoginAuth Is Nothing Then If FrmLoginAuth Is Nothing Then
Return New McLoginServer(McLoginType.Auth) With {.Token = "Auth", .BaseUrl = Server, .UserName = "", .Password = "", .Description = "Authlib-Injector", .Type = McLoginType.Auth} Return New McLoginServer(McLoginType.Auth) With {.Token = "Auth", .BaseUrl = Server, .UserName = "", .Password = "", .Description = "Authlib-Injector", .Type = McLoginType.Auth}
Else Else
@@ -49,20 +49,20 @@
'保存输入信息 '保存输入信息
Private Sub ComboName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged Private Sub ComboName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged
If sender.Text = "" Then TextPass.Password = "" If sender.Text = "" Then TextPass.Password = ""
If AniControlEnabled = 0 Then Setup.Set("CacheAuthAccess", "") '迫使其不进行 Validate If AniControlEnabled = 0 Then Settings.Set("CacheAuthAccess", "") '迫使其不进行 Validate
End Sub End Sub
Private Sub TextPass_PasswordChanged(sender As Object, e As RoutedEventArgs) Handles TextPass.PasswordChanged Private Sub TextPass_PasswordChanged(sender As Object, e As RoutedEventArgs) Handles TextPass.PasswordChanged
If AniControlEnabled = 0 Then Setup.Set("CacheAuthAccess", "") If AniControlEnabled = 0 Then Settings.Set("CacheAuthAccess", "")
End Sub End Sub
Private Sub ComboName_SelectionChanged(sender As MyComboBox, e As SelectionChangedEventArgs) Handles ComboName.SelectionChanged Private Sub ComboName_SelectionChanged(sender As MyComboBox, e As SelectionChangedEventArgs) Handles ComboName.SelectionChanged
If sender.SelectedIndex = -1 OrElse Not Setup.Get("LoginRemember") Then If sender.SelectedIndex = -1 OrElse Not Settings.Get("LoginRemember") Then
TextPass.Password = "" TextPass.Password = ""
Else Else
TextPass.Password = Setup.Get("LoginAuthPass").ToString.Split("¨")(sender.SelectedIndex).Trim TextPass.Password = Settings.Get("LoginAuthPass").ToString.Split("¨")(sender.SelectedIndex).Trim
End If End If
End Sub End Sub
Private Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckRemember.Change Private Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckRemember.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Checked)
End Sub End Sub
'链接处理 '链接处理
@@ -71,15 +71,15 @@
End Sub End Sub
Private Sub Btn_Click(sender As Object, e As EventArgs) Handles BtnLink.Click Private Sub Btn_Click(sender As Object, e As EventArgs) Handles BtnLink.Click
If BtnLink.Content = "注册账号" Then If BtnLink.Content = "注册账号" Then
OpenWebsite(If(McInstanceSelected IsNot Nothing, Setup.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Setup.Get("CacheAuthServerRegister"))) OpenWebsite(If(McInstanceSelected IsNot Nothing, Settings.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get("CacheAuthServerRegister")))
Else Else
Dim Website As String = If(McInstanceSelected IsNot Nothing, Setup.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Setup.Get("CacheAuthServerRegister")) Dim Website As String = If(McInstanceSelected IsNot Nothing, Settings.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get("CacheAuthServerRegister"))
OpenWebsite(Website.Replace("/auth/register", "/auth/forgot")) OpenWebsite(Website.Replace("/auth/register", "/auth/forgot"))
End If End If
End Sub End Sub
'切换注册按钮可见性 '切换注册按钮可见性
Private Sub ReloadRegisterButton() Handles Me.Loaded Private Sub ReloadRegisterButton() Handles Me.Loaded
Dim Address As String = If(McInstanceSelected IsNot Nothing, Setup.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Setup.Get("CacheAuthServerRegister")) Dim Address As String = If(McInstanceSelected IsNot Nothing, Settings.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get("CacheAuthServerRegister"))
BtnLink.Visibility = If(String.IsNullOrEmpty(New ValidateHttp().Validate(Address)), Visibility.Visible, Visibility.Collapsed) BtnLink.Visibility = If(String.IsNullOrEmpty(New ValidateHttp().Validate(Address)), Visibility.Visible, Visibility.Collapsed)
End Sub End Sub
@@ -12,17 +12,17 @@
''' 刷新页面显示的所有信息。 ''' 刷新页面显示的所有信息。
''' </summary> ''' </summary>
Public Sub Reload(KeepInput As Boolean) Public Sub Reload(KeepInput As Boolean)
TextName.Text = Setup.Get("CacheAuthName") TextName.Text = Settings.Get("CacheAuthName")
TextEmail.Text = Setup.Get("CacheAuthUsername") TextEmail.Text = Settings.Get("CacheAuthUsername")
TextEmail.Visibility = If(Setup.Get("UiLauncherEmail"), Visibility.Collapsed, Visibility.Visible) TextEmail.Visibility = If(Settings.Get("UiLauncherEmail"), Visibility.Collapsed, Visibility.Visible)
PageLoginLegacy_Loaded() PageLoginLegacy_Loaded()
End Sub End Sub
''' <summary> ''' <summary>
''' 获取当前页面的登录信息。 ''' 获取当前页面的登录信息。
''' </summary> ''' </summary>
Public Shared Function GetLoginData() As McLoginServer Public Shared Function GetLoginData() As McLoginServer
Dim Server As String = If(IsNothing(McInstanceSelected), Setup.Get("CacheAuthServerServer"), Setup.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/authserver" Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get("CacheAuthServerServer"), Settings.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/authserver"
Return New McLoginServer(McLoginType.Auth) With {.Token = "Auth", .BaseUrl = Server, .UserName = Setup.Get("CacheAuthUsername"), .Password = Setup.Get("CacheAuthPass"), .Description = "Authlib-Injector", .Type = McLoginType.Auth} Return New McLoginServer(McLoginType.Auth) With {.Token = "Auth", .BaseUrl = Server, .UserName = Settings.Get("CacheAuthUsername"), .Password = Settings.Get("CacheAuthPass"), .Description = "Authlib-Injector", .Type = McLoginType.Auth}
End Function End Function
Private Sub PageLoginAuthSkin_MouseEnter(sender As Object, e As MouseEventArgs) Handles PanData.MouseEnter Private Sub PageLoginAuthSkin_MouseEnter(sender As Object, e As MouseEventArgs) Handles PanData.MouseEnter
@@ -47,7 +47,7 @@
Private Sub BtnEdit_Click(sender As Object, e As EventArgs) Handles BtnEdit.Click Private Sub BtnEdit_Click(sender As Object, e As EventArgs) Handles BtnEdit.Click
If McLoginLoader.State = LoadState.Loading Then If McLoginLoader.State = LoadState.Loading Then
Log("[Launch] 要求更换角色,但登录加载器繁忙", LogLevel.Debug) Log("[Launch] 要求更换角色,但登录加载器繁忙", LogLevel.Debug)
If CType(McLoginLoader.Input, McLoginServer).ForceReselectProfile Then If TypeOf McLoginLoader.Input Is McLoginServer AndAlso CType(McLoginLoader.Input, McLoginServer).ForceReselectProfile Then
Hint("正在尝试更换,请稍候!") Hint("正在尝试更换,请稍候!")
Else Else
Hint("正在登录中,请稍后再更换角色!", HintType.Red) Hint("正在登录中,请稍后再更换角色!", HintType.Red)
@@ -55,8 +55,8 @@
Return Return
End If End If
Hint("正在尝试更换,请稍候!") Hint("正在尝试更换,请稍候!")
Setup.Set("CacheAuthUuid", "") '清空选择缓存 Settings.Set("CacheAuthUuid", "") '清空选择缓存
Setup.Set("CacheAuthName", "") Settings.Set("CacheAuthName", "")
RunInThread( RunInThread(
Sub() Sub()
Try Try
@@ -70,15 +70,15 @@
End Sub) End Sub)
End Sub End Sub
Public Shared Sub ExitLogin() Handles BtnExit.Click Public Shared Sub ExitLogin() Handles BtnExit.Click
Setup.Set("CacheAuthAccess", "") Settings.Set("CacheAuthAccess", "")
Setup.Set("CacheAuthUuid", "") Settings.Set("CacheAuthUuid", "")
Setup.Set("CacheAuthName", "") Settings.Set("CacheAuthName", "")
McLoginAuthLoader.Input = Nothing '防止因为输入的用户名密码相同,直接使用了上次登录的加载器结果 McLoginAuthLoader.Input = Nothing '防止因为输入的用户名密码相同,直接使用了上次登录的加载器结果
FrmLaunchLeft.RefreshPage(False, True) FrmLaunchLeft.RefreshPage(False, True)
End Sub End Sub
Private Sub Skin_Click(sender As Object, e As MouseButtonEventArgs) Handles Skin.Click Private Sub Skin_Click(sender As Object, e As MouseButtonEventArgs) Handles Skin.Click
Dim Address As String = If(McInstanceSelected IsNot Nothing, Setup.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Setup.Get("CacheAuthServerRegister")) Dim Address As String = If(McInstanceSelected IsNot Nothing, Settings.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get("CacheAuthServerRegister"))
If String.IsNullOrEmpty(New ValidateHttp().Validate(Address)) Then OpenWebsite(Address.Replace("/auth/register", "/user/closet")) If String.IsNullOrEmpty(New ValidateHttp().Validate(Address)) Then OpenWebsite(Address.Replace("/auth/register", "/user/closet"))
End Sub End Sub
@@ -18,15 +18,15 @@ Public Class PageLoginLegacy
If KeepInput AndAlso IsReloaded Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西 If KeepInput AndAlso IsReloaded Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西
'保留输入,只刷新下拉框列表 '保留输入,只刷新下拉框列表
Dim Input As String = ComboName.Text.Trim Dim Input As String = ComboName.Text.Trim
ComboName.ItemsSource = If(Setup.Get("LoginLegacyName") = "", Nothing, Setup.Get("LoginLegacyName").ToString.Split("¨")) ComboName.ItemsSource = If(Settings.Get("LoginLegacyName") = "", Nothing, Settings.Get("LoginLegacyName").ToString.Split("¨"))
ComboName.Text = Input ComboName.Text = Input
Else Else
'不保留输入,刷新列表后自动选择第一项 '不保留输入,刷新列表后自动选择第一项
If Setup.Get("LoginLegacyName") = "" Then If Settings.Get("LoginLegacyName") = "" Then
ComboName.ItemsSource = Nothing ComboName.ItemsSource = Nothing
Else Else
ComboName.ItemsSource = Setup.Get("LoginLegacyName").ToString.Split("¨") ComboName.ItemsSource = Settings.Get("LoginLegacyName").ToString.Split("¨")
ComboName.Text = Setup.Get("LoginLegacyName").ToString.BeforeFirst("¨").Trim ComboName.Text = Settings.Get("LoginLegacyName").ToString.BeforeFirst("¨").Trim
End If End If
End If End If
IsReloaded = True IsReloaded = True
@@ -36,7 +36,7 @@ Public Class PageLoginLegacy
''' </summary> ''' </summary>
Public Shared Function GetLoginData() As McLoginData Public Shared Function GetLoginData() As McLoginData
Dim UserName As String = If(FrmLoginLegacy Is Nothing, "", FrmLoginLegacy.ComboName.Text.Replace("¨", "").Trim) Dim UserName As String = If(FrmLoginLegacy Is Nothing, "", FrmLoginLegacy.ComboName.Text.Replace("¨", "").Trim)
Return New McLoginLegacy With {.UserName = UserName, .SkinType = Setup.Get("LaunchSkinType"), .SkinName = Setup.Get("LaunchSkinID")} Return New McLoginLegacy With {.UserName = UserName, .SkinType = Settings.Get("LaunchSkinType"), .SkinName = Settings.Get("LaunchSkinID")}
End Function End Function
''' <summary> ''' <summary>
''' 当前页面的登录信息是否有效。 ''' 当前页面的登录信息是否有效。
@@ -62,12 +62,12 @@ Public Class PageLoginLegacy
End If End If
End Sub End Sub
Private Sub ComboLegacy_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged Private Sub ComboLegacy_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged
If Setup.Get("LaunchSkinType") = 0 Then PageLaunchLeft.SkinLegacy.Start(IsForceRestart:=True) If Settings.Get("LaunchSkinType") = 0 Then PageLaunchLeft.SkinLegacy.Start(IsForceRestart:=True)
HintChinese.Visibility = If(RegexCheck(ComboName.Text, "^[0-9A-Za-z_]*$"), Visibility.Collapsed, Visibility.Visible) HintChinese.Visibility = If(RegexCheck(ComboName.Text, "^[0-9A-Za-z_]*$"), Visibility.Collapsed, Visibility.Visible)
RunInUi(Sub() PanMain.InvalidateMeasure(), True) '由于 WPF 的 Bug,它不一定会自动更新 HintChinese 的大小(#6627) RunInUi(Sub() PanMain.InvalidateMeasure(), True) '由于 WPF 的 Bug,它不一定会自动更新 HintChinese 的大小(#6627)
End Sub End Sub
Private Sub Skin_Click() Handles Skin.Click Private Sub Skin_Click() Handles Skin.Click
If (Setup.Get("UiHiddenPageSetup") OrElse Setup.Get("UiHiddenSetupLaunch")) AndAlso Not PageSetupUI.HiddenForceShow Then If (Settings.Get("UiHiddenPageSetup") OrElse Settings.Get("UiHiddenSetupLaunch")) AndAlso Not PageSetupUI.HiddenForceShow Then
Hint("启动设置已被禁用!", HintType.Red) Hint("启动设置已被禁用!", HintType.Red)
Else Else
FrmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupLaunch) '切换到皮肤设置页面 FrmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupLaunch) '切换到皮肤设置页面
@@ -9,7 +9,7 @@
ComboAccounts.Items.Clear() ComboAccounts.Items.Clear()
ComboAccounts.Items.Add(New MyComboBoxItem With {.Content = "添加新账号"}) ComboAccounts.Items.Add(New MyComboBoxItem With {.Content = "添加新账号"})
Try Try
Dim MsJson As JObject = GetJson(Setup.Get("LoginMsJson")) Dim MsJson As JObject = GetJson(Settings.Get("LoginMsJson"))
For Each Account In MsJson For Each Account In MsJson
Dim Item As MyListItem = CType(FindResource("ComboBoxItemTemplateWithDelete"), DataTemplate).LoadContent() Dim Item As MyListItem = CType(FindResource("ComboBoxItemTemplateWithDelete"), DataTemplate).LoadContent()
Item.Tag = Account.Value.ToString Item.Tag = Account.Value.ToString
@@ -18,8 +18,8 @@
ComboAccounts.Items.Add(Item) ComboAccounts.Items.Add(Item)
Next Next
Catch ex As Exception Catch ex As Exception
Log(ex, $"微软登录信息出错,登录信息已被重置({Setup.Get("LoginMsJson")})", LogLevel.Hint) Log(ex, $"微软登录信息出错,登录信息已被重置({Settings.Get("LoginMsJson")})", LogLevel.Hint)
Setup.Set("LoginMsJson", "{}") Settings.Set("LoginMsJson", "{}")
End Try End Try
'如果不保留输入,刷新列表后自动选择第一项 '如果不保留输入,刷新列表后自动选择第一项
ComboAccounts.SelectedIndex = If(KeepInput, Math.Max(0, IndexBefore), 0) ComboAccounts.SelectedIndex = If(KeepInput, Math.Max(0, IndexBefore), 0)
@@ -37,7 +37,7 @@
''' 获取当前页面的登录信息。 ''' 获取当前页面的登录信息。
''' </summary> ''' </summary>
Public Shared Function GetLoginData() As McLoginMs Public Shared Function GetLoginData() As McLoginMs
If FrmLoginMs Is Nothing Then Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsV2OAuthRefresh"), .UserName = Setup.Get("CacheMsV2Name")} If FrmLoginMs Is Nothing Then Return New McLoginMs With {.OAuthRefreshToken = Settings.Get("CacheMsV2OAuthRefresh"), .UserName = Settings.Get("CacheMsV2Name")}
Dim Result As McLoginMs = Nothing Dim Result As McLoginMs = Nothing
RunInUiWait( RunInUiWait(
Sub() Sub()
@@ -78,7 +78,7 @@
Loop Loop
If McLoginMsLoader.State = LoadState.Finished Then If McLoginMsLoader.State = LoadState.Finished Then
RunInUi(Sub() FrmLaunchLeft.RefreshPage(False, True)) RunInUi(Sub() FrmLaunchLeft.RefreshPage(False, True))
ElseIf McLoginMsLoader.State = LoadState.Aborted Then ElseIf McLoginMsLoader.State = LoadState.Interrupted Then
Throw New ThreadInterruptedException Throw New ThreadInterruptedException
ElseIf McLoginMsLoader.Error Is Nothing Then ElseIf McLoginMsLoader.Error Is Nothing Then
Throw New Exception("未知错误!") Throw New Exception("未知错误!")
@@ -89,7 +89,7 @@
Hint("已取消登录!") Hint("已取消登录!")
Catch ex As Exception Catch ex As Exception
If ex.Message = "$$" Then If ex.Message = "$$" Then
ElseIf ex.Message.StartsWith("$") Then ElseIf ex.Message.StartsWithF("$") Then
Hint(ex.Message.TrimStart("$"), HintType.Red) Hint(ex.Message.TrimStart("$"), HintType.Red)
ElseIf TypeOf ex Is Security.Authentication.AuthenticationException AndAlso ex.Message.ContainsF("SSL/TLS") Then ElseIf TypeOf ex Is Security.Authentication.AuthenticationException AndAlso ex.Message.ContainsF("SSL/TLS") Then
Log(ex, "正版登录验证失败,请考虑在 [设置 → 其他] 中关闭 [在正版登录时验证 SSL 证书],然后再试。" & vbCrLf & vbCrLf & "原始错误信息:", LogLevel.Msgbox) Log(ex, "正版登录验证失败,请考虑在 [设置 → 其他] 中关闭 [在正版登录时验证 SSL 证书],然后再试。" & vbCrLf & vbCrLf & "原始错误信息:", LogLevel.Msgbox)
@@ -12,7 +12,7 @@
''' 刷新页面显示的所有信息。 ''' 刷新页面显示的所有信息。
''' </summary> ''' </summary>
Public Sub Reload(KeepInput As Boolean) Public Sub Reload(KeepInput As Boolean)
TextName.Text = Setup.Get("CacheMsV2Name") TextName.Text = Settings.Get("CacheMsV2Name")
'皮肤在 Loaded 加载 '皮肤在 Loaded 加载
End Sub End Sub
''' <summary> ''' <summary>
@@ -20,9 +20,9 @@
''' </summary> ''' </summary>
Public Shared Function GetLoginData() As McLoginMs Public Shared Function GetLoginData() As McLoginMs
If McLoginMsLoader.State = LoadState.Finished Then If McLoginMsLoader.State = LoadState.Finished Then
Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsV2OAuthRefresh"), .UserName = Setup.Get("CacheMsV2Name"), .AccessToken = Setup.Get("CacheMsV2Access"), .Uuid = Setup.Get("CacheMsV2Uuid"), .ProfileJson = Setup.Get("CacheMsV2ProfileJson")} Return New McLoginMs With {.OAuthRefreshToken = Settings.Get("CacheMsV2OAuthRefresh"), .UserName = Settings.Get("CacheMsV2Name"), .AccessToken = Settings.Get("CacheMsV2Access"), .Uuid = Settings.Get("CacheMsV2Uuid"), .ProfileJson = Settings.Get("CacheMsV2ProfileJson")}
Else Else
Return New McLoginMs With {.OAuthRefreshToken = Setup.Get("CacheMsV2OAuthRefresh"), .UserName = Setup.Get("CacheMsV2Name")} Return New McLoginMs With {.OAuthRefreshToken = Settings.Get("CacheMsV2OAuthRefresh"), .UserName = Settings.Get("CacheMsV2Name")}
End If End If
End Function End Function
@@ -50,12 +50,12 @@
'退出登录 '退出登录
Private Sub BtnExit_Click() Handles BtnExit.Click Private Sub BtnExit_Click() Handles BtnExit.Click
Setup.Set("CacheMsV2OAuthRefresh", "") Settings.Set("CacheMsV2OAuthRefresh", "")
Setup.Set("CacheMsV2Access", "") Settings.Set("CacheMsV2Access", "")
Setup.Set("CacheMsV2ProfileJson", "") Settings.Set("CacheMsV2ProfileJson", "")
Setup.Set("CacheMsV2Uuid", "") Settings.Set("CacheMsV2Uuid", "")
Setup.Set("CacheMsV2Name", "") Settings.Set("CacheMsV2Name", "")
McLoginMsLoader.Abort() McLoginMsLoader.Interrupt()
FrmLaunchLeft.RefreshPage(False, True) FrmLaunchLeft.RefreshPage(False, True)
End Sub End Sub
@@ -85,51 +85,56 @@
Hint("正在更改皮肤……") Hint("正在更改皮肤……")
IsChanging = True IsChanging = True
'开始实际获取 '开始实际获取
RunInNewThread( RunInNewThread(Sub() EditSkin(SkinInfo), "Ms Skin Upload")
Sub() End Sub
Try Private Sub EditSkin(SkinInfo As McSkinInfo)
Retry: Retry:
Do While McLoginMsLoader.State = LoadState.Loading '等待登录结束 Try
Thread.Sleep(10) Do While McLoginMsLoader.State = LoadState.Loading '等待登录结束
Loop Thread.Sleep(10)
If McLoginMsLoader.State = LoadState.Failed Then Throw New Exception("登录失败", McLoginMsLoader.Error) Loop
Dim AccessToken As String = Setup.Get("CacheMsV2Access") If McLoginMsLoader.State = LoadState.Failed Then Throw New Exception("登录失败", McLoginMsLoader.Error)
Dim Uuid As String = Setup.Get("CacheMsV2Uuid") Dim AccessToken As String = Settings.Get("CacheMsV2Access")
Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/skins", HttpMethod.Post, Dim Uuid As String = Settings.Get("CacheMsV2Uuid")
Content:=New Net.Http.MultipartFormDataContent From { Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/skins", HttpMethod.Post,
{New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"}, Content:=New Net.Http.MultipartFormDataContent From {
{New Net.Http.ByteArrayContent(ReadFileBytes(SkinInfo.LocalFile)), "file", GetFileNameFromPath(SkinInfo.LocalFile)} {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 Headers:={{"Authorization", "Bearer " & AccessToken}, {"Accept", "*/*"}, {"User-Agent", "MojangSharp/0.1"}})
Hint("正在登录,将在登录完成后继续更改皮肤……") If Result.Contains("request requires user authentication") Then
McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True) Hint("正在重新登录,将在登录后自动更改皮肤……")
GoTo Retry McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
ElseIf Result.Contains("""error""") Then GoTo Retry
Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Red) ElseIf Result.Contains("""error""") Then
Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Red)
Return
End If
'获取新皮肤地址
Log("[Skin] 皮肤修改返回值:" & vbCrLf & Result)
Dim ResultJson As JObject = GetJson(Result)
If ResultJson.ContainsKey("errorMessage") Then Throw New Exception(ResultJson("errorMessage").ToString) '#5309
For Each Skin As JObject In ResultJson("skins")
If Skin("state").ToString = "ACTIVE" Then
MySkin.ReloadCache(Skin("url"))
Return Return
End If End If
'获取新皮肤地址 Next
Log("[Skin] 皮肤修改返回值:" & vbCrLf & Result) Throw New Exception("未知错误(" & Result & ")")
Dim ResultJson As JObject = GetJson(Result) Catch ex As Exception
If ResultJson.ContainsKey("errorMessage") Then Throw New Exception(ResultJson("errorMessage").ToString) '#5309 If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then
For Each Skin As JObject In ResultJson("skins") Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red)
If Skin("state").ToString = "ACTIVE" Then ElseIf TypeOf ex Is ResponsedWebException AndAlso CType(ex, ResponsedWebException).StatusCode = HttpStatusCode.Unauthorized Then
MySkin.ReloadCache(Skin("url")) Log(ex, "更改皮肤时遭遇 401 错误", LogLevel.Developer)
Return Hint("正在重新登录,将在登录后自动更改皮肤……")
End If McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True)
Next GoTo Retry
Throw New Exception("未知错误(" & Result & ")") Else
Catch ex As Exception Log(ex, "更改皮肤失败", LogLevel.Hint)
If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then End If
Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red) Finally
Else IsChanging = False
Log(ex, "更改皮肤失败", LogLevel.Hint) End Try
End If
Finally
IsChanging = False
End Try
End Sub, "Ms Skin Upload")
End Sub End Sub
'保存皮肤 '保存皮肤
@@ -5,20 +5,20 @@
''' </summary> ''' </summary>
Public Sub Reload(KeepInput As Boolean) Public Sub Reload(KeepInput As Boolean)
'记住密码 '记住密码
CheckRemember.Checked = Setup.Get("LoginRemember") CheckRemember.Checked = Settings.Get("LoginRemember")
If KeepInput AndAlso Not IsFirstLoad Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西 If KeepInput AndAlso Not IsFirstLoad Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西
'保留输入,只刷新下拉框列表 '保留输入,只刷新下拉框列表
Dim Input As String = ComboName.Text Dim Input As String = ComboName.Text
ComboName.ItemsSource = If(Setup.Get("LoginNideEmail") = "", Nothing, Setup.Get("LoginNideEmail").ToString.Split("¨")) ComboName.ItemsSource = If(Settings.Get("LoginNideEmail") = "", Nothing, Settings.Get("LoginNideEmail").ToString.Split("¨"))
ComboName.Text = Input ComboName.Text = Input
Else Else
'不保留输入,刷新列表后自动选择第一项 '不保留输入,刷新列表后自动选择第一项
If Setup.Get("LoginNideEmail") = "" Then If Settings.Get("LoginNideEmail") = "" Then
ComboName.ItemsSource = Nothing ComboName.ItemsSource = Nothing
Else Else
ComboName.ItemsSource = Setup.Get("LoginNideEmail").ToString.Split("¨") ComboName.ItemsSource = Settings.Get("LoginNideEmail").ToString.Split("¨")
ComboName.Text = Setup.Get("LoginNideEmail").ToString.BeforeFirst("¨") ComboName.Text = Settings.Get("LoginNideEmail").ToString.BeforeFirst("¨")
If Setup.Get("LoginRemember") Then TextPass.Password = Setup.Get("LoginNidePass").ToString.BeforeFirst("¨").Trim If Settings.Get("LoginRemember") Then TextPass.Password = Settings.Get("LoginNidePass").ToString.BeforeFirst("¨").Trim
End If End If
End If End If
IsFirstLoad = False IsFirstLoad = False
@@ -27,7 +27,7 @@
''' 获取当前页面的登录信息。 ''' 获取当前页面的登录信息。
''' </summary> ''' </summary>
Public Shared Function GetLoginData() As McLoginServer Public Shared Function GetLoginData() As McLoginServer
Dim Server As String = If(IsNothing(McInstanceSelected), Setup.Get("CacheNideServer"), Setup.Get("VersionServerNide", Instance:=McInstanceSelected)) Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get("CacheNideServer"), Settings.Get("VersionServerNide", Instance:=McInstanceSelected))
If FrmLoginNide Is Nothing Then If FrmLoginNide Is Nothing Then
Return New McLoginServer(McLoginType.Nide) With {.Token = "Nide", .UserName = "", .Password = "", .Description = "统一通行证", .Type = McLoginType.Nide, .BaseUrl = "https://auth.mc-user.com:233/" & Server & "/authserver"} Return New McLoginServer(McLoginType.Nide) With {.Token = "Nide", .UserName = "", .Password = "", .Description = "统一通行证", .Type = McLoginType.Nide, .BaseUrl = "https://auth.mc-user.com:233/" & Server & "/authserver"}
Else Else
@@ -49,20 +49,20 @@
'保存输入信息 '保存输入信息
Private Sub ComboName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged Private Sub ComboName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged
If sender.Text = "" Then TextPass.Password = "" If sender.Text = "" Then TextPass.Password = ""
If AniControlEnabled = 0 Then Setup.Set("CacheNideAccess", "") '迫使其不进行 Validate If AniControlEnabled = 0 Then Settings.Set("CacheNideAccess", "") '迫使其不进行 Validate
End Sub End Sub
Private Sub TextPass_PasswordChanged(sender As Object, e As RoutedEventArgs) Handles TextPass.PasswordChanged Private Sub TextPass_PasswordChanged(sender As Object, e As RoutedEventArgs) Handles TextPass.PasswordChanged
If AniControlEnabled = 0 Then Setup.Set("CacheNideAccess", "") If AniControlEnabled = 0 Then Settings.Set("CacheNideAccess", "")
End Sub End Sub
Private Sub ComboName_SelectionChanged(sender As MyComboBox, e As SelectionChangedEventArgs) Handles ComboName.SelectionChanged Private Sub ComboName_SelectionChanged(sender As MyComboBox, e As SelectionChangedEventArgs) Handles ComboName.SelectionChanged
If sender.SelectedIndex = -1 OrElse Not Setup.Get("LoginRemember") Then If sender.SelectedIndex = -1 OrElse Not Settings.Get("LoginRemember") Then
TextPass.Password = "" TextPass.Password = ""
Else Else
TextPass.Password = Setup.Get("LoginNidePass").ToString.Split("¨")(sender.SelectedIndex).Trim TextPass.Password = Settings.Get("LoginNidePass").ToString.Split("¨")(sender.SelectedIndex).Trim
End If End If
End Sub End Sub
Private Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckRemember.Change Private Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckRemember.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Checked)
End Sub End Sub
'链接处理 '链接处理
@@ -71,7 +71,7 @@
End Sub End Sub
Private Sub Btn_Click(sender As Object, e As EventArgs) Handles BtnLink.Click Private Sub Btn_Click(sender As Object, e As EventArgs) Handles BtnLink.Click
If BtnLink.Content = "注册账号" Then If BtnLink.Content = "注册账号" Then
OpenWebsite("https://login.mc-user.com:233/" & Setup.Get("VersionServerNide", Instance:=McInstanceSelected) & "/register") OpenWebsite("https://login.mc-user.com:233/" & Settings.Get("VersionServerNide", Instance:=McInstanceSelected) & "/register")
Else Else
OpenWebsite("https://login.mc-user.com:233/account/login") OpenWebsite("https://login.mc-user.com:233/account/login")
End If End If
@@ -12,17 +12,17 @@
''' 刷新页面显示的所有信息。 ''' 刷新页面显示的所有信息。
''' </summary> ''' </summary>
Public Sub Reload(KeepInput As Boolean) Public Sub Reload(KeepInput As Boolean)
TextName.Text = Setup.Get("CacheNideName") TextName.Text = Settings.Get("CacheNideName")
TextEmail.Text = Setup.Get("CacheNideUsername") TextEmail.Text = Settings.Get("CacheNideUsername")
TextEmail.Visibility = If(Setup.Get("UiLauncherEmail"), Visibility.Collapsed, Visibility.Visible) TextEmail.Visibility = If(Settings.Get("UiLauncherEmail"), Visibility.Collapsed, Visibility.Visible)
'皮肤在 Loaded 加载 '皮肤在 Loaded 加载
End Sub End Sub
''' <summary> ''' <summary>
''' 获取当前页面的登录信息。 ''' 获取当前页面的登录信息。
''' </summary> ''' </summary>
Public Shared Function GetLoginData() As McLoginServer Public Shared Function GetLoginData() As McLoginServer
Dim Server As String = If(IsNothing(McInstanceSelected), Setup.Get("CacheNideServer"), Setup.Get("VersionServerNide", Instance:=McInstanceSelected)) Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get("CacheNideServer"), Settings.Get("VersionServerNide", Instance:=McInstanceSelected))
Return New McLoginServer(McLoginType.Nide) With {.Token = "Nide", .UserName = Setup.Get("CacheNideUsername"), .Password = Setup.Get("CacheNidePass"), .Description = "统一通行证", .Type = McLoginType.Nide, .BaseUrl = "https://auth.mc-user.com:233/" & Server & "/authserver"} Return New McLoginServer(McLoginType.Nide) With {.Token = "Nide", .UserName = Settings.Get("CacheNideUsername"), .Password = Settings.Get("CacheNidePass"), .Description = "统一通行证", .Type = McLoginType.Nide, .BaseUrl = "https://auth.mc-user.com:233/" & Server & "/authserver"}
End Function End Function
Private Sub PageLoginNideSkin_MouseEnter(sender As Object, e As MouseEventArgs) Handles PanData.MouseEnter Private Sub PageLoginNideSkin_MouseEnter(sender As Object, e As MouseEventArgs) Handles PanData.MouseEnter
@@ -48,13 +48,13 @@
OpenWebsite("https://login.mc-user.com:233/account/changepw") OpenWebsite("https://login.mc-user.com:233/account/changepw")
End Sub End Sub
Public Shared Sub ExitLogin() Handles BtnExit.Click Public Shared Sub ExitLogin() Handles BtnExit.Click
Setup.Set("CacheNideAccess", "") Settings.Set("CacheNideAccess", "")
McLoginNideLoader.Input = Nothing '防止因为输入的用户名密码相同,直接使用了上次登录的加载器结果 McLoginNideLoader.Input = Nothing '防止因为输入的用户名密码相同,直接使用了上次登录的加载器结果
FrmLaunchLeft.RefreshPage(False, True) FrmLaunchLeft.RefreshPage(False, True)
End Sub End Sub
Private Sub Skin_Click(sender As Object, e As MouseButtonEventArgs) Handles Skin.Click Private Sub Skin_Click(sender As Object, e As MouseButtonEventArgs) Handles Skin.Click
OpenWebsite("https://login.mc-user.com:233/" & If(IsNothing(McInstanceSelected), Setup.Get("CacheNideServer"), Setup.Get("VersionServerNide", Instance:=McInstanceSelected)) & "/skin") OpenWebsite("https://login.mc-user.com:233/" & If(IsNothing(McInstanceSelected), Settings.Get("CacheNideServer"), Settings.Get("VersionServerNide", Instance:=McInstanceSelected)) & "/skin")
End Sub End Sub
End Class End Class
@@ -70,7 +70,7 @@ Public Class PageLinkMain
'由任意状态切换到 Waiting '由任意状态切换到 Waiting
Private Sub SwitchToWaiting(OldState As LinkStates) Private Sub SwitchToWaiting(OldState As LinkStates)
'加载器与进程状态 '加载器与进程状态
LinkLoader.Abort() LinkLoader.Interrupt()
SyncLock LinkLoader.LockState SyncLock LinkLoader.LockState
LinkLoader.State = LoadState.Waiting LinkLoader.State = LoadState.Waiting
End SyncLock End SyncLock
@@ -171,7 +171,7 @@ Public Class PageLinkMain
End Function End Function
Private Shared Function FixCodeFormat(Code As String) As String Private Shared Function FixCodeFormat(Code As String) As String
Code = Code.Between("【", "】").Between("[", "]") '从完整消息中提取 Code = Code.Between("【", "】").Between("[", "]") '从完整消息中提取
Code = Code.ToUpper.Replace("O", "0").Replace("I", "1") '输入修正 Code = Code.Upper.Replace("O", "0").Replace("I", "1") '输入修正
'版本 1 兼容 '版本 1 兼容
If Code.Length >= 17 AndAlso (Code.Length < 23 OrElse (Code.Length >= 18 AndAlso Code(17) <> "-"c)) Then If Code.Length >= 17 AndAlso (Code.Length < 23 OrElse (Code.Length >= 18 AndAlso Code(17) <> "-"c)) Then
Code = Code.Substring(0, 17) & "-0105E" Code = Code.Substring(0, 17) & "-0105E"
@@ -223,7 +223,7 @@ Public Class PageLinkMain
'由 Loading 状态切换到 Failed '由 Loading 状态切换到 Failed
Private Sub SwitchToFailed(OldState As LinkStates) Private Sub SwitchToFailed(OldState As LinkStates)
'加载器与进程状态 '加载器与进程状态
LinkLoader.Abort() LinkLoader.Interrupt()
ProcessStop() ProcessStop()
'UI 更新 'UI 更新
UpdateProgressBar(1) UpdateProgressBar(1)
@@ -356,7 +356,7 @@ Public Class PageLinkMain
Private Sub Copy() Handles BtnFinishCopy.Click Private Sub Copy() Handles BtnFinishCopy.Click
Dim CodeText As String = $"在 PCL 启动器中输入邀请码【{GetInviteCode()}】,即可加入联机房间!" Dim CodeText As String = $"在 PCL 启动器中输入邀请码【{GetInviteCode()}】,即可加入联机房间!"
ClipboardSet(CodeText, False) ClipboardSet(CodeText, False)
Setup.Set("LinkLastAutoJoinInviteCode", CodeText) Settings.Set("LinkLastAutoJoinInviteCode", CodeText)
Hint("已复制邀请码!", HintType.Green) Hint("已复制邀请码!", HintType.Green)
End Sub End Sub
Private Function GetInviteCode() As String Private Function GetInviteCode() As String
@@ -460,9 +460,9 @@ Public Class PageLinkMain
UpdateLoadingPage("正在检查联机模块版本……", "检查联机模块版本") UpdateLoadingPage("正在检查联机模块版本……", "检查联机模块版本")
If Not (File.Exists(PathEasyTier & "联机模块 CLI.exe") AndAlso File.Exists(PathEasyTier & "联机模块.exe") AndAlso If Not (File.Exists(PathEasyTier & "联机模块 CLI.exe") AndAlso File.Exists(PathEasyTier & "联机模块.exe") AndAlso
File.Exists(PathEasyTier & "Packet.dll")) Then File.Exists(PathEasyTier & "Packet.dll")) Then
Setup.Set("LinkEasyTierVersion", -1) Settings.Set("LinkEasyTierVersion", -1)
End If End If
Dim LocalVersion As Integer = Setup.Get("LinkEasyTierVersion") Dim LocalVersion As Integer = Settings.Get("LinkEasyTierVersion")
ServerVersion = ServerConfig("Link")("EasyTierVersion") ServerVersion = ServerConfig("Link")("EasyTierVersion")
Dim RequiredFiles As New List(Of NetFile) Dim RequiredFiles As New List(Of NetFile)
Log($"[Link] EasyTier 本地版本:{LocalVersion},需求版本:{ServerVersion}") Log($"[Link] EasyTier 本地版本:{LocalVersion},需求版本:{ServerVersion}")
@@ -491,18 +491,18 @@ Public Class PageLinkMain
CopyDirectory(ExtractedPath, PathEasyTier) CopyDirectory(ExtractedPath, PathEasyTier)
'重命名 '重命名
File.Delete(PathEasyTier & "联机模块.exe") File.Delete(PathEasyTier & "联机模块.exe")
Rename(PathEasyTier & "easytier-core.exe", PathEasyTier & "联机模块.exe") File.Move(PathEasyTier & "easytier-core.exe", PathEasyTier & "联机模块.exe")
File.Delete(PathEasyTier & "联机模块 CLI.exe") File.Delete(PathEasyTier & "联机模块 CLI.exe")
Rename(PathEasyTier & "easytier-cli.exe", PathEasyTier & "联机模块 CLI.exe") File.Move(PathEasyTier & "easytier-cli.exe", PathEasyTier & "联机模块 CLI.exe")
'清理 '清理
File.Delete(PathEasyTier & "EasyTier.zip") File.Delete(PathEasyTier & "EasyTier.zip")
Setup.Set("LinkEasyTierVersion", ServerVersion) Settings.Set("LinkEasyTierVersion", ServerVersion)
End If End If
Task.Progress = 0.07 Task.Progress = 0.07
'获取节点列表 '获取节点列表
UpdateLoadingPage("正在获取节点列表……", "获取节点列表") UpdateLoadingPage("正在获取节点列表……", "获取节点列表")
Dim RawPeers As List(Of String) Dim RawPeers As List(Of String)
Dim CustomPeers As String = Setup.Get("LinkCustomPeer") Dim CustomPeers As String = Settings.Get("LinkCustomPeer")
If String.IsNullOrWhiteSpace(CustomPeers) Then If String.IsNullOrWhiteSpace(CustomPeers) Then
If DiscoverNodeID = -2 AndAlso Not IsServerSide Then If DiscoverNodeID = -2 AndAlso Not IsServerSide Then
Panic("未填写自定义节点设置", $"$你必须在 {vbLQ}自定义节点{vbRQ} 设置中填写与房主相同的内容,{vbCrLf}才能进入该房间!") Panic("未填写自定义节点设置", $"$你必须在 {vbLQ}自定义节点{vbRQ} 设置中填写与房主相同的内容,{vbCrLf}才能进入该房间!")
@@ -539,7 +539,7 @@ Public Class PageLinkMain
For Each Peer As String In RawPeers For Each Peer As String In RawPeers
Arguments += $" -p=""{Peer}""" Arguments += $" -p=""{Peer}"""
Next Next
If Setup.Get("LinkLatencyMode") = 1 Then Arguments += " --latency-first" If Settings.Get("LinkLatencyMode") = 1 Then Arguments += " --latency-first"
'启动进程 '启动进程
ProcessStart(Arguments) ProcessStart(Arguments)
Task.Progress = 0.15 Task.Progress = 0.15
@@ -585,8 +585,8 @@ Public Class PageLinkMain
Panic("无法连接到房主", $"可能的原因:{vbCrLf}- 你或者房主的网络环境不佳{vbCrLf}- 房主已关闭房间{vbCrLf}- 邀请码输错了") Panic("无法连接到房主", $"可能的原因:{vbCrLf}- 你或者房主的网络环境不佳{vbCrLf}- 房主已关闭房间{vbCrLf}- 邀请码输错了")
End Select End Select
End If End If
Loop Until Task.IsAborted Loop Until Task.IsInterrupted
If Task.IsAborted Then Throw New ThreadInterruptedException If Task.IsInterrupted Then Throw New ThreadInterruptedException
'等待连接稳定,最多 5s '等待连接稳定,最多 5s
If IsServerSide Then Return If IsServerSide Then Return
UpdateLoadingPage("连接优化中……", "优化连接") UpdateLoadingPage("连接优化中……", "优化连接")
@@ -594,7 +594,7 @@ Public Class PageLinkMain
For i = 1 To 50 For i = 1 To 50
Dim Server = GetTargetPeer() Dim Server = GetTargetPeer()
If Server IsNot Nothing AndAlso Not Server.Relay AndAlso Server.Ping < 100 Then Return '结束 If Server IsNot Nothing AndAlso Not Server.Relay AndAlso Server.Ping < 100 Then Return '结束
If Task.IsAborted Then Throw New ThreadInterruptedException If Task.IsInterrupted Then Throw New ThreadInterruptedException
Thread.Sleep(100) Thread.Sleep(100)
Next Next
End Sub End Sub
@@ -1060,7 +1060,7 @@ ForcedPass:
Else Else
HintFinish.Text = "你或者房主的网络环境不太好," HintFinish.Text = "你或者房主的网络环境不太好,"
End If End If
If String.IsNullOrWhiteSpace(Setup.Get("LinkCustomPeer")) Then If String.IsNullOrWhiteSpace(Settings.Get("LinkCustomPeer")) Then
HintFinish.Text &= "正使用社区节点进行中继。" HintFinish.Text &= "正使用社区节点进行中继。"
Else Else
HintFinish.Text &= "正通过自定义节点进行中继。" HintFinish.Text &= "正通过自定义节点进行中继。"
File diff suppressed because it is too large Load Diff
@@ -144,13 +144,13 @@
If Not Entry.ShowInSearch OrElse (Val(VersionBranchCode) <> 50 AndAlso Not Entry.ShowInSnapshot) Then Continue For If Not Entry.ShowInSearch OrElse (Val(VersionBranchCode) <> 50 AndAlso Not Entry.ShowInSnapshot) Then Continue For
QueryList.Add(New SearchEntry(Of HelpEntry) With { QueryList.Add(New SearchEntry(Of HelpEntry) With {
.Item = Entry, .Item = Entry,
.SearchSource = New List(Of KeyValuePair(Of String, Double)) From { .SearchSource = New List(Of SearchSource) From {
New KeyValuePair(Of String, Double)(Entry.Title, 1), New SearchSource(Entry.Title, 1),
New KeyValuePair(Of String, Double)(Entry.Desc, 0.5), New SearchSource(Entry.Desc, 0.5),
New KeyValuePair(Of String, Double)(Entry.Search, 1.5) New SearchSource(Entry.Search, 1.5)
} }
}) })
'New KeyValuePair(Of String, Double)(If(Entry.IsEvent, If(Entry.EventData, ""), Entry.XamlContent), 0.2) 'New SearchSource(If(Entry.IsEvent, If(Entry.EventData, ""), Entry.XamlContent), 0.2)
Next Next
'进行搜索,构造列表 '进行搜索,构造列表
Dim SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=5, MinBlurSimilarity:=0.08) Dim SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=5, MinBlurSimilarity:=0.08)
@@ -5,9 +5,9 @@
Private Sub PageOtherLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded Private Sub PageOtherLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
'是否处于隐藏的子页面 '是否处于隐藏的子页面
Dim IsHiddenPage As Boolean = False Dim IsHiddenPage As Boolean = False
If ItemHelp.Checked AndAlso Setup.Get("UiHiddenOtherHelp") Then IsHiddenPage = True If ItemHelp.Checked AndAlso Settings.Get("UiHiddenOtherHelp") Then IsHiddenPage = True
If ItemAbout.Checked AndAlso Setup.Get("UiHiddenOtherAbout") Then IsHiddenPage = True If ItemAbout.Checked AndAlso Settings.Get("UiHiddenOtherAbout") Then IsHiddenPage = True
If ItemTest.Checked AndAlso Setup.Get("UiHiddenOtherTest") Then IsHiddenPage = True If ItemTest.Checked AndAlso Settings.Get("UiHiddenOtherTest") Then IsHiddenPage = True
If PageSetupUI.HiddenForceShow Then IsHiddenPage = False If PageSetupUI.HiddenForceShow Then IsHiddenPage = False
'若页面错误,或尚未加载,则继续 '若页面错误,或尚未加载,则继续
If IsLoad AndAlso Not IsHiddenPage Then Return If IsLoad AndAlso Not IsHiddenPage Then Return
@@ -16,9 +16,9 @@
PageSetupUI.HiddenRefresh() PageSetupUI.HiddenRefresh()
'选择第一个未被禁用的子页面 '选择第一个未被禁用的子页面
If IsPageSwitched Then Return If IsPageSwitched Then Return
If Not Setup.Get("UiHiddenOtherHelp") Then If Not Settings.Get("UiHiddenOtherHelp") Then
ItemHelp.SetChecked(True, False, False) ItemHelp.SetChecked(True, False, False)
ElseIf Not Setup.Get("UiHiddenOtherAbout") Then ElseIf Not Settings.Get("UiHiddenOtherAbout") Then
ItemAbout.SetChecked(True, False, False) ItemAbout.SetChecked(True, False, False)
Else Else
ItemTest.SetChecked(True, False, False) ItemTest.SetChecked(True, False, False)
@@ -37,9 +37,9 @@
Public Sub New() Public Sub New()
InitializeComponent() InitializeComponent()
'选择第一个未被禁用的子页面 '选择第一个未被禁用的子页面
If Not Setup.Get("UiHiddenOtherHelp") Then If Not Settings.Get("UiHiddenOtherHelp") Then
PageID = FormMain.PageSubType.OtherHelp PageID = FormMain.PageSubType.OtherHelp
ElseIf Not Setup.Get("UiHiddenOtherAbout") Then ElseIf Not Settings.Get("UiHiddenOtherAbout") Then
PageID = FormMain.PageSubType.OtherAbout PageID = FormMain.PageSubType.OtherAbout
Else Else
PageID = FormMain.PageSubType.OtherTest PageID = FormMain.PageSubType.OtherTest
@@ -119,7 +119,7 @@
Hint("正在刷新……", Log:=False) Hint("正在刷新……", Log:=False)
End Sub End Sub
Public Shared Sub RefreshHelp() Public Shared Sub RefreshHelp()
Setup.Set("SystemHelpVersion", 0) '强制重新解压文件 Settings.Set("SystemHelpVersion", 0) '强制重新解压文件
FrmOtherHelp.PageLoaderRestart() FrmOtherHelp.PageLoaderRestart()
FrmOtherHelp.SearchBox.Text = "" FrmOtherHelp.SearchBox.Text = ""
End Sub End Sub
@@ -34,7 +34,7 @@
'添加控件 '添加控件
Dim ContMenu As ContextMenu = Nothing Dim ContMenu As ContextMenu = Nothing
Select Case Folder.Type Select Case Folder.Type
Case McFolder.Types.Original Case McFolder.Types.Vanilla
ContMenu = GetObjectFromXML( ContMenu = GetObjectFromXML(
<ContextMenu xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PCL;assembly=Plain Craft Launcher 2"> <ContextMenu xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PCL;assembly=Plain Craft Launcher 2">
<local:MyMenuItem x:Name="Rename" Header="重命名" Padding="0,2,0,0" Icon="F1 M 53.2929,21.2929L 54.7071,22.7071C 56.4645,24.4645 56.4645,27.3137 54.7071,29.0711L 52.2323,31.5459L 44.4541,23.7677L 46.9289,21.2929C 48.6863,19.5355 51.5355,19.5355 53.2929,21.2929 Z M 31.7262,52.052L 23.948,44.2738L 43.0399,25.182L 50.818,32.9601L 31.7262,52.052 Z M 23.2409,47.1023L 28.8977,52.7591L 21.0463,54.9537L 23.2409,47.1023 Z"/> <local:MyMenuItem x:Name="Rename" Header="重命名" Padding="0,2,0,0" Icon="F1 M 53.2929,21.2929L 54.7071,22.7071C 56.4645,24.4645 56.4645,27.3137 54.7071,29.0711L 52.2323,31.5459L 44.4541,23.7677L 46.9289,21.2929C 48.6863,19.5355 51.5355,19.5355 53.2929,21.2929 Z M 31.7262,52.052L 23.948,44.2738L 43.0399,25.182L 50.818,32.9601L 31.7262,52.052 Z M 23.2409,47.1023L 28.8977,52.7591L 21.0463,54.9537L 23.2409,47.1023 Z"/>
@@ -43,7 +43,7 @@
<local:MyMenuItem x:Name="Delete" Header="删除" Padding="0,0,0,2" Icon="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z "/> <local:MyMenuItem x:Name="Delete" Header="删除" Padding="0,0,0,2" Icon="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z "/>
</ContextMenu> </ContextMenu>
) )
Case McFolder.Types.RenamedOriginal Case McFolder.Types.RenamedVanilla
ContMenu = GetObjectFromXML( ContMenu = GetObjectFromXML(
<ContextMenu xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PCL;assembly=Plain Craft Launcher 2"> <ContextMenu xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PCL;assembly=Plain Craft Launcher 2">
<local:MyMenuItem x:Name="Remove" Header="复原名称" Padding="0,2,0,0" Icon="F1 M 53.2929,21.2929L 54.7071,22.7071C 56.4645,24.4645 56.4645,27.3137 54.7071,29.0711L 52.2323,31.5459L 44.4541,23.7677L 46.9289,21.2929C 48.6863,19.5355 51.5355,19.5355 53.2929,21.2929 Z M 31.7262,52.052L 23.948,44.2738L 43.0399,25.182L 50.818,32.9601L 31.7262,52.052 Z M 23.2409,47.1023L 28.8977,52.7591L 21.0463,54.9537L 23.2409,47.1023 Z"/> <local:MyMenuItem x:Name="Remove" Header="复原名称" Padding="0,2,0,0" Icon="F1 M 53.2929,21.2929L 54.7071,22.7071C 56.4645,24.4645 56.4645,27.3137 54.7071,29.0711L 52.2323,31.5459L 44.4541,23.7677L 46.9289,21.2929C 48.6863,19.5355 51.5355,19.5355 53.2929,21.2929 Z M 31.7262,52.052L 23.948,44.2738L 43.0399,25.182L 50.818,32.9601L 31.7262,52.052 Z M 23.2409,47.1023L 28.8977,52.7591L 21.0463,54.9537L 23.2409,47.1023 Z"/>
@@ -64,9 +64,9 @@
</ContextMenu> </ContextMenu>
) )
End Select End Select
If (Folder.Type = McFolder.Types.Original OrElse Folder.Type = McFolder.Types.RenamedOriginal) AndAlso Folder.Location = Path & ".minecraft\" AndAlso McFolderList.Count = 1 Then CType(ContMenu.FindName("Delete"), MyMenuItem).Header = "清空" If (Folder.Type = McFolder.Types.Vanilla OrElse Folder.Type = McFolder.Types.RenamedVanilla) AndAlso Folder.Location = Path & ".minecraft\" AndAlso McFolderList.IsSingle Then CType(ContMenu.FindName("Delete"), MyMenuItem).Header = "清空"
'注册事件 '注册事件
If Not Folder.Type = McFolder.Types.Original Then CType(ContMenu.FindName("Remove"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Remove_Click)) If Not Folder.Type = McFolder.Types.Vanilla Then CType(ContMenu.FindName("Remove"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Remove_Click))
CType(ContMenu.FindName("Open"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Open_Click)) CType(ContMenu.FindName("Open"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Open_Click))
CType(ContMenu.FindName("Delete"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Delete_Click)) CType(ContMenu.FindName("Delete"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Delete_Click))
CType(ContMenu.FindName("Rename"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Rename_Click)) CType(ContMenu.FindName("Rename"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Rename_Click))
@@ -133,7 +133,7 @@
If Not McFolderList.Any() Then If Not McFolderList.Any() Then
Throw New ArgumentNullException("没有可用的 Minecraft 文件夹") Throw New ArgumentNullException("没有可用的 Minecraft 文件夹")
Else Else
Setup.Set("LaunchFolderSelect", McFolderList(0).Location.Replace(Path, "$")) McFolderSelected = McFolderList.First.Location
CType(FrmSelectLeft.PanList.Children(1), MyListItem).Checked = True CType(FrmSelectLeft.PanList.Children(1), MyListItem).Checked = True
End If End If
@@ -178,7 +178,7 @@
RunInThread( RunInThread(
Sub() Sub()
Try Try
If Not FolderPath.EndsWith("\") Then FolderPath &= "\" '加上斜杠…… If Not FolderPath.EndsWithF("\") Then FolderPath &= "\"
'检查文件夹权限 '检查文件夹权限
If Not CheckPermission(FolderPath) Then If Not CheckPermission(FolderPath) Then
If ShowHint Then If ShowHint Then
@@ -198,7 +198,7 @@
Next Next
End If End If
'判断是否已经添加过,若添加过则直接修改自定义名 '判断是否已经添加过,若添加过则直接修改自定义名
Dim Folders As New List(Of String)(Setup.Get("LaunchFolders").ToString.Split("|")) Dim Folders As New List(Of String)(Settings.Get("LaunchFolders").ToString.Split("|"))
Dim IsAdded As Boolean = False Dim IsAdded As Boolean = False
Dim IsReplace As Boolean = False Dim IsReplace As Boolean = False
For i = 0 To Folders.Count - 1 For i = 0 To Folders.Count - 1
@@ -220,9 +220,9 @@
'如果没有添加过,则添加进去 '如果没有添加过,则添加进去
If Not IsAdded Then Folders.Add(DisplayName & ">" & FolderPath) If Not IsAdded Then Folders.Add(DisplayName & ">" & FolderPath)
'保存 '保存
Setup.Set("LaunchFolders", Join(Folders.ToArray, "|")) Settings.Set("LaunchFolders", Folders.Join("|"))
'切换选择并更新列表 '切换选择并更新列表
Setup.Set("LaunchFolderSelect", FolderPath.Replace(Path, "$")) McFolderSelected = FolderPath
McFolderListLoader.Start(IsForceRestart:=True) McFolderListLoader.Start(IsForceRestart:=True)
'提示 '提示
If IsReplace Then Return If IsReplace Then Return
@@ -243,8 +243,8 @@
Dim ModIndieFolder As New DirectoryInfo(Instance.PathVersion & "mods\") Dim ModIndieFolder As New DirectoryInfo(Instance.PathVersion & "mods\")
If ModIndieFolder.Exists AndAlso ModIndieFolder.EnumerateFiles.Any Then Return If ModIndieFolder.Exists AndAlso ModIndieFolder.EnumerateFiles.Any Then Return
'满足以上全部条件则视为根目录整合包 '满足以上全部条件则视为根目录整合包
Setup.Set("VersionArgumentIndie", 2, Instance:=Instance) Settings.Set("VersionArgumentIndie", 2, Instance:=Instance)
Setup.Set("VersionArgumentIndieV2", False, Instance:=Instance) Settings.Set("VersionArgumentIndieV2", False, Instance:=Instance)
Log("[Setup] 已自动关闭单版本隔离:" & Instance.Name, LogLevel.Debug) Log("[Setup] 已自动关闭单版本隔离:" & Instance.Name, LogLevel.Debug)
Next Next
Catch ex As Exception Catch ex As Exception
@@ -260,94 +260,95 @@
Hint("在下载任务进行时,无法创建游戏文件夹!", HintType.Red) Hint("在下载任务进行时,无法创建游戏文件夹!", HintType.Red)
Return Return
End If End If
If Not Directory.Exists(Path & ".minecraft\") Then CreateMcFolderInCurrentPath()
Directory.CreateDirectory(Path & ".minecraft\") Hint("新建 .minecraft 文件夹成功!", HintType.Green)
Directory.CreateDirectory(Path & ".minecraft\versions\") End Sub
Setup.Set("LaunchFolderSelect", "$.minecraft\") Public Shared Sub CreateMcFolderInCurrentPath()
McFolderLauncherProfilesJsonCreate(Path & ".minecraft\") McFolderSelected = Path & ".minecraft\"
Hint("新建 .minecraft 文件夹成功!", HintType.Green) If Not Directory.Exists(McFolderSelected) Then
Directory.CreateDirectory(McFolderSelected)
Directory.CreateDirectory(McFolderSelected & "versions\")
McFolderLauncherProfilesJsonCreate(McFolderSelected)
End If End If
McFolderListLoader.Start(IsForceRestart:=True) AddFolder(McFolderSelected, GetFolderNameFromPath(Path), False)
End Sub End Sub
'右键菜单 '右键菜单
Public Sub Remove_Click(sender As Object, e As RoutedEventArgs) Public Sub Remove_Click(sender As Object, e As RoutedEventArgs)
Try Try
Dim Folder As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag Dim Target As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
'若为 “移除”,则提醒是否删除 PCL 的配置文件 '若为 “移除”,则提醒是否删除 PCL 的配置文件
If Folder.Type = McFolder.Types.Custom Then If Target.Type = McFolder.Types.Custom Then
Select Case MyMsgBox("是否需要清理 PCL 在该文件夹中的配置文件?" & vbCrLf & "这包括各个版本的独立设置(如自定义图标、第三方登录配置)等,对游戏本身没有影响。", "配置文件清理", "删除", "保留", "取消") Select Case MyMsgBox("是否需要清理 PCL 在该文件夹中的配置文件?" & vbCrLf & "这包括各个版本的独立设置(如自定义图标、第三方登录配置)等,对游戏本身没有影响。", "配置文件清理", "删除", "保留", "取消")
Case 1 Case 1
'删除配置文件 '删除配置文件
If File.Exists(Folder.Location & "PCL.ini") Then File.Delete(Folder.Location & "PCL.ini") If File.Exists(Target.Location & "PCL.ini") Then File.Delete(Target.Location & "PCL.ini")
If Directory.Exists(Folder.Location & "versions\") Then If Directory.Exists(Target.Location & "versions\") Then
For Each InstanceInfo In New DirectoryInfo(Folder.Location & "versions\").EnumerateDirectories For Each InstanceInfo In New DirectoryInfo(Target.Location & "versions\").EnumerateDirectories
If Directory.Exists(InstanceInfo.FullName & "\PCL\") Then Directory.Delete(InstanceInfo.FullName & "\PCL\", True) If Directory.Exists(InstanceInfo.FullName & "\PCL\") Then DeleteDirectory(InstanceInfo.FullName & "\PCL\", True)
Next Next
End If End If
Case 2 Case 2
'不删除 '不删除
Case 3 Case 3
'取消 '取消
Return Return
End Select End Select
End If End If
'若修改了本部分代码,应对应修改 Delete_Click 中的代码 Dim DeletedName As String = RemoveFolderFromSetup(Target)
'获取并删除列表项 Hint(If(Target.Type = McFolder.Types.Custom, "文件夹 " & DeletedName & " 已从列表中移除!", "文件夹名称已复原!"), HintType.Green)
Dim Folders As New List(Of String)(Setup.Get("LaunchFolders").ToString.Split("|"))
Dim Name As String = ""
For i = 0 To Folders.Count - 1
If Folders(i) = "" Then Exit For
If Folders(i).ToString.EndsWith(Folder.Location) Then
Name = Folders(i).ToString.BeforeFirst(">")
Folders.RemoveAt(i)
Exit For
End If
Next
'保存
Setup.Set("LaunchFolders", If(Not Folders.Any(), "", Join(Folders.ToArray, "|")))
Hint(If(Folder.Type = McFolder.Types.Custom, "文件夹 " & Name & " 已从列表中移除!", "文件夹名称已复原!"), HintType.Green)
McFolderListLoader.Start(IsForceRestart:=True) McFolderListLoader.Start(IsForceRestart:=True)
Catch ex As Exception Catch ex As Exception
Log(ex, "从列表中移除游戏文件夹失败", LogLevel.Feedback) Log(ex, "从列表中移除游戏文件夹失败", LogLevel.Feedback)
End Try End Try
End Sub End Sub
Public Sub Delete_Click(sender As Object, e As RoutedEventArgs) Public Sub Delete_Click(sender As Object, e As RoutedEventArgs)
Dim Folder As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag Dim Target As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
Dim DeleteText As String = If((Folder.Type = McFolder.Types.Original OrElse Folder.Type = McFolder.Types.RenamedOriginal) AndAlso Folder.Location = Path & ".minecraft\" AndAlso McFolderList.Count = 1, "清空", "删除") Dim DeleteText As String = If((Target.Type = McFolder.Types.Vanilla OrElse Target.Type = McFolder.Types.RenamedVanilla) AndAlso Target.Location = Path & ".minecraft\" AndAlso McFolderList.IsSingle, "清空", "删除")
If MyMsgBox("你确定要" & DeleteText & "这个文件夹吗?" & vbCrLf & "目标文件夹:" & Folder.Location & vbCrLf & vbCrLf & "这会导致该文件夹中的所有存档与其他文件永久丢失,且不可恢复!", "删除警告", "取消", "确认", "取消") <> 2 Then Return If MyMsgBox("你确定要" & DeleteText & "这个文件夹吗?" & vbCrLf &
If MyMsgBox("如果你在该文件夹中存放了除 MC 以外的其他文件,这些文件也会被一同删除!" & vbCrLf & "继续删除会导致该文件夹中的所有文件永久丢失,请在仔细确认后再继续!" & vbCrLf & "目标文件夹:" & Folder.Location & vbCrLf & vbCrLf & "这是最后一次警告!", "删除警告", "确认" & DeleteText, "取消", IsWarn:=True) <> 1 Then Return "目标文件夹:" & Target.Location & vbCrLf & vbCrLf &
'移出列表 "该文件夹中的游戏存档、游戏版本,以及 MC 之外的其他文件,都会永久丢失,不可恢复!", "警告", "取消", "确认", "取消") <> 2 Then Return
If Folder.Type = McFolder.Types.Custom Then If MyMsgBoxInput("删除确认",
Dim Folders As New List(Of String)(Setup.Get("LaunchFolders").ToString.Split("|")) "该文件夹中的游戏存档、游戏版本,以及 MC 之外的其他文件,都会永久丢失,不可恢复!" & vbCrLf &
For i = 0 To Folders.Count - 1 "目标文件夹:" & Target.Location & vbCrLf & vbCrLf &
If Folders(i) = "" Then Exit For "如果确实要删除,请在下面输入【确认删除】以继续。",
If Folders(i).ToString.EndsWith(Folder.Location) Then ValidateRules:=New ObjectModel.Collection(Of Validate) From {New ValidateSame("确认删除", $"请输入 {vbLQ}确认删除{vbRQ} 这四个字!")},
'Name = Folders(i).ToString.Before(">") Button1:="永久删除文件夹", Button2:="取消", IsWarn:=True) Is Nothing Then Return
Folders.RemoveAt(i) RemoveFolderFromSetup(Target)
Exit For
End If
Next
Setup.Set("LaunchFolders", If(Not Folders.Any(), "", Join(Folders.ToArray, "|")))
End If
RunInNewThread( RunInNewThread(
Sub() Sub()
'删除文件夹 '删除文件夹
Try Try
Hint("正在" & DeleteText & "文件夹 " & Folder.Name & "!", HintType.Blue) Hint("正在" & DeleteText & "文件夹 " & Target.Name & "!", HintType.Blue)
DeleteDirectory(Folder.Location) DeleteDirectory(Target.Location)
If DeleteText = "清空" Then Directory.CreateDirectory(Folder.Location) If DeleteText = "清空" Then Directory.CreateDirectory(Target.Location)
Hint("已" & DeleteText & "文件夹 " & Folder.Name & "!", HintType.Green) Hint("已" & DeleteText & "文件夹 " & Target.Name & "!", HintType.Green)
Catch ex As Exception Catch ex As Exception
Log(ex, DeleteText & "文件夹 " & Folder.Name & " 失败", LogLevel.Hint) Log(ex, DeleteText & "文件夹 " & Target.Name & " 失败", LogLevel.Hint)
Finally Finally
'刷新列表 '刷新列表
McFolderListLoader.Start(IsForceRestart:=True) McFolderListLoader.Start(IsForceRestart:=True)
End Try End Try
End Sub, "Folder Delete " & GetUuid(), ThreadPriority.BelowNormal) End Sub, "Folder Delete " & GetUuid(), ThreadPriority.BelowNormal)
End Sub End Sub
''' <summary>
''' 从设置的文件夹列表中删除指定的文件夹。
''' 返回被删除的文件夹的显示名称。如果没有,返回 Nothing。
''' </summary>
Private Shared Function RemoveFolderFromSetup(Target As McFolder) As String
Dim DeletedName As String = Nothing
Dim Folders = Settings.Get("LaunchFolders").ToString.Split({"|"c}, StringSplitOptions.RemoveEmptyEntries).ToList
For Each Folder In Folders.ToList
If Not Folder.EndsWithF(Target.Location) Then Continue For
DeletedName = Folder.BeforeFirst(">")
Folders.Remove(Folder)
Exit For
Next
Settings.Set("LaunchFolders", Folders.Join("|"))
Return DeletedName
End Function
Public Sub Open_Click(sender As Object, e As RoutedEventArgs) Public Sub Open_Click(sender As Object, e As RoutedEventArgs)
OpenExplorer(CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Info) OpenExplorer(CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Info)
End Sub End Sub
@@ -371,7 +372,7 @@
New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})}) New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})})
If String.IsNullOrWhiteSpace(NewName) Then Return If String.IsNullOrWhiteSpace(NewName) Then Return
'修改自定义名 '修改自定义名
Dim Folders As New List(Of String)(Setup.Get("LaunchFolders").ToString.Split("|")) Dim Folders As New List(Of String)(Settings.Get("LaunchFolders").ToString.Split("|"))
Dim IsAdded As Boolean = False Dim IsAdded As Boolean = False
For i = 0 To Folders.Count - 1 For i = 0 To Folders.Count - 1
Dim FolderCurrent As String = Folders(i) Dim FolderCurrent As String = Folders(i)
@@ -391,7 +392,7 @@
If Not IsAdded Then Folders.Add(NewName & ">" & Folder.Location) If Not IsAdded Then Folders.Add(NewName & ">" & Folder.Location)
Hint("文件夹名称已更新为 " & NewName & " !", HintType.Green) Hint("文件夹名称已更新为 " & NewName & " !", HintType.Green)
'保存 '保存
Setup.Set("LaunchFolders", Join(Folders.ToArray, "|")) Settings.Set("LaunchFolders", Folders.Join("|"))
McFolderListLoader.Start(IsForceRestart:=True) McFolderListLoader.Start(IsForceRestart:=True)
Catch ex As Exception Catch ex As Exception
Log(ex, "重命名文件夹失败", LogLevel.Feedback) Log(ex, "重命名文件夹失败", LogLevel.Feedback)
@@ -408,7 +409,7 @@
Return Return
End If End If
'更换 '更换
Setup.Set("LaunchFolderSelect", CType(sender.Tag, McFolder).Location.Replace(Path, "$")) McFolderSelected = CType(sender.Tag, McFolder).Location
McFolderListLoader.Start(IsForceRestart:=True) McFolderListLoader.Start(IsForceRestart:=True)
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.RunOnUpdated, MaxDepth:=1, ExtraPath:="versions\") '刷新版本列表 LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.RunOnUpdated, MaxDepth:=1, ExtraPath:="versions\") '刷新版本列表
End Sub End Sub
@@ -102,7 +102,7 @@
Else Else
LabEmptyTitle.Text = "无可用版本" LabEmptyTitle.Text = "无可用版本"
LabEmptyContent.Text = "未找到任何版本的游戏,请先下载任意版本的游戏。" & vbCrLf & "若有已存在的游戏,请在左边的列表中选择添加文件夹,选择 .minecraft 文件夹将其导入。" LabEmptyContent.Text = "未找到任何版本的游戏,请先下载任意版本的游戏。" & vbCrLf & "若有已存在的游戏,请在左边的列表中选择添加文件夹,选择 .minecraft 文件夹将其导入。"
BtnEmptyDownload.Visibility = If(Setup.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow, Visibility.Collapsed, Visibility.Visible) BtnEmptyDownload.Visibility = If(Settings.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow, Visibility.Collapsed, Visibility.Visible)
End If End If
Else Else
PanBack.Visibility = Visibility.Visible PanBack.Visibility = Visibility.Visible
@@ -184,7 +184,6 @@
If New McInstance(Instance.PathVersion).Check Then If New McInstance(Instance.PathVersion).Check Then
'正常版本 '正常版本
McInstanceSelected = Instance McInstanceSelected = Instance
Setup.Set("LaunchVersionSelect", McInstanceSelected.Name)
FrmMain.PageBack() FrmMain.PageBack()
Else Else
'错误版本 '错误版本
@@ -246,7 +245,7 @@
End Sub End Sub
Public Sub BtnEmptyDownload_Loaded() Handles BtnEmptyDownload.Loaded Public Sub BtnEmptyDownload_Loaded() Handles BtnEmptyDownload.Loaded
Dim NewVisibility = If((Setup.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow) OrElse ShowHidden, Visibility.Collapsed, Visibility.Visible) Dim NewVisibility = If((Settings.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow) OrElse ShowHidden, Visibility.Collapsed, Visibility.Visible)
If BtnEmptyDownload.Visibility <> NewVisibility Then If BtnEmptyDownload.Visibility <> NewVisibility Then
BtnEmptyDownload.Visibility = NewVisibility BtnEmptyDownload.Visibility = NewVisibility
PanLoad.TriggerForceResize() PanLoad.TriggerForceResize()
@@ -1,781 +0,0 @@
Public Class ModSetup
Private Const VersionSetup As Integer = 1
''' <summary>
''' 设置列表。
''' </summary>
Private ReadOnly SetupDict As New Dictionary(Of String, SetupEntry) From {
{"Identify", New SetupEntry("", Source:=SetupSource.Registry)},
{"WindowHeight", New SetupEntry(550)},
{"WindowWidth", New SetupEntry(900)},
{"HintDownloadThread", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintNotice", New SetupEntry(0, Source:=SetupSource.Registry)},
{"HintDownload", New SetupEntry(0, Source:=SetupSource.Registry)},
{"HintHide", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintHandInstall", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintBuy", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintClearRubbish", New SetupEntry(0, Source:=SetupSource.Registry)},
{"HintUpdateMod", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintCustomCommand", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintCustomWarn", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintMoreAdvancedSetup", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintIndieSetup", New SetupEntry(False, Source:=SetupSource.Registry)},
{"HintExportConfig", New SetupEntry(False, Source:=SetupSource.Registry)},
{"SystemEula", New SetupEntry(False, Source:=SetupSource.Registry)}, '仅老版本兼容,现已换用 SystemEulaVersion
{"SystemEulaVersion", New SetupEntry(0, Source:=SetupSource.Registry)},
{"SystemCount", New SetupEntry(0, Source:=SetupSource.Registry, Encoded:=True)},
{"SystemLaunchCount", New SetupEntry(0, Source:=SetupSource.Registry, Encoded:=True)},
{"SystemLastVersionReg", New SetupEntry(0, Source:=SetupSource.Registry, Encoded:=True)},
{"SystemHighestSavedBetaVersionReg", New SetupEntry(0, Source:=SetupSource.Registry, Encoded:=True)},
{"SystemHighestBetaVersionReg", New SetupEntry(0, Source:=SetupSource.Registry, Encoded:=True)},
{"SystemHighestAlphaVersionReg", New SetupEntry(0, Source:=SetupSource.Registry, Encoded:=True)},
{"SystemSetupVersionReg", New SetupEntry(VersionSetup, Source:=SetupSource.Registry)},
{"SystemSetupVersionIni", New SetupEntry(VersionSetup)},
{"SystemHelpVersion", New SetupEntry(0, Source:=SetupSource.Registry)},
{"SystemDebugMode", New SetupEntry(False, Source:=SetupSource.Registry)},
{"SystemDebugAnim", New SetupEntry(9, Source:=SetupSource.Registry)},
{"SystemDebugDelay", New SetupEntry(False, Source:=SetupSource.Registry)},
{"SystemDebugSkipCopy", New SetupEntry(False, Source:=SetupSource.Registry)},
{"SystemSystemCache", New SetupEntry("", Source:=SetupSource.Registry)},
{"SystemSystemUpdate", New SetupEntry(0)},
{"SystemSystemActivity", New SetupEntry(0)},
{"SystemSystemTelemetry", New SetupEntry(True, Source:=SetupSource.Registry)},
{"CacheDrops", New SetupEntry("", Source:=SetupSource.Registry)},
{"CacheConfig", New SetupEntry(0, Source:=SetupSource.Registry)},
{"CacheExportConfig", New SetupEntry("", Source:=SetupSource.Registry)},
{"CacheSavedPageUrl", New SetupEntry("", Source:=SetupSource.Registry)},
{"CacheSavedPageVersion", New SetupEntry("", Source:=SetupSource.Registry)},
{"CacheMsOAuthRefresh", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsAccess", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsProfileJson", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsUuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsName", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsV2Migrated", New SetupEntry(False, Source:=SetupSource.Registry)},
{"CacheMsV2OAuthRefresh", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsV2OAuthExpires", New SetupEntry(0, Source:=SetupSource.Registry)},
{"CacheMsV2Access", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsV2ProfileJson", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsV2Uuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheMsV2Name", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheNideAccess", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheNideClient", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheNideUuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheNideName", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheNideUsername", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheNidePass", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheNideServer", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthAccess", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthClient", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthUuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthName", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthUsername", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthPass", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthServerServer", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthServerName", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheAuthServerRegister", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"CacheDownloadFolder", New SetupEntry("", Source:=SetupSource.Registry)},
{"CacheJavaListVersion", New SetupEntry(0, Source:=SetupSource.Registry)},
{"LoginRemember", New SetupEntry(True, Source:=SetupSource.Registry, Encoded:=True)},
{"LoginLegacyName", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"LoginMsJson", New SetupEntry("{}", Source:=SetupSource.Registry, Encoded:=True)}, '{UserName: OAuthToken, ...}
{"LoginNideEmail", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"LoginNidePass", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"LoginAuthEmail", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"LoginAuthPass", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"LoginType", New SetupEntry(McLoginType.Legacy, Source:=SetupSource.Registry)},
{"LoginPageType", New SetupEntry(0)},
{"LaunchSkinID", New SetupEntry("", Source:=SetupSource.Registry)},
{"LaunchSkinType", New SetupEntry(0, Source:=SetupSource.Registry)},
{"LaunchSkinSlim", New SetupEntry(False, Source:=SetupSource.Registry)},
{"LaunchVersionSelect", New SetupEntry("")},
{"LaunchFolderSelect", New SetupEntry("")},
{"LaunchFolders", New SetupEntry("", Source:=SetupSource.Registry)},
{"LaunchArgumentTitle", New SetupEntry("")},
{"LaunchArgumentInfo", New SetupEntry("PCL")},
{"LaunchArgumentJavaSelect", New SetupEntry("", Source:=SetupSource.Registry)},
{"LaunchArgumentJavaAll", New SetupEntry("[]", Source:=SetupSource.Registry)},
{"LaunchArgumentIndie", New SetupEntry(0)},
{"LaunchArgumentIndieV2", New SetupEntry(4)},
{"LaunchArgumentVisible", New SetupEntry(5, Source:=SetupSource.Registry)},
{"LaunchArgumentPriority", New SetupEntry(1, Source:=SetupSource.Registry)},
{"LaunchArgumentWindowWidth", New SetupEntry(854)},
{"LaunchArgumentWindowHeight", New SetupEntry(480)},
{"LaunchArgumentWindowType", New SetupEntry(1)},
{"LaunchArgumentRam", New SetupEntry(False, Source:=SetupSource.Registry)},
{"LaunchAdvanceJvm", New SetupEntry("-XX:+UseG1GC -XX:-UseAdaptiveSizePolicy -XX:-OmitStackTraceInFastThrow -Djdk.lang.Process.allowAmbiguousCommands=true -Dfml.ignoreInvalidMinecraftCertificates=True -Dfml.ignorePatchDiscrepancies=True -Dlog4j2.formatMsgNoLookups=true")},
{"LaunchAdvanceGame", New SetupEntry("")},
{"LaunchAdvanceRun", New SetupEntry("")},
{"LaunchAdvanceRunWait", New SetupEntry(True)},
{"LaunchAdvanceDisableJLW", New SetupEntry(False)},
{"LaunchAdvanceGraphicCard", New SetupEntry(True, Source:=SetupSource.Registry)},
{"LaunchRamType", New SetupEntry(0)},
{"LaunchRamCustom", New SetupEntry(15)},
{"LinkLastAutoJoinInviteCode", New SetupEntry("", Source:=SetupSource.Registry)},
{"LinkLatencyMode", New SetupEntry(0, Source:=SetupSource.Registry)},
{"LinkCustomPeer", New SetupEntry("")},
{"LinkEasyTierVersion", New SetupEntry(-1, Source:=SetupSource.Registry)},
{"ToolHelpChinese", New SetupEntry(True, Source:=SetupSource.Registry)},
{"ToolDownloadThread", New SetupEntry(63, Source:=SetupSource.Registry)},
{"ToolDownloadSpeed", New SetupEntry(42, Source:=SetupSource.Registry)},
{"ToolDownloadSource", New SetupEntry(1, Source:=SetupSource.Registry)},
{"ToolDownloadVersion", New SetupEntry(1, Source:=SetupSource.Registry)},
{"ToolDownloadTranslate", New SetupEntry(0, Source:=SetupSource.Registry)},
{"ToolDownloadTranslateV2", New SetupEntry(1, Source:=SetupSource.Registry)},
{"ToolDownloadIgnoreQuilt", New SetupEntry(True, Source:=SetupSource.Registry)},
{"ToolDownloadCert", New SetupEntry(False, 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)},
{"ToolUpdateSnapshot", New SetupEntry(False, Source:=SetupSource.Registry)},
{"ToolUpdateReleaseLast", New SetupEntry("", Source:=SetupSource.Registry)},
{"ToolUpdateSnapshotLast", New SetupEntry("", Source:=SetupSource.Registry)},
{"UiLauncherTransparent", New SetupEntry(600)}, '避免与 PCL1 设置冲突(UiLauncherOpacity)
{"UiLauncherHue", New SetupEntry(180)},
{"UiLauncherSat", New SetupEntry(80)},
{"UiLauncherDelta", New SetupEntry(90)},
{"UiLauncherLight", New SetupEntry(20)},
{"UiLauncherTheme", New SetupEntry(0)},
{"UiLauncherThemeGold", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)},
{"UiLauncherThemeHide", New SetupEntry("0|1|2|3|4", Source:=SetupSource.Registry, Encoded:=True)},
{"UiLauncherThemeHide2", New SetupEntry("0|1|2|3|4", Source:=SetupSource.Registry, Encoded:=True)},
{"UiLauncherLogo", New SetupEntry(True)},
{"UiLauncherEmail", New SetupEntry(False)},
{"UiBackgroundColorful", New SetupEntry(True)},
{"UiBackgroundOpacity", New SetupEntry(1000)},
{"UiBackgroundBlur", New SetupEntry(0)},
{"UiBackgroundSuit", New SetupEntry(0)},
{"UiCustomType", New SetupEntry(0)},
{"UiCustomPreset", New SetupEntry(0)},
{"UiCustomNet", New SetupEntry("")},
{"UiLogoType", New SetupEntry(1)},
{"UiLogoText", New SetupEntry("")},
{"UiLogoLeft", New SetupEntry(False)},
{"UiMusicVolume", New SetupEntry(500)},
{"UiMusicStop", New SetupEntry(False)},
{"UiMusicStart", New SetupEntry(False)},
{"UiMusicRandom", New SetupEntry(True)},
{"UiMusicAuto", New SetupEntry(True)},
{"UiHiddenPageDownload", New SetupEntry(False)},
{"UiHiddenPageLink", New SetupEntry(False)},
{"UiHiddenPageSetup", New SetupEntry(False)},
{"UiHiddenPageOther", New SetupEntry(False)},
{"UiHiddenFunctionSelect", New SetupEntry(False)},
{"UiHiddenFunctionModUpdate", New SetupEntry(False)},
{"UiHiddenFunctionHidden", New SetupEntry(False)},
{"UiHiddenSetupLaunch", New SetupEntry(False)},
{"UiHiddenSetupUi", New SetupEntry(False)},
{"UiHiddenSetupLink", New SetupEntry(False)},
{"UiHiddenSetupSystem", New SetupEntry(False)},
{"UiHiddenOtherHelp", New SetupEntry(False)},
{"UiHiddenOtherFeedback", New SetupEntry(False)},
{"UiHiddenOtherVote", New SetupEntry(False)},
{"UiHiddenOtherAbout", New SetupEntry(False)},
{"UiHiddenOtherTest", New SetupEntry(False)},
{"VersionAdvanceJvm", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionAdvanceGame", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionAdvanceAssets", New SetupEntry(0, Source:=SetupSource.Instance)},
{"VersionAdvanceAssetsV2", New SetupEntry(False, Source:=SetupSource.Instance)},
{"VersionAdvanceJava", New SetupEntry(False, Source:=SetupSource.Instance)},
{"VersionAdvanceRun", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionAdvanceRunWait", New SetupEntry(True, Source:=SetupSource.Instance)},
{"VersionAdvanceDisableJLW", New SetupEntry(False, Source:=SetupSource.Instance)},
{"VersionAdvanceDisableModUpdate", New SetupEntry(False, Source:=SetupSource.Instance)},
{"VersionRamType", New SetupEntry(2, Source:=SetupSource.Instance)},
{"VersionRamCustom", New SetupEntry(15, Source:=SetupSource.Instance)},
{"VersionRamOptimize", New SetupEntry(0, Source:=SetupSource.Instance)},
{"VersionArgumentTitle", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionArgumentInfo", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionArgumentIndie", New SetupEntry(-1, Source:=SetupSource.Instance)},
{"VersionArgumentIndieV2", New SetupEntry(False, Source:=SetupSource.Instance)},
{"VersionArgumentJavaSelect", New SetupEntry("使用全局设置", Source:=SetupSource.Instance)},
{"VersionServerEnter", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionServerLogin", New SetupEntry(0, Source:=SetupSource.Instance)},
{"VersionServerNide", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionServerAuthRegister", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionServerAuthName", New SetupEntry("", Source:=SetupSource.Instance)},
{"VersionServerAuthServer", New SetupEntry("", Source:=SetupSource.Instance)}
}
#Region "基础"
Private Enum SetupSource
Normal
Registry
Instance
End Enum
Private Class SetupEntry
Public Encoded As Boolean
Public DefaultValue
Public DefaultValueEncoded
Public Value
Public Source As SetupSource
''' <summary>
''' 加载状态:0/未读取 1/已读取未处理 2/已处理
''' 我也不知道当年写这坨的时候为啥没用 Enum……
''' </summary>
Public State As Byte = 0
Public Type As Type
Public Sub New(Value, Optional Source = SetupSource.Normal, Optional Encoded = False)
Try
Me.DefaultValue = Value
Me.Encoded = Encoded
Me.Value = Value
Me.Source = Source
Me.Type = If(Value, New Object).GetType
Me.DefaultValueEncoded = If(Encoded, SecretEncrypt(Value, "PCL" & Identify), Value)
Catch ex As Exception
Log(ex, "初始化 SetupEntry 失败", LogLevel.Feedback) '#5095 的 fallback
End Try
End Sub
End Class
''' <summary>
''' 改变某个设置项的值。
''' </summary>
Public Sub [Set](Key As String, Value As Object, Optional ForceReload As Boolean = False, Optional Instance As McInstance = Nothing)
[Set](Key, Value, SetupDict(Key), ForceReload, Instance)
End Sub
''' <summary>
''' 写入某个未经加密的设置项。
''' 若该设置项经过了加密,则会抛出异常。
''' </summary>
Public Sub SetSafe(Key As String, Value As Object, Optional ForceReload As Boolean = False, Optional Instance As McInstance = Nothing)
If SetupDict(Key).Encoded Then Throw New InvalidOperationException("禁止写入加密设置项:" & Key)
[Set](Key, Instance, ForceReload, Instance)
End Sub
Private Sub [Set](Key As String, Value As Object, E As SetupEntry, ForceReload As Boolean, Instance As McInstance)
Try
Value = CTypeDynamic(Value, E.Type)
If E.State = 2 Then
'如果已应用,且值相同,则无需再次更改
If E.Value = Value AndAlso Not ForceReload Then Return
Else
'如果未应用,则直接更改并应用
If E.Source <> SetupSource.Instance Then E.State = 2
End If
'设置新值
E.Value = Value
'写入值
If E.Encoded Then
Try
If Value Is Nothing Then Value = ""
Value = SecretEncrypt(Value, "PCL" & Identify)
Catch ex As Exception
Log(ex, "加密设置失败:" & Key, LogLevel.Developer)
End Try
End If
Select Case E.Source
Case SetupSource.Normal
WriteIni("Setup", Key, Value)
Case SetupSource.Registry
WriteReg(Key, Value)
Case SetupSource.Instance
If Instance Is Nothing Then Throw New Exception($"更改版本设置 {Key} 时未提供目标版本")
WriteIni(Instance.PathVersion & "PCL\Setup.ini", Key, Value)
End Select
'应用
'例如 VersionServerLogin 要求在设置之后再引发事件
Dim Method As Reflection.MethodInfo = GetType(ModSetup).GetMethod(Key)
If Method IsNot Nothing Then Method.Invoke(Me, {Value})
Catch ex As Exception
Log(ex, "设置设置项时出错(" & Key & ", " & Value & ")", LogLevel.Feedback)
End Try
End Sub
''' <summary>
''' 应用某个设置项的值。
''' </summary>
Public Function Load(Key As String, Optional ForceReload As Boolean = False, Optional Instance As McInstance = Nothing)
Return Load(Key, SetupDict(Key), ForceReload, Instance)
End Function
Private Function Load(Key As String, E As SetupEntry, ForceReload As Boolean, Instance As McInstance)
'如果已经应用过,则什么也不干
If E.State = 2 AndAlso Not ForceReload Then Return E.Value
'读取,应用并设置状态
Read(Key, E, Instance)
If E.Source <> SetupSource.Instance Then E.State = 2
Dim Method As Reflection.MethodInfo = GetType(ModSetup).GetMethod(Key)
If Method IsNot Nothing Then Method.Invoke(Me, {E.Value})
Return E.Value
End Function
''' <summary>
''' 获取某个设置项的值。
''' </summary>
Public Function [Get](Key As String, Optional Instance As McInstance = Nothing)
If Not SetupDict.ContainsKey(Key) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
Return [Get](Key, SetupDict(Key), Instance)
End Function
''' <summary>
''' 获取某个未经加密的设置项的值。
''' 若该设置项经过了加密,则会抛出异常。
''' </summary>
Public Function GetSafe(Key As String, Optional Instance As McInstance = Nothing)
If SetupDict(Key).Encoded Then Throw New InvalidOperationException("禁止读取加密设置项:" & Key)
Return [Get](Key, Instance)
End Function
Private Function [Get](Key As String, E As SetupEntry, Instance As McInstance)
'获取强制值
Dim Force As String = ForceValue(Key)
If Force IsNot Nothing Then
E.Value = CTypeDynamic(Force, E.Type)
E.State = 1
End If
'如果尚未读取过,则读取
If E.State = 0 Then
Read(Key, E, Instance)
If E.Source <> SetupSource.Instance Then E.State = 1
End If
'返回现在的值
Return E.Value
End Function
''' <summary>
''' 初始化某个设置项的值。
''' </summary>
Public Sub Reset(Key As String, Optional ForceReload As Boolean = False, Optional Instance As McInstance = Nothing)
Dim E As SetupEntry = SetupDict(Key)
[Set](Key, E.DefaultValue, E, ForceReload, Instance)
Select Case SetupDict(Key).Source
Case SetupSource.Normal
DeleteIniKey("Setup", Key)
Case SetupSource.Registry
DeleteReg(Key)
Case Else 'SetupSource.Instance
If Instance Is Nothing Then Throw New Exception($"重置版本设置 {Key} 时未提供目标版本")
DeleteIniKey(Instance.PathVersion & "PCL\Setup.ini", Key)
End Select
End Sub
''' <summary>
''' 获取某个设置项的默认值。
''' </summary>
Public Function GetDefault(Key As String) As String
Return SetupDict(Key).DefaultValue
End Function
''' <summary>
''' 某个设置项是否从未被设置过。
''' </summary>
Public Function IsUnset(Key As String, Optional Instance As McInstance = Nothing) As Boolean
Select Case SetupDict(Key).Source
Case SetupSource.Normal
Return Not HasIniKey("Setup", Key)
Case SetupSource.Registry
Return Not HasReg(Key)
Case Else 'SetupSource.Instance
If Instance Is Nothing Then Throw New Exception($"判断版本设置 {Key} 是否存在时未提供目标版本")
Return Not HasIniKey(Instance.PathVersion & "PCL\Setup.ini", Key)
End Select
End Function
''' <summary>
''' 读取设置。
''' </summary>
Private Sub Read(Key As String, ByRef E As SetupEntry, Instance As McInstance)
Try
If Not E.State = 0 Then Return
Dim SourceValue As String = Nothing '先用 String 储存,避免类型转换
Select Case E.Source
Case SetupSource.Normal
SourceValue = ReadIni("Setup", Key, E.DefaultValueEncoded)
Case SetupSource.Registry
SourceValue = ReadReg(Key, E.DefaultValueEncoded)
Case SetupSource.Instance
If Instance Is Nothing Then
Throw New Exception("读取版本设置 " & Key & " 时未提供目标版本")
Else
SourceValue = ReadIni(Instance.PathVersion & "PCL\Setup.ini", Key, E.DefaultValueEncoded)
End If
End Select
If E.Encoded Then
If SourceValue.Equals(E.DefaultValueEncoded) Then
SourceValue = E.DefaultValue
Else
Try
SourceValue = SecretDecrypt(SourceValue, "PCL" & Identify)
Catch ex As Exception
Log(ex, "解密设置失败:" & Key, LogLevel.Developer)
SourceValue = E.DefaultValue
Setup.Set(Key, E.DefaultValue, True)
End Try
End If
End If
E.Value = CTypeDynamic(SourceValue, E.Type)
Catch ex As Exception
Log(ex, "读取设置失败:" & Key, LogLevel.Hint)
E.Value = CTypeDynamic(E.DefaultValue, E.Type)
End Try
End Sub
'对部分设置强制赋值
Private Function ForceValue(Key As String) As String
#If BETA Then
If Key = "UiLauncherTheme" Then Return "0"
#End If
If Key = "UiHiddenPageLink" Then Return True
If Key = "UiHiddenSetupLink" Then Return True
Return Nothing
End Function
#End Region
#Region "Launch"
'切换选择
Public Sub LaunchVersionSelect(Value As String)
Log("[Setup] 当前选择的 Minecraft 版本:" & Value)
WriteIni(McFolderSelected & "PCL.ini", "Version", If(IsNothing(McInstanceSelected), "", McInstanceSelected.Name))
End Sub
Public Sub LaunchFolderSelect(Value As String)
Log("[Setup] 当前选择的 Minecraft 文件夹:" & Value.ToString.Replace("$", Path))
McFolderSelected = Value.ToString.Replace("$", Path)
End Sub
'游戏内存
Public Sub LaunchRamType(Type As Integer)
If FrmSetupLaunch Is Nothing Then Return
FrmSetupLaunch.RamType(Type)
End Sub
'离线皮肤
Public Sub LaunchSkinType(Value As Integer)
RunInUi(Sub()
If Not IsNothing(FrmSetupLaunch) Then
Select Case Value
Case 0, 1, 2 '默认
FrmSetupLaunch.PanSkinID.Visibility = Visibility.Collapsed
FrmSetupLaunch.PanSkinChange.Visibility = Visibility.Collapsed
Case 3 '正版
FrmSetupLaunch.PanSkinID.Visibility = Visibility.Visible
FrmSetupLaunch.PanSkinChange.Visibility = Visibility.Collapsed
Case 4 '自定义
FrmSetupLaunch.PanSkinID.Visibility = Visibility.Collapsed
FrmSetupLaunch.PanSkinChange.Visibility = Visibility.Visible
End Select
FrmSetupLaunch.CardSkin.TriggerForceResize()
End If
PageLaunchLeft.SkinLegacy.Start()
End Sub)
End Sub
Public Sub LaunchSkinID(Value As String)
PageLaunchLeft.SkinLegacy.Start()
End Sub
#End Region
#Region "Tool"
Public Sub ToolDownloadThread(Value As Integer)
NetTaskThreadLimit = Value + 1
End Sub
Public Sub ToolDownloadCert(Value As Boolean)
ServicePointManager.ServerCertificateValidationCallback =
Function(Sender, Certificate, Chain, Failure)
Dim Request As HttpWebRequest = TryCast(Sender, HttpWebRequest)
If Failure = Net.Security.SslPolicyErrors.None Then Return True '已通过验证
'基于 #3018 和 #5879,只在访问正版登录 API 时跳过证书验证
Log($"[System] 未通过 SSL 证书验证({Failure}),提供的证书为 {Certificate?.Subject},URL:{Request?.Address}", LogLevel.Debug)
If Request Is Nothing Then
Return Not Value
ElseIf Request.Address.Host.Contains("xboxlive") OrElse Request.Address.Host.Contains("minecraftservices") Then
Return Not Value '根据设置决定是否忽略错误
Else
Return False
End If
End Function
End Sub
Public Sub ToolDownloadSpeed(Value As Integer)
If Value <= 14 Then
NetTaskSpeedLimitHigh = (Value + 1) * 0.1 * 1024 * 1024L
ElseIf Value <= 31 Then
NetTaskSpeedLimitHigh = (Value - 11) * 0.5 * 1024 * 1024L
ElseIf Value <= 41 Then
NetTaskSpeedLimitHigh = (Value - 21) * 1024 * 1024L
Else
NetTaskSpeedLimitHigh = -1
End If
End Sub
#End Region
#Region "UI"
'启动器
Public Sub UiLauncherTransparent(Value As Integer)
FrmMain.Opacity = Value / 1000 + 0.4
End Sub
Public Sub UiLauncherTheme(Value As Integer)
ThemeRefresh(Value)
End Sub
Public Sub UiBackgroundColorful(Value As Boolean)
ThemeRefresh()
End Sub
'背景图片
Public Sub UiBackgroundOpacity(Value As Integer)
FrmMain.ImgBack.Opacity = Value / 1000
End Sub
Public Sub UiBackgroundBlur(Value As Integer)
If Value = 0 Then
FrmMain.ImgBack.Effect = Nothing
Else
FrmMain.ImgBack.Effect = New Effects.BlurEffect With {.Radius = Value + 1}
End If
FrmMain.ImgBack.Margin = New Thickness(-(Value + 1) / 1.8)
End Sub
Public Sub UiBackgroundSuit(Value As Integer)
If IsNothing(FrmMain.ImgBack.Background) Then Return
Dim Width As Double = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
Dim Height As Double = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
If Value = 0 Then
'智能:当图片较小时平铺,较大时适应
If Width < FrmMain.PanMain.ActualWidth / 2 AndAlso Height < FrmMain.PanMain.ActualHeight / 2 Then
Value = 4 '平铺
Else
Value = 2 '适应
End If
End If
CType(FrmMain.ImgBack.Background, ImageBrush).TileMode = TileMode.None
CType(FrmMain.ImgBack.Background, ImageBrush).Viewport = New Rect(0, 0, 1, 1)
CType(FrmMain.ImgBack.Background, ImageBrush).ViewportUnits = BrushMappingMode.RelativeToBoundingBox
Select Case Value
Case 1 '居中
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Center
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Center
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
Case 2 '适应
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Stretch
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Stretch
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.UniformToFill
FrmMain.ImgBack.Width = Double.NaN
FrmMain.ImgBack.Height = Double.NaN
Case 3 '拉伸
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Stretch
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Stretch
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.Fill
FrmMain.ImgBack.Width = Double.NaN
FrmMain.ImgBack.Height = Double.NaN
Case 4 '平铺
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Stretch
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Stretch
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
CType(FrmMain.ImgBack.Background, ImageBrush).TileMode = TileMode.Tile
CType(FrmMain.ImgBack.Background, ImageBrush).Viewport = New Rect(0, 0, CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width, CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height)
CType(FrmMain.ImgBack.Background, ImageBrush).ViewportUnits = BrushMappingMode.Absolute
FrmMain.ImgBack.Width = Double.NaN
FrmMain.ImgBack.Height = Double.NaN
Case 5 '左上
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Left
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Top
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
Case 6 '右上
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Right
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Top
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
Case 7 '左下
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Left
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Bottom
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
Case 8 '右下
FrmMain.ImgBack.HorizontalAlignment = HorizontalAlignment.Right
FrmMain.ImgBack.VerticalAlignment = VerticalAlignment.Bottom
CType(FrmMain.ImgBack.Background, ImageBrush).Stretch = Stretch.None
FrmMain.ImgBack.Width = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Width
FrmMain.ImgBack.Height = CType(FrmMain.ImgBack.Background, ImageBrush).ImageSource.Height
End Select
End Sub
'主页
Public Sub UiCustomType(Value As Integer)
If FrmSetupUI Is Nothing Then Return
Select Case Value
Case 0 '无
FrmSetupUI.PanCustomPreset.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomNet.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustom.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustomWarn.Visibility = Visibility.Collapsed
Case 1 '本地
FrmSetupUI.PanCustomPreset.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomLocal.Visibility = Visibility.Visible
FrmSetupUI.PanCustomNet.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustom.Visibility = Visibility.Visible
FrmSetupUI.HintCustomWarn.Visibility = If(Setup.Get("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible)
FrmSetupUI.HintCustom.Text = $"从 PCL 文件夹下的 Custom.xaml 读取主页内容。{vbCrLf}你可以手动编辑该文件,向主页添加文本、图片、常用网站、快捷启动等功能。"
CustomEventService.SetEventType(FrmSetupUI.HintCustom, CustomEvent.EventType.None)
Case 2 '联网
FrmSetupUI.PanCustomPreset.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomNet.Visibility = Visibility.Visible
FrmSetupUI.HintCustom.Visibility = Visibility.Visible
FrmSetupUI.HintCustomWarn.Visibility = If(Setup.Get("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible)
FrmSetupUI.HintCustom.Text = $"从指定网址联网获取主页内容。服主也可以用于动态更新服务器公告。{vbCrLf}如果你制作了稳定运行的联网主页,可以点击这条提示投稿,若合格即可加入预设!"
CustomEventService.SetEventType(FrmSetupUI.HintCustom, CustomEvent.EventType.打开网页)
CustomEventService.SetEventData(FrmSetupUI.HintCustom, "https://github.com/Meloong-Git/PCL/discussions/2528")
Case 3 '预设
FrmSetupUI.PanCustomPreset.Visibility = Visibility.Visible
FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomNet.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustom.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustomWarn.Visibility = Visibility.Collapsed
End Select
FrmSetupUI.CardCustom.TriggerForceResize()
End Sub
'顶部栏
Public Sub UiLogoType(Value As Integer)
Select Case Value
Case 0 '无
FrmMain.ShapeTitleLogo.Visibility = Visibility.Collapsed
FrmMain.LabTitleLogo.Visibility = Visibility.Collapsed
FrmMain.ImageTitleLogo.Visibility = Visibility.Collapsed
If Not IsNothing(FrmSetupUI) Then
FrmSetupUI.CheckLogoLeft.Visibility = Visibility.Visible
FrmSetupUI.PanLogoText.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoChange.Visibility = Visibility.Collapsed
End If
Case 1 '默认
FrmMain.ShapeTitleLogo.Visibility = Visibility.Visible
FrmMain.LabTitleLogo.Visibility = Visibility.Collapsed
FrmMain.ImageTitleLogo.Visibility = Visibility.Collapsed
If Not IsNothing(FrmSetupUI) Then
FrmSetupUI.CheckLogoLeft.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoText.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoChange.Visibility = Visibility.Collapsed
End If
Case 2 '文本
FrmMain.ShapeTitleLogo.Visibility = Visibility.Collapsed
FrmMain.LabTitleLogo.Visibility = Visibility.Visible
FrmMain.ImageTitleLogo.Visibility = Visibility.Collapsed
If Not IsNothing(FrmSetupUI) Then
FrmSetupUI.CheckLogoLeft.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoText.Visibility = Visibility.Visible
FrmSetupUI.PanLogoChange.Visibility = Visibility.Collapsed
End If
Setup.Load("UiLogoText", True)
Case 3 '图片
FrmMain.ShapeTitleLogo.Visibility = Visibility.Collapsed
FrmMain.LabTitleLogo.Visibility = Visibility.Collapsed
FrmMain.ImageTitleLogo.Visibility = Visibility.Visible
If Not IsNothing(FrmSetupUI) Then
FrmSetupUI.CheckLogoLeft.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoText.Visibility = Visibility.Collapsed
FrmSetupUI.PanLogoChange.Visibility = Visibility.Visible
End If
Try
FrmMain.ImageTitleLogo.Source = Path & "PCL\Logo.png"
Catch ex As Exception
FrmMain.ImageTitleLogo.Source = Nothing
Log(ex, "显示标题栏图片失败", LogLevel.Msgbox)
End Try
End Select
Setup.Load("UiLogoLeft", True)
If Not IsNothing(FrmSetupUI) Then FrmSetupUI.CardLogo.TriggerForceResize()
End Sub
Public Sub UiLogoText(Value As String)
FrmMain.LabTitleLogo.Text = Value
End Sub
Public Sub UiLogoLeft(Value As Boolean)
FrmMain.PanTitleMain.ColumnDefinitions(0).Width = New GridLength(If(Value AndAlso (Setup.Get("UiLogoType") = 0), 0, 1), GridUnitType.Star)
End Sub
'功能隐藏
Public Sub UiHiddenPageLink(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenPageDownload(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenPageSetup(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenPageOther(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenFunctionSelect(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenFunctionModUpdate(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenFunctionHidden(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenSetupLaunch(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenSetupUi(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenSetupLink(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenSetupSystem(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenOtherHelp(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenOtherFeedback(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenOtherVote(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenOtherAbout(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
Public Sub UiHiddenOtherTest(Value As Boolean)
PageSetupUI.HiddenRefresh()
End Sub
#End Region
#Region "System"
'调试选项
Public Sub SystemDebugMode(Value As Boolean)
ModeDebug = Value
End Sub
Public Sub SystemDebugAnim(Value As Integer)
AniSpeed = If(Value >= 30, 200, MathClamp(Value * 0.1 + 0.1, 0.1, 3))
End Sub
#End Region
#Region "Version"
'游戏内存
Public Sub VersionRamType(Type As Integer)
If FrmInstanceSetup Is Nothing Then Return
FrmInstanceSetup.RamType(Type)
End Sub
'服务器
Public Sub VersionServerLogin(Type As Integer)
If FrmInstanceSetup Is Nothing Then Return
'为第三方登录清空缓存以更新描述
WriteIni(McFolderSelected & "PCL.ini", "InstanceCache", "")
If PageInstanceLeft.Instance Is Nothing Then Return
PageInstanceLeft.Instance = New McInstance(PageInstanceLeft.Instance.Name).Load()
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
End Sub
#End Region
End Class
@@ -32,18 +32,25 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </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="ComboArgumentIndieV2" Grid.Row="0" Grid.ColumnSpan="2" Tag="LaunchArgumentIndieV2" Grid.Column="1" <local:MyComboBox local:SettingService.Key="LaunchArgumentIndieV2" x:Name="ComboArgumentIndieV2"
ToolTip="当安装新版本时,据此自动设置新版本的隔离选项。&#xa;若想调整已有版本的隔离策略,请前往它的版本设置。"> Grid.Row="0" Grid.ColumnSpan="2" Grid.Column="1"
<local:MyComboBoxItem Content="关闭" ToolTip="所有版本均使用同一档案,存档、Mod、资源包等均为公用。&#xa;若存在多个安装了 Mod 的版本,可能会导致 Mod 冲突。" /> ToolTip="当安装新版本时,据此自动设置新版本的隔离选项。&#xa;若想调整已有版本的隔离策略,请前往它的版本设置。">
<local:MyComboBoxItem Content="隔离可安装 Mod 的版本" IsSelected="True" ToolTip="可安装 Mod 的版本(例如 Forge、Fabric)均互相独立以避免 Mod 冲突,其他版本(例如原版)则不会被隔离。" /> <local:MyComboBoxItem Content="关闭"
<local:MyComboBoxItem Content="隔离非正式版" ToolTip="将 Minecraft 快照、预发布版、远古版本、愚人节版本与其他版本进行隔离" /> ToolTip="所有版本均使用同一档案,存档、Mod、资源包等均为公用。&#xa;若存在多个安装了 Mod 的版本,可能会导致 Mod 冲突。" />
<local:MyComboBoxItem Content="隔离可安装 Mod 的版本"
ToolTip="可安装 Mod 的版本(例如 Forge、Fabric)均互相独立以避免 Mod 冲突,其他版本(例如原版)则不会被隔离。" />
<local:MyComboBoxItem Content="隔离非正式版"
ToolTip="将 Minecraft 快照、预发布版、远古版本、愚人节版本与其他版本进行隔离" />
<local:MyComboBoxItem Content="隔离可安装 Mod 的版本与非正式版" /> <local:MyComboBoxItem Content="隔离可安装 Mod 的版本与非正式版" />
<local:MyComboBoxItem Content="隔离所有版本" ToolTip="不同版本之间的存档、Mod、资源包等均不互通。&#xa;这会导致不同原版版本间的存档不能共用,所以一般不推荐。" /> <local:MyComboBoxItem Content="隔离所有版本"
ToolTip="不同版本之间的存档、Mod、资源包等均不互通。&#xa;这会导致不同原版版本间的存档不能共用,所以一般不推荐。" />
</local:MyComboBox> </local:MyComboBox>
<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="TextArgumentTitle" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则不进行更改。&#xa;你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" HintText="默认" MaxLength="100" /> <local:MyTextBox local:SettingService.Key="LaunchArgumentTitle"
Grid.Row="2" Grid.ColumnSpan="2" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则不进行更改。&#xa;你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" HintText="默认" MaxLength="100" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义信息" Margin="0,0,25,0" /> <TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义信息" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchArgumentInfo" Text="PCL" Grid.Column="1" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。&#xa;你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。"> <local:MyTextBox local:SettingService.Key="LaunchArgumentInfo"
Grid.Row="4" Grid.ColumnSpan="2" Text="PCL" Grid.Column="1" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。&#xa;你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。">
<local:MyTextBox.ValidateRules> <local:MyTextBox.ValidateRules>
<local:ValidateExcept> <local:ValidateExcept>
<local:ValidateExcept.Excepts> <local:ValidateExcept.Excepts>
@@ -55,18 +62,18 @@
</local:MyTextBox.ValidateRules> </local:MyTextBox.ValidateRules>
</local:MyTextBox> </local:MyTextBox>
<TextBlock VerticalAlignment="Center" Grid.Row="6" HorizontalAlignment="Left" Text="启动器可见性" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" Grid.Row="6" HorizontalAlignment="Left" Text="启动器可见性" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboArgumentVisibie" Grid.Row="6" Grid.ColumnSpan="2" Tag="LaunchArgumentVisible" Grid.Column="1"> <local:MyComboBox local:SettingService.Key="LaunchArgumentVisible"
x:Name="ComboArgumentVisibie" Grid.Row="6" Grid.ColumnSpan="2" Grid.Column="1">
<local:MyComboBoxItem Content="游戏启动后立即关闭" /> <local:MyComboBoxItem Content="游戏启动后立即关闭" />
<local:MyComboBoxItem Content="" IsEnabled="False" Visibility="Collapsed" /> <local:MyComboBoxItem Content="游戏启动后隐藏,游戏退出后自动关闭" local:SettingService.Value="2" />
<local:MyComboBoxItem Content="游戏启动后隐藏,游戏退出后自动关闭" /> <local:MyComboBoxItem Content="游戏启动后隐藏,游戏退出后重新打开" local:SettingService.Value="3" />
<local:MyComboBoxItem Content="游戏启动后隐藏,游戏退出后重新打开" /> <local:MyComboBoxItem Content="游戏启动后最小化" local:SettingService.Value="4" />
<local:MyComboBoxItem Content="游戏启动后最小化" /> <local:MyComboBoxItem Content="游戏启动后仍保持不变" local:SettingService.Value="5" />
<local:MyComboBoxItem Content="游戏启动后仍保持不变" IsSelected="True" />
</local:MyComboBox> </local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="8" HorizontalAlignment="Left" Text="进程优先级" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" Grid.Row="8" HorizontalAlignment="Left" Text="进程优先级" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboArgumentPriority" Grid.Row="8" Grid.ColumnSpan="2" Tag="LaunchArgumentPriority" Grid.Column="1"> <local:MyComboBox local:SettingService.Key="LaunchArgumentPriority" Grid.Row="8" Grid.ColumnSpan="2" Grid.Column="1">
<local:MyComboBoxItem Content="高(优先保证游戏运行,游戏性能更佳,但可能造成其他程序卡顿)" /> <local:MyComboBoxItem Content="高(优先保证游戏运行,游戏性能更佳,但可能造成其他程序卡顿)" />
<local:MyComboBoxItem Content="中(平衡)" IsSelected="True" /> <local:MyComboBoxItem Content="中(平衡)" />
<local:MyComboBoxItem Content="低(优先保证其他程序运行,但可能让游戏卡顿,适合挂机时使用)" /> <local:MyComboBoxItem Content="低(优先保证其他程序运行,但可能让游戏卡顿,适合挂机时使用)" />
</local:MyComboBox> </local:MyComboBox>
<TextBlock VerticalAlignment="Center" Grid.Row="10" HorizontalAlignment="Left" Text="窗口大小" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" Grid.Row="10" HorizontalAlignment="Left" Text="窗口大小" Margin="0,0,25,0" />
@@ -77,28 +84,30 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:MyComboBox x:Name="ComboArgumentWindowType" Tag="LaunchArgumentWindowType"> <local:MyComboBox local:SettingService.Key="LaunchArgumentWindowType" x:Name="ComboArgumentWindowType">
<local:MyComboBoxItem Content="全屏" /> <local:MyComboBoxItem Content="全屏" />
<local:MyComboBoxItem Content="默认" IsSelected="True" /> <local:MyComboBoxItem Content="默认" />
<local:MyComboBoxItem Content="与启动器尺寸一致" /> <local:MyComboBoxItem Content="与启动器尺寸一致" />
<local:MyComboBoxItem Content="自定义尺寸" ToolTip="Forge 1.12.2 等个别版本存在 Bug,会导致高度设定无效" /> <local:MyComboBoxItem Content="自定义尺寸" ToolTip="Forge 1.12.2 等个别版本存在 Bug,会导致高度设定无效" />
<local:MyComboBoxItem Content="最大化" /> <local:MyComboBoxItem Content="最大化" />
</local:MyComboBox> </local:MyComboBox>
<local:MyTextBox Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="1" Margin="50,0,0,0" x:Name="TextArgumentWindowWidth" Tag="LaunchArgumentWindowWidth" Width="60" HorizontalContentAlignment="Center" Text="854"> <local:MyTextBox local:SettingService.Key="LaunchArgumentWindowWidth" x:Name="TextArgumentWindowWidth"
Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="1" Margin="50,0,0,0" Width="60" HorizontalContentAlignment="Center" Text="854">
<local:MyTextBox.ValidateRules> <local:MyTextBox.ValidateRules>
<local:ValidateInteger Min="1" Max="99999" /> <local:ValidateInteger Min="1" Max="99999" />
</local:MyTextBox.ValidateRules> </local:MyTextBox.ValidateRules>
</local:MyTextBox> </local:MyTextBox>
<TextBlock x:Name="LabArgumentWindowMiddle" Visibility="Collapsed" Grid.Column="2" Text=" × " VerticalAlignment="Center" FontSize="18" /> <TextBlock x:Name="LabArgumentWindowMiddle" Visibility="Collapsed" Grid.Column="2" Text=" × " VerticalAlignment="Center" FontSize="18" />
<local:MyTextBox Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="3" Width="60" HorizontalContentAlignment="Center" x:Name="TextArgumentWindowHeight" Tag="LaunchArgumentWindowHeight" Text="480" <local:MyTextBox local:SettingService.Key="LaunchArgumentWindowHeight" x:Name="TextArgumentWindowHeight"
ToolTip="Forge 1.12.2 等个别版本存在 Bug,会导致高度设定无效" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5"> Padding="0,0,5,0" Visibility="Collapsed" Grid.Column="3" Width="60" HorizontalContentAlignment="Center" Text="480"
ToolTip="Forge 1.12.2 等个别版本存在 Bug,会导致高度设定无效" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5">
<local:MyTextBox.ValidateRules> <local:MyTextBox.ValidateRules>
<local:ValidateInteger Min="1" Max="99999" /> <local:ValidateInteger Min="1" Max="99999" />
</local:MyTextBox.ValidateRules> </local:MyTextBox.ValidateRules>
</local:MyTextBox> </local:MyTextBox>
</Grid> </Grid>
<TextBlock VerticalAlignment="Center" Grid.Row="12" HorizontalAlignment="Left" Text="游戏 Java" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" Grid.Row="12" HorizontalAlignment="Left" Text="游戏 Java" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboArgumentJava" Grid.ColumnSpan="2" Grid.Row="12" Grid.Column="1" MaxDropDownHeight="240" <local:MyComboBox x:Name="ComboArgumentJava" Grid.ColumnSpan="2" Grid.Row="12" Grid.Column="1"
ToolTip="若将 Java 放在游戏文件夹或 PCL 文件夹,在进行自动选择时 PCL 会尽量优先选择它"> ToolTip="若将 Java 放在游戏文件夹或 PCL 文件夹,在进行自动选择时 PCL 会尽量优先选择它">
<ComboBoxItem Content="加载中……" IsSelected="True" /> <ComboBoxItem Content="加载中……" IsSelected="True" />
<!--<local:MyComboBoxItem Content="Java 8 (1.8.0_171),64 位:C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" IsSelected="True" ToolTip="C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe" />--> <!--<local:MyComboBoxItem Content="Java 8 (1.8.0_171),64 位:C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="5" IsSelected="True" ToolTip="C:\Program Files (x86)\Common Files\Oracle\Java\javapath\javaw.exe" />-->
@@ -116,7 +125,7 @@
</Grid> </Grid>
</StackPanel> </StackPanel>
</local:MyCard> </local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="游戏内存"> <local:MyCard Margin="0,0,0,15" Title="内存分配">
<StackPanel Margin="25,40,25,15"> <StackPanel Margin="25,40,25,15">
<local:MyHint x:Name="LabRamWarn" Visibility="Visible" Text="32 位 Java 只能分配最多 1 GB 的内存。强烈建议换用 64 位的 Java!" Theme="Yellow" Margin="0,0,0,12" /> <local:MyHint x:Name="LabRamWarn" Visibility="Visible" Text="32 位 Java 只能分配最多 1 GB 的内存。强烈建议换用 64 位的 Java!" Theme="Yellow" Margin="0,0,0,12" />
<Grid Margin="0,0,0,3"> <Grid Margin="0,0,0,3">
@@ -131,13 +140,16 @@
<RowDefinition Height="9" /> <RowDefinition Height="9" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<local:MyRadioBox Text="自动配置" Width="110" Checked="True" x:Name="RadioRamType0" Tag="LaunchRamType/0" Margin="0,0,20,0" <local:MyRadioBox local:SettingService.Key="LaunchRamType" local:SettingService.Value="0"
ToolTip="根据安装的 Mod 量与电脑剩余内存,动态调整为游戏分配的内存" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="-10" ToolTipService.VerticalOffset="-3" /> Text="自动配置" Width="110" Checked="True" x:Name="RadioRamType0" Margin="0,0,20,0"
<local:MyRadioBox Grid.Row="2" Text="自定义" x:Name="RadioRamType1" Tag="LaunchRamType/1" Margin="0,0,20,0" /> ToolTip="根据安装的 Mod 量与电脑剩余内存,动态调整为游戏分配的内存" ToolTipService.Placement="Right" ToolTipService.HorizontalOffset="-10" ToolTipService.VerticalOffset="-3" />
<local:MySlider Grid.Row="2" Grid.Column="1" IsEnabled="False" x:Name="SliderRamCustom" Tag="LaunchRamCustom" MaxValue="49" Value="13" /> <local:MyRadioBox local:SettingService.Key="LaunchRamType" local:SettingService.Value="1"
<local:MyCheckBox Grid.Row="4" Grid.ColumnSpan="3" Text="启动游戏前进行内存优化" Height="22" x:Name="CheckArgumentRam" Tag="LaunchArgumentRam" Grid.Row="2" Text="自定义" x:Name="RadioRamType1" Margin="0,0,20,0" />
ToolTipService.Placement="Left" ToolTipService.HorizontalOffset="525" ToolTipService.VerticalOffset="-30" <local:MySlider Grid.Row="2" Grid.Column="1" IsEnabled="False" x:Name="SliderRamCustom" local:SettingService.Key="LaunchRamCustom" MaxValue="49" Value="13" />
ToolTip="内存优化能将当前物理内存占用降低约 1/3,不仅限于 MC!&#xa;如果使用机械硬盘,这还可能会导致一小段时间的严重卡顿。&#xa;使用 --memory 参数启动 PCL 可以静默执行内存优化。" /> <local:MyCheckBox local:SettingService.Key="LaunchArgumentRam"
Grid.Row="4" Grid.ColumnSpan="3" Text="启动游戏前进行内存优化" Height="22" x:Name="CheckArgumentRam"
ToolTipService.Placement="Left" ToolTipService.HorizontalOffset="525" ToolTipService.VerticalOffset="-30"
ToolTip="内存优化能将当前物理内存占用降低约 1/3,不仅限于 MC!&#xa;如果使用机械硬盘,这还可能会导致一小段时间的严重卡顿。&#xa;使用 --memory 参数启动 PCL 可以静默执行内存优化。" />
<!--<local:MyTextBox Grid.Row="2" Grid.Column="3" Width="100" VerticalAlignment="Center" Margin="30,0,0,0" Text="2048 MB" />--> <!--<local:MyTextBox Grid.Row="2" Grid.Column="3" Width="100" VerticalAlignment="Center" Margin="30,0,0,0" Text="2048 MB" />-->
</Grid> </Grid>
<Grid x:Name="PanRamDisplay" Margin="0,11,2,0" SnapsToDevicePixels="True" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1"> <Grid x:Name="PanRamDisplay" Margin="0,11,2,0" SnapsToDevicePixels="True" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1">
@@ -182,11 +194,21 @@
<ColumnDefinition /> <ColumnDefinition />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:MyRadioBox Text="随机" x:Name="RadioSkinType0" Height="22" Tag="LaunchSkinType/0" Grid.Column="0" ToolTip="随机选择一个默认皮肤" /> <local:MyRadioBox local:SettingService.Key="LaunchSkinType" local:SettingService.Value="0"
<local:MyRadioBox Text="Steve" x:Name="RadioSkinType1" Height="22" Tag="LaunchSkinType/1" Grid.Column="1" /> x:Name="RadioSkinType0" Height="22" Grid.Column="0"
<local:MyRadioBox Text="Alex" x:Name="RadioSkinType2" Height="22" Tag="LaunchSkinType/2" Grid.Column="2" /> Text="随机" ToolTip="随机选择一个默认皮肤" />
<local:MyRadioBox Text="正版皮肤" x:Name="RadioSkinType3" Height="22" Tag="LaunchSkinType/3" Grid.Column="3" ToolTip="使用某个正版玩家的皮肤" /> <local:MyRadioBox local:SettingService.Key="LaunchSkinType" local:SettingService.Value="1"
<local:MyRadioBox Text="自定义" x:Name="RadioSkinType4" Height="22" Tag="LaunchSkinType/4" Grid.Column="4" ToolTip="以资源包的形式加载自定义皮肤。&#xa;使用此方式更换的皮肤在多人游戏中仅自己可见,且会替换游戏中所有的角色。" /> x:Name="RadioSkinType1" Height="22" Grid.Column="1"
Text="Steve" />
<local:MyRadioBox local:SettingService.Key="LaunchSkinType" local:SettingService.Value="2"
x:Name="RadioSkinType2" Height="22" Grid.Column="2"
Text="Alex" />
<local:MyRadioBox local:SettingService.Key="LaunchSkinType" local:SettingService.Value="3"
x:Name="RadioSkinType3" Height="22" Grid.Column="3"
Text="正版皮肤" ToolTip="使用某个正版玩家的皮肤" />
<local:MyRadioBox local:SettingService.Key="LaunchSkinType" local:SettingService.Value="4"
x:Name="RadioSkinType4" Height="22" Grid.Column="4"
Text="自定义" ToolTip="以资源包的形式加载自定义皮肤。&#xa;使用此方式更换的皮肤在多人游戏中仅自己可见,且会替换游戏中所有的角色。" />
</Grid> </Grid>
<Grid x:Name="PanSkinID" Margin="0,14,0,2" Visibility="Collapsed"> <Grid x:Name="PanSkinID" Margin="0,14,0,2" Visibility="Collapsed">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -198,7 +220,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="正版玩家名" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="正版玩家名" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextSkinID" Tag="LaunchSkinID" Grid.Column="1" MaxLength="50" /> <local:MyTextBox local:SettingService.Key="LaunchSkinID" Grid.Column="1" MaxLength="50" />
<Grid Height="35" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,14,0,0"> <Grid Height="35" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,14,0,0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" /> <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
@@ -231,6 +253,8 @@
<RowDefinition Height="9" /> <RowDefinition Height="9" />
<RowDefinition Height="28" /> <RowDefinition Height="28" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
@@ -240,22 +264,38 @@
ToolTip="还原" ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="200" ToolTipService.VerticalOffset="-1" 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" /> 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> </StackPanel>
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Tag="LaunchAdvanceJvm" Grid.Column="1" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,除非有确定把握,否则请不要修改。&#xa;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" MaxLength="4000" <local:MyTextBox local:SettingService.Key="LaunchAdvanceJvm" x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Grid.Column="1"
Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" /> ToolTip="启动 Minecraft 时使用的额外 JVM 参数,除非有确定把握,否则请不要修改。&#xa;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" 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;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" /> <local:MyTextBox local:SettingService.Key="LaunchAdvanceGame" x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,0" /> <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="" <local:MyTextBox local:SettingService.Key="LaunchAdvanceRun" x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="1" HintText=""
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" /> ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="LaunchAdvanceRunWait" Visibility="Collapsed" <local:MyCheckBox local:SettingService.Key="LaunchAdvanceRunWait" x:Name="CheckAdvanceRunWait" Grid.Row="5" Grid.Column="1" Visibility="Collapsed"
Text="等待命令执行完成后再继续启动" Margin="0,8,0,7" /> Text="等待命令执行完成后再继续启动" Margin="0,8,0,7" />
<StackPanel Margin="0,12,0,4" Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Left"> <TextBlock VerticalAlignment="Center" Grid.Row="7" HorizontalAlignment="Left" Text="内存管理" Margin="0,0,25,0" />
<local:MyCheckBox Height="28" Text="禁用 Java Launch Wrapper" x:Name="CheckAdvanceDisableJLW" Tag="LaunchAdvanceDisableJLW" <local:MyComboBox local:SettingService.Key="LaunchAdvanceGC" Grid.Row="7" Grid.ColumnSpan="2" Grid.Column="1">
ToolTipService.Placement="Right" ToolTip="PCL 会使用 Java Launch Wrapper 来修复老版本 Java 在中文路径下无法启动的问题。&#xa;如果这被反作弊拦截,或遇到其他问题,也可以将其关闭。" /> <local:MyComboBoxItem Content="尽量使用 ZGC"
<local:MyCheckBox Height="28" Text="使用高性能显卡" x:Name="CheckAdvanceGraphicCard" Tag="LaunchAdvanceGraphicCard" ToolTipService.BetweenShowDelay="0" ToolTip="在 Java 21+ 使用分代 ZGC,20~15 使用非分代的 ZGC,14- 使用 G1GC。&#xa;ZGC 的内存占用比 G1GC 更高,不过在回收内存时不会导致卡顿。&#xa;覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
<local:MyComboBoxItem Content="尽量使用分代 ZGC"
ToolTipService.BetweenShowDelay="0" ToolTip="在 Java 21+ 使用分代 ZGC,20- 使用 G1GC。&#xa;ZGC 的内存占用比 G1GC 更高,不过在回收内存时不会导致卡顿。&#xa;覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
<local:MyComboBoxItem Content="标准 G1GC"
ToolTipService.BetweenShowDelay="0" ToolTip="总是使用 G1GC,附带 Mojang 官方的优化参数。&#xa;G1GC 的内存占用比 ZGC 更低,但在回收内存时会导致突然的卡顿。&#xa;覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
<local:MyComboBoxItem Content="调优 G1GC" local:SettingService.Value="4"
ToolTipService.BetweenShowDelay="0" ToolTip="总是使用 G1GC,附带 PCL 调优过的优化参数。&#xa;G1GC 的内存占用比 ZGC 更低,但在回收内存时会导致突然的卡顿。&#xa;覆盖 “Java 虚拟机参数” 设置中的 GC 相关参数。" />
<local:MyComboBoxItem Content="不指定(可自定义)" local:SettingService.Value="3"
ToolTipService.BetweenShowDelay="0" ToolTip="不自动添加 GC 参数。&#xa;仅当选择此项时,你可以在 “Java 虚拟机参数” 设置中手动添加 GC 参数。" />
</local:MyComboBox>
<StackPanel Margin="0,12,0,4" Grid.Row="8" Grid.ColumnSpan="2" HorizontalAlignment="Left">
<local:MyCheckBox Height="28" Text="禁用 Java Launch Wrapper" local:SettingService.Key="LaunchAdvanceDisableJLW"
ToolTipService.Placement="Right" ToolTip="是否使用 Java Launch Wrapper 修复 Java 18- 在中文路径下可能无法正常启动的问题。&#xa;详见:https://github.com/00ll00/java_launch_wrapper" />
<local:MyCheckBox Height="28" Text="禁用 LWJGL Unsafe Agent" local:SettingService.Key="LaunchAdvanceDisableLUA"
ToolTipService.Placement="Right" ToolTip="是否使用 LWJGL Unsafe Agent 修复 Java 25+ 的一个性能问题。&#xa;详见:https://github.com/HMCL-dev/lwjgl-unsafe-agent" />
<local:MyCheckBox Height="28" Text="使用高性能显卡" local:SettingService.Key="LaunchAdvanceGraphicCard"
ToolTipService.Placement="Right" ToolTip="自动在 Windows 设置 → 系统 → 屏幕 → 显示卡 中将 PCL 和 Java 改为使用高性能显卡。&#xa;如果同时有集成显卡和独立显卡,这能确保 MC 使用独立显卡进行渲染,以大幅提高帧率。" /> ToolTipService.Placement="Right" ToolTip="自动在 Windows 设置 → 系统 → 屏幕 → 显示卡 中将 PCL 和 Java 改为使用高性能显卡。&#xa;如果同时有集成显卡和独立显卡,这能确保 MC 使用独立显卡进行渲染,以大幅提高帧率。" />
</StackPanel> </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="9" Grid.ColumnSpan="2"
CanClose="True" RelativeSetup="HintMoreAdvancedSetup" /> CanClose="True" RelativeSetup="HintMoreAdvancedSetup" />
</Grid> </Grid>
</local:MyCard> </local:MyCard>
@@ -1,63 +1,31 @@
Public Class PageSetupLaunch Public Class PageSetupLaunch
Private IsLoad As Boolean = False
Private Sub PageSetupLaunch_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded Private Sub PageSetupLaunch_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
'重复加载部分 '重复加载部分
PanBack.ScrollToHome() PanBack.ScrollToHome()
RefreshRam(False) RefreshRam(False)
If McInstanceSelected Is Nothing Then BtnSwitch.Visibility = If(McInstanceSelected Is Nothing, Visibility.Collapsed, Visibility.Visible)
BtnSwitch.Visibility = Visibility.Collapsed
Else
BtnSwitch.Visibility = Visibility.Visible
End If
'非重复加载部分 '非重复加载部分
If IsLoad Then Return Static Reloaded As Boolean = False
IsLoad = True If Reloaded Then Return
Reloaded = True
AniControlEnabled += 1 AniControlEnabled += 1
Reload() Refresh()
AniControlEnabled -= 1 AniControlEnabled -= 1
'内存自动刷新 '内存自动刷新
Dim timer As New Threading.DispatcherTimer With {.Interval = New TimeSpan(0, 0, 0, 1)} Dim timer As New Threading.DispatcherTimer With {.Interval = New TimeSpan(0, 0, 0, 1)}
AddHandler timer.Tick, AddressOf RefreshRam AddHandler timer.Tick, AddressOf RefreshRam
timer.Start() timer.Start()
End Sub End Sub
Public Sub Reload() Public Sub Refresh()
Try Try
SettingService.RefreshSettings(Me)
'离线皮肤 UpdateSkinType()
CType(FindName("RadioSkinType" & Setup.Load("LaunchSkinType")), MyRadioBox).Checked = True UpdateRamType()
TextSkinID.Text = Setup.Get("LaunchSkinID") UpdateJavaComboBox()
'启动参数
TextArgumentTitle.Text = Setup.Get("LaunchArgumentTitle")
TextArgumentInfo.Text = Setup.Get("LaunchArgumentInfo")
ComboArgumentIndieV2.SelectedIndex = Setup.Get("LaunchArgumentIndieV2")
ComboArgumentVisibie.SelectedIndex = Setup.Get("LaunchArgumentVisible")
ComboArgumentPriority.SelectedIndex = Setup.Get("LaunchArgumentPriority")
ComboArgumentWindowType.SelectedIndex = Setup.Get("LaunchArgumentWindowType")
TextArgumentWindowWidth.Text = Setup.Get("LaunchArgumentWindowWidth")
TextArgumentWindowHeight.Text = Setup.Get("LaunchArgumentWindowHeight")
CheckArgumentRam.Checked = Setup.Get("LaunchArgumentRam")
RefreshJavaComboBox()
'游戏内存
CType(FindName("RadioRamType" & Setup.Load("LaunchRamType")), MyRadioBox).Checked = True
SliderRamCustom.Value = Setup.Get("LaunchRamCustom")
'高级设置
TextAdvanceJvm.Text = Setup.Get("LaunchAdvanceJvm")
TextAdvanceGame.Text = Setup.Get("LaunchAdvanceGame")
TextAdvanceRun.Text = Setup.Get("LaunchAdvanceRun")
CheckAdvanceRunWait.Checked = Setup.Get("LaunchAdvanceRunWait")
CheckAdvanceDisableJLW.Checked = Setup.Get("LaunchAdvanceDisableJLW")
CheckAdvanceGraphicCard.Checked = Setup.Get("LaunchAdvanceGraphicCard")
Catch ex As NullReferenceException Catch ex As NullReferenceException
Log(ex, "启动设置项存在异常,已被自动重置", LogLevel.Msgbox) Log(ex, "启动设置项存在异常,已被自动重置", LogLevel.Msgbox)
Reset() Reset()
@@ -65,57 +33,18 @@
Log(ex, "重载启动设置时出错", LogLevel.Feedback) Log(ex, "重载启动设置时出错", LogLevel.Feedback)
End Try End Try
End Sub End Sub
'初始化
Public Sub Reset() Public Sub Reset()
Try Try
Setup.Reset("LaunchArgumentTitle") SettingService.ResetSettings(Me)
Setup.Reset("LaunchArgumentInfo") Settings.Set("LaunchArgumentIndieV2", Settings.GetDefault("LaunchArgumentIndieV2"))
Setup.Set("LaunchArgumentIndieV2", Setup.GetDefault("LaunchArgumentIndieV2")) Settings.Reset("LaunchArgumentJavaAll")
Setup.Reset("LaunchArgumentVisible") Settings.Reset("LaunchArgumentJavaSelect")
Setup.Reset("LaunchArgumentWindowType")
Setup.Reset("LaunchArgumentWindowWidth")
Setup.Reset("LaunchArgumentWindowHeight")
Setup.Reset("LaunchArgumentPriority")
Setup.Reset("LaunchArgumentRam")
Setup.Reset("LaunchRamType")
Setup.Reset("LaunchRamCustom")
Setup.Reset("LaunchSkinType")
Setup.Reset("LaunchSkinID")
Setup.Reset("LaunchAdvanceJvm")
Setup.Reset("LaunchAdvanceGame")
Setup.Reset("LaunchAdvanceRun")
Setup.Reset("LaunchAdvanceRunWait")
Setup.Reset("LaunchAdvanceDisableJLW")
Setup.Reset("LaunchAdvanceGraphicCard")
Setup.Reset("LaunchArgumentJavaAll")
Setup.Reset("LaunchArgumentJavaSelect")
JavaSearchLoader.Start(IsForceRestart:=True) JavaSearchLoader.Start(IsForceRestart:=True)
Hint("已初始化启动设置!", HintType.Green)
Log("[Setup] 已初始化启动设置")
Hint("已初始化启动设置!", HintType.Green, False)
Catch ex As Exception Catch ex As Exception
Log(ex, "初始化启动设置失败", LogLevel.Msgbox) Log(ex, "初始化启动设置失败", LogLevel.Msgbox)
End Try End Try
Refresh()
Reload()
End Sub
'将控件改变路由到设置改变
Private Shared Sub RadioBoxChange(sender As MyRadioBox, e As Object) Handles RadioSkinType0.Check, RadioSkinType1.Check, RadioSkinType2.Check, RadioSkinType3.Check, RadioSkinType4.Check, RadioRamType0.Check, RadioRamType1.Check
If AniControlEnabled = 0 Then Setup.Set(sender.Tag.ToString.Split("/")(0), Val(sender.Tag.ToString.Split("/")(1)))
End Sub
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextSkinID.ValidatedTextChanged, TextArgumentWindowHeight.ValidatedTextChanged, TextArgumentWindowWidth.ValidatedTextChanged, TextArgumentInfo.ValidatedTextChanged, TextAdvanceGame.ValidatedTextChanged, TextAdvanceJvm.ValidatedTextChanged, TextArgumentTitle.ValidatedTextChanged, TextAdvanceRun.ValidatedTextChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Text)
End Sub
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderRamCustom.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value)
End Sub
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboArgumentIndieV2.SelectionChanged, ComboArgumentVisibie.SelectionChanged, ComboArgumentWindowType.SelectionChanged, ComboArgumentPriority.SelectionChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex)
End Sub
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckAdvanceRunWait.Change, CheckArgumentRam.Change, CheckAdvanceDisableJLW.Change, CheckAdvanceGraphicCard.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
End Sub End Sub
#Region "离线皮肤" #Region "离线皮肤"
@@ -156,7 +85,7 @@
NewBitmap.Save(PathAppdata & "CustomSkin.png") NewBitmap.Save(PathAppdata & "CustomSkin.png")
End If End If
'更新设置 '更新设置
Setup.Set("LaunchSkinSlim", SkinInfo.IsSlim) Settings.Set("LaunchSkinSlim", SkinInfo.IsSlim)
ChangeSkin = True ChangeSkin = True
Catch ex As Exception Catch ex As Exception
Log(ex, "改变离线皮肤失败", LogLevel.Msgbox) Log(ex, "改变离线皮肤失败", LogLevel.Msgbox)
@@ -182,13 +111,31 @@
MySkin.RefreshCache(Nothing) MySkin.RefreshCache(Nothing)
End Sub End Sub
Public Shared Sub UpdateSkinType()
PageLaunchLeft.SkinLegacy.Start()
'设置 UI 改变
If FrmSetupLaunch Is Nothing Then Return
Select Case Settings.Get("LaunchSkinType")
Case 0, 1, 2 '默认
FrmSetupLaunch.PanSkinID.Visibility = Visibility.Collapsed
FrmSetupLaunch.PanSkinChange.Visibility = Visibility.Collapsed
Case 3 '正版
FrmSetupLaunch.PanSkinID.Visibility = Visibility.Visible
FrmSetupLaunch.PanSkinChange.Visibility = Visibility.Collapsed
Case 4 '自定义
FrmSetupLaunch.PanSkinID.Visibility = Visibility.Collapsed
FrmSetupLaunch.PanSkinChange.Visibility = Visibility.Visible
End Select
FrmSetupLaunch.CardSkin.TriggerForceResize()
End Sub
#End Region #End Region
#Region "游戏内存" #Region "游戏内存"
Public Sub RamType(Type As Integer) Public Shared Sub UpdateRamType()
If SliderRamCustom Is Nothing Then Return If FrmSetupLaunch?.SliderRamCustom Is Nothing Then Return
SliderRamCustom.IsEnabled = (Type = 1) FrmSetupLaunch.SliderRamCustom.IsEnabled = Settings.Get("LaunchRamType") = 1
End Sub End Sub
''' <summary> ''' <summary>
@@ -331,7 +278,7 @@
'------------------------------------------ '------------------------------------------
Dim RamGive As Double Dim RamGive As Double
If Setup.Get("LaunchRamType") = 0 Then If Settings.Get("LaunchRamType") = 0 Then
'自动配置 '自动配置
Dim RamAvailable As Double = Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024 / 1024 * 10) / 10 Dim RamAvailable As Double = Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024 / 1024 * 10) / 10
'确定需求的内存值 '确定需求的内存值
@@ -343,7 +290,7 @@
If Instance IsNot Nothing AndAlso Instance.Modable Then If Instance IsNot Nothing AndAlso Instance.Modable Then
'可安装 Mod 的版本 '可安装 Mod 的版本
Dim ModDir As New DirectoryInfo(Instance.PathIndie & "mods\") Dim ModDir As New DirectoryInfo(Instance.PathIndie & "mods\")
Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Length, 0) Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Count(Function(f) {".jar", ".zip", ".litemod"}.Contains(f.Extension.Lower)), 0)
RamMininum = 0.5 + ModCount / 150 RamMininum = 0.5 + ModCount / 150
RamTarget1 = 1.5 + ModCount / 90 RamTarget1 = 1.5 + ModCount / 90
RamTarget2 = 2.7 + ModCount / 50 RamTarget2 = 2.7 + ModCount / 50
@@ -387,7 +334,7 @@ PreFin:
RamGive = Math.Round(Math.Max(RamGive, RamMininum), 1) RamGive = Math.Round(Math.Max(RamGive, RamMininum), 1)
Else Else
'手动配置 '手动配置
Dim Value As Integer = Setup.Get("LaunchRamCustom") Dim Value As Integer = Settings.Get("LaunchRamCustom")
If Value <= 12 Then If Value <= 12 Then
RamGive = Value * 0.1 + 0.3 RamGive = Value * 0.1 + 0.3
ElseIf Value <= 25 Then ElseIf Value <= 25 Then
@@ -408,14 +355,14 @@ PreFin:
#Region "Java 选择" #Region "Java 选择"
'刷新 Java 下拉框显示 '刷新 Java 下拉框显示
Public Sub RefreshJavaComboBox() Public Sub UpdateJavaComboBox()
If ComboArgumentJava Is Nothing Then Return If ComboArgumentJava Is Nothing Then Return
'初始化列表 '初始化列表
ComboArgumentJava.Items.Clear() ComboArgumentJava.Items.Clear()
ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "自动选择合适的 Java", .Tag = "自动选择"}) ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "自动选择合适的 Java", .Tag = "自动选择"})
'更新列表 '更新列表
Dim SelectedItem As MyComboBoxItem = Nothing Dim SelectedItem As MyComboBoxItem = Nothing
Dim SelectedBySetup As String = Setup.Get("LaunchArgumentJavaSelect") Dim SelectedBySetup As String = Settings.Get("LaunchArgumentJavaSelect")
Try Try
For Each Java In JavaList.Clone().OrderByDescending(Function(v) v.MajorVersion) For Each Java In JavaList.Clone().OrderByDescending(Function(v) v.MajorVersion)
Dim ListItem = New MyComboBoxItem With {.Content = Java.ToString, .ToolTip = Java.PathFolder, .Tag = Java} Dim ListItem = New MyComboBoxItem With {.Content = Java.ToString, .ToolTip = Java.PathFolder, .Tag = Java}
@@ -426,7 +373,7 @@ PreFin:
If JavaEntry.FromJson(GetJson(SelectedBySetup)).PathFolder = Java.PathFolder Then SelectedItem = ListItem If JavaEntry.FromJson(GetJson(SelectedBySetup)).PathFolder = Java.PathFolder Then SelectedItem = ListItem
Next Next
Catch ex As Exception Catch ex As Exception
Setup.Set("LaunchArgumentJavaSelect", "") Settings.Set("LaunchArgumentJavaSelect", "")
Log(ex, "更新设置 Java 下拉框失败", LogLevel.Feedback) Log(ex, "更新设置 Java 下拉框失败", LogLevel.Feedback)
End Try End Try
'更新选择项 '更新选择项
@@ -455,11 +402,11 @@ PreFin:
Dim SelectedJava = ComboArgumentJava.SelectedItem.Tag Dim SelectedJava = ComboArgumentJava.SelectedItem.Tag
If "自动选择".Equals(SelectedJava) Then If "自动选择".Equals(SelectedJava) Then
'选择 “自动” '选择 “自动”
Setup.Set("LaunchArgumentJavaSelect", "") Settings.Set("LaunchArgumentJavaSelect", "")
Log("[Java] 修改 Java 选择设置:自动选择") Log("[Java] 修改 Java 选择设置:自动选择")
Else Else
'选择指定项 '选择指定项
Setup.Set("LaunchArgumentJavaSelect", CType(SelectedJava.ToJson(), JObject).ToString(Newtonsoft.Json.Formatting.None)) Settings.Set("LaunchArgumentJavaSelect", CType(SelectedJava.ToJson(), JObject).ToString(Newtonsoft.Json.Formatting.None))
Log("[Java] 修改 Java 选择设置:" & SelectedJava.ToString) Log("[Java] 修改 Java 选择设置:" & SelectedJava.ToString)
End If End If
RefreshRam(True) RefreshRam(True)
@@ -481,12 +428,12 @@ PreFin:
NewEntry.Check() NewEntry.Check()
'加入列表 '加入列表
Dim JavaNewList As New JArray From {NewEntry.ToJson} Dim JavaNewList As New JArray From {NewEntry.ToJson}
For Each JsonEntry In GetJson(Setup.Get("LaunchArgumentJavaAll")) For Each JsonEntry In GetJson(Settings.Get("LaunchArgumentJavaAll"))
Dim Entry = JavaEntry.FromJson(JsonEntry) Dim Entry = JavaEntry.FromJson(JsonEntry)
If Entry.PathFolder = NewEntry.PathFolder Then Continue For If Entry.PathFolder = NewEntry.PathFolder Then Continue For
JavaNewList.Add(JsonEntry) JavaNewList.Add(JsonEntry)
Next Next
Setup.Set("LaunchArgumentJavaAll", JavaNewList.ToString(Newtonsoft.Json.Formatting.None)) Settings.Set("LaunchArgumentJavaAll", JavaNewList.ToString(Newtonsoft.Json.Formatting.None))
'重新加载列表 '重新加载列表
JavaSearchLoader.Start(IsForceRestart:=True) JavaSearchLoader.Start(IsForceRestart:=True)
Hint("已将该 Java 加入 Java 列表!", HintType.Green) Hint("已将该 Java 加入 Java 列表!", HintType.Green)
@@ -518,16 +465,10 @@ PreFin:
#Region "其他选项" #Region "其他选项"
Private Sub WindowTypeUIRefresh() Handles ComboArgumentWindowType.SelectionChanged Private Sub WindowTypeUIRefresh() Handles ComboArgumentWindowType.SelectionChanged
If ComboArgumentWindowType Is Nothing Then Return Dim IsVisibie = (ComboArgumentWindowType.SelectedIndex = 3).ToVisibility
If ComboArgumentWindowType.SelectedIndex = 3 AndAlso LabArgumentWindowMiddle IsNot Nothing AndAlso LabArgumentWindowMiddle.Visibility = Visibility.Collapsed Then TextArgumentWindowHeight.Visibility = IsVisibie
LabArgumentWindowMiddle.Visibility = Visibility.Visible LabArgumentWindowMiddle.Visibility = IsVisibie
TextArgumentWindowHeight.Visibility = Visibility.Visible TextArgumentWindowWidth.Visibility = IsVisibie
TextArgumentWindowWidth.Visibility = Visibility.Visible
ElseIf ComboArgumentWindowType.SelectedIndex <> 3 AndAlso LabArgumentWindowMiddle IsNot Nothing AndAlso LabArgumentWindowMiddle.Visibility = Visibility.Visible Then
LabArgumentWindowMiddle.Visibility = Visibility.Collapsed
TextArgumentWindowHeight.Visibility = Visibility.Collapsed
TextArgumentWindowWidth.Visibility = Visibility.Collapsed
End If
End Sub End Sub
'可见性选择直接关闭的警告 '可见性选择直接关闭的警告
@@ -569,11 +510,20 @@ PreFin:
'JVM 参数重设 'JVM 参数重设
Private Sub TextAdvanceJvm_TextChanged() Handles TextAdvanceJvm.ValidatedTextChanged Private Sub TextAdvanceJvm_TextChanged() Handles TextAdvanceJvm.ValidatedTextChanged
BtnAdvanceJvmReset.Visibility = If(TextAdvanceJvm.Text = Setup.GetDefault("LaunchAdvanceJvm"), Visibility.Hidden, Visibility.Visible) BtnAdvanceJvmReset.Visibility = If(TextAdvanceJvm.Text = Settings.GetDefault("LaunchAdvanceJvm"), Visibility.Hidden, Visibility.Visible)
End Sub End Sub
Private Sub BtnAdvanceJvmReset_Click(sender As Object, e As EventArgs) Handles BtnAdvanceJvmReset.Click Private Sub BtnAdvanceJvmReset_Click(sender As Object, e As EventArgs) Handles BtnAdvanceJvmReset.Click
Setup.Reset("LaunchAdvanceJvm") Settings.Reset("LaunchAdvanceJvm")
Reload() Refresh()
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 Sub
#End Region #End Region
@@ -585,12 +535,4 @@ PreFin:
FrmMain.PageChange(FormMain.PageType.InstanceSetup, FormMain.PageSubType.InstanceSetup) FrmMain.PageChange(FormMain.PageType.InstanceSetup, FormMain.PageSubType.InstanceSetup)
End Sub 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 End Class
@@ -5,10 +5,10 @@
Private Sub PageSetupLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded Private Sub PageSetupLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
'是否处于隐藏的子页面 '是否处于隐藏的子页面
Dim IsHiddenPage As Boolean = False Dim IsHiddenPage As Boolean = False
If ItemLaunch.Checked AndAlso Setup.Get("UiHiddenSetupLaunch") Then IsHiddenPage = True If ItemLaunch.Checked AndAlso Settings.Get("UiHiddenSetupLaunch") Then IsHiddenPage = True
If ItemUI.Checked AndAlso Setup.Get("UiHiddenSetupUi") Then IsHiddenPage = True If ItemUI.Checked AndAlso Settings.Get("UiHiddenSetupUi") Then IsHiddenPage = True
If ItemSystem.Checked AndAlso Setup.Get("UiHiddenSetupSystem") Then IsHiddenPage = True If ItemSystem.Checked AndAlso Settings.Get("UiHiddenSetupSystem") Then IsHiddenPage = True
If ItemLink.Checked AndAlso Setup.Get("UiHiddenSetupLink") Then IsHiddenPage = True If ItemLink.Checked AndAlso Settings.Get("UiHiddenSetupLink") Then IsHiddenPage = True
If PageSetupUI.HiddenForceShow Then IsHiddenPage = False If PageSetupUI.HiddenForceShow Then IsHiddenPage = False
'若页面错误,或尚未加载,则继续 '若页面错误,或尚未加载,则继续
If IsLoad AndAlso Not IsHiddenPage Then Return If IsLoad AndAlso Not IsHiddenPage Then Return
@@ -17,13 +17,13 @@
PageSetupUI.HiddenRefresh() PageSetupUI.HiddenRefresh()
'选择第一个未被禁用的子页面 '选择第一个未被禁用的子页面
If IsPageSwitched Then Return If IsPageSwitched Then Return
If Not Setup.Get("UiHiddenSetupLaunch") Then If Not Settings.Get("UiHiddenSetupLaunch") Then
ItemLaunch.SetChecked(True, False, False) ItemLaunch.SetChecked(True, False, False)
ElseIf Not Setup.Get("UiHiddenSetupUi") Then ElseIf Not Settings.Get("UiHiddenSetupUi") Then
ItemUI.SetChecked(True, False, False) ItemUI.SetChecked(True, False, False)
ElseIf Not Setup.Get("UiHiddenSetupSystem") Then ElseIf Not Settings.Get("UiHiddenSetupSystem") Then
ItemSystem.SetChecked(True, False, False) ItemSystem.SetChecked(True, False, False)
ElseIf Not Setup.Get("UiHiddenSetupLink") Then ElseIf Not Settings.Get("UiHiddenSetupLink") Then
ItemLink.SetChecked(True, False, False) ItemLink.SetChecked(True, False, False)
Else Else
ItemLaunch.SetChecked(True, False, False) ItemLaunch.SetChecked(True, False, False)
@@ -42,13 +42,13 @@
Public Sub New() Public Sub New()
InitializeComponent() InitializeComponent()
'选择第一个未被禁用的子页面 '选择第一个未被禁用的子页面
If Not Setup.Get("UiHiddenSetupLaunch") Then If Not Settings.Get("UiHiddenSetupLaunch") Then
PageID = FormMain.PageSubType.SetupLaunch PageID = FormMain.PageSubType.SetupLaunch
ElseIf Not Setup.Get("UiHiddenSetupUi") Then ElseIf Not Settings.Get("UiHiddenSetupUi") Then
PageID = FormMain.PageSubType.SetupUI PageID = FormMain.PageSubType.SetupUI
ElseIf Not Setup.Get("UiHiddenSetupSystem") Then ElseIf Not Settings.Get("UiHiddenSetupSystem") Then
PageID = FormMain.PageSubType.SetupSystem PageID = FormMain.PageSubType.SetupSystem
ElseIf Not Setup.Get("UiHiddenSetupLink") Then ElseIf Not Settings.Get("UiHiddenSetupLink") Then
PageID = FormMain.PageSubType.SetupLink PageID = FormMain.PageSubType.SetupLink
Else Else
PageID = FormMain.PageSubType.SetupLaunch PageID = FormMain.PageSubType.SetupLaunch
@@ -17,15 +17,15 @@
End Sub End Sub
Public Sub Reload() Public Sub Reload()
ComboLatencyMode.SelectedIndex = Setup.Get("LinkLatencyMode") ComboLatencyMode.SelectedIndex = Settings.Get("LinkLatencyMode")
TextCustomPeer.Text = Setup.Get("LinkCustomPeer") TextCustomPeer.Text = Settings.Get("LinkCustomPeer")
End Sub End Sub
'初始化 '初始化
Public Sub Reset() Public Sub Reset()
Try Try
Setup.Reset("LinkLatencyMode") Settings.Reset("LinkLatencyMode")
Setup.Reset("LinkCustomPeer") Settings.Reset("LinkCustomPeer")
Log("[Setup] 已初始化联机页设置") Log("[Setup] 已初始化联机页设置")
Hint("已初始化联机页设置!", HintType.Green, False) Hint("已初始化联机页设置!", HintType.Green, False)
@@ -38,10 +38,10 @@
'将控件改变路由到设置改变 '将控件改变路由到设置改变
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextCustomPeer.ValidatedTextChanged Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextCustomPeer.ValidatedTextChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Text) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Text)
End Sub End Sub
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboLatencyMode.SelectionChanged Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboLatencyMode.SelectionChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.SelectedIndex)
End Sub End Sub
End Class End Class
@@ -27,62 +27,62 @@
Public Sub Reload() Public Sub Reload()
'下载 '下载
SliderDownloadThread.Value = Setup.Get("ToolDownloadThread") SliderDownloadThread.Value = Settings.Get("ToolDownloadThread")
SliderDownloadSpeed.Value = Setup.Get("ToolDownloadSpeed") SliderDownloadSpeed.Value = Settings.Get("ToolDownloadSpeed")
ComboDownloadSource.SelectedIndex = Setup.Get("ToolDownloadSource") ComboDownloadSource.SelectedIndex = Settings.Get("ToolDownloadSource")
ComboDownloadVersion.SelectedIndex = Setup.Get("ToolDownloadVersion") ComboDownloadVersion.SelectedIndex = Settings.Get("ToolDownloadVersion")
CheckDownloadCert.Checked = Setup.Get("ToolDownloadCert") CheckDownloadCert.Checked = Settings.Get("ToolDownloadCert")
'Mod 与整合包 'Mod 与整合包
ComboDownloadTranslateV2.SelectedIndex = Setup.Get("ToolDownloadTranslateV2") ComboDownloadTranslateV2.SelectedIndex = Settings.Get("ToolDownloadTranslateV2")
ComboDownloadMod.SelectedIndex = Setup.Get("ToolDownloadMod") ComboDownloadMod.SelectedIndex = Settings.Get("ToolDownloadMod")
ComboModLocalNameStyle.SelectedIndex = Setup.Get("ToolModLocalNameStyle") ComboModLocalNameStyle.SelectedIndex = Settings.Get("ToolModLocalNameStyle")
CheckDownloadIgnoreQuilt.Checked = Setup.Get("ToolDownloadIgnoreQuilt") CheckDownloadIgnoreQuilt.Checked = Settings.Get("ToolDownloadIgnoreQuilt")
'Minecraft 更新提示 'Minecraft 更新提示
CheckUpdateRelease.Checked = Setup.Get("ToolUpdateRelease") CheckUpdateRelease.Checked = Settings.Get("ToolUpdateRelease")
CheckUpdateSnapshot.Checked = Setup.Get("ToolUpdateSnapshot") CheckUpdateSnapshot.Checked = Settings.Get("ToolUpdateSnapshot")
'辅助设置 '辅助设置
CheckHelpChinese.Checked = Setup.Get("ToolHelpChinese") CheckHelpChinese.Checked = Settings.Get("ToolHelpChinese")
'系统设置 '系统设置
ComboSystemUpdate.SelectedIndex = Setup.Get("SystemSystemUpdate") ComboSystemUpdate.SelectedIndex = Settings.Get("SystemSystemUpdate")
ComboSystemActivity.SelectedIndex = Setup.Get("SystemSystemActivity") ComboSystemActivity.SelectedIndex = Settings.Get("SystemSystemActivity")
TextSystemCache.Text = Setup.Get("SystemSystemCache") TextSystemCache.Text = Settings.Get("SystemSystemCache")
CheckSystemTelemetry.Checked = Setup.Get("SystemSystemTelemetry") CheckSystemTelemetry.Checked = Settings.Get("SystemSystemTelemetry")
'调试选项 '调试选项
CheckDebugMode.Checked = Setup.Get("SystemDebugMode") CheckDebugMode.Checked = Settings.Get("SystemDebugMode")
SliderDebugAnim.Value = Setup.Get("SystemDebugAnim") SliderDebugAnim.Value = Settings.Get("SystemDebugAnim")
CheckDebugDelay.Checked = Setup.Get("SystemDebugDelay") CheckDebugDelay.Checked = Settings.Get("SystemDebugDelay")
CheckDebugSkipCopy.Checked = Setup.Get("SystemDebugSkipCopy") CheckDebugSkipCopy.Checked = Settings.Get("SystemDebugSkipCopy")
End Sub End Sub
'初始化 '初始化
Public Sub Reset() Public Sub Reset()
Try Try
Setup.Reset("ToolDownloadThread") Settings.Reset("ToolDownloadThread")
Setup.Reset("ToolDownloadSpeed") Settings.Reset("ToolDownloadSpeed")
Setup.Reset("ToolDownloadSource") Settings.Reset("ToolDownloadSource")
Setup.Reset("ToolDownloadVersion") Settings.Reset("ToolDownloadVersion")
Setup.Reset("ToolDownloadTranslateV2") Settings.Reset("ToolDownloadTranslateV2")
Setup.Reset("ToolDownloadIgnoreQuilt") Settings.Reset("ToolDownloadIgnoreQuilt")
Setup.Reset("ToolDownloadCert") Settings.Reset("ToolDownloadCert")
Setup.Reset("ToolDownloadMod") Settings.Reset("ToolDownloadMod")
Setup.Reset("ToolModLocalNameStyle") Settings.Reset("ToolModLocalNameStyle")
Setup.Reset("ToolUpdateRelease") Settings.Reset("ToolUpdateRelease")
Setup.Reset("ToolUpdateSnapshot") Settings.Reset("ToolUpdateSnapshot")
Setup.Reset("ToolHelpChinese") Settings.Reset("ToolHelpChinese")
Setup.Reset("SystemDebugMode") Settings.Reset("SystemDebugMode")
Setup.Reset("SystemDebugAnim") Settings.Reset("SystemDebugAnim")
Setup.Reset("SystemDebugDelay") Settings.Reset("SystemDebugDelay")
Setup.Reset("SystemDebugSkipCopy") Settings.Reset("SystemDebugSkipCopy")
Setup.Reset("SystemSystemCache") Settings.Reset("SystemSystemCache")
Setup.Reset("SystemSystemUpdate") Settings.Reset("SystemSystemUpdate")
Setup.Reset("SystemSystemActivity") Settings.Reset("SystemSystemActivity")
Setup.Reset("SystemSystemTelemetry") Settings.Reset("SystemSystemTelemetry")
Log("[Setup] 已初始化启动器页设置") Log("[Setup] 已初始化启动器页设置")
Hint("已初始化启动器页设置!", HintType.Green, False) Hint("已初始化启动器页设置!", HintType.Green, False)
@@ -95,16 +95,16 @@
'将控件改变路由到设置改变 '将控件改变路由到设置改变
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 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) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Checked)
End Sub End Sub
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderDebugAnim.Change, SliderDownloadThread.Change, SliderDownloadSpeed.Change 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) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Value)
End Sub 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, ComboDownloadMod.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) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.SelectedIndex)
End Sub End Sub
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextSystemCache.ValidatedTextChanged Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextSystemCache.ValidatedTextChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Text) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Text)
End Sub End Sub
'滑动条 '滑动条
@@ -127,8 +127,8 @@
End Sub End Sub
Private Sub SliderDownloadThread_PreviewChange(sender As Object, e As RouteEventArgs) Handles SliderDownloadThread.PreviewChange Private Sub SliderDownloadThread_PreviewChange(sender As Object, e As RouteEventArgs) Handles SliderDownloadThread.PreviewChange
If SliderDownloadThread.Value < 100 Then Return If SliderDownloadThread.Value < 100 Then Return
If Not Setup.Get("HintDownloadThread") Then If Not Settings.Get("HintDownloadThread") Then
Setup.Set("HintDownloadThread", True) Settings.Set("HintDownloadThread", True)
MyMsgBox("如果设置过多的下载线程,可能会导致下载时出现非常严重的卡顿。" & vbCrLf & MyMsgBox("如果设置过多的下载线程,可能会导致下载时出现非常严重的卡顿。" & vbCrLf &
"一般设置 64 线程即可满足大多数下载需求,除非你知道你在干什么,否则不建议设置更多的线程数!", "警告", "我知道了", IsWarn:=True) "一般设置 64 线程即可满足大多数下载需求,除非你知道你在干什么,否则不建议设置更多的线程数!", "警告", "我知道了", IsWarn:=True)
End If End If
@@ -23,15 +23,20 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="不透明度" Margin="0,0,20,0" /> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="不透明度" Margin="0,0,20,0" />
<local:MySlider Grid.ColumnSpan="5" x:Name="SliderLauncherOpacity" Tag="UiLauncherTransparent" MaxValue="600" ValueByKey="10" Grid.Column="1" /> <local:MySlider local:SettingService.Key="UiLauncherTransparent"
MaxValue="600" ValueByKey="10" Grid.ColumnSpan="5" x:Name="SliderLauncherTransparent" Grid.Column="1" />
<TextBlock Grid.Row="1" VerticalAlignment="Center" Name="LabLauncherHue" Visibility="Collapsed" HorizontalAlignment="Left" Text="色调" Margin="0,10,20,0" /> <TextBlock Grid.Row="1" VerticalAlignment="Center" Name="LabLauncherHue" Visibility="Collapsed" HorizontalAlignment="Left" Text="色调" Margin="0,10,20,0" />
<local:MySlider Grid.Row="1" Grid.Column="1" x:Name="SliderLauncherHue" Tag="UiLauncherHue" Visibility="Collapsed" MaxValue="360" ValueByKey="10" Margin="0,10,0,0" /> <local:MySlider local:SettingService.Key="UiLauncherHue"
Grid.Row="1" Grid.Column="1" x:Name="SliderLauncherHue" Visibility="Collapsed" MaxValue="360" ValueByKey="10" Margin="0,10,0,0" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" Name="LabLauncherDelta" Visibility="Collapsed" HorizontalAlignment="Left" Text="色调渐变" Margin="0,10,20,0" /> <TextBlock Grid.Row="2" VerticalAlignment="Center" Name="LabLauncherDelta" Visibility="Collapsed" HorizontalAlignment="Left" Text="色调渐变" Margin="0,10,20,0" />
<local:MySlider Grid.Row="2" Grid.Column="1" x:Name="SliderLauncherDelta" Tag="UiLauncherDelta" Visibility="Collapsed" MaxValue="180" ValueByKey="5" Margin="0,10,0,0" /> <local:MySlider local:SettingService.Key="UiLauncherDelta"
Grid.Row="2" Grid.Column="1" x:Name="SliderLauncherDelta" Visibility="Collapsed" MaxValue="180" ValueByKey="5" Margin="0,10,0,0" />
<TextBlock Grid.Row="1" Grid.Column="3" VerticalAlignment="Center" Name="LabLauncherSat" Visibility="Collapsed" HorizontalAlignment="Left" Text="饱和度" Margin="0,10,20,0" /> <TextBlock Grid.Row="1" Grid.Column="3" VerticalAlignment="Center" Name="LabLauncherSat" Visibility="Collapsed" HorizontalAlignment="Left" Text="饱和度" Margin="0,10,20,0" />
<local:MySlider Grid.Row="1" Grid.Column="4" x:Name="SliderLauncherSat" Tag="UiLauncherSat" Visibility="Collapsed" MaxValue="100" ValueByKey="5" Margin="0,10,0,0" /> <local:MySlider local:SettingService.Key="UiLauncherSat"
Grid.Row="1" Grid.Column="4" x:Name="SliderLauncherSat" Visibility="Collapsed" MaxValue="100" ValueByKey="5" Margin="0,10,0,0" />
<TextBlock Grid.Row="2" Grid.Column="3" VerticalAlignment="Center" Name="LabLauncherLight" Visibility="Collapsed" HorizontalAlignment="Left" Text="亮度" Margin="0,10,20,0" /> <TextBlock Grid.Row="2" Grid.Column="3" VerticalAlignment="Center" Name="LabLauncherLight" Visibility="Collapsed" HorizontalAlignment="Left" Text="亮度" Margin="0,10,20,0" />
<local:MySlider Grid.Row="2" Grid.Column="4" x:Name="SliderLauncherLight" Tag="UiLauncherLight" Visibility="Collapsed" MaxValue="40" ValueByKey="5" Margin="0,10,0,0" /> <local:MySlider local:SettingService.Key="UiLauncherLight"
Grid.Row="2" Grid.Column="4" x:Name="SliderLauncherLight" Visibility="Collapsed" MaxValue="40" ValueByKey="5" Margin="0,10,0,0" />
</Grid> </Grid>
<Grid x:Name="PanLauncherTheme" Height="90" Margin="0,0,0,7"> <Grid x:Name="PanLauncherTheme" Height="90" Margin="0,0,0,7">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -49,33 +54,49 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="主题" Margin="0,0,20,0" /> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="主题" Margin="0,0,20,0" />
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="隐藏主题" Margin="0,0,20,0" Grid.Row="1" /> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="隐藏主题" Margin="0,0,20,0" Grid.Row="1" />
<local:MyRadioBox Grid.Column="1" Grid.Row="0" Text="龙猫蓝" x:Name="RadioLauncherTheme0" Tag="UiLauncherTheme/0" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="0"
<local:MyRadioBox Grid.Column="2" Grid.Row="0" Text="甜柠青" x:Name="RadioLauncherTheme1" Tag="UiLauncherTheme/1" /> Grid.Column="1" Grid.Row="0" Text="龙猫蓝" x:Name="RadioLauncherTheme0" />
<local:MyRadioBox Grid.Column="3" Grid.Row="0" Text="小草绿" x:Name="RadioLauncherTheme2" Tag="UiLauncherTheme/2" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="1"
<local:MyRadioBox Grid.Column="4" Grid.Row="0" Text="菠萝黄" x:Name="RadioLauncherTheme3" Tag="UiLauncherTheme/3" /> Grid.Column="2" Grid.Row="0" Text="甜柠青" x:Name="RadioLauncherTheme1" />
<local:MyRadioBox Grid.Column="5" Grid.Row="0" Text="橡木棕" x:Name="RadioLauncherTheme4" Tag="UiLauncherTheme/4" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="2"
<local:MyRadioBox Grid.Column="1" Grid.Row="1" Text="玄素黑" x:Name="RadioLauncherTheme5" Tag="UiLauncherTheme/5" Opacity="0" ToolTip="灰色是个谎言" ToolTipService.Placement="Bottom" /> Grid.Column="3" Grid.Row="0" Text="小草绿" x:Name="RadioLauncherTheme2" />
<local:MyRadioBox Grid.Column="1" Grid.Row="1" Text="???" x:Name="RadioLauncherTheme5Gray" IsEnabled="False" Opacity="1" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="3"
Grid.Column="4" Grid.Row="0" Text="菠萝黄" x:Name="RadioLauncherTheme3" />
<local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="4"
Grid.Column="5" Grid.Row="0" Text="橡木棕" x:Name="RadioLauncherTheme4" />
<local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="5"
Grid.Column="1" Grid.Row="1" Text="玄素黑" x:Name="RadioLauncherTheme5" Opacity="0" ToolTip="灰色是个谎言" ToolTipService.Placement="Bottom" />
<local:MyRadioBox Grid.Column="1" Grid.Row="1" Text="玄素黑" x:Name="RadioLauncherTheme5Gray" IsEnabled="False" Opacity="1" />
<TextBlock Grid.Column="1" Grid.Row="1" x:Name="LabLauncherTheme5Unlock" Background="{StaticResource ColorBrushSemiTransparent}" ToolTip="灰色是个谎言" ToolTipService.Placement="Bottom" /> <TextBlock Grid.Column="1" Grid.Row="1" x:Name="LabLauncherTheme5Unlock" Background="{StaticResource ColorBrushSemiTransparent}" ToolTip="灰色是个谎言" ToolTipService.Placement="Bottom" />
<local:MyRadioBox Grid.Column="2" Grid.Row="1" Text="???" x:Name="RadioLauncherTheme12" Tag="UiLauncherTheme/12" IsEnabled="False" ToolTip="滑稽树上滑稽果,滑稽树下你和我,滑稽之日搞事情,欢乐多又多" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="12"
<local:MyRadioBox Grid.Column="3" Grid.Row="1" Text="???" x:Name="RadioLauncherTheme6" Tag="UiLauncherTheme/6" IsEnabled="False" ToolTip="99 次重逢的喜悦" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" /> Grid.Column="2" Grid.Row="1" Text="滑稽彩" x:Name="RadioLauncherTheme12" IsEnabled="False" ToolTip="滑稽树上滑稽果,滑稽树下你和我,滑稽之日搞事情,欢乐多又多" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" />
<local:MyRadioBox Grid.Column="4" Grid.Row="1" Text="???" x:Name="RadioLauncherTheme7" Tag="UiLauncherTheme/7" IsEnabled="False" ToolTip="072 101 108 112 032 068 101 118 032 048 046 052 046 052" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="6"
<local:MyRadioBox Grid.Column="5" Grid.Row="1" Text="???" x:Name="RadioLauncherTheme13" Tag="UiLauncherTheme/13" IsEnabled="False" ToolTip="这就是传说中的欧皇了吧" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" /> Grid.Column="3" Grid.Row="1" Text="铁杆粉" x:Name="RadioLauncherTheme6" IsEnabled="False" ToolTip="99 次重逢的喜悦" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" />
<local:MyRadioBox Grid.Column="1" Grid.Row="2" Text="???" x:Name="RadioLauncherTheme8" Tag="UiLauncherTheme/8" IsEnabled="False" ToolTipService.Placement="Bottom" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="7"
Grid.Column="4" Grid.Row="1" Text="神秘紫" x:Name="RadioLauncherTheme7" IsEnabled="False" ToolTip="072 101 108 112 032 068 101 118 032 048 046 052 046 052" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" />
<local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="13"
Grid.Column="5" Grid.Row="1" Text="欧皇彩" x:Name="RadioLauncherTheme13" IsEnabled="False" ToolTip="这就是传说中的欧皇了吧" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" />
<local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="8"
Grid.Column="1" Grid.Row="2" Text="秋仪金" x:Name="RadioLauncherTheme8" IsEnabled="False" ToolTipService.Placement="Bottom" />
<TextBlock Grid.Column="1" Grid.Row="2" x:Name="LabLauncherTheme8Copy" Background="{StaticResource ColorBrushSemiTransparent}" ToolTipService.Placement="Bottom" /> <TextBlock Grid.Column="1" Grid.Row="2" x:Name="LabLauncherTheme8Copy" Background="{StaticResource ColorBrushSemiTransparent}" ToolTipService.Placement="Bottom" />
<local:MyRadioBox Grid.Column="2" Grid.Row="2" Text="???" x:Name="RadioLauncherTheme9" Tag="UiLauncherTheme/9" IsEnabled="False" ToolTipService.Placement="Bottom" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="9"
Grid.Column="2" Grid.Row="2" Text="活跃橙" x:Name="RadioLauncherTheme9" IsEnabled="False" ToolTipService.Placement="Bottom" />
<TextBlock Grid.Column="2" Grid.Row="2" x:Name="LabLauncherTheme9Copy" Background="{StaticResource ColorBrushSemiTransparent}" ToolTipService.Placement="Bottom" /> <TextBlock Grid.Column="2" Grid.Row="2" x:Name="LabLauncherTheme9Copy" Background="{StaticResource ColorBrushSemiTransparent}" ToolTipService.Placement="Bottom" />
<local:MyRadioBox Grid.Column="3" Grid.Row="2" Text="???" x:Name="RadioLauncherTheme10" Tag="UiLauncherTheme/10" IsEnabled="False" ToolTip="进行一次正版登录,支持正版游戏!" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="10"
<local:MyRadioBox Grid.Column="4" Grid.Row="2" Text="???" x:Name="RadioLauncherTheme11" Tag="UiLauncherTheme/11" IsEnabled="False" ToolTipService.Placement="Bottom" ToolTip="右键打开解密游戏入口" /> Grid.Column="3" Grid.Row="2" Text="跳票红" x:Name="RadioLauncherTheme10" IsEnabled="False" ToolTip="进行一次正版登录,支持正版游戏!" ToolTipService.ShowOnDisabled="True" ToolTipService.Placement="Bottom" />
<local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="11"
Grid.Column="4" Grid.Row="2" Text="极客蓝" x:Name="RadioLauncherTheme11" IsEnabled="False" ToolTipService.Placement="Bottom" ToolTip="右键打开解密游戏入口" />
<TextBlock Grid.Column="4" Grid.Row="2" x:Name="LabLauncherTheme11Click" Background="{StaticResource ColorBrushSemiTransparent}" ToolTipService.Placement="Bottom" /> <TextBlock Grid.Column="4" Grid.Row="2" x:Name="LabLauncherTheme11Click" Background="{StaticResource ColorBrushSemiTransparent}" ToolTipService.Placement="Bottom" />
<local:MyRadioBox Grid.Column="5" Grid.Row="2" Text="自定义" x:Name="RadioLauncherTheme14" Tag="UiLauncherTheme/14" IsEnabled="False" ToolTipService.Placement="Bottom" ToolTip="需要解锁五个隐藏主题" ToolTipService.ShowOnDisabled="True" /> <local:MyRadioBox local:SettingService.Key="UiLauncherTheme" local:SettingService.Value="14"
Grid.Column="5" Grid.Row="2" Text="自定义" x:Name="RadioLauncherTheme14" IsEnabled="False" ToolTipService.Placement="Bottom" ToolTip="需要解锁五个隐藏主题" ToolTipService.ShowOnDisabled="True" />
</Grid> </Grid>
<local:MyCheckBox Text="打开启动器时显示 PCL 图标" Margin="-1,0,0,1" Height="22" x:Name="CheckLauncherLogo" Tag="UiLauncherLogo" /> <local:MyCheckBox local:SettingService.Key="UiLauncherLogo" Text="打开启动器时显示 PCL 图标" Margin="-1,0,0,1" Height="22" />
</StackPanel> </StackPanel>
<Border Background="#DDDDDDDD" Margin="-8,23,-5,28" CornerRadius="4" Name="PanLauncherHide" Visibility="Collapsed"> <Border Background="#DDDDDDDD" Margin="-8,23,-5,28" CornerRadius="4" Name="PanLauncherHide" Visibility="Collapsed">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="如果可以小小赞助一下 PCL,就能解锁主题颜色更换功能啦……&#xa;多亏了大家的支持,PCL 才能在免费、无任何广告的情况下维持数年的更新(磕头)!" FontSize="13" Margin="0,0,0,0" /> <TextBlock Text="如果可以小小赞助一下 PCL,就能解锁主题颜色更换功能啦……&#xa;多亏了大家的支持,PCL 才能在免费、无任何广告的情况下维持数年的更新(磕头)!" FontSize="13" Margin="0,0,0,0" />
<local:MyButton Height="32" x:Name="BtnLauncherDonate" MinWidth="140" Text="支持 PCL 开发!" Padding="13,0" HorizontalAlignment="Center" Margin="0,9,0,0" ColorType="Highlight" /> <local:MyButton Height="32" MinWidth="140" Text="支持 PCL 开发!" Padding="13,0" HorizontalAlignment="Center" Margin="0,9,0,0" ColorType="Highlight"
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://meloong.com/afd/a/LTCat" />
</StackPanel> </StackPanel>
</Border> </Border>
</Grid> </Grid>
@@ -88,16 +109,20 @@
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="自适应方式" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="自适应方式" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboBackgroundSuit" Tag="UiBackgroundSuit" Grid.Column="1"> <local:MyComboBox local:SettingService.Key="UiBackgroundSuit" Grid.Column="1">
<local:MyComboBoxItem Content="智能" IsSelected="True" ToolTip="当图片较小时选择平铺,较大时选择适应" /> <local:MyComboBoxItem local:SettingService.Value="0" Content="自动" ToolTip="当图片较小时选择平铺,较大时选择居中 (保持长宽比)" />
<local:MyComboBoxItem Content="居中" /> <local:MyComboBoxItem local:SettingService.Value="4" Content="平铺" />
<local:MyComboBoxItem Content="适应" ToolTip="拉伸图片并保持长宽比不变,直至填满整个窗口" /> <local:MyComboBoxItem local:SettingService.Value="1" Content="居中" />
<local:MyComboBoxItem Content="拉伸" ToolTip="拉伸图片使其恰好填满整个窗口,很可能会导致长宽比的改变" /> <local:MyComboBoxItem local:SettingService.Value="3" Content="拉伸" ToolTip="拉伸图片使其恰好填满整个窗口,很可能会导致长宽比的改变" />
<local:MyComboBoxItem Content="平铺" /> <local:MyComboBoxItem local:SettingService.Value="5" Content="左上 (保持长宽比)" />
<local:MyComboBoxItem Content="居于左上" /> <local:MyComboBoxItem local:SettingService.Value="9" Content="左中 (保持长宽比)" />
<local:MyComboBoxItem Content="居于右上" /> <local:MyComboBoxItem local:SettingService.Value="7" Content="左下 (保持长宽比)" />
<local:MyComboBoxItem Content="居于左下" /> <local:MyComboBoxItem local:SettingService.Value="11" Content="中上 (保持长宽比)" />
<local:MyComboBoxItem Content="居于右下" /> <local:MyComboBoxItem local:SettingService.Value="2" Content="居中 (保持长宽比)" />
<local:MyComboBoxItem local:SettingService.Value="12" Content="中下 (保持长宽比)" />
<local:MyComboBoxItem local:SettingService.Value="6" Content="右上 (保持长宽比)" />
<local:MyComboBoxItem local:SettingService.Value="10" Content="右中 (保持长宽比)" />
<local:MyComboBoxItem local:SettingService.Value="8" Content="右下 (保持长宽比)" />
</local:MyComboBox> </local:MyComboBox>
</Grid> </Grid>
<Grid x:Name="PanBackgroundOpacity" Height="22" Margin="0,0,0,7" Visibility="Collapsed"> <Grid x:Name="PanBackgroundOpacity" Height="22" Margin="0,0,0,7" Visibility="Collapsed">
@@ -106,7 +131,7 @@
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="不透明度" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="不透明度" Margin="0,0,25,0" />
<local:MySlider x:Name="SliderBackgroundOpacity" Tag="UiBackgroundOpacity" MaxValue="1000" ValueByKey="10" Grid.Column="1" /> <local:MySlider local:SettingService.Key="UiBackgroundOpacity" x:Name="SliderBackgroundOpacity" MaxValue="1000" ValueByKey="10" Grid.Column="1" />
</Grid> </Grid>
<Grid x:Name="PanBackgroundBlur" Height="22" Margin="0,0,0,10" Visibility="Collapsed"> <Grid x:Name="PanBackgroundBlur" Height="22" Margin="0,0,0,10" Visibility="Collapsed">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -114,9 +139,10 @@
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="背景模糊" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="背景模糊" Margin="0,0,25,0" />
<local:MySlider x:Name="SliderBackgroundBlur" Tag="UiBackgroundBlur" MaxValue="40" Grid.Column="1" ToolTip="较强的模糊会导致启动器严重掉帧,请谨慎使用。&#13;不建议在制作整合包时开启模糊,以确保 PCL 在低性能电脑上可以流畅运行。" /> <local:MySlider local:SettingService.Key="UiBackgroundBlur" x:Name="SliderBackgroundBlur" MaxValue="40" Grid.Column="1"
ToolTip="高度的模糊会严重掉帧,请谨慎。&#13;不建议在制作整合包时开启模糊,以确保 PCL 在低性能电脑上可以流畅运行。" />
</Grid> </Grid>
<local:MyCheckBox Text="叠加彩色背景" Margin="-1,0,0,8" Height="22" x:Name="CheckBackgroundColorful" Tag="UiBackgroundColorful" /> <local:MyCheckBox local:SettingService.Key="UiBackgroundColorful" Text="叠加彩色背景" Margin="-1,0,0,8" Height="22" />
<Grid Height="35" Margin="0,2,0,0"> <Grid Height="35" Margin="0,2,0,0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" /> <ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
@@ -239,23 +265,23 @@
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="主页预设" Margin="0,0,25,0" /> <TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="主页预设" Margin="0,0,25,0" />
<local:MyComboBox x:Name="ComboCustomPreset" Grid.ColumnSpan="2" Tag="UiCustomPreset" Grid.Column="1"> <local:MyComboBox local:SettingService.Key="UiCustomPreset" Grid.ColumnSpan="2" Grid.Column="1">
<local:MyComboBoxItem Content="你知道吗?" IsSelected="True" /> <local:MyComboBoxItem local:SettingService.Value="0" Content="你知道吗?" />
<local:MyComboBoxItem Content="回声洞" /> <local:MyComboBoxItem local:SettingService.Value="1" Content="回声洞" />
<local:MyComboBoxItem Content="Minecraft 新闻(作者:最亮的信标)" /> <local:MyComboBoxItem local:SettingService.Value="2" Content="Minecraft 新闻(作者:最亮的信标)" />
<local:MyComboBoxItem Content="简单主页(作者:MFn233)" /> <local:MyComboBoxItem local:SettingService.Value="3" Content="简单主页(作者:MFn233)" />
<local:MyComboBoxItem Content="每日整合包推荐(作者:wkea)" /> <local:MyComboBoxItem local:SettingService.Value="4" Content="每日整合包推荐(作者:wkea)" />
<local:MyComboBoxItem Content="Minecraft 皮肤推荐(作者:wkea)" /> <local:MyComboBoxItem local:SettingService.Value="5" Content="Minecraft 皮肤推荐(作者:wkea)" />
<local:MyComboBoxItem Content="OpenBMCLAPI 仪表盘 Lite(作者:Silverteal、Mxmilu666)" /> <local:MyComboBoxItem local:SettingService.Value="6" Content="OpenBMCLAPI 仪表盘 Lite(作者:Silverteal、Mxmilu666)" />
<local:MyComboBoxItem Content="PCL 主页市场(作者:凌云)" /> <local:MyComboBoxItem local:SettingService.Value="7" Content="PCL 主页市场(作者:凌云)" />
<local:MyComboBoxItem Content="PCL 新闻速报(作者:Joker2184)" Visibility="Collapsed" /> <!--<local:MyComboBoxItem local:SettingService.Value="8" Content="PCL 新闻速报(作者:Joker2184)" />-->
<local:MyComboBoxItem Content="PCL 新功能说明书(作者:WForst-Breeze)" /> <local:MyComboBoxItem local:SettingService.Value="9" Content="PCL 新功能说明书(作者:WForst-Breeze)" />
<local:MyComboBoxItem Content="OpenMCIM 仪表盘(作者:SALTWOOD)" Visibility="Collapsed" /> <!--<local:MyComboBoxItem local:SettingService.Value="10" Content="OpenMCIM 仪表盘(作者:SALTWOOD)" />-->
<local:MyComboBoxItem Content="杂志主页(作者:CreeperIsASpy)" /> <local:MyComboBoxItem local:SettingService.Value="11" Content="杂志主页(作者:CreeperIsASpy)" />
<local:MyComboBoxItem Content="PCL GitHub 仪表盘(作者:Deep-Dark-Forest)" /> <local:MyComboBoxItem local:SettingService.Value="12" Content="PCL GitHub 仪表盘(作者:Deep-Dark-Forest)" />
<local:MyComboBoxItem Content="Minecraft 更新摘要(作者:pynickle,部分由 AI 生成)" /> <local:MyComboBoxItem local:SettingService.Value="13" Content="Minecraft 更新摘要(作者:pynickle)" />
<local:MyComboBoxItem Content="今日新闻热点(作者:EYicheng,部分由 AI 生成)" /> <local:MyComboBoxItem local:SettingService.Value="14" Content="今日新闻热点(作者:EYicheng)" />
<local:MyComboBoxItem Content="Minecraft 芝士站(作者:awaEric233,部分由 AI 生成)" /> <local:MyComboBoxItem local:SettingService.Value="15" Content="Minecraft 芝士站(作者:awaEric233)" />
</local:MyComboBox> </local:MyComboBox>
</Grid> </Grid>
</StackPanel> </StackPanel>
@@ -1,37 +1,30 @@
Public Class PageSetupUI Public Class PageSetupUI
Public Shadows IsLoaded As Boolean = False
Private Sub PageSetupUI_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded Private Sub PageSetupUI_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
'重复加载部分 '重复加载部分
PanBack.ScrollToHome() PanBack.ScrollToHome()
ThemeCheckAll(True) ThemeCheckAll(True)
If ThemeDontClick <> 0 Then If ThemeDontClick <> 0 Then
Dim NewText As String Dim NewText As String = Nothing
Select Case ThemeDontClick Select Case ThemeDontClick
Case 1 Case 1
NewText = "眼瞎白" NewText = "眼瞎白"
Case 2 Case 2
NewText = "真·滑稽彩" NewText = "真·滑稽彩"
Case Else
NewText = "???"
End Select End Select
For Each Control In PanLauncherTheme.Children For Each Control In PanLauncherTheme.Children
If (TypeOf Control Is MyRadioBox) AndAlso CType(Control, MyRadioBox).IsEnabled Then If (TypeOf Control Is MyRadioBox) AndAlso CType(Control, MyRadioBox).IsEnabled Then CType(Control, MyRadioBox).Text = NewText
CType(Control, MyRadioBox).Text = NewText
End If
Next Next
End If End If
AniControlEnabled += 1 AniControlEnabled += 1
Reload() '#4826,在每次进入页面时都刷新一下 Refresh() '#4826
AniControlEnabled -= 1 AniControlEnabled -= 1
'非重复加载部分 '非重复加载部分
If IsLoaded Then Return Static Reloaded As Boolean = False
IsLoaded = True If Reloaded Then Return
Reloaded = True
SliderLoad() SliderLoad()
@@ -47,68 +40,50 @@
'极客蓝的处理在 ThemeCheck 中 '极客蓝的处理在 ThemeCheck 中
End Sub End Sub
Public Sub Reload() Public Sub Refresh()
Try Try
SettingService.RefreshSettings(Me)
'启动器
SliderLauncherOpacity.Value = Setup.Get("UiLauncherTransparent")
SliderLauncherHue.Value = Setup.Get("UiLauncherHue")
SliderLauncherSat.Value = Setup.Get("UiLauncherSat")
SliderLauncherDelta.Value = Setup.Get("UiLauncherDelta")
SliderLauncherLight.Value = Setup.Get("UiLauncherLight")
If Setup.Get("UiLauncherTheme") <= 14 Then CType(FindName("RadioLauncherTheme" & Setup.Get("UiLauncherTheme")), MyRadioBox).Checked = True
CheckLauncherLogo.Checked = Setup.Get("UiLauncherLogo")
CheckLauncherEmail.Checked = Setup.Get("UiLauncherEmail")
'背景图片
SliderBackgroundOpacity.Value = Setup.Get("UiBackgroundOpacity")
SliderBackgroundBlur.Value = Setup.Get("UiBackgroundBlur")
ComboBackgroundSuit.SelectedIndex = Setup.Get("UiBackgroundSuit")
CheckBackgroundColorful.Checked = Setup.Get("UiBackgroundColorful")
BackgroundRefresh(False, False) BackgroundRefresh(False, False)
'标题栏 '标题栏
CType(FindName("RadioLogoType" & Setup.Get("UiLogoType")), MyRadioBox).Checked = True CType(FindName("RadioLogoType" & Settings.Get("UiLogoType")), MyRadioBox).Checked = True
CheckLogoLeft.Visibility = If(RadioLogoType0.Checked, Visibility.Visible, Visibility.Collapsed) CheckLogoLeft.Visibility = If(RadioLogoType0.Checked, Visibility.Visible, Visibility.Collapsed)
PanLogoText.Visibility = If(RadioLogoType2.Checked, Visibility.Visible, Visibility.Collapsed) PanLogoText.Visibility = If(RadioLogoType2.Checked, Visibility.Visible, Visibility.Collapsed)
PanLogoChange.Visibility = If(RadioLogoType3.Checked, Visibility.Visible, Visibility.Collapsed) PanLogoChange.Visibility = If(RadioLogoType3.Checked, Visibility.Visible, Visibility.Collapsed)
TextLogoText.Text = Setup.Get("UiLogoText") TextLogoText.Text = Settings.Get("UiLogoText")
CheckLogoLeft.Checked = Setup.Get("UiLogoLeft") CheckLogoLeft.Checked = Settings.Get("UiLogoLeft")
'背景音乐 '背景音乐
CheckMusicRandom.Checked = Setup.Get("UiMusicRandom") CheckMusicRandom.Checked = Settings.Get("UiMusicRandom")
CheckMusicAuto.Checked = Setup.Get("UiMusicAuto") CheckMusicAuto.Checked = Settings.Get("UiMusicAuto")
CheckMusicStop.Checked = Setup.Get("UiMusicStop") CheckMusicStop.Checked = Settings.Get("UiMusicStop")
CheckMusicStart.Checked = Setup.Get("UiMusicStart") CheckMusicStart.Checked = Settings.Get("UiMusicStart")
SliderMusicVolume.Value = Setup.Get("UiMusicVolume") SliderMusicVolume.Value = Settings.Get("UiMusicVolume")
MusicRefreshUI() MusicRefreshUI()
'主页 '主页
Try CType(FindName("RadioCustomType" & Settings.Get("UiCustomType")), MyRadioBox).Checked = True
ComboCustomPreset.SelectedIndex = Setup.Get("UiCustomPreset") OnUiCustomTypeChanged(Settings.Get("UiCustomType"))
Catch TextCustomNet.Text = Settings.Get("UiCustomNet")
Setup.Reset("UiCustomPreset")
End Try
CType(FindName("RadioCustomType" & Setup.Load("UiCustomType", ForceReload:=True)), MyRadioBox).Checked = True
TextCustomNet.Text = Setup.Get("UiCustomNet")
'功能隐藏 '功能隐藏
CheckHiddenPageDownload.Checked = Setup.Get("UiHiddenPageDownload") CheckLauncherEmail.Checked = Settings.Get("UiLauncherEmail")
CheckHiddenPageLink.Checked = Setup.Get("UiHiddenPageLink") CheckHiddenPageDownload.Checked = Settings.Get("UiHiddenPageDownload")
CheckHiddenPageSetup.Checked = Setup.Get("UiHiddenPageSetup") CheckHiddenPageLink.Checked = Settings.Get("UiHiddenPageLink")
CheckHiddenPageOther.Checked = Setup.Get("UiHiddenPageOther") CheckHiddenPageSetup.Checked = Settings.Get("UiHiddenPageSetup")
CheckHiddenFunctionSelect.Checked = Setup.Get("UiHiddenFunctionSelect") CheckHiddenPageOther.Checked = Settings.Get("UiHiddenPageOther")
CheckHiddenFunctionModUpdate.Checked = Setup.Get("UiHiddenFunctionModUpdate") CheckHiddenFunctionSelect.Checked = Settings.Get("UiHiddenFunctionSelect")
CheckHiddenFunctionHidden.Checked = Setup.Get("UiHiddenFunctionHidden") CheckHiddenFunctionModUpdate.Checked = Settings.Get("UiHiddenFunctionModUpdate")
CheckHiddenSetupLaunch.Checked = Setup.Get("UiHiddenSetupLaunch") CheckHiddenFunctionHidden.Checked = Settings.Get("UiHiddenFunctionHidden")
CheckHiddenSetupUI.Checked = Setup.Get("UiHiddenSetupUi") CheckHiddenSetupLaunch.Checked = Settings.Get("UiHiddenSetupLaunch")
CheckHiddenSetupLink.Checked = Setup.Get("UiHiddenSetupLink") CheckHiddenSetupUI.Checked = Settings.Get("UiHiddenSetupUi")
CheckHiddenSetupSystem.Checked = Setup.Get("UiHiddenSetupSystem") CheckHiddenSetupLink.Checked = Settings.Get("UiHiddenSetupLink")
CheckHiddenOtherAbout.Checked = Setup.Get("UiHiddenOtherAbout") CheckHiddenSetupSystem.Checked = Settings.Get("UiHiddenSetupSystem")
CheckHiddenOtherFeedback.Checked = Setup.Get("UiHiddenOtherFeedback") CheckHiddenOtherAbout.Checked = Settings.Get("UiHiddenOtherAbout")
CheckHiddenOtherVote.Checked = Setup.Get("UiHiddenOtherVote") CheckHiddenOtherFeedback.Checked = Settings.Get("UiHiddenOtherFeedback")
CheckHiddenOtherHelp.Checked = Setup.Get("UiHiddenOtherHelp") CheckHiddenOtherVote.Checked = Settings.Get("UiHiddenOtherVote")
CheckHiddenOtherTest.Checked = Setup.Get("UiHiddenOtherTest") CheckHiddenOtherHelp.Checked = Settings.Get("UiHiddenOtherHelp")
CheckHiddenOtherTest.Checked = Settings.Get("UiHiddenOtherTest")
Catch ex As NullReferenceException Catch ex As NullReferenceException
Log(ex, "个性化设置项存在异常,已被自动重置", LogLevel.Msgbox) Log(ex, "个性化设置项存在异常,已被自动重置", LogLevel.Msgbox)
@@ -121,45 +96,35 @@
'初始化 '初始化
Public Sub Reset() Public Sub Reset()
Try Try
Setup.Reset("UiLauncherTransparent") SettingService.ResetSettings(Me)
Setup.Reset("UiLauncherTheme") Settings.Reset("UiLauncherLogo")
Setup.Reset("UiLauncherLogo") Settings.Reset("UiLauncherEmail")
Setup.Reset("UiLauncherHue") Settings.Reset("UiLogoType")
Setup.Reset("UiLauncherSat") Settings.Reset("UiLogoText")
Setup.Reset("UiLauncherDelta") Settings.Reset("UiLogoLeft")
Setup.Reset("UiLauncherLight") Settings.Reset("UiMusicVolume")
Setup.Reset("UiLauncherEmail") Settings.Reset("UiMusicStop")
Setup.Reset("UiBackgroundColorful") Settings.Reset("UiMusicStart")
Setup.Reset("UiBackgroundOpacity") Settings.Reset("UiMusicRandom")
Setup.Reset("UiBackgroundBlur") Settings.Reset("UiMusicAuto")
Setup.Reset("UiBackgroundSuit") Settings.Reset("UiCustomType")
Setup.Reset("UiLogoType") Settings.Reset("UiCustomNet")
Setup.Reset("UiLogoText") Settings.Reset("UiHiddenPageDownload")
Setup.Reset("UiLogoLeft") Settings.Reset("UiHiddenPageLink")
Setup.Reset("UiMusicVolume") Settings.Reset("UiHiddenPageSetup")
Setup.Reset("UiMusicStop") Settings.Reset("UiHiddenPageOther")
Setup.Reset("UiMusicStart") Settings.Reset("UiHiddenFunctionSelect")
Setup.Reset("UiMusicRandom") Settings.Reset("UiHiddenFunctionModUpdate")
Setup.Reset("UiMusicAuto") Settings.Reset("UiHiddenFunctionHidden")
Setup.Reset("UiCustomType") Settings.Reset("UiHiddenSetupLaunch")
Setup.Reset("UiCustomPreset") Settings.Reset("UiHiddenSetupUi")
Setup.Reset("UiCustomNet") Settings.Reset("UiHiddenSetupLink")
Setup.Reset("UiHiddenPageDownload") Settings.Reset("UiHiddenSetupSystem")
Setup.Reset("UiHiddenPageLink") Settings.Reset("UiHiddenOtherAbout")
Setup.Reset("UiHiddenPageSetup") Settings.Reset("UiHiddenOtherFeedback")
Setup.Reset("UiHiddenPageOther") Settings.Reset("UiHiddenOtherVote")
Setup.Reset("UiHiddenFunctionSelect") Settings.Reset("UiHiddenOtherHelp")
Setup.Reset("UiHiddenFunctionModUpdate") Settings.Reset("UiHiddenOtherTest")
Setup.Reset("UiHiddenFunctionHidden")
Setup.Reset("UiHiddenSetupLaunch")
Setup.Reset("UiHiddenSetupUi")
Setup.Reset("UiHiddenSetupLink")
Setup.Reset("UiHiddenSetupSystem")
Setup.Reset("UiHiddenOtherAbout")
Setup.Reset("UiHiddenOtherFeedback")
Setup.Reset("UiHiddenOtherVote")
Setup.Reset("UiHiddenOtherHelp")
Setup.Reset("UiHiddenOtherTest")
Log("[Setup] 已初始化个性化设置!") Log("[Setup] 已初始化个性化设置!")
Hint("已初始化个性化设置", HintType.Green, False) Hint("已初始化个性化设置", HintType.Green, False)
@@ -167,24 +132,21 @@
Log(ex, "初始化个性化设置失败", LogLevel.Msgbox) Log(ex, "初始化个性化设置失败", LogLevel.Msgbox)
End Try End Try
Reload() Refresh()
End Sub End Sub
'将控件改变路由到设置改变 '将控件改变路由到设置改变
Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderBackgroundOpacity.Change, SliderBackgroundBlur.Change, SliderLauncherOpacity.Change, SliderMusicVolume.Change, SliderLauncherHue.Change, SliderLauncherLight.Change, SliderLauncherSat.Change, SliderLauncherDelta.Change Private Shared Sub SliderChange(sender As MySlider, e As Object) Handles SliderMusicVolume.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Value) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Value)
End Sub End Sub
Private Shared Sub ComboChange(sender As MyComboBox, e As Object) Handles ComboBackgroundSuit.SelectionChanged, ComboCustomPreset.SelectionChanged Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckMusicStop.Change, CheckMusicRandom.Change, CheckMusicAuto.Change, CheckLogoLeft.Change, CheckHiddenFunctionHidden.Change, CheckHiddenFunctionSelect.Change, CheckHiddenFunctionModUpdate.Change, CheckHiddenPageDownload.Change, CheckHiddenPageLink.Change, CheckHiddenPageOther.Change, CheckHiddenPageSetup.Change, CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change, CheckHiddenOtherHelp.Change, CheckHiddenOtherTest.Change, CheckMusicStart.Change, CheckLauncherEmail.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.SelectedIndex) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Checked)
End Sub
Private Shared Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckMusicStop.Change, CheckMusicRandom.Change, CheckMusicAuto.Change, CheckBackgroundColorful.Change, CheckLogoLeft.Change, CheckLauncherLogo.Change, CheckHiddenFunctionHidden.Change, CheckHiddenFunctionSelect.Change, CheckHiddenFunctionModUpdate.Change, CheckHiddenPageDownload.Change, CheckHiddenPageLink.Change, CheckHiddenPageOther.Change, CheckHiddenPageSetup.Change, CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change, CheckHiddenOtherHelp.Change, CheckHiddenOtherTest.Change, CheckMusicStart.Change, CheckLauncherEmail.Change
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Checked)
End Sub End Sub
Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextLogoText.ValidatedTextChanged, TextCustomNet.ValidatedTextChanged Private Shared Sub TextBoxChange(sender As MyTextBox, e As Object) Handles TextLogoText.ValidatedTextChanged, TextCustomNet.ValidatedTextChanged
If AniControlEnabled = 0 Then Setup.Set(sender.Tag, sender.Text) If AniControlEnabled = 0 Then Settings.Set(sender.Tag, sender.Text)
End Sub End Sub
Private Shared Sub RadioBoxChange(sender As MyRadioBox, e As Object) Handles RadioLogoType0.Check, RadioLogoType1.Check, RadioLogoType2.Check, RadioLogoType3.Check, RadioLauncherTheme0.Check, RadioLauncherTheme1.Check, RadioLauncherTheme2.Check, RadioLauncherTheme3.Check, RadioLauncherTheme4.Check, RadioLauncherTheme5.Check, RadioLauncherTheme6.Check, RadioLauncherTheme7.Check, RadioLauncherTheme8.Check, RadioLauncherTheme9.Check, RadioLauncherTheme10.Check, RadioLauncherTheme11.Check, RadioLauncherTheme12.Check, RadioLauncherTheme13.Check, RadioLauncherTheme14.Check, RadioCustomType0.Check, RadioCustomType1.Check, RadioCustomType2.Check, RadioCustomType3.Check Private Shared Sub RadioBoxChange(sender As MyRadioBox, e As Object) Handles RadioLogoType0.Check, RadioLogoType1.Check, RadioLogoType2.Check, RadioLogoType3.Check, RadioCustomType0.Check, RadioCustomType1.Check, RadioCustomType2.Check, RadioCustomType3.Check
If AniControlEnabled = 0 Then Setup.Set(sender.Tag.ToString.Split("/")(0), Val(sender.Tag.ToString.Split("/")(1))) If AniControlEnabled = 0 Then Settings.Set(sender.Tag.ToString.Split("/")(0), Val(sender.Tag.ToString.Split("/")(1)))
End Sub End Sub
'背景图片 '背景图片
@@ -230,7 +192,7 @@
Directory.CreateDirectory(Path & "PCL\Pictures\") Directory.CreateDirectory(Path & "PCL\Pictures\")
Dim Pic As New List(Of String) Dim Pic As New List(Of String)
For Each File In EnumerateFiles(Path & "PCL\Pictures\") For Each File In EnumerateFiles(Path & "PCL\Pictures\")
If File.Extension.ToLower <> ".ini" AndAlso File.Extension.ToLower <> ".db" Then '文件夹可能会被加入 .ini 和 thumbs.db If File.Extension.Lower <> ".ini" AndAlso File.Extension.Lower <> ".db" Then '文件夹可能会被加入 .ini 和 thumbs.db
Pic.Add(File.FullName) Pic.Add(File.FullName)
End If End If
Next Next
@@ -251,8 +213,8 @@
Try Try
Log("[UI] 加载背景图片:" & Address) Log("[UI] 加载背景图片:" & Address)
FrmMain.ImgBack.Background = New MyBitmap(Address) FrmMain.ImgBack.Background = New MyBitmap(Address)
Setup.Load("UiBackgroundSuit", True)
FrmMain.ImgBack.Visibility = Visibility.Visible FrmMain.ImgBack.Visibility = Visibility.Visible
FrmMain.UpdateBackgroundAndTitleBar()
If IsHint Then Hint("背景图片已刷新:" & GetFileNameFromPath(Address), HintType.Green, False) If IsHint Then Hint("背景图片已刷新:" & GetFileNameFromPath(Address), HintType.Green, False)
Catch ex As Exception Catch ex As Exception
If ex.Message.Contains("参数无效") Then If ex.Message.Contains("参数无效") Then
@@ -358,7 +320,7 @@ Refresh:
PanMusicDetail.Visibility = Visibility.Visible PanMusicDetail.Visibility = Visibility.Visible
BtnMusicClear.Visibility = Visibility.Visible BtnMusicClear.Visibility = Visibility.Visible
CardMusic.Title = "背景音乐(" & CardMusic.Title = "背景音乐(" &
EnumerateFiles(Path & "PCL\Musics\").Count(Function(f) Not {".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.Lower)) &
" 首)" " 首)"
Else Else
PanMusicVolume.Visibility = Visibility.Collapsed PanMusicVolume.Visibility = Visibility.Collapsed
@@ -428,16 +390,51 @@ Refresh:
"你可以在生成教学文件后直接刷新主页,对照着进行修改,更有助于理解。" & vbCrLf & "你可以在生成教学文件后直接刷新主页,对照着进行修改,更有助于理解。" & vbCrLf &
"直接将主页文件拖进 PCL 窗口也可以快捷加载。", "主页自定义教程") "直接将主页文件拖进 PCL 窗口也可以快捷加载。", "主页自定义教程")
End Sub End Sub
Public Shared Sub OnUiCustomTypeChanged(Value As Integer)
If FrmSetupUI Is Nothing Then Return
Select Case Value
Case 0 '无
FrmSetupUI.PanCustomPreset.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomNet.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustom.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustomWarn.Visibility = Visibility.Collapsed
Case 1 '本地
FrmSetupUI.PanCustomPreset.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomLocal.Visibility = Visibility.Visible
FrmSetupUI.PanCustomNet.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustom.Visibility = Visibility.Visible
FrmSetupUI.HintCustomWarn.Visibility = If(Settings.Get("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible)
FrmSetupUI.HintCustom.Text = $"从 PCL 文件夹下的 Custom.xaml 读取主页内容。{vbCrLf}你可以手动编辑该文件,向主页添加文本、图片、常用网站、快捷启动等功能。"
CustomEventService.SetEventType(FrmSetupUI.HintCustom, CustomEvent.EventType.None)
Case 2 '联网
FrmSetupUI.PanCustomPreset.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomNet.Visibility = Visibility.Visible
FrmSetupUI.HintCustom.Visibility = Visibility.Visible
FrmSetupUI.HintCustomWarn.Visibility = If(Settings.Get("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible)
FrmSetupUI.HintCustom.Text = $"从指定网址联网获取主页内容。服主也可以用于动态更新服务器公告。{vbCrLf}如果你制作了稳定运行的联网主页,可以点击这条提示投稿,若合格即可加入预设!"
CustomEventService.SetEventType(FrmSetupUI.HintCustom, CustomEvent.EventType.打开网页)
CustomEventService.SetEventData(FrmSetupUI.HintCustom, "https://github.com/Meloong-Git/PCL/discussions/2528")
Case 3 '预设
FrmSetupUI.PanCustomPreset.Visibility = Visibility.Visible
FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed
FrmSetupUI.PanCustomNet.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustom.Visibility = Visibility.Collapsed
FrmSetupUI.HintCustomWarn.Visibility = Visibility.Collapsed
End Select
FrmSetupUI.CardCustom.TriggerForceResize()
End Sub
'主题 '主题
Private Sub LabLauncherTheme5Unlock_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles LabLauncherTheme5Unlock.MouseLeftButtonUp Private Sub LabLauncherTheme5Unlock_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles LabLauncherTheme5Unlock.MouseLeftButtonUp
RadioLauncherTheme5Gray.Opacity -= 0.23 RadioLauncherTheme5Gray.Opacity -= 0.7
RadioLauncherTheme5.Opacity += 0.23 RadioLauncherTheme5.Opacity += 0.7
AniStart({ AniStart({
AaOpacity(RadioLauncherTheme5Gray, 1, 1000 * AniSpeed), AaOpacity(RadioLauncherTheme5Gray, 1, 1000 * AniSpeed, 500 * AniSpeed, New AniEaseInFluent),
AaOpacity(RadioLauncherTheme5, -1, 1000 * AniSpeed) AaOpacity(RadioLauncherTheme5, -1, 1000 * AniSpeed, 500 * AniSpeed, New AniEaseInFluent)
}, "ThemeUnlock") }, "ThemeUnlock")
If RadioLauncherTheme5Gray.Opacity < 0.08 Then If RadioLauncherTheme5Gray.Opacity < 0.02 Then
ThemeUnlock(5, UnlockHint:="隐藏主题 玄素黑 已解锁!") ThemeUnlock(5, UnlockHint:="隐藏主题 玄素黑 已解锁!")
AniStop("ThemeUnlock") AniStop("ThemeUnlock")
RadioLauncherTheme5.Checked = True RadioLauncherTheme5.Checked = True
@@ -452,12 +449,12 @@ Refresh:
"若违规,可能会被从任意相关群中踢出!", "若违规,可能会被从任意相关群中踢出!",
"解密游戏的基本规则", "我知道了", "恕我拒绝") = 1 Then "解密游戏的基本规则", "我知道了", "恕我拒绝") = 1 Then
MyMsgBox("你需要用自己的智慧来找到下一步的线索……" & vbCrLf & MyMsgBox("你需要用自己的智慧来找到下一步的线索……" & vbCrLf &
"初始线索:gnp.dorC61\60\20\0202\moc.x1xa.2s\\:sp" & "T".ToLower & "th", "解密游戏") '防止触发病毒检测规则 "初始线索:gnp.dorC61\60\20\0202\moc.x1xa.2s\\:sp" & "T".Lower & "th", "解密游戏") '防止触发病毒检测规则
End If End If
End If End If
End Sub End Sub
Private Sub LabLauncherTheme8Copy_MouseRightButtonUp() Handles LabLauncherTheme8Copy.MouseRightButtonUp, RadioLauncherTheme8.MouseRightButtonUp Private Sub LabLauncherTheme8Copy_MouseRightButtonUp() Handles LabLauncherTheme8Copy.MouseRightButtonUp, RadioLauncherTheme8.MouseRightButtonUp
OpenWebsite("https://afdian.com/a/LTCat") OpenWebsite("https://meloong.com/afd/a/LTCat")
End Sub End Sub
Private Sub LabLauncherTheme9Copy_MouseRightButtonUp() Handles LabLauncherTheme9Copy.MouseRightButtonUp, RadioLauncherTheme9.MouseRightButtonUp Private Sub LabLauncherTheme9Copy_MouseRightButtonUp() Handles LabLauncherTheme9Copy.MouseRightButtonUp, RadioLauncherTheme9.MouseRightButtonUp
PageOtherLeft.TryFeedback() PageOtherLeft.TryFeedback()
@@ -516,56 +513,56 @@ Refresh:
If FrmMain.PanTitleSelect Is Nothing OrElse Not FrmMain.PanTitleSelect.IsLoaded Then Return If FrmMain.PanTitleSelect Is Nothing OrElse Not FrmMain.PanTitleSelect.IsLoaded Then Return
Try Try
'顶部栏 '顶部栏
If Not HiddenForceShow AndAlso Setup.Get("UiHiddenPageDownload") AndAlso Setup.Get("UiHiddenPageLink") AndAlso Setup.Get("UiHiddenPageSetup") AndAlso Setup.Get("UiHiddenPageOther") Then If Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageDownload") AndAlso Settings.Get("UiHiddenPageLink") AndAlso Settings.Get("UiHiddenPageSetup") AndAlso Settings.Get("UiHiddenPageOther") Then
'顶部栏已被全部隐藏 '顶部栏已被全部隐藏
FrmMain.PanTitleSelect.Visibility = Visibility.Collapsed FrmMain.PanTitleSelect.Visibility = Visibility.Collapsed
Else Else
'顶部栏未被全部隐藏 '顶部栏未被全部隐藏
FrmMain.PanTitleSelect.Visibility = Visibility.Visible FrmMain.PanTitleSelect.Visibility = Visibility.Visible
FrmMain.BtnTitleSelect1.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenPageDownload"), Visibility.Collapsed, Visibility.Visible) FrmMain.BtnTitleSelect1.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageDownload"), Visibility.Collapsed, Visibility.Visible)
FrmMain.BtnTitleSelect2.Visibility = Visibility.Collapsed 'If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenPageLink"), Visibility.Collapsed, Visibility.Visible) FrmMain.BtnTitleSelect2.Visibility = Visibility.Collapsed 'If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageLink"), Visibility.Collapsed, Visibility.Visible)
FrmMain.BtnTitleSelect3.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenPageSetup"), Visibility.Collapsed, Visibility.Visible) FrmMain.BtnTitleSelect3.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageSetup"), Visibility.Collapsed, Visibility.Visible)
FrmMain.BtnTitleSelect4.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenPageOther"), Visibility.Collapsed, Visibility.Visible) FrmMain.BtnTitleSelect4.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageOther"), Visibility.Collapsed, Visibility.Visible)
End If End If
'功能 '功能
FrmLaunchLeft.RefreshButtonsUI() FrmLaunchLeft.RefreshButtonsUI()
If FrmSetupUI IsNot Nothing Then If FrmSetupUI IsNot Nothing Then
FrmSetupUI.CardSwitch.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenFunctionHidden"), Visibility.Collapsed, Visibility.Visible) FrmSetupUI.CardSwitch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenFunctionHidden"), Visibility.Collapsed, Visibility.Visible)
End If End If
'设置子页面 '设置子页面
If FrmSetupLeft IsNot Nothing Then If FrmSetupLeft IsNot Nothing Then
FrmSetupLeft.ItemLaunch.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenSetupLaunch"), Visibility.Collapsed, Visibility.Visible) FrmSetupLeft.ItemLaunch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenSetupLaunch"), Visibility.Collapsed, Visibility.Visible)
FrmSetupLeft.ItemUI.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenSetupUi"), Visibility.Collapsed, Visibility.Visible) FrmSetupLeft.ItemUI.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenSetupUi"), Visibility.Collapsed, Visibility.Visible)
FrmSetupLeft.ItemLink.Visibility = Visibility.Collapsed 'If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenSetupLink"), Visibility.Collapsed, Visibility.Visible) FrmSetupLeft.ItemLink.Visibility = Visibility.Collapsed 'If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenSetupLink"), Visibility.Collapsed, Visibility.Visible)
FrmSetupLeft.ItemSystem.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenSetupSystem"), Visibility.Collapsed, Visibility.Visible) FrmSetupLeft.ItemSystem.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenSetupSystem"), Visibility.Collapsed, Visibility.Visible)
'隐藏左边选择卡 '隐藏左边选择卡
Dim AvaliableCount As Integer = 0 Dim AvaliableCount As Integer = 0
If Not Setup.Get("UiHiddenSetupLaunch") Then AvaliableCount += 1 If Not Settings.Get("UiHiddenSetupLaunch") Then AvaliableCount += 1
If Not Setup.Get("UiHiddenSetupUi") Then AvaliableCount += 1 If Not Settings.Get("UiHiddenSetupUi") Then AvaliableCount += 1
'If Not Setup.Get("UiHiddenSetupLink") Then AvaliableCount += 1 'If Not Settings.Get("UiHiddenSetupLink") Then AvaliableCount += 1
If Not Setup.Get("UiHiddenSetupSystem") Then AvaliableCount += 1 If Not Settings.Get("UiHiddenSetupSystem") Then AvaliableCount += 1
FrmSetupLeft.PanItem.Visibility = If(AvaliableCount < 2 AndAlso Not HiddenForceShow, Visibility.Collapsed, Visibility.Visible) FrmSetupLeft.PanItem.Visibility = If(AvaliableCount < 2 AndAlso Not HiddenForceShow, Visibility.Collapsed, Visibility.Visible)
End If End If
'更多子页面 '更多子页面
Dim OtherAvaliableCount As Integer = 0 Dim OtherAvaliableCount As Integer = 0
If Not Setup.Get("UiHiddenOtherHelp") Then OtherAvaliableCount += 1 If Not Settings.Get("UiHiddenOtherHelp") Then OtherAvaliableCount += 1
If Not Setup.Get("UiHiddenOtherAbout") Then OtherAvaliableCount += 1 If Not Settings.Get("UiHiddenOtherAbout") Then OtherAvaliableCount += 1
If Not Setup.Get("UiHiddenOtherTest") Then OtherAvaliableCount += 1 If Not Settings.Get("UiHiddenOtherTest") Then OtherAvaliableCount += 1
If Not Setup.Get("UiHiddenOtherFeedback") Then OtherAvaliableCount += 1 If Not Settings.Get("UiHiddenOtherFeedback") Then OtherAvaliableCount += 1
If Not Setup.Get("UiHiddenOtherVote") Then OtherAvaliableCount += 1 If Not Settings.Get("UiHiddenOtherVote") Then OtherAvaliableCount += 1
If FrmOtherLeft IsNot Nothing Then If FrmOtherLeft IsNot Nothing Then
FrmOtherLeft.ItemHelp.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenOtherHelp"), Visibility.Collapsed, Visibility.Visible) FrmOtherLeft.ItemHelp.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherHelp"), Visibility.Collapsed, Visibility.Visible)
FrmOtherLeft.ItemFeedback.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenOtherFeedback"), Visibility.Collapsed, Visibility.Visible) FrmOtherLeft.ItemFeedback.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherFeedback"), Visibility.Collapsed, Visibility.Visible)
FrmOtherLeft.ItemVote.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenOtherVote"), Visibility.Collapsed, Visibility.Visible) FrmOtherLeft.ItemVote.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherVote"), Visibility.Collapsed, Visibility.Visible)
FrmOtherLeft.ItemAbout.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenOtherAbout"), Visibility.Collapsed, Visibility.Visible) FrmOtherLeft.ItemAbout.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherAbout"), Visibility.Collapsed, Visibility.Visible)
FrmOtherLeft.ItemTest.Visibility = If(Not HiddenForceShow AndAlso Setup.Get("UiHiddenOtherTest"), Visibility.Collapsed, Visibility.Visible) FrmOtherLeft.ItemTest.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherTest"), Visibility.Collapsed, Visibility.Visible)
'隐藏左边选择卡 '隐藏左边选择卡
FrmOtherLeft.PanItem.Visibility = If(OtherAvaliableCount < 2 AndAlso Not HiddenForceShow, Visibility.Collapsed, Visibility.Visible) FrmOtherLeft.PanItem.Visibility = If(OtherAvaliableCount < 2 AndAlso Not HiddenForceShow, Visibility.Collapsed, Visibility.Visible)
End If End If
If OtherAvaliableCount = 1 AndAlso Not HiddenForceShow Then If OtherAvaliableCount = 1 AndAlso Not HiddenForceShow Then
If Not Setup.Get("UiHiddenOtherHelp") Then If Not Settings.Get("UiHiddenOtherHelp") Then
FrmMain.BtnTitleSelect4.Text = "帮助" FrmMain.BtnTitleSelect4.Text = "帮助"
ElseIf Not Setup.Get("UiHiddenOtherAbout") Then ElseIf Not Settings.Get("UiHiddenOtherAbout") Then
FrmMain.BtnTitleSelect4.Text = "关于" FrmMain.BtnTitleSelect4.Text = "关于"
Else Else
FrmMain.BtnTitleSelect4.Text = "百宝箱" FrmMain.BtnTitleSelect4.Text = "百宝箱"
@@ -595,7 +592,7 @@ Refresh:
CheckHiddenSetupUI.Checked = True CheckHiddenSetupUI.Checked = True
Else Else
'关闭 '关闭
If Setup.Get("UiHiddenSetupLaunch") AndAlso Setup.Get("UiHiddenSetupUi") AndAlso Setup.Get("UiHiddenSetupSystem") AndAlso Setup.Get("UiHiddenSetupLink") Then If Settings.Get("UiHiddenSetupLaunch") AndAlso Settings.Get("UiHiddenSetupUi") AndAlso Settings.Get("UiHiddenSetupSystem") AndAlso Settings.Get("UiHiddenSetupLink") Then
CheckHiddenSetupLaunch.Checked = False CheckHiddenSetupLaunch.Checked = False
CheckHiddenSetupSystem.Checked = False CheckHiddenSetupSystem.Checked = False
CheckHiddenSetupLink.Checked = False CheckHiddenSetupLink.Checked = False
@@ -605,7 +602,7 @@ Refresh:
End Sub End Sub
Private Sub HiddenSetupSub() Handles CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change Private Sub HiddenSetupSub() Handles CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change
'设置子页面 '设置子页面
If Setup.Get("UiHiddenSetupLaunch") AndAlso Setup.Get("UiHiddenSetupUi") AndAlso Setup.Get("UiHiddenSetupSystem") AndAlso Setup.Get("UiHiddenSetupLink") Then If Settings.Get("UiHiddenSetupLaunch") AndAlso Settings.Get("UiHiddenSetupUi") AndAlso Settings.Get("UiHiddenSetupSystem") AndAlso Settings.Get("UiHiddenSetupLink") Then
'已被全部隐藏 '已被全部隐藏
CheckHiddenPageSetup.Checked = True CheckHiddenPageSetup.Checked = True
Else Else
@@ -624,8 +621,8 @@ Refresh:
CheckHiddenOtherHelp.Checked = True CheckHiddenOtherHelp.Checked = True
Else Else
'关闭 '关闭
If Setup.Get("UiHiddenOtherHelp") AndAlso Setup.Get("UiHiddenOtherAbout") AndAlso Setup.Get("UiHiddenOtherTest") AndAlso If Settings.Get("UiHiddenOtherHelp") AndAlso Settings.Get("UiHiddenOtherAbout") AndAlso Settings.Get("UiHiddenOtherTest") AndAlso
Setup.Get("UiHiddenOtherVote") AndAlso Setup.Get("UiHiddenOtherFeedback") Then Settings.Get("UiHiddenOtherVote") AndAlso Settings.Get("UiHiddenOtherFeedback") Then
CheckHiddenOtherAbout.Checked = False CheckHiddenOtherAbout.Checked = False
CheckHiddenOtherTest.Checked = False CheckHiddenOtherTest.Checked = False
CheckHiddenOtherFeedback.Checked = False CheckHiddenOtherFeedback.Checked = False
@@ -636,7 +633,7 @@ Refresh:
End Sub End Sub
Private Sub HiddenOtherSub(sender As Object, user As Boolean) Handles CheckHiddenOtherHelp.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherTest.Change Private Sub HiddenOtherSub(sender As Object, user As Boolean) Handles CheckHiddenOtherHelp.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherTest.Change
'更多子页面(有具体内容的) '更多子页面(有具体内容的)
If Setup.Get("UiHiddenOtherHelp") AndAlso Setup.Get("UiHiddenOtherAbout") AndAlso Setup.Get("UiHiddenOtherTest") Then If Settings.Get("UiHiddenOtherHelp") AndAlso Settings.Get("UiHiddenOtherAbout") AndAlso Settings.Get("UiHiddenOtherTest") Then
'已被全部隐藏 '已被全部隐藏
CheckHiddenPageOther.Checked = True CheckHiddenPageOther.Checked = True
Else Else
@@ -645,7 +642,7 @@ Refresh:
End If End If
'修改无具体内容的项 '修改无具体内容的项
If Not user Then Return If Not user Then Return
If Setup.Get("UiHiddenOtherHelp") AndAlso Setup.Get("UiHiddenOtherAbout") AndAlso Setup.Get("UiHiddenOtherTest") Then If Settings.Get("UiHiddenOtherHelp") AndAlso Settings.Get("UiHiddenOtherAbout") AndAlso Settings.Get("UiHiddenOtherTest") Then
CheckHiddenOtherFeedback.Checked = True CheckHiddenOtherFeedback.Checked = True
CheckHiddenOtherVote.Checked = True CheckHiddenOtherVote.Checked = True
End If End If
@@ -653,8 +650,8 @@ Refresh:
Private Sub HiddenOtherNet(sender As Object, user As Boolean) Handles CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change Private Sub HiddenOtherNet(sender As Object, user As Boolean) Handles CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change
'更多子页面(无具体内容的) '更多子页面(无具体内容的)
If Not user Then Return If Not user Then Return
If Setup.Get("UiHiddenOtherHelp") AndAlso Setup.Get("UiHiddenOtherAbout") AndAlso Setup.Get("UiHiddenOtherTest") AndAlso If Settings.Get("UiHiddenOtherHelp") AndAlso Settings.Get("UiHiddenOtherAbout") AndAlso Settings.Get("UiHiddenOtherTest") AndAlso
(Not Setup.Get("UiHiddenOtherFeedback") OrElse Not Setup.Get("UiHiddenOtherVote")) Then (Not Settings.Get("UiHiddenOtherFeedback") OrElse Not Settings.Get("UiHiddenOtherVote")) Then
CheckHiddenOtherAbout.Checked = False CheckHiddenOtherAbout.Checked = False
CheckHiddenOtherTest.Checked = False CheckHiddenOtherTest.Checked = False
CheckHiddenOtherHelp.Checked = False CheckHiddenOtherHelp.Checked = False
@@ -668,15 +665,10 @@ Refresh:
#End Region #End Region
'赞助
Private Sub BtnLauncherDonate_Click(sender As Object, e As EventArgs) Handles BtnLauncherDonate.Click
OpenWebsite("https://afdian.com/a/LTCat")
End Sub
'滑动条 '滑动条
Private Sub SliderLoad() Private Sub SliderLoad()
SliderMusicVolume.GetHintText = Function(v) Math.Ceiling(v * 0.1) & "%" SliderMusicVolume.GetHintText = Function(v) Math.Ceiling(v * 0.1) & "%"
SliderLauncherOpacity.GetHintText = Function(v) Math.Round(40 + v * 0.1) & "%" SliderLauncherTransparent.GetHintText = Function(v) Math.Round(40 + v * 0.1) & "%"
SliderLauncherHue.GetHintText = Function(v) v & "°" SliderLauncherHue.GetHintText = Function(v) v & "°"
SliderLauncherSat.GetHintText = Function(v) v & "%" SliderLauncherSat.GetHintText = Function(v) v & "%"
SliderLauncherDelta.GetHintText = SliderLauncherDelta.GetHintText =
@@ -0,0 +1,81 @@
Public Class SettingService
#Region "属性"
''' <summary>
''' 指定该控件所对应的设置项。
''' </summary>
Public Shared Function GetKey(obj As DependencyObject) As String
If obj Is Nothing Then Return Nothing
Return obj.GetValue(KeyProperty)
End Function
Public Shared Sub SetKey(obj As DependencyObject, value As String)
obj.SetValue(KeyProperty, value)
End Sub
Public Shared ReadOnly KeyProperty As DependencyProperty =
DependencyProperty.RegisterAttached("Key", GetType(String), GetType(SettingService), New PropertyMetadata(Nothing))
''' <summary>
''' 指定该控件所对应的设置值。
''' </summary>
Public Shared Function GetValue(obj As DependencyObject) As String
If obj Is Nothing Then Return Nothing
Return obj.GetValue(ValueProperty)
End Function
Public Shared Sub SetValue(obj As DependencyObject, value As String)
obj.SetValue(ValueProperty, value)
End Sub
Public Shared ReadOnly ValueProperty As DependencyProperty =
DependencyProperty.RegisterAttached("Value", GetType(String), GetType(SettingService), New PropertyMetadata(Nothing))
#End Region
''' <summary>
''' 重置该控件以及它所有的子控件的设置值。
''' </summary>
Public Shared Sub ResetSettings(Target As DependencyObject)
LogicalTreeHelper.GetChildren(Target).OfType(Of DependencyObject)().ForEach(Sub(c) ResetSettings(c)) '处理子控件
Dim Key = GetKey(Target)
If Key Is Nothing Then Return
Settings.Reset(Key, Instance:=PageInstanceLeft.Instance)
End Sub
''' <summary>
''' 更新该控件以及它所有的子控件当前显示的设置值。
''' </summary>
Public Shared Sub RefreshSettings(Target As DependencyObject)
LogicalTreeHelper.GetChildren(Target).OfType(Of DependencyObject)().ForEach(Sub(c) RefreshSettings(c)) '处理子控件
Dim Key = GetKey(Target)
If Key Is Nothing Then Return
Dim NewValue = Settings.Get(Key, Instance:=PageInstanceLeft.Instance)
If TypeOf Target Is ISettingControl Then DirectCast(Target, ISettingControl).RefreshSetting(NewValue)
End Sub
''' <summary>
''' 当控件对应的设置改变时,将内容保存到设置中。
''' </summary>
Public Shared Sub SaveSetting(sender As Object)
If AniControlEnabled <> 0 Then Return
If TypeOf sender IsNot ISettingControl Then Return
Dim Key = GetKey(sender)
If Key Is Nothing Then Return
Dim NewValue As String = DirectCast(sender, ISettingControl).GetCurrentSetting()
If NewValue Is Nothing Then Return
Settings.Set(Key, NewValue, Instance:=PageInstanceLeft.Instance)
End Sub
End Class
Public Interface ISettingControl
''' <summary>
''' 更新该控件当前所显示的设置值。
''' </summary>
Sub RefreshSetting(NewValue As String)
''' <summary>
''' 获取该控件当前设定的设置值。
''' 若不应当关联该设置值,则返回 Nothing。
''' </summary>
Function GetCurrentSetting() As String
End Interface
@@ -0,0 +1,410 @@
Public Class Settings
Private Shared ReadOnly Entries As Dictionary(Of String, Setting) = (New List(Of Setting) From {
New Setting("Identify", "", Source:=Sources.Registry),
New Setting("WindowHeight", 550),
New Setting("WindowWidth", 900),
New Setting("AprilDoneYear", 0, Source:=Sources.Registry),
New Setting("HintDownloadThread", False, Source:=Sources.Registry),
New Setting("HintNotice", 0, Source:=Sources.Registry),
New Setting("HintDownload", 0, Source:=Sources.Registry),
New Setting("HintHide", False, Source:=Sources.Registry),
New Setting("HintHandInstall", False, Source:=Sources.Registry),
New Setting("HintBuy", False, Source:=Sources.Registry),
New Setting("HintClearRubbish", 0, Source:=Sources.Registry),
New Setting("HintUpdateMod", False, Source:=Sources.Registry),
New Setting("HintCustomCommand", False, Source:=Sources.Registry),
New Setting("HintCustomWarn", False, Source:=Sources.Registry),
New Setting("HintMoreAdvancedSetup", False, Source:=Sources.Registry),
New Setting("HintIndieSetup", False, Source:=Sources.Registry),
New Setting("HintExportConfig", False, Source:=Sources.Registry),
New Setting("SystemEulaVersion", 0, Source:=Sources.Registry),
New Setting("SystemCount", 0, Source:=Sources.Registry, Encrypted:=True),
New Setting("SystemLaunchCount", 0, Source:=Sources.Registry, Encrypted:=True),
New Setting("SystemLastVersionReg", 0, Source:=Sources.Registry, Encrypted:=True),
New Setting("SystemHighestSavedBetaVersionReg", 0, Source:=Sources.Registry, Encrypted:=True),
New Setting("SystemHighestBetaVersionReg", 0, Source:=Sources.Registry, Encrypted:=True),
New Setting("SystemHighestAlphaVersionReg", 0, Source:=Sources.Registry, Encrypted:=True),
New Setting("SystemHelpVersion", 0, Source:=Sources.Registry),
New Setting("SystemDebugMode", False, Source:=Sources.Registry),
New Setting("SystemDebugAnim", 9, Source:=Sources.Registry),
New Setting("SystemDebugDelay", False, Source:=Sources.Registry),
New Setting("SystemDebugSkipCopy", False, Source:=Sources.Registry),
New Setting("SystemSystemCache", "", Source:=Sources.Registry),
New Setting("SystemSystemUpdate", 0),
New Setting("SystemSystemActivity", 0),
New Setting("SystemSystemTelemetry", True, Source:=Sources.Registry),
New Setting("CacheDrops", "", Source:=Sources.Registry),
New Setting("CacheConfig", 0, Source:=Sources.Registry),
New Setting("CacheExportConfig", "", Source:=Sources.Registry),
New Setting("CacheSavedPageUrl", "", Source:=Sources.Registry),
New Setting("CacheSavedPageVersion", "", Source:=Sources.Registry),
New Setting("CacheMsOAuthRefresh", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsAccess", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsProfileJson", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsUuid", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsName", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsV2Migrated", False, Source:=Sources.Registry),
New Setting("CacheMsV2OAuthRefresh", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsV2Access", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsV2ProfileJson", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsV2Uuid", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheMsV2Name", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheNideAccess", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheNideClient", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheNideUuid", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheNideName", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheNideUsername", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheNidePass", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheNideServer", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthAccess", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthClient", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthUuid", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthName", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthUsername", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthPass", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthServerServer", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthServerName", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheAuthServerRegister", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("CacheDownloadFolder", "", Source:=Sources.Registry),
New Setting("CacheJavaListVersion", 0, Source:=Sources.Registry),
New Setting("LoginRemember", True, Source:=Sources.Registry, Encrypted:=True),
New Setting("LoginLegacyName", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("LoginMsJson", "{}", Source:=Sources.Registry, Encrypted:=True), '{UserName: OAuthToken, ...}
New Setting("LoginNideEmail", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("LoginNidePass", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("LoginAuthEmail", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("LoginAuthPass", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("LoginType", McLoginType.Legacy, Source:=Sources.Registry),
New Setting("LoginPageType", 0),
New Setting("LaunchSkinID", "", Source:=Sources.Registry, OnChanged:=Sub() PageLaunchLeft.SkinLegacy.Start()),
New Setting("LaunchSkinType", 0, Source:=Sources.Registry, OnChanged:=AddressOf PageSetupLaunch.UpdateSkinType),
New Setting("LaunchSkinSlim", False, Source:=Sources.Registry),
New Setting("LaunchFolderSelect", ""),
New Setting("LaunchFolders", "", Source:=Sources.Registry),
New Setting("LaunchArgumentTitle", ""),
New Setting("LaunchArgumentInfo", "PCL"),
New Setting("LaunchArgumentJavaSelect", "", Source:=Sources.Registry),
New Setting("LaunchArgumentJavaAll", "[]", Source:=Sources.Registry),
New Setting("LaunchArgumentIndie", 0),
New Setting("LaunchArgumentIndieV2", 4),
New Setting("LaunchArgumentVisible", 5, Source:=Sources.Registry),
New Setting("LaunchArgumentPriority", 1, Source:=Sources.Registry),
New Setting("LaunchArgumentWindowWidth", 854),
New Setting("LaunchArgumentWindowHeight", 480),
New Setting("LaunchArgumentWindowType", 1),
New Setting("LaunchArgumentRam", False, Source:=Sources.Registry),
New Setting("LaunchAdvanceJvm", "-XX:-OmitStackTraceInFastThrow -Djdk.lang.Process.allowAmbiguousCommands=True -Dfml.ignoreInvalidMinecraftCertificates=True -Dfml.ignorePatchDiscrepancies=True"),
New Setting("LaunchAdvanceGame", ""),
New Setting("LaunchAdvanceRun", ""),
New Setting("LaunchAdvanceRunWait", True),
New Setting("LaunchAdvanceDisableJLW", False),
New Setting("LaunchAdvanceDisableLUA", False),
New Setting("LaunchAdvanceGraphicCard", True, Source:=Sources.Registry),
New Setting("LaunchAdvanceGC", 4),
New Setting("LaunchRamType", 0, OnChanged:=AddressOf PageSetupLaunch.UpdateRamType),
New Setting("LaunchRamCustom", 15),
New Setting("LinkLastAutoJoinInviteCode", "", Source:=Sources.Registry),
New Setting("LinkLatencyMode", 0, Source:=Sources.Registry),
New Setting("LinkCustomPeer", ""),
New Setting("LinkEasyTierVersion", -1, Source:=Sources.Registry),
New Setting("ToolHelpChinese", True, Source:=Sources.Registry),
New Setting("ToolDownloadThread", 63, Source:=Sources.Registry),
New Setting("ToolDownloadSpeed", 42, Source:=Sources.Registry, OnChanged:=AddressOf ModNet.UpdateNetTaskSpeedLimitHigh),
New Setting("ToolDownloadSource", 1, Source:=Sources.Registry),
New Setting("ToolDownloadVersion", 1, Source:=Sources.Registry),
New Setting("ToolDownloadTranslate", 0, Source:=Sources.Registry),
New Setting("ToolDownloadTranslateV2", 1, Source:=Sources.Registry),
New Setting("ToolDownloadIgnoreQuilt", True, Source:=Sources.Registry),
New Setting("ToolDownloadCert", False, Source:=Sources.Registry, OnChanged:=AddressOf ModNet.ShouldValidateSslCertificateOnLogin),
New Setting("ToolDownloadMod", 2, Source:=Sources.Registry),
New Setting("ToolModLocalNameStyle", 0, Source:=Sources.Registry),
New Setting("ToolUpdateRelease", False, Source:=Sources.Registry),
New Setting("ToolUpdateSnapshot", False, Source:=Sources.Registry),
New Setting("ToolUpdateReleaseLast", "", Source:=Sources.Registry),
New Setting("ToolUpdateSnapshotLast", "", Source:=Sources.Registry),
New Setting("UiLauncherTransparent", 600, OnChanged:=Sub(Value As Integer) If FrmMain IsNot Nothing Then FrmMain.Opacity = Value / 1000 + 0.4), '避免与 PCL1 设置冲突(UiLauncherOpacity)
New Setting("UiLauncherHue", 180),
New Setting("UiLauncherSat", 80),
New Setting("UiLauncherDelta", 90),
New Setting("UiLauncherLight", 20),
New Setting("UiLauncherTheme", 0, OnChanged:=AddressOf ThemeRefresh),
New Setting("UiLauncherThemeGold", "", Source:=Sources.Registry, Encrypted:=True),
New Setting("UiLauncherThemeHide", "0|1|2|3|4", Source:=Sources.Registry, Encrypted:=True),
New Setting("UiLauncherThemeHide2", "0|1|2|3|4", Source:=Sources.Registry, Encrypted:=True),
New Setting("UiLauncherLogo", True),
New Setting("UiLauncherEmail", False),
New Setting("UiBackgroundColorful", True, OnChanged:=Sub() ThemeRefresh()), '不传入参数
New Setting("UiBackgroundOpacity", 1000, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
New Setting("UiBackgroundBlur", 0, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
New Setting("UiBackgroundSuit", 0, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
New Setting("UiCustomType", 0, OnChanged:=AddressOf PageSetupUI.OnUiCustomTypeChanged),
New Setting("UiCustomPreset", 0),
New Setting("UiCustomNet", ""),
New Setting("UiLogoType", 1, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
New Setting("UiLogoText", "", OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
New Setting("UiLogoLeft", False, OnChanged:=AddressOf FormMain.UpdateBackgroundAndTitleBar),
New Setting("UiMusicVolume", 500),
New Setting("UiMusicStop", False),
New Setting("UiMusicStart", False),
New Setting("UiMusicRandom", True),
New Setting("UiMusicAuto", True),
New Setting("UiHiddenPageDownload", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenPageLink", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenPageSetup", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenPageOther", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenFunctionSelect", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenFunctionModUpdate", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenFunctionHidden", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenSetupLaunch", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenSetupUi", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenSetupLink", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenSetupSystem", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenOtherHelp", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenOtherFeedback", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenOtherVote", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenOtherAbout", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenOtherTest", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("VersionAdvanceJvm", "", Source:=Sources.Instance),
New Setting("VersionAdvanceGame", "", Source:=Sources.Instance),
New Setting("VersionAdvanceAssets", 0, Source:=Sources.Instance),
New Setting("VersionAdvanceAssetsV2", False, Source:=Sources.Instance),
New Setting("VersionAdvanceJava", False, Source:=Sources.Instance),
New Setting("VersionAdvanceRun", "", Source:=Sources.Instance),
New Setting("VersionAdvanceRunWait", True, Source:=Sources.Instance),
New Setting("VersionAdvanceDisableJLW", False, Source:=Sources.Instance),
New Setting("VersionAdvanceDisableLUA", False, Source:=Sources.Instance),
New Setting("VersionAdvanceDisableModUpdate", False, Source:=Sources.Instance),
New Setting("VersionAdvanceGC", 0, Source:=Sources.Instance),
New Setting("VersionRamType", 2, Source:=Sources.Instance, OnChanged:=AddressOf PageInstanceSetup.OnVersionRamTypeChanged),
New Setting("VersionRamCustom", 15, Source:=Sources.Instance),
New Setting("VersionRamOptimize", 0, Source:=Sources.Instance),
New Setting("VersionArgumentTitle", "", Source:=Sources.Instance),
New Setting("VersionArgumentInfo", "", Source:=Sources.Instance),
New Setting("VersionArgumentIndie", -1, Source:=Sources.Instance),
New Setting("VersionArgumentIndieV2", False, Source:=Sources.Instance),
New Setting("VersionArgumentJavaSelect", "使用全局设置", Source:=Sources.Instance),
New Setting("VersionServerEnter", "", Source:=Sources.Instance),
New Setting("VersionServerLogin", 0, Source:=Sources.Instance, OnChanged:=AddressOf PageInstanceSetup.OnVersionServerLoginChanged),
New Setting("VersionServerNide", "", Source:=Sources.Instance),
New Setting("VersionServerAuthRegister", "", Source:=Sources.Instance),
New Setting("VersionServerAuthName", "", Source:=Sources.Instance),
New Setting("VersionServerAuthServer", "", Source:=Sources.Instance)
}).ToDictionary(Function(e) e.Key)
Private Enum Sources
Normal
Registry
Instance
End Enum
Private Class Setting
Public Key As String
''' <summary>
''' 若已调用过 Get 方法,则为当前值;否则为 Nothing。
''' </summary>
Public Value = Nothing
Public Encrypted As Boolean
Public DefaultValue
Public Source As Sources
''' <summary>
''' 当设置项的值实际被改变时触发,参数为新值。
''' </summary>
Public OnChanged As Action(Of Object)
''' <summary>
''' 该设置的值的实际类型。
''' </summary>
Public Type As Type
Public Sub New(Key As String, Value As Object, Optional Source As Sources = Sources.Normal, Optional Encrypted As Boolean = False, Optional OnChanged As Action(Of Object) = Nothing)
Try
Me.Key = Key
Me.DefaultValue = Value
Me.Encrypted = Encrypted
Me.Source = Source
Me.Type = If(Value, "").GetType
Me.OnChanged = OnChanged
Catch ex As Exception
Log(ex, "初始化设置项失败", LogLevel.Feedback) '#5095 的 fallback
End Try
End Sub
''' <summary>
''' 立即将当前的 Value 写入对应的注册表或文件。
''' </summary>
Public Sub Save(Optional Instance As McInstance = Nothing)
Dim Value As String = Me.Value
If Encrypted Then
Try
If Value Is Nothing Then Value = ""
Value = SecretEncrypt(Value, "PCL" & Identify)
Catch ex As Exception
Log(ex, "加密设置失败:" & Key, LogLevel.Developer)
End Try
End If
Select Case Source
Case Sources.Normal
WriteIni("Setup", Key, Value)
Case Sources.Registry
WriteReg(Key, Value)
Case Sources.Instance
If Instance Is Nothing Then Throw New Exception($"保存版本独立设置 {Key} 时未提供目标版本")
WriteIni(Instance.PathVersion & "PCL\Setup.ini", Key, Value)
End Select
End Sub
End Class
''' <summary>
''' 改变某个设置项的值。
''' </summary>
Public Shared Sub [Set](Key As String, Value As Object, Optional Instance As McInstance = Nothing)
Dim Entry As Setting = Nothing
If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
Try
'判断是否一致
If Entry.Value Is Nothing Then [Get](Key, Instance)
Value = CTypeDynamic(Value, Entry.Type)
If Entry.Value = Value Then Return
'设置新值
Entry.Value = Value
Entry.Save(Instance)
'触发改变事件(必须在保存之后,以保证 VersionServerLogin 之类的在事件中读取到的是最新的值)
If Entry.OnChanged IsNot Nothing Then Entry.OnChanged.Invoke(Entry.Value)
Catch ex As Exception
Log(ex, "设置设置项时出错(" & Key & ", " & Value & ")", LogLevel.Feedback)
End Try
End Sub
''' <summary>
''' 写入某个未经加密的设置项。
''' 若该设置项经过了加密,则会抛出异常。
''' </summary>
Public Shared Sub SetSafe(Key As String, Value As Object, Optional Instance As McInstance = Nothing)
Dim Entry As Setting = Nothing
If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
If Entry.Encrypted Then Throw New InvalidOperationException("禁止写入加密设置项:" & Key)
[Set](Key, Instance, Instance)
End Sub
''' <summary>
''' 获取某个设置项的值。
''' </summary>
Public Shared Function [Get](Key As String, Optional Instance As McInstance = Nothing)
Dim Entry As Setting = Nothing
If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
If Entry.Value IsNot Nothing Then Return Entry.Value
'对部分设置强制赋值
Static ForcedSettings As New Dictionary(Of String, Object) From {
{"UiHiddenPageLink", True},
{"UiHiddenSetupLink", True}
}
Dim ForcedSetting As Object = Nothing
If ForcedSettings.TryGetValue(Key, ForcedSetting) Then
Entry.Value = ForcedSetting
Return Entry.Value
End If
'正常读取
Try
Dim GotValue As String = Nothing '先用 String 储存,避免类型转换
Dim DefaultValue As String = If(Entry.Encrypted, SecretEncrypt(Entry.DefaultValue, "PCL" & Identify), Entry.DefaultValue)
Select Case Entry.Source
Case Sources.Normal
GotValue = ReadIni("Setup", Key, DefaultValue)
Case Sources.Registry
GotValue = ReadReg(Key, DefaultValue)
Case Sources.Instance
If Instance Is Nothing Then
Throw New Exception($"读取版本设置 {Key} 时未提供目标版本")
Else
GotValue = ReadIni(Instance.PathVersion & "PCL\Setup.ini", Key, DefaultValue)
End If
End Select
If Entry.Encrypted Then
If GotValue = DefaultValue Then
GotValue = Entry.DefaultValue
Else
Try
GotValue = SecretDecrypt(GotValue, "PCL" & Identify)
Catch ex As Exception
Log(ex, "解密设置失败:" & Key, LogLevel.Developer)
GotValue = Entry.DefaultValue
Entry.Value = Entry.DefaultValue
Entry.Save(Instance)
End Try
End If
End If
Entry.Value = CTypeDynamic(GotValue, Entry.Type)
Catch ex As Exception
Log(ex, "读取设置失败:" & Key, LogLevel.Hint)
Entry.Value = CTypeDynamic(Entry.DefaultValue, Entry.Type)
End Try
Return Entry.Value
End Function
''' <summary>
''' 获取某个未经加密的设置项的值。
''' 若该设置项经过了加密,则会抛出异常。
''' </summary>
Public Shared Function GetSafe(Key As String, Optional Instance As McInstance = Nothing)
Dim Entry As Setting = Nothing
If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
If Entry.Encrypted Then Throw New InvalidOperationException("禁止读取加密设置项:" & Key)
Return [Get](Key, Instance)
End Function
''' <summary>
''' 初始化某个设置项的值。
''' </summary>
Public Shared Sub Reset(Key As String, Optional Instance As McInstance = Nothing)
Dim Entry As Setting = Nothing
If Not Entries.TryGetValue(Key, Entry) Then Throw New KeyNotFoundException("未找到设置项:" & Key)
Try
'判断是否一致
If Entry.Value Is Nothing Then [Get](Key, Instance)
If Entry.Value = Entry.DefaultValue Then Return
'设置新值
Entry.Value = Entry.DefaultValue
Select Case Entry.Source
Case Sources.Normal
DeleteIniKey("Setup", Key)
Case Sources.Registry
DeleteReg(Key)
Case Sources.Instance
If Instance Is Nothing Then Throw New Exception($"重置版本设置 {Key} 时未提供目标版本")
DeleteIniKey(Instance.PathVersion & "PCL\Setup.ini", Key)
End Select
'触发改变事件
If Entry.OnChanged IsNot Nothing Then Entry.OnChanged.Invoke(Entry.Value)
Catch ex As Exception
Log(ex, "重置设置项时出错(" & Key & ")", LogLevel.Feedback)
End Try
End Sub
''' <summary>
''' 获取某个设置项的默认值。
''' </summary>
Public Shared Function GetDefault(Key As String) As String
Return Entries(Key).DefaultValue
End Function
''' <summary>
''' 对应的注册表或文件是否已经储存了某个设置项。
''' 若改成了和默认值一样的,在 2.12.3- 会储存更改,在 2.12.4+ 不会储存更改。
''' </summary>
Public Shared Function HasSaved(Key As String, Optional Instance As McInstance = Nothing) As Boolean
Select Case Entries(Key).Source
Case Sources.Normal
Return HasIniKey("Setup", Key)
Case Sources.Registry
Return HasReg(Key)
Case Else 'Source.Instance
If Instance Is Nothing Then Throw New Exception($"判断版本设置 {Key} 是否存在时未提供目标版本")
Return HasIniKey(Instance.PathVersion & "PCL\Setup.ini", Key)
End Select
End Function
''' <summary>
''' 当前版本改变时,要求所有版本独立设置需要重新读取。
''' </summary>
Public Shared Sub MakeInstanceDirty()
For Each Entry In Entries.Values
If Entry.Source = Sources.Instance Then Entry.Value = Nothing
Next
End Sub
End Class
@@ -140,7 +140,7 @@
Catch ex As Exception Catch ex As Exception
Log(ex, "更新下载管理显示失败(" & Loader.State.ToString & ")", LogLevel.Feedback) Log(ex, "更新下载管理显示失败(" & Loader.State.ToString & ")", LogLevel.Feedback)
End Try End Try
ElseIf Not (Loader.State = LoadState.Aborted OrElse Loader.State = LoadState.Finished) Then ElseIf Not (Loader.State = LoadState.Interrupted OrElse Loader.State = LoadState.Finished) Then
Try Try
#Region "没有卡片且未中断或完成,添加新的卡片" #Region "没有卡片且未中断或完成,添加新的卡片"
Dim CardXAML As String = " Dim CardXAML As String = "
@@ -194,7 +194,7 @@
RightCards.Remove(Loader.Name) RightCards.Remove(Loader.Name)
LoaderTaskbar.Remove(Loader) LoaderTaskbar.Remove(Loader)
Log($"[Taskbar] 关闭下载管理卡片:{Loader.Name},且移出任务列表") Log($"[Taskbar] 关闭下载管理卡片:{Loader.Name},且移出任务列表")
RunInThread(Sub() Loader.Abort()) RunInThread(Sub() Loader.Interrupt())
End Sub End Sub
'如果已经失败,再刷新一次,修改成失败的控件 '如果已经失败,再刷新一次,修改成失败的控件
If Loader.State = LoadState.Failed Then If Loader.State = LoadState.Failed Then
@@ -383,7 +383,7 @@
<Compile Include="Pages\PageSetup\PageSetupLeft.xaml.vb"> <Compile Include="Pages\PageSetup\PageSetupLeft.xaml.vb">
<DependentUpon>PageSetupLeft.xaml</DependentUpon> <DependentUpon>PageSetupLeft.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\PageSetup\ModSetup.vb" /> <Compile Include="Pages\PageSetup\Settings.vb" />
<Compile Include="Pages\PageSetup\PageSetupLaunch.xaml.vb"> <Compile Include="Pages\PageSetup\PageSetupLaunch.xaml.vb">
<DependentUpon>PageSetupLaunch.xaml</DependentUpon> <DependentUpon>PageSetupLaunch.xaml</DependentUpon>
</Compile> </Compile>
@@ -396,6 +396,7 @@
<Compile Include="Pages\PageSetup\PageSetupUI.xaml.vb"> <Compile Include="Pages\PageSetup\PageSetupUI.xaml.vb">
<DependentUpon>PageSetupUI.xaml</DependentUpon> <DependentUpon>PageSetupUI.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Pages\PageSetup\SettingService.vb" />
<Compile Include="Pages\PageSpeedLeft.xaml.vb"> <Compile Include="Pages\PageSpeedLeft.xaml.vb">
<DependentUpon>PageSpeedLeft.xaml</DependentUpon> <DependentUpon>PageSpeedLeft.xaml</DependentUpon>
</Compile> </Compile>
@@ -760,6 +761,7 @@
<ItemGroup> <ItemGroup>
<Resource Include="Resources\Font.ttf" /> <Resource Include="Resources\Font.ttf" />
<None Include="Resources\Help.zip" /> <None Include="Resources\Help.zip" />
<None Include="Resources\moddata.zip" />
<None Include="Resources\NAudio.dll" /> <None Include="Resources\NAudio.dll" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -874,9 +876,6 @@
<ItemGroup> <ItemGroup>
<None Include="Resources\java-wrapper.jar" /> <None Include="Resources\java-wrapper.jar" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Resource Include="Resources\ModData.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Resource Include="Images\Skins\Ari.png" /> <Resource Include="Images\Skins\Ari.png" />
<Resource Include="Images\Skins\Efe.png" /> <Resource Include="Images\Skins\Efe.png" />
@@ -922,7 +921,10 @@
<Resource Include="Images\Heads\EasyTier.png" /> <Resource Include="Images\Heads\EasyTier.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Resources\System.ValueTuple.dll" /> <None Include="Resources\System.ValueTuple.dll" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\lwjgl-unsafe-agent.jar" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project> </Project>
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+2 -2
View File
@@ -3,7 +3,7 @@
[![Stars](https://img.shields.io/github/stars/Meloong-Git/PCL?style=flat&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTggLjI1YS43NS43NSAwIDAgMSAuNjczLjQxOGwxLjg4MiAzLjgxNSA0LjIxLjYxMmEuNzUuNzUgMCAwIDEgLjQxNiAxLjI3OWwtMy4wNDYgMi45Ny43MTkgNC4xOTJhLjc1MS43NTEgMCAwIDEtMS4wODguNzkxTDggMTIuMzQ3bC0zLjc2NiAxLjk4YS43NS43NSAwIDAgMS0xLjA4OC0uNzlsLjcyLTQuMTk0TC44MTggNi4zNzRhLjc1Ljc1IDAgMCAxIC40MTYtMS4yOGw0LjIxLS42MTFMNy4zMjcuNjY4QS43NS43NSAwIDAgMSA4IC4yNVoiIGZpbGw9IiNlYWM1NGYiLz48L3N2Zz4=&logoSize=auto&label=Stars&labelColor=444444&color=eac54f)](https://github.com/Meloong-Git/PCL/) [![Stars](https://img.shields.io/github/stars/Meloong-Git/PCL?style=flat&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTggLjI1YS43NS43NSAwIDAgMSAuNjczLjQxOGwxLjg4MiAzLjgxNSA0LjIxLjYxMmEuNzUuNzUgMCAwIDEgLjQxNiAxLjI3OWwtMy4wNDYgMi45Ny43MTkgNC4xOTJhLjc1MS43NTEgMCAwIDEtMS4wODguNzkxTDggMTIuMzQ3bC0zLjc2NiAxLjk4YS43NS43NSAwIDAgMS0xLjA4OC0uNzlsLjcyLTQuMTk0TC44MTggNi4zNzRhLjc1Ljc1IDAgMCAxIC40MTYtMS4yOGw0LjIxLS42MTFMNy4zMjcuNjY4QS43NS43NSAwIDAgMSA4IC4yNVoiIGZpbGw9IiNlYWM1NGYiLz48L3N2Zz4=&logoSize=auto&label=Stars&labelColor=444444&color=eac54f)](https://github.com/Meloong-Git/PCL/)
[![Issues](https://img.shields.io/github/issues/Meloong-Git/PCL?style=flat&label=Issues&labelColor=444444&color=1F883D)](https://github.com/Meloong-Git/PCL/issues) [![Issues](https://img.shields.io/github/issues/Meloong-Git/PCL?style=flat&label=Issues&labelColor=444444&color=1F883D)](https://github.com/Meloong-Git/PCL/issues)
[![哔哩哔哩](https://img.shields.io/badge/动态-BiliBili-00A4DB?style=flat&labelColor=444444&logoSize=auto)](https://space.bilibili.com/11343203/dynamic) [![哔哩哔哩](https://img.shields.io/badge/动态-BiliBili-00A4DB?style=flat&labelColor=444444&logoSize=auto)](https://space.bilibili.com/11343203/dynamic)
[![爱发电](https://img.shields.io/badge/赞助-爱发电-946ce6?style=flat&labelColor=444444&logoSize=auto)](https://afdian.com/@LTCat) [![爱发电](https://img.shields.io/badge/赞助-爱发电-946ce6?style=flat&labelColor=444444&logoSize=auto)](https://meloong.com/afd/a/LTCat)
包含 PCL 的大部分源代码,包括 UI 库、动画模块、下载模块、Minecraft 启动模块等!<br/> 包含 PCL 的大部分源代码,包括 UI 库、动画模块、下载模块、Minecraft 启动模块等!<br/>
代码并不是实时更新的,它会在每次 PCL 发布更新时同步一次。<br/> 代码并不是实时更新的,它会在每次 PCL 发布更新时同步一次。<br/>
@@ -12,6 +12,6 @@
<br/> <br/>
### 相关资源 ### 相关资源
- [PCL 下载](https://afdian.com/p/0164034c016c11ebafcb52540025c377):下载可免费使用的正式版 PCL! - [PCL 下载](https://meloong.com/afd/p/0164034c016c11ebafcb52540025c377):下载可免费使用的正式版 PCL!
- [PCL 功能投票](https://github.com/Meloong-Git/PCL/discussions/2):来参加投票吧,开发者会优先处理票数较高的项目! - [PCL 功能投票](https://github.com/Meloong-Git/PCL/discussions/2):来参加投票吧,开发者会优先处理票数较高的项目!
- [帮助文档库](https://github.com/LTCatt/PCL2Help):PCL 内置帮助文档的存储库 - [帮助文档库](https://github.com/LTCatt/PCL2Help):PCL 内置帮助文档的存储库
Binary file not shown.