diff --git a/Plain Craft Launcher 2/Application.xaml.vb b/Plain Craft Launcher 2/Application.xaml.vb index db86a37..cdde3cd 100644 --- a/Plain Craft Launcher 2/Application.xaml.vb +++ b/Plain Craft Launcher 2/Application.xaml.vb @@ -78,7 +78,6 @@ Public Class Application End If End Try Directory.CreateDirectory(PathTemp & "Cache") - Directory.CreateDirectory(PathTemp & "Download") Directory.CreateDirectory(PathAppdata) '检测单例 #If Not DEBUG Then @@ -124,9 +123,9 @@ WaitRetry: '添加日志 Log($"[Start] 程序版本:{VersionDisplayName} ({VersionCode}{If(CommitHash = "", "", $",#{CommitHash}")})") #If RELEASE Then - Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",正式版", "")}") + Log($"[Start] 识别码:{Identify}{If(ThemeCheckOne(9), ",正式版", "")}") #Else - Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}") + Log($"[Start] 识别码:{Identify}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}") #End If Log($"[Start] 程序路径:{PathWithName}") Log($"[Start] 系统编码:{Encoding.Default.HeaderName} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})") diff --git a/Plain Craft Launcher 2/Controls/IMyRadio.vb b/Plain Craft Launcher 2/Controls/Behaviors/IMyRadio.vb similarity index 100% rename from Plain Craft Launcher 2/Controls/IMyRadio.vb rename to Plain Craft Launcher 2/Controls/Behaviors/IMyRadio.vb diff --git a/Plain Craft Launcher 2/Controls/Interfaces.vb b/Plain Craft Launcher 2/Controls/Behaviors/Interfaces.vb similarity index 100% rename from Plain Craft Launcher 2/Controls/Interfaces.vb rename to Plain Craft Launcher 2/Controls/Behaviors/Interfaces.vb diff --git a/Plain Craft Launcher 2/Controls/MyButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyButton.xaml.vb index 2eeaa05..992673e 100644 --- a/Plain Craft Launcher 2/Controls/MyButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyButton.xaml.vb @@ -140,51 +140,14 @@ Public Class MyButton End Try End Sub - '实现自定义事件 + '鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行) + Private IsMouseDown As Boolean = False Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp If Not IsMouseDown Then Return Log("[Control] 按下按钮:" & Text) RaiseEvent Click(sender, e) - If Not String.IsNullOrEmpty(Tag) Then - If Tag.ToString.StartsWithF("链接-") OrElse Tag.ToString.StartsWithF("启动-") Then - Hint("主页自定义按钮语法已更新,且不再兼容老版本语法,请查看新的自定义示例!") - End If - End If - ModEvent.ProcessCustomEvents(EventType, EventData, _CustomEvents) + RaiseCustomEvent() '自定义事件 End Sub - Public Property EventType As String - Get - Return GetValue(EventTypeProperty) - End Get - Set(value As String) - SetValue(EventTypeProperty, value) - End Set - End Property - Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyButton), New PropertyMetadata(Nothing)) - Public Property EventData As String - Get - Return GetValue(EventDataProperty) - End Get - Set(value As String) - SetValue(EventDataProperty, value) - End Set - End Property - Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyButton), New PropertyMetadata(Nothing)) - Public Property CustomEvents As CustomEventCollection - Get - If _CustomEvents Is Nothing Then - _CustomEvents = New CustomEventCollection - End If - Return _CustomEvents - End Get - Set(value As CustomEventCollection) - _CustomEvents = value - End Set - End Property - Private _CustomEvents As CustomEventCollection = Nothing - - '鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行) - Private IsMouseDown As Boolean = False Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown IsMouseDown = True Focus() diff --git a/Plain Craft Launcher 2/Controls/MyCard.vb b/Plain Craft Launcher 2/Controls/MyCard.vb index 0274be0..b84cae2 100644 --- a/Plain Craft Launcher 2/Controls/MyCard.vb +++ b/Plain Craft Launcher 2/Controls/MyCard.vb @@ -132,7 +132,9 @@ For Each Data As Object In Stack.Tag Select Case Type Case 0 - Stack.Children.Add(PageSelectRight.McVersionListItem(Data)) + Dim VersionItem As MyListItem = CType(Data, McVersion).ToListItem + VersionItem.ContentHandler = AddressOf PageSelectRight.McVersionListContent + Stack.Children.Add(VersionItem) Case 2 Stack.Children.Add(McDownloadListItem(Data, AddressOf McDownloadMenuSave, True)) Case 3 @@ -309,9 +311,6 @@ End Set End Property Private _IsSwapped As Boolean = False - ''' - ''' 是否已被折叠。(已过时,请使用 IsSwapped) - ''' Public Property IsSwaped As Boolean Get @@ -325,37 +324,45 @@ Sub(sender, e) If sender IsNot Nothing AndAlso TypeOf sender Is MyCard Then CType(sender, MyCard).IsSwapped = CType(e.NewValue, Boolean))) Public Property SwapLogoRight As Boolean = False - Private IsMouseDown As Boolean = False + Private IsSwapMouseDown As Boolean = False '用于触发卡片展开/折叠的 MouseDown + Private IsCustomMouseDown As Boolean = False '用于触发自定义事件的 MouseDown Public Event PreviewSwap(sender As Object, e As RouteEventArgs) Public Event Swap(sender As Object, e As RouteEventArgs) Public Const SwapedHeight As Integer = 40 Private Sub MyCard_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown Dim Pos As Double = Mouse.GetPosition(Me).Y + If Not IsSwapped AndAlso + (Pos > If(IsSwapped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return + IsCustomMouseDown = True If Not IsSwapped AndAlso (SwapControl Is Nothing OrElse Pos > If(IsSwapped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return '检测点击位置;或已经不在可视树上的误判 - IsMouseDown = True + IsSwapMouseDown = True End Sub - Private Sub MyCard_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp - If Not IsMouseDown Then Return - IsMouseDown = False + Private Sub MyCard_MouseLeftButtonUp() Handles Me.MouseLeftButtonUp + If Not IsCustomMouseDown Then Return + IsCustomMouseDown = False + RaiseCustomEvent() '触发自定义事件 + + If Not IsSwapMouseDown Then Return + IsSwapMouseDown = False Dim Pos As Double = Mouse.GetPosition(Me).Y If Not IsSwapped AndAlso (SwapControl Is Nothing OrElse Pos > If(IsSwapped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return '检测点击位置;或已经不在可视树上的误判 - Dim ee = New RouteEventArgs(True) - RaiseEvent PreviewSwap(Me, ee) - If ee.Handled Then - IsMouseDown = False + Dim e = New RouteEventArgs(True) + RaiseEvent PreviewSwap(Me, e) + If e.Handled Then + IsSwapMouseDown = False Return End If IsSwapped = Not IsSwapped Log("[Control] " & If(IsSwapped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title)) - RaiseEvent Swap(Me, ee) + RaiseEvent Swap(Me, e) End Sub Private Sub MyCard_MouseLeave_Swap(sender As Object, e As MouseEventArgs) Handles Me.MouseLeave - IsMouseDown = False + IsSwapMouseDown = False End Sub #End Region diff --git a/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.vb b/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.vb index a0e8c9c..3703419 100644 --- a/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.vb @@ -12,9 +12,6 @@ Public Class MyCheckBox ''' 是否为用户手动改变的勾选状态。 Public Event Change(sender As Object, user As Boolean) Public Event PreviewChange(sender As Object, e As RouteEventArgs) - Public Sub RaiseChange() - RaiseEvent Change(Me, False) - End Sub '使外部程序引发本控件的 Change 事件 '自定义属性 Public Property Checked As Boolean @@ -59,6 +56,7 @@ Public Class MyCheckBox '更改动画 SyncUI() + RaiseCustomEvent() Catch ex As Exception Log(ex, "设置 Checked 失败") End Try diff --git a/Plain Craft Launcher 2/Controls/MyComboBox.vb b/Plain Craft Launcher 2/Controls/MyComboBox.vb index 874b48a..69f7ae2 100644 --- a/Plain Craft Launcher 2/Controls/MyComboBox.vb +++ b/Plain Craft Launcher 2/Controls/MyComboBox.vb @@ -117,15 +117,14 @@ Private IsTextChanging As Boolean = False Private Sub MyComboBox_TextChanged(sender As Object, e As TextChangedEventArgs) Handles Me.TextChanged If IsTextChanging OrElse Not IsEditable Then Return - If SelectedItem IsNot Nothing AndAlso Text <> SelectedItem.ToString Then - Dim RawText As String = Text - Dim RawSelectionStart As Integer = TextBox.SelectionStart - IsTextChanging = True - SelectedItem = Nothing - Text = RawText - TextBox.SelectionStart = RawSelectionStart - IsTextChanging = False - End If + If SelectedItem Is Nothing OrElse Text = SelectedItem.ToString Then Return + Dim RawText As String = Text + Dim RawSelectionStart As Integer = TextBox.SelectionStart + IsTextChanging = True + SelectedItem = Nothing + Text = RawText + TextBox.SelectionStart = RawSelectionStart + IsTextChanging = False End Sub Public ReadOnly Property ContentPresenter As ContentPresenter @@ -134,4 +133,8 @@ End Get End Property + Private Sub MyComboBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles Me.SelectionChanged + If IsLoaded AndAlso AniControlEnabled = 0 Then RaiseCustomEvent() + End Sub + End Class diff --git a/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.vb index 0bb1b3a..6f90827 100644 --- a/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.vb @@ -53,25 +53,26 @@ Set(value As Boolean) If _Show = value Then Return _Show = value - RunInUi(Sub() - If value Then - '有了 - Visibility = Visibility.Visible - AniStart({ - AaScaleTransform(Me, 0.3 - CType(RenderTransform, ScaleTransform).ScaleX, 500, 60, New AniEaseOutFluent(AniEasePower.Weak)), - AaScaleTransform(Me, 0.7, 500, 60, New AniEaseOutBack(AniEasePower.Weak)), - AaHeight(Me, 50 - Height, 200,, New AniEaseOutFluent(AniEasePower.Weak)) - }, "MyExtraButton MainScale " & Uuid) - Else - '没了 - AniStart({ - AaScaleTransform(Me, -CType(RenderTransform, ScaleTransform).ScaleX, 100,, New AniEaseInFluent(AniEasePower.Weak)), - AaHeight(Me, -Height, 400, 100, New AniEaseOutFluent()), - AaCode(Sub() Visibility = Visibility.Collapsed,, True) - }, "MyExtraButton MainScale " & Uuid) - End If - IsHitTestVisible = value '防止缩放动画中依然可以点进去 - End Sub) + RunInUi( + Sub() + If value Then + '有了 + Visibility = Visibility.Visible + AniStart({ + AaScaleTransform(Me, 0.3 - CType(RenderTransform, ScaleTransform).ScaleX, 500, 60, New AniEaseOutFluent(AniEasePower.Weak)), + AaScaleTransform(Me, 0.7, 500, 60, New AniEaseOutBack(AniEasePower.Weak)), + AaHeight(Me, 50 - Height, 200,, New AniEaseOutFluent(AniEasePower.Weak)) + }, "MyExtraButton MainScale " & Uuid) + Else + '没了 + AniStart({ + AaScaleTransform(Me, -CType(RenderTransform, ScaleTransform).ScaleX, 100,, New AniEaseInFluent(AniEasePower.Weak)), + AaHeight(Me, -Height, 400, 100, New AniEaseOutFluent()), + AaCode(Sub() Visibility = Visibility.Collapsed,, True) + }, "MyExtraButton MainScale " & Uuid) + End If + IsHitTestVisible = value '防止缩放动画中依然可以点进去 + End Sub) End Set End Property Public Delegate Function ShowCheckDelegate() As Boolean @@ -137,6 +138,7 @@ AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 300,, New AniEaseOutBack) }, "MyExtraButton Scale " & Uuid) End If + If IsLeftMouseHeld Then RaiseCustomEvent() IsLeftMouseHeld = False RefreshColor() '直接刷新颜色以判断是否已触发 MouseLeave End Sub @@ -199,16 +201,17 @@ ''' 发出一圈波浪效果提示。 ''' Public Sub Ribble() - RunInUi(Sub() - Dim Shape As New Border With {.CornerRadius = New CornerRadius(1000), .BorderThickness = New Thickness(0.001), .Opacity = 0.5, .RenderTransformOrigin = New Point(0.5, 0.5), .RenderTransform = New ScaleTransform()} - Shape.SetResourceReference(Border.BackgroundProperty, "ColorBrush5") - PanScale.Children.Insert(0, Shape) - AniStart({ - AaScaleTransform(Shape, 13, 1000, Ease:=New AniEaseInoutFluent(AniEasePower.Strong, 0.3)), - AaOpacity(Shape, -Shape.Opacity, 1000), - AaCode(Sub() PanScale.Children.Remove(Shape), After:=True) - }, "ExtraButton Ribble " & GetUuid()) - End Sub) + RunInUi( + Sub() + Dim Shape As New Border With {.CornerRadius = New CornerRadius(1000), .BorderThickness = New Thickness(0.001), .Opacity = 0.5, .RenderTransformOrigin = New Point(0.5, 0.5), .RenderTransform = New ScaleTransform()} + Shape.SetResourceReference(Border.BackgroundProperty, "ColorBrush5") + PanScale.Children.Insert(0, Shape) + AniStart({ + AaScaleTransform(Shape, 13, 1000, Ease:=New AniEaseInoutFluent(AniEasePower.Strong, 0.3)), + AaOpacity(Shape, -Shape.Opacity, 1000), + AaCode(Sub() PanScale.Children.Remove(Shape), After:=True) + }, "ExtraButton Ribble " & GetUuid()) + End Sub) End Sub End Class diff --git a/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.vb index 9784cd0..266ba47 100644 --- a/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.vb @@ -81,12 +81,12 @@ Public Class MyExtraTextButton '触发点击事件 Private Sub Button_LeftMouseUp(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseLeftButtonUp - If IsLeftMouseHeld Then - Log("[Control] 按下附加图标按钮:" & Text) - RaiseEvent Click(sender, e) - e.Handled = True - Button_LeftMouseUp() - End If + If Not IsLeftMouseHeld Then Return + Log("[Control] 按下附加图标按钮:" & Text) + RaiseEvent Click(sender, e) + e.Handled = True + RaiseCustomEvent() + Button_LeftMouseUp() End Sub '鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行) diff --git a/Plain Craft Launcher 2/Controls/MyHint.xaml.vb b/Plain Craft Launcher 2/Controls/MyHint.xaml.vb index dba944a..9498b37 100644 --- a/Plain Craft Launcher 2/Controls/MyHint.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyHint.xaml.vb @@ -113,7 +113,7 @@ Public Class MyHint IsMouseDown = False Log("[Control] 按下提示条" & If(String.IsNullOrEmpty(Name), "", ":" & Name)) e.Handled = True - ModEvent.ProcessCustomEvents(EventType, EventData, _CustomEvents) + RaiseCustomEvent() '自定义事件 End Sub Private Sub MyHint_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown IsMouseDown = True @@ -121,36 +121,6 @@ Public Class MyHint Private Sub MyHint_MouseLeave() Handles Me.MouseLeave IsMouseDown = False End Sub - Public Property EventType As String - Get - Return GetValue(EventTypeProperty) - End Get - Set(value As String) - SetValue(EventTypeProperty, value) - End Set - End Property - Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyHint), New PropertyMetadata(Nothing)) - Public Property EventData As String - Get - Return GetValue(EventDataProperty) - End Get - Set(value As String) - SetValue(EventDataProperty, value) - End Set - End Property - Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyHint), New PropertyMetadata(Nothing)) - Public Property CustomEvents As CustomEventCollection - Get - If _CustomEvents Is Nothing Then - _CustomEvents = New CustomEventCollection - End If - Return _CustomEvents - End Get - Set(value As CustomEventCollection) - _CustomEvents = value - End Set - End Property - Private _CustomEvents As CustomEventCollection = Nothing End Class Partial Public Module ModAnimation diff --git a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb index d060e88..5da1eaf 100644 --- a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb @@ -48,48 +48,16 @@ End Set End Property - '触发点击事件 + '鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行) + Private IsMouseDown As Boolean = False Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp If Not IsMouseDown Then Return Log("[Control] 按下图标按钮" & If(String.IsNullOrEmpty(Name), "", ":" & Name)) RaiseEvent Click(sender, e) e.Handled = True Button_MouseUp() - ModEvent.ProcessCustomEvents(EventType, EventData, _CustomEvents) + RaiseCustomEvent() '自定义事件 End Sub - Public Property EventType As String - Get - Return GetValue(EventTypeProperty) - End Get - Set(value As String) - SetValue(EventTypeProperty, value) - End Set - End Property - Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyIconButton), New PropertyMetadata(Nothing)) - Public Property EventData As String - Get - Return GetValue(EventDataProperty) - End Get - Set(value As String) - SetValue(EventDataProperty, value) - End Set - End Property - Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyIconButton), New PropertyMetadata(Nothing)) - Public Property CustomEvents As CustomEventCollection - Get - If _CustomEvents Is Nothing Then - _CustomEvents = New CustomEventCollection - End If - Return _CustomEvents - End Get - Set(value As CustomEventCollection) - _CustomEvents = value - End Set - End Property - Private _CustomEvents As CustomEventCollection = Nothing - - '鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行) - Private IsMouseDown As Boolean = False Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown IsMouseDown = True Focus() @@ -114,7 +82,6 @@ RefreshAnim() '直接刷新颜色以判断是否已触发 MouseLeave End Sub - '自定义事件 '务必放在 IsMouseDown 更新之后 Private Const AnimationColorIn As Integer = 120 Private Const AnimationColorOut As Integer = 150 diff --git a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.vb index 1fe5557..dd5ed21 100644 --- a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.vb @@ -8,9 +8,6 @@ Public Class MyIconTextButton Public Uuid As Integer = GetUuid() Public Event Check(sender As Object, raiseByMouse As Boolean) Public Event Change(sender As Object, raiseByMouse As Boolean) - Public Sub RaiseChange() - RaiseEvent Change(Me, False) - End Sub '使外部程序可以引发本控件的 Change 事件 '自定义属性 @@ -76,7 +73,7 @@ Public Class MyIconTextButton Log("[Control] 按下带图标按钮:" & Text) IsMouseDown = False RaiseEvent Click(Me, New RouteEventArgs(True)) - ModEvent.ProcessCustomEvents(EventType, EventData, _CustomEvents) + RaiseCustomEvent() '自定义事件 RefreshColor() End Sub Private Sub MyIconTextButton_MouseDown() Handles Me.MouseLeftButtonDown @@ -87,36 +84,6 @@ Public Class MyIconTextButton IsMouseDown = False RefreshColor() End Sub - Public Property EventType As String - Get - Return GetValue(EventTypeProperty) - End Get - Set(value As String) - SetValue(EventTypeProperty, value) - End Set - End Property - Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(Nothing)) - Public Property EventData As String - Get - Return GetValue(EventDataProperty) - End Get - Set(value As String) - SetValue(EventDataProperty, value) - End Set - End Property - Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(Nothing)) - Public Property CustomEvents As CustomEventCollection - Get - If _CustomEvents Is Nothing Then - _CustomEvents = New CustomEventCollection - End If - Return _CustomEvents - End Get - Set(value As CustomEventCollection) - _CustomEvents = value - End Set - End Property - Private _CustomEvents As CustomEventCollection = Nothing '动画 diff --git a/Plain Craft Launcher 2/Controls/MyImage.vb b/Plain Craft Launcher 2/Controls/MyImage.vb index 8f6de5b..d4c5cf1 100644 --- a/Plain Craft Launcher 2/Controls/MyImage.vb +++ b/Plain Craft Launcher 2/Controls/MyImage.vb @@ -46,7 +46,7 @@ Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyImage).Source = e.NewValue.ToString()))) ''' - ''' 若 Source 是一个网络图片,该地址将作为第二下载源。 + ''' 若 Source 是一个网络图片,该地址将作为第二图片源。 ''' Public Property FallbackSource As String Get @@ -120,11 +120,12 @@ End If RunInNewThread( Sub() + Dim IsLocalFallback As Boolean = FallbackSource IsNot Nothing AndAlso Not FallbackSource.StartsWithF("http") Try '下载 ActualSource = LoadingSource '显示加载中的占位图片 NetDownloadByLoader( - If(String.IsNullOrEmpty(FallbackSource), {Source}, {Source, FallbackSource}), + If(String.IsNullOrEmpty(FallbackSource) OrElse IsLocalFallback, {Source}, {Source, FallbackSource}), TempPath, SimulateBrowserHeaders:=True) If EnableCache Then '保存缓存并显示 @@ -139,7 +140,19 @@ If TempPath IsNot Nothing Then File.Delete(TempPath) Catch End Try - Log(ex, $"下载图片失败", LogLevel.Hint) + '加载本地备用图片 + If IsLocalFallback Then + Try + RunInUiWait(Sub() ActualSource = FallbackSource) + Log(ex, $"下载图片失败,使用本地备用图片({Source})") + Return + Catch exx As Exception + Log(ex, $"下载图片失败({Source})", LogLevel.Hint) + Log(exx, $"加载备用图片失败({FallbackSource})", LogLevel.Hint) + End Try + Else + Log(ex, $"下载图片失败({Source},备用:{FallbackSource})", LogLevel.Hint) + End If End Try End Sub, "MyImage PicLoader " & GetUuid() & "#", ThreadPriority.BelowNormal) End Sub diff --git a/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb b/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb index 48c5d8e..cf462ec 100644 --- a/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb @@ -506,8 +506,8 @@ Public Class MyListItem RaiseEvent Click(sender, e) If e.Handled Then Return '触发自定义事件 - If Not String.IsNullOrEmpty(EventType) Then - ModEvent.ProcessCustomEvents(EventType, EventData, _CustomEvents) + If CustomEventService.GetEventType(sender) <> CustomEvent.EventType.None Then + RaiseCustomEvent() e.Handled = True End If If e.Handled Then Return @@ -537,38 +537,6 @@ Public Class MyListItem If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = True End Sub - '实现自定义事件 - Public Property EventType As String - Get - Return GetValue(EventTypeProperty) - End Get - Set(value As String) - SetValue(EventTypeProperty, value) - End Set - End Property - Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyListItem), New PropertyMetadata(Nothing)) - Public Property EventData As String - Get - Return GetValue(EventDataProperty) - End Get - Set(value As String) - SetValue(EventDataProperty, value) - End Set - End Property - Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyListItem), New PropertyMetadata(Nothing)) - Public Property CustomEvents As CustomEventCollection - Get - If _CustomEvents Is Nothing Then - _CustomEvents = New CustomEventCollection - End If - Return _CustomEvents - End Get - Set(value As CustomEventCollection) - _CustomEvents = value - End Set - End Property - Private _CustomEvents As CustomEventCollection = Nothing - #End Region Private StateLast As String @@ -669,13 +637,14 @@ Public Class MyListItem SetResourceReference(ForegroundProperty, "ColorBrush1") End If ColumnPaddingRight.Width = New GridLength(MinPaddingRight) - If EventType = "打开帮助" AndAlso Not (Title <> "" AndAlso Info <> "") Then '#3266 + If CustomEventService.GetEventType(Me) = CustomEvent.EventType.打开帮助 AndAlso Not (Title <> "" AndAlso Info <> "") Then '#3266 Try - Dim Unused = New HelpEntry(GetEventAbsoluteUrls(EventData, EventType)(0)).SetToListItem(Me) + Dim Entry As New HelpEntry(CustomEvent.GetAbsoluteUrls(CustomEventService.GetEventData(Me), CustomEventService.GetEventType(Me))(0)) + Entry.SetToListItem(Me) Catch ex As Exception Log(ex, "设置帮助 MyListItem 失败", LogLevel.Msgbox) - EventType = Nothing - EventData = Nothing + CustomEventService.SetEventType(Me, CustomEvent.EventType.None) + CustomEventService.SetEventData(Me, "") End Try End If End Sub diff --git a/Plain Craft Launcher 2/Controls/MyMenuItem.vb b/Plain Craft Launcher 2/Controls/MyMenuItem.vb index cc70ee6..4c22da3 100644 --- a/Plain Craft Launcher 2/Controls/MyMenuItem.vb +++ b/Plain Craft Launcher 2/Controls/MyMenuItem.vb @@ -54,4 +54,7 @@ End If End Sub + Private Sub MyMenuItem_Click(sender As Object, e As RoutedEventArgs) Handles Me.Click + RaiseCustomEvent() + End Sub End Class diff --git a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb index 5dd839f..ba77d6f 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb @@ -93,6 +93,7 @@ Public Class MyRadioBox If IsChanged Then If Checked Then RaiseEvent Check(Me, New RouteEventArgs(user)) RaiseEvent Changed(Me, New RouteEventArgs(user)) + RaiseCustomEvent() End If '更改动画 diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb index 4be05b8..2753034 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb @@ -7,10 +7,6 @@ Public Class MyRadioButton Public Uuid As Integer = GetUuid() Public Event Check(sender As Object, raiseByMouse As Boolean) - Public Event Change(sender As Object, raiseByMouse As Boolean) - Public Sub RaiseChange() - RaiseEvent Change(Me, False) - End Sub '使外部程序可以引发本控件的 Change 事件 '自定义属性 @@ -46,23 +42,22 @@ Public Class MyRadioButton ''' 手动设置 Checked 属性。 ''' ''' 新的 Checked 属性。 - ''' 是否由用户引发。 + ''' 是否由用户引发。 ''' 是否执行动画。 - Public Sub SetChecked(value As Boolean, user As Boolean, anime As Boolean) + Public Sub SetChecked(value As Boolean, raiseByMouse As Boolean, anime As Boolean) Try '自定义属性基础 Dim IsChanged As Boolean = False - If IsLoaded AndAlso Not value = _Checked Then RaiseEvent Change(Me, user) - If Not value = _Checked Then + If _Checked <> value Then _Checked = value IsChanged = True End If '保证只有一个单选框选中 - If IsNothing(Parent) Then Return + If Parent Is Nothing Then Return Dim RadioboxList As New List(Of MyRadioButton) Dim CheckedCount As Integer = 0 '收集控件列表与选中个数 @@ -105,7 +100,8 @@ Public Class MyRadioButton RefreshColor(Nothing, anime) '触发事件 - If Checked Then RaiseEvent Check(Me, user) + If Checked Then RaiseEvent Check(Me, raiseByMouse) + RaiseCustomEvent() Catch ex As Exception Log(ex, "单选按钮勾选改变错误", LogLevel.Hint) diff --git a/Plain Craft Launcher 2/Controls/MySearchBox.xaml.vb b/Plain Craft Launcher 2/Controls/MySearchBox.xaml.vb index ee3bb15..a8fde05 100644 --- a/Plain Craft Launcher 2/Controls/MySearchBox.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MySearchBox.xaml.vb @@ -39,4 +39,7 @@ TextBox.Focus() End Sub + Private Sub MySearchBox_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp + If e.Key = Key.Enter Then RaiseCustomEvent() + End Sub End Class diff --git a/Plain Craft Launcher 2/Controls/MyTextBox.vb b/Plain Craft Launcher 2/Controls/MyTextBox.vb index e847a58..55a00b3 100644 --- a/Plain Craft Launcher 2/Controls/MyTextBox.vb +++ b/Plain Craft Launcher 2/Controls/MyTextBox.vb @@ -291,4 +291,8 @@ End If End Sub + '在按下回车时触发自定义事件 + Private Sub MyTextBox_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp + If e.Key = Key.Enter Then RaiseCustomEvent() + End Sub End Class diff --git a/Plain Craft Launcher 2/Controls/MyTextButton.vb b/Plain Craft Launcher 2/Controls/MyTextButton.vb index bea7021..4bde410 100644 --- a/Plain Craft Launcher 2/Controls/MyTextButton.vb +++ b/Plain Craft Launcher 2/Controls/MyTextButton.vb @@ -22,15 +22,15 @@ End Set End Property Public Shared ReadOnly TextProperty As DependencyProperty = - DependencyProperty.Register("Text", GetType(String), GetType(MyTextButton), New PropertyMetadata("", Sub(sender As MyTextButton, e As DependencyPropertyChangedEventArgs) - If Not e.OldValue = e.NewValue Then - AniStart({ - AaOpacity(sender, -sender.Opacity, 50), - AaCode(Sub() sender.Content = e.NewValue,, True), - AaOpacity(sender, 1, 170) - }, "MyTextButton Text " & sender.Uuid) - End If - End Sub)) + DependencyProperty.Register("Text", GetType(String), GetType(MyTextButton), New PropertyMetadata("", + Sub(sender As MyTextButton, e As DependencyPropertyChangedEventArgs) + If e.OldValue = e.NewValue Then Return + AniStart({ + AaOpacity(sender, -sender.Opacity, 50), + AaCode(Sub() sender.Content = e.NewValue,, True), + AaOpacity(sender, 1, 170) + }, "MyTextButton Text " & sender.Uuid) + End Sub)) '鼠标事件 @@ -43,13 +43,12 @@ IsMouseDown = False End Sub Private Sub MyTextButton_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp - If IsMouseDown Then - IsMouseDown = False - Log("[Control] 按下文本按钮:" & Text) - RaiseEvent Click(Me, Nothing) - ModEvent.ProcessCustomEvents(EventType, EventData, _CustomEvents) - e.Handled = True - End If + If Not IsMouseDown Then Return + IsMouseDown = False + Log("[Control] 按下文本按钮:" & Text) + RaiseEvent Click(Me, Nothing) + RaiseCustomEvent() + e.Handled = True End Sub '指向动画 @@ -85,38 +84,4 @@ End If End Sub - '实现自定义事件 - Public Property EventType As String - Get - Return GetValue(EventTypeProperty) - End Get - Set(value As String) - SetValue(EventTypeProperty, value) - End Set - End Property - Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register( - "EventType", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing)) - Public Property EventData As String - Get - Return GetValue(EventDataProperty) - End Get - Set(value As String) - SetValue(EventDataProperty, value) - End Set - End Property - Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register( - "EventData", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing)) - Public Property CustomEvents As CustomEventCollection - Get - If _CustomEvents Is Nothing Then - _CustomEvents = New CustomEventCollection - End If - Return _CustomEvents - End Get - Set(value As CustomEventCollection) - _CustomEvents = value - End Set - End Property - Private _CustomEvents As CustomEventCollection = Nothing - End Class diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb index 7799e8f..7f1c0b1 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.vb +++ b/Plain Craft Launcher 2/FormMain.xaml.vb @@ -104,6 +104,15 @@ Public Class FormMain '3:BUG+ IMP* FEAT- '2:BUG* IMP- '1:BUG- + If LastVersion < 371 Then 'Snapshot 2.10.9 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:如果版本设置了自定义描述,会在标题后面以淡灰色显示其版本号")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:支持为一个控件设置多个自定义事件")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:修改变量、弹出提示自定义事件")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:添加大量替换标记,允许在更多设置和 XAML 中使用更多替换标记")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法安装 MMC 整合包")) + FeatureCount += 33 + BugCount += 11 + End If If LastVersion < 370 Then 'Snapshot 2.10.8 If LastVersion >= 368 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化")) FeatureCount += 3 @@ -318,7 +327,7 @@ Public Class FormMain FrmLaunchRight.PageState = MyPageRight.PageStates.ContentStay '模式提醒 #If DEBUG Then - Hint("[开发者模式] PCL 正以开发者模式运行,这可能会造成严重的性能下降,请务必立即向开发者反馈此问题!", HintType.Critical) + Hint("[开发者模式] PCL 正以开发者模式运行,这可能会造成严重的性能下降,请务必立即向开发者反馈此问题!", HintType.Red) #End If If ModeDebug Then Hint("[调试模式] PCL 正以调试模式运行,这可能会导致性能下降,若无必要请不要开启!") '尽早执行的加载池 @@ -687,9 +696,9 @@ Public Class FormMain If e.Key = Key.F12 Then PageSetupUI.HiddenForceShow = Not PageSetupUI.HiddenForceShow If PageSetupUI.HiddenForceShow Then - Hint("功能隐藏设置已暂时关闭!", HintType.Finish) + Hint("功能隐藏设置已暂时关闭!", HintType.Green) Else - Hint("功能隐藏设置已重新开启!", HintType.Finish) + Hint("功能隐藏设置已重新开启!", HintType.Green) End If PageSetupUI.HiddenRefresh() Return @@ -785,12 +794,12 @@ Public Class FormMain Dim AuthlibServer As String = Net.WebUtility.UrlDecode(Str.Substring("authlib-injector:yggdrasil-server:".Length)) Log("[System] Authlib 拖拽:" & AuthlibServer) If Not String.IsNullOrEmpty(New ValidateHttp().Validate(AuthlibServer)) Then - Hint($"输入的 Authlib 验证服务器不符合网址格式({AuthlibServer})!", HintType.Critical) + Hint($"输入的 Authlib 验证服务器不符合网址格式({AuthlibServer})!", HintType.Red) Return End If Dim TargetVersion = If(PageCurrent = PageType.VersionSetup, PageVersionLeft.Version, McVersionCurrent) If TargetVersion Is Nothing Then - Hint("请先下载游戏,再设置第三方登录!", HintType.Critical) + Hint("请先下载游戏,再设置第三方登录!", HintType.Red) Return End If If AuthlibServer = "https://littleskin.cn/api/yggdrasil" Then @@ -837,7 +846,7 @@ Public Class FormMain '获取文件并检查 Dim FilePathRaw = e.Data.GetData(DataFormats.FileDrop) If FilePathRaw Is Nothing Then '#2690 - Hint("请将文件解压后再拖入!", HintType.Critical) + Hint("请将文件解压后再拖入!", HintType.Red) Return End If e.Handled = True @@ -855,10 +864,10 @@ Public Class FormMain Log("[System] 接受文件拖拽:" & FilePath & If(FilePathList.Any, $" 等 {FilePathList.Count} 个文件", ""), LogLevel.Developer) '基础检查 If Directory.Exists(FilePathList.First) AndAlso Not File.Exists(FilePathList.First) Then - Hint("请拖入一个文件,而非文件夹!", HintType.Critical) + Hint("请拖入一个文件,而非文件夹!", HintType.Red) Return ElseIf Not File.Exists(FilePathList.First) Then - Hint("拖入的文件不存在:" & FilePathList.First, HintType.Critical) + Hint("拖入的文件不存在:" & FilePathList.First, HintType.Red) Return End If '多文件拖拽 @@ -866,7 +875,7 @@ Public Class FormMain '必须要求全部为 jar 文件 For Each File In FilePathList If Not {"jar", "litemod", "disabled", "old"}.Contains(File.AfterLast(".").ToLower) Then - Hint("一次请只拖入一个文件!", HintType.Critical) + Hint("一次请只拖入一个文件!", HintType.Red) Return End If Next @@ -885,7 +894,7 @@ Public Class FormMain Sub() Setup.Set("UiCustomType", 1) FrmLaunchRight.ForceRefresh() - Hint("已加载主页自定义文件!", HintType.Finish) + Hint("已加载主页自定义文件!", HintType.Green) End Sub) Return End If @@ -995,9 +1004,9 @@ Public Class FormMain #Region "切换页面" '页面种类与属性 - '注意,这一枚举在 “切换页面” EventType 中调用,应视作公开 API 的一部分 ''' ''' 页面种类。 + ''' 该枚举在自定义事件中使用,是公开 API 的一部分。 ''' Public Enum PageType ''' @@ -1043,6 +1052,7 @@ Public Class FormMain End Enum ''' ''' 次要页面种类。其数值必须与 StackPanel 中的下标一致。 + ''' 该枚举在自定义事件中使用,是公开 API 的一部分。 ''' Public Enum PageSubType [Default] = 0 @@ -1485,7 +1495,7 @@ Public Class FormMain '投降 Public Sub AprilGiveup() Handles BtnExtraApril.Click If IsAprilEnabled AndAlso Not IsAprilGiveup Then - Hint("=D", HintType.Finish) + Hint("=D", HintType.Green) IsAprilGiveup = True FrmLaunchLeft.AprilScaleTrans.ScaleX = 1 FrmLaunchLeft.AprilScaleTrans.ScaleY = 1 @@ -1503,7 +1513,7 @@ Public Class FormMain For Each Watcher In McWatcherList Watcher.Kill() Next - Hint("已关闭运行中的 Minecraft!", HintType.Finish) + Hint("已关闭运行中的 Minecraft!", HintType.Green) Catch ex As Exception Log(ex, "强制关闭所有 Minecraft 失败", LogLevel.Feedback) End Try diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb index 8d026e1..3ad35f4 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModBase.vb @@ -13,13 +13,13 @@ Public Module ModBase #Region "声明" '下列版本信息由更新器自动修改 - Public Const VersionBaseName As String = "2.10.8" '不含分支前缀的显示用版本名 - Public Const VersionStandardCode As String = "2.10.8." & VersionBranchCode '标准格式的四段式版本号 + Public Const VersionBaseName As String = "2.10.9" '不含分支前缀的显示用版本名 + Public Const VersionStandardCode As String = "2.10.9." & VersionBranchCode '标准格式的四段式版本号 Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换 #If BETA Then - Public Const VersionCode As Integer = 367 'Release + Public Const VersionCode As Integer = 369 'Release #Else - Public Const VersionCode As Integer = 370 'Snapshot + Public Const VersionCode As Integer = 371 'Snapshot #End If '自动生成的版本信息 Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName @@ -69,7 +69,7 @@ Public Module ModBase ''' ''' 识别码。 ''' - Public UniqueAddress As String = SecretGetUniqueAddress() + Public Identify As String = SecretGetIdentify() ''' ''' 程序是否已结束。 ''' @@ -761,7 +761,6 @@ Public Module ModBase If FilePath.Contains("\") Then FilePath = FilePath.Substring(FilePath.LastIndexOfF("\") + 1) Dim length As Integer = FilePath.Length If length = 0 Then Throw New Exception("不包含文件名:" & FilePath) - If length > 250 Then Throw New PathTooLongException("文件名过长:" & FilePath) Return FilePath End Function ''' @@ -1400,12 +1399,13 @@ RetryDir: ''' ''' 若路径长度大于指定值,则将长路径转换为短路径。 + ''' 如果路径不存在,则返回原始路径。 ''' Public Function ShortenPath(LongPath As String) As String If LongPath.Length <= 200 OrElse LongPath.StartsWithF("http", True) Then Return LongPath If Not Directory.Exists(LongPath) AndAlso Not File.Exists(LongPath) Then Return LongPath Dim ShortPath As New StringBuilder(260) - GetShortPathName(LongPath, ShortPath, 260) + GetShortPathName(LongPath.Replace("/", "\"), ShortPath, 260) '第一个参数也会在调用后被修改,使用 Replace 后不会影响原始字符串 ShortenPath = ShortPath.ToString If String.IsNullOrEmpty(ShortenPath) Then Return LongPath End Function @@ -1511,6 +1511,19 @@ RetryDir: Return [Enum].GetName(EnumData.GetType, EnumData) End Function ''' + ''' 将字符串转换为枚举类型,支持数字或原文两种格式,若为空字符串则返回 0。 + ''' 若转换失败会抛出异常。 + ''' + Public Function ParseToEnum(Of T)(Str As String) As T + If String.IsNullOrEmpty(Str) Then + Return CType(0, Object) + ElseIf IsNumeric(Str) Then + Return CType(CInt(Str), Object) + Else + Return [Enum].Parse(GetType(T), Str, True) + End If + End Function + ''' ''' 将文件大小转化为适合的文本形式,如“1.28 M”。 ''' ''' 以字节为单位的大小表示。 @@ -2579,7 +2592,7 @@ Retry: Log(ex, "可能由于剪贴板被其他程序占用,文本复制失败", LogLevel.Hint) End If End Try - If ShowSuccessHint Then Hint("已成功复制!", HintType.Finish) + If ShowSuccessHint Then Hint("已成功复制!", HintType.Green) End Sub) End Sub @@ -2716,6 +2729,11 @@ Retry: ''' 将 XML 转换为对应 UI 对象。 ''' Public Function GetObjectFromXML(Str As String) As Object + Str = Str. '兼容旧版自定义事件写法 + Replace("EventType=""", "local:CustomEventService.EventType="""). + Replace("EventData=""", "local:CustomEventService.EventData="""). + Replace("Property=""EventType""", "Property=""local:CustomEventService.EventType"""). + Replace("Property=""EventData""", "Property=""local:CustomEventService.EventData""") Using Stream As New MemoryStream(Encoding.UTF8.GetBytes(Str)) '类型检查 Using Reader As New XamlXmlReader(Stream) @@ -2831,7 +2849,7 @@ Retry: File.Create(Path & "PCL\Log1.txt").Dispose() Catch ex As IOException IsInitSuccess = False - Hint("可能同时开启了多个 PCL,程序可能会出现未知问题!", HintType.Critical) + Hint("可能同时开启了多个 PCL,程序可能会出现未知问题!", HintType.Red) Log(ex, "日志初始化失败(疑似文件占用问题)") Catch ex As Exception IsInitSuccess = False @@ -2884,6 +2902,7 @@ Retry: '输出日志 Dim AppendText As String = $"[{GetTimeNow()}] <{If(Thread.CurrentThread.Name = "", "主线程", Thread.CurrentThread.Name)}> {Text}{vbCrLf}" '减轻同步锁占用 + AppendText = FilterUserName(FilterAccessToken(AppendText, "*"), "*") If ModeDebug Then SyncLock LogListLock LogList.Append(AppendText) @@ -2903,16 +2922,16 @@ Retry: Select Case Level #If DEBUG Then Case LogLevel.Developer - Hint("[开发者模式] " & Text, HintType.Info, False) + Hint("[开发者模式] " & Text, HintType.Blue, False) Case LogLevel.Debug - Hint("[调试模式] " & Text, HintType.Info, False) + Hint("[调试模式] " & Text, HintType.Blue, False) #Else Case LogLevel.Developer Case LogLevel.Debug - If ModeDebug Then Hint("[调试模式] " & Text, HintType.Info, False) + If ModeDebug Then Hint("[调试模式] " & Text, HintType.Blue, False) #End If Case LogLevel.Hint - Hint(Text, HintType.Critical, False) + Hint(Text, HintType.Red, False) Case LogLevel.Msgbox MyMsgBox(Text, Title, IsWarn:=True) Case LogLevel.Feedback @@ -2955,6 +2974,7 @@ Retry: '输出日志 Dim AppendText As String = $"[{GetTimeNow()}] <{If(Thread.CurrentThread.Name = "", "主线程", Thread.CurrentThread.Name)}> {Desc}:{Ex.GetDetail(True)}{vbCrLf}" '减轻同步锁占用 + AppendText = FilterUserName(FilterAccessToken(AppendText, "*"), "*") If ModeDebug Then SyncLock LogListLock LogList.Append(AppendText) @@ -2973,19 +2993,19 @@ Retry: #If DEBUG Then Case LogLevel.Developer Dim ExLine As String = Desc & ":" & Ex.GetBrief() - Hint("[开发者模式] " & ExLine, HintType.Info, False) + Hint("[开发者模式] " & ExLine, HintType.Blue, False) Case LogLevel.Debug Dim ExLine As String = Desc & ":" & Ex.GetBrief() - Hint("[调试模式] " & ExLine, HintType.Info, False) + Hint("[调试模式] " & ExLine, HintType.Blue, False) #Else Case LogLevel.Developer Case LogLevel.Debug Dim ExLine As String = Desc & ":" & Ex.GetBrief() - If ModeDebug Then Hint("[调试模式] " & ExLine, HintType.Info, False) + If ModeDebug Then Hint("[调试模式] " & ExLine, HintType.Blue, False) #End If Case LogLevel.Hint Dim ExLine As String = Desc & ":" & Ex.GetBrief() - Hint(ExLine, HintType.Critical, False) + Hint(ExLine, HintType.Red, False) Case LogLevel.Msgbox MyMsgBox(ExFull, Title, IsWarn:=True) Case LogLevel.Feedback diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb index 806da0b..e19c8b9 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModNet.vb @@ -998,20 +998,18 @@ StartThread: If ModeDebug AndAlso Response.RequestMessage.RequestUri.ToString <> Th.Source.Url Then Log($"[Download] {LocalName}:重定向至 {Response.RequestMessage.RequestUri}") '文件大小校验 ContentLength = Response.Content.Headers.ContentLength.GetValueOrDefault(-1) - If ContentLength = -1 Then + If ContentLength < 0 Then If FileSize > 1 Then If Th.DownloadStart = 0 Then Log($"[Download] {LocalName}:文件大小未知,但已从其他下载源获取,不作处理") Else - Log($"[Download] {LocalName}:ContentLength 返回了 -1,无法确定是否支持分段下载,视作不支持") + Log($"[Download] {LocalName}:ContentLength 返回了 {ContentLength},无法确定是否支持分段下载,视作不支持") GoTo NotSupportRange End If Else FileSize = -1 : IsUnknownSize = True Log($"[Download] {LocalName}:文件大小未知") End If - ElseIf ContentLength < 0 Then - Throw New Exception("获取片大小失败,结果为 " & ContentLength & "。") ElseIf Th.IsFirstThread Then If Check IsNot Nothing Then If ContentLength < Check.MinSize AndAlso Check.MinSize > 0 Then @@ -1040,15 +1038,11 @@ StartThread: ElseIf Th.DownloadStart > 0 AndAlso ContentLength = FileSize Then NotSupportRange: SyncLock LockSource - If SourcesOnce.Contains(Th.Source) Then - GoTo SourceBreak - Else - SourcesOnce.Add(Th.Source) - End If + If SourcesOnce.Contains(Th.Source) Then GoTo SourceBreak End SyncLock - Throw New WebException($"该下载源不支持分段下载:Range 起始于 {Th.DownloadStart},预期 ContentLength 为 {FileSize - Th.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}") + Throw New RangeNotSupportedException($"该下载源不支持分段下载:Range 起始于 {Th.DownloadStart},预期 ContentLength 为 {FileSize - Th.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}") ElseIf Not FileSize - Th.DownloadStart = ContentLength Then - Throw New WebException($"获取到的分段大小不一致:Range 起始于 {Th.DownloadStart},预期 ContentLength 为 {FileSize - Th.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}") + Throw New RangeNotSupportedException($"获取到的分段大小不一致:Range 起始于 {Th.DownloadStart},预期 ContentLength 为 {FileSize - Th.DownloadStart},返回 ContentLength 为 {ContentLength},总文件大小 {FileSize}") End If 'Log($"[Download] {LocalName} {Info.Uuid}#:通过大小检查,文件大小 {FileSize},起始点 {Info.DownloadStart},ContentLength {ContentLength}") Th.State = NetState.Get @@ -1061,6 +1055,7 @@ NotSupportRange: Cache = New MemoryStream ResultStream = Cache Else + Directory.CreateDirectory(PathTemp & "Download") Th.Temp = $"{PathTemp}Download\{Uuid}_{Th.Uuid}_{RandomInteger(0, 999999)}.tmp" ResultStream = New FileStream(Th.Temp, FileMode.Create, FileAccess.Write, FileShare.Read) End If @@ -1165,9 +1160,10 @@ SourceBreak: Th.State = NetState.Error Th.Source.Ex = ex '根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传) - If IsMergeFailure OrElse - ex.Message.Contains("该下载源不支持") OrElse ex.Message.Contains("未能解析") OrElse ex.Message.Contains("(404)") OrElse - ex.Message.Contains("(502)") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse ex.Message.Contains("获取到的分段大小不一致") OrElse + Dim IsRangeNotSupported As Boolean = TypeOf ex Is RangeNotSupportedException OrElse ex.Message.Contains("(416)") + If IsMergeFailure OrElse IsRangeNotSupported 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("(403)") OrElse ex.Message.Contains("(429)")) AndAlso Not Th.Source.Url.ContainsF("bmclapi")) OrElse 'BMCLAPI 的部分源在高频率请求下会返回 403/429,所以不应因此禁用下载源 (Th.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 30) AndAlso DownloadDone < 1) OrElse Th.Source.FailCount > NetTaskThreadLimit + 2 Then '当一个下载源有多个线程在下载时,只选择其中一个线程进行后续处理 @@ -1180,9 +1176,9 @@ SourceBreak: End SyncLock '……后续处理 If IsThisFail Then - Log($"[Download] {LocalName}:下载源被禁用({Th.Source.Id}):{Th.Source.Url}") + Log($"[Download] {LocalName}:下载源被禁用({Th.Source.Id},Range 问题:{IsRangeNotSupported}):{Th.Source.Url}") Log(ex, $"{If(SourcesOnce.FirstOrDefault?.SingleThread Is Nothing, "", "单线程")}下载源 {Th.Source.Id} 已被禁用", - If(ex.Message.Contains("不支持分段下载") OrElse ex.Message.Contains("(404)") OrElse ex.Message.Contains("(416)"), LogLevel.Developer, LogLevel.Debug)) + If(IsRangeNotSupported OrElse ex.Message.Contains("(404)"), LogLevel.Developer, LogLevel.Debug)) SyncLock LockSource SourcesOnce.Remove(Th.Source) End SyncLock @@ -1191,9 +1187,10 @@ SourceBreak: Fail(ex) ElseIf HasAvailableSource() AndAlso Not IsMergeFailure Then '当前源失败,但还有下载源:正常地继续执行 - ElseIf Not Retried AndAlso Sources.Count > 1 Then + ElseIf Not Retried Then '合并失败或首次下载失败,未重试:将所有下载源重新标记为不允许断点续传的下载源,逐个重新尝试下载 - Hint($"{LocalName}:文件下载失败,正在自动重试……", If(ModeDebug, HintType.Critical, HintType.Info)) '在调试模式下给出红色提示 + '若所有源均不支持 Range,也会走到这里重试 + If Not IsRangeNotSupported Then Hint($"{LocalName}:文件下载失败,正在自动重试……", If(ModeDebug, HintType.Red, HintType.Blue)) '在调试模式下给出红色提示 Retried = True SyncLock LockSource SourcesOnce.Clear() @@ -1388,6 +1385,12 @@ Retry: End Sub End Class + Private Class RangeNotSupportedException + Inherits WebException + Public Sub New(Message As String) + MyBase.New(Message) + End Sub + End Class ''' ''' 下载一系列文件的加载器。 ''' @@ -1890,7 +1893,6 @@ Retry: Catch ex As Exception Log(ex, "清理下载缓存失败") End Try - Directory.CreateDirectory(PathTemp & "Download") End If IsDownloadCacheCleared = True End SyncLock diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb index bc11865..8b97b0f 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb @@ -908,8 +908,7 @@ NextStack: If File.Exists(OutputFile) Then If FileEncoding Is Nothing Then FileEncoding = GetEncoding(ReadFileBytes(OutputFile)) Dim FileContent As String = ReadFile(OutputFile, FileEncoding) - FileContent = FilterAccessToken(FileContent, If(FileName = "启动脚本.bat", "F", "*")) - FileContent = FilterUserName(FileContent, "*") + FileContent = FilterUserName(FilterAccessToken(FileContent, If(FileName = "启动脚本.bat", "F", "*")), "*") WriteFile(TempFolder & "Report\" & FileName, FileContent, Encoding:=FileEncoding) Log($"[Crash] 导出文件:{FileName},编码:{FileEncoding.HeaderName}") End If @@ -917,7 +916,7 @@ NextStack: '导出报告 Compression.ZipFile.CreateFromDirectory(TempFolder & "Report\", FileAddress) DeleteDirectory(TempFolder & "Report\") - Hint("错误报告已导出!", HintType.Finish) + Hint("错误报告已导出!", HintType.Green) Catch ex As Exception Log(ex, "导出错误报告失败", LogLevel.Feedback) Return diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index ccaddd1..c4c8fdb 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -35,7 +35,7 @@ Public Module ModLaunch '预检查 If Not RunInUi() Then Throw New Exception("McLaunchStart 必须在 UI 线程调用!") If McLaunchLoader.State = LoadState.Loading Then - Hint("已有游戏正在启动中!", HintType.Critical) + Hint("已有游戏正在启动中!", HintType.Red) Return False End If '强制切换需要启动的版本 @@ -44,7 +44,7 @@ Public Module ModLaunch '检查版本 CurrentLaunchOptions.Version.Load() If CurrentLaunchOptions.Version.State = McVersionState.Error Then - Hint("无法启动 Minecraft:" & CurrentLaunchOptions.Version.Info, HintType.Critical) + Hint("无法启动 Minecraft:" & CurrentLaunchOptions.Version.Info, HintType.Red) Return False End If '切换版本 @@ -98,7 +98,7 @@ Public Module ModLaunch McLaunchPrecheck() McLaunchLog("预检测已通过") Catch ex As Exception - If Not ex.Message.StartsWithF("$$") Then Hint(ex.Message, HintType.Critical) + If Not ex.Message.StartsWithF("$$") Then Hint(ex.Message, HintType.Red) Throw End Try Dim IsSavingBatch As Boolean = CurrentLaunchOptions?.SaveBatch IsNot Nothing @@ -146,7 +146,7 @@ Public Module ModLaunch '成功与失败处理 Select Case LaunchLoader.State Case LoadState.Finished - Hint(McVersionCurrent.Name & " 启动成功!", HintType.Finish) + Hint(McVersionCurrent.Name & " 启动成功!", HintType.Green) '上报 If Not IsSavingBatch Then Telemetry("Minecraft 启动成功", @@ -155,9 +155,9 @@ Public Module ModLaunch End If Case LoadState.Aborted If AbortHint Is Nothing Then - Hint(If(IsSavingBatch, "已取消导出启动脚本!", "已取消启动!"), HintType.Info) + Hint(If(IsSavingBatch, "已取消导出启动脚本!", "已取消启动!"), HintType.Blue) Else - Hint(AbortHint, HintType.Finish) + Hint(AbortHint, HintType.Green) End If Case LoadState.Failed Throw LaunchLoader.Error @@ -270,7 +270,7 @@ NextInner: Select Case MyMsgBox("你必须先登录正版账号,才能进行离线登录!", "正版验证", "购买正版", "试玩", "返回", Button1Action:=Sub() OpenWebsite("https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj")) Case 2 - Hint("游戏将以试玩模式启动!", HintType.Critical) + Hint("游戏将以试玩模式启动!", HintType.Red) CurrentLaunchOptions.ExtraArgs.Add("--demo") Case 3 Throw New Exception("$$") @@ -755,10 +755,10 @@ LoginFinish: ContentType:="application/json; charset=utf-8", RequireJson:=True)) '检查登录结果 If LoginJson("availableProfiles").Count = 0 Then - If Data.Input.ForceReselectProfile Then Hint("你还没有创建角色,无法更换!", HintType.Critical) + If Data.Input.ForceReselectProfile Then Hint("你还没有创建角色,无法更换!", HintType.Red) Throw New Exception("$你还没有创建角色,请在创建角色后再试!") ElseIf Data.Input.ForceReselectProfile AndAlso LoginJson("availableProfiles").Count = 1 Then - Hint("你的账户中只有一个角色,无法更换!", HintType.Critical) + Hint("你的账户中只有一个角色,无法更换!", HintType.Red) End If Dim SelectedName As String = Nothing Dim SelectedId As String = Nothing @@ -1304,7 +1304,7 @@ Retry: If McLaunchJavaSelected IsNot Nothing Then McLaunchLog("选择的 Java:" & McLaunchJavaSelected.ToString) Else - Hint("没有可用的 Java,已取消启动!", HintType.Critical) + Hint("没有可用的 Java,已取消启动!", HintType.Red) Throw New Exception("$$") End If @@ -1395,7 +1395,7 @@ Retry: Next '自定义 Dim ArgumentGame As String = Setup.Get("VersionAdvanceGame", Version:=McVersionCurrent) - Arguments += " " & If(ArgumentGame = "", Setup.Get("LaunchAdvanceGame"), ArgumentGame) + Arguments += " " & ArgumentReplace(If(ArgumentGame = "", Setup.Get("LaunchAdvanceGame"), ArgumentGame)) '进行参数替换 Dim ReplaceArguments = McLaunchArgumentsReplace(McVersionCurrent, Loader) If String.IsNullOrWhiteSpace(ReplaceArguments("${version_type}")) Then @@ -1412,6 +1412,9 @@ Retry: FinalArguments += Argument & " " Next FinalArguments = FinalArguments.TrimEnd + '替换 Module Path 为短路径(Forge 会在版本 JSON 硬编码这些路径) + FinalArguments = FinalArguments.RegexReplaceEach("(?<= (-p|--module-path) "")[^""]+(?="" )", + Function(ModulePath) ModulePath.Value.RegexReplaceEach("[A-Z]{1}:\\[^;]+", Function(m) ShortenPath(m.Value))) '进服 Dim Server As String = If(String.IsNullOrEmpty(CurrentLaunchOptions.ServerIp), Setup.Get("VersionServerEnter", McVersionCurrent), CurrentLaunchOptions.ServerIp) If Server.Length > 0 Then @@ -1427,7 +1430,7 @@ Retry: '不包含端口号 FinalArguments += $" --server {Server} --port 25565" End If - If McVersionCurrent.Version.HasOptiFine Then Hint("OptiFine 与自动进入服务器可能不兼容,有概率导致材质丢失甚至游戏崩溃!", HintType.Critical) + If McVersionCurrent.Version.HasOptiFine Then Hint("OptiFine 与自动进入服务器可能不兼容,有概率导致材质丢失甚至游戏崩溃!", HintType.Red) End If End If '输出 @@ -1447,7 +1450,7 @@ Retry: If ArgumentJvm = "" Then ArgumentJvm = Setup.Get("LaunchAdvanceJvm") If Not ArgumentJvm.Contains("-Dlog4j2.formatMsgNoLookups=true") Then ArgumentJvm += " -Dlog4j2.formatMsgNoLookups=true" ArgumentJvm = ArgumentJvm.Replace(" -XX:MaxDirectMemorySize=256M", "") '#3511 的清理 - DataList.Insert(0, ArgumentJvm) '可变 JVM 参数 + DataList.Insert(0, ArgumentReplace(ArgumentJvm)) '可变 JVM 参数 DataList.Add("-Xmn" & Math.Floor(PageVersionSetup.GetRam(McVersionCurrent, Not McLaunchJavaSelected.Is64Bit) * 1024 * 0.15) & "m") DataList.Add("-Xmx" & Math.Floor(PageVersionSetup.GetRam(McVersionCurrent, Not McLaunchJavaSelected.Is64Bit) * 1024) & "m") DataList.Add("""-Djava.library.path=" & GetNativesFolder() & """") @@ -1571,7 +1574,7 @@ NextVersion: '去重 DeDuplicateDataList.Remove("-XX:MaxDirectMemorySize=256M") '#3511 的清理 - Dim Result As String = Join(DeDuplicateDataList.Distinct.ToList, " ") + Dim Result As String = DeDuplicateDataList.Distinct.Join(" ") '添加 MainClass If Version.JsonObject("mainClass") Is Nothing Then @@ -1592,7 +1595,7 @@ NextVersion: If Not BasicString.Contains("--height") Then BasicString += " --height ${resolution_height} --width ${resolution_width}" DataList.Add(BasicString) - Dim Result As String = Join(DataList, " ") + Dim Result As String = DataList.Join(" ") '特别改变 OptiFineTweaker If (Version.Version.HasForge OrElse Version.Version.HasLiteLoader) AndAlso Version.Version.HasOptiFine Then @@ -1697,7 +1700,7 @@ NextVersion: GameArguments.Add("${launcher_version}", VersionCode) GameArguments.Add("${version_name}", Version.Name) Dim ArgumentInfo As String = Setup.Get("VersionArgumentInfo", Version:=McVersionCurrent) - GameArguments.Add("${version_type}", If(ArgumentInfo = "", Setup.Get("LaunchArgumentInfo"), ArgumentInfo)) + GameArguments.Add("${version_type}", ArgumentReplace(If(ArgumentInfo = "", Setup.Get("LaunchArgumentInfo"), ArgumentInfo))) GameArguments.Add("${game_directory}", ShortenPath(Left(McVersionCurrent.PathIndie, McVersionCurrent.PathIndie.Count - 1))) GameArguments.Add("${assets_root}", ShortenPath(PathMcFolder & "assets")) GameArguments.Add("${user_properties}", "{}") @@ -1707,7 +1710,7 @@ NextVersion: GameArguments.Add("${access_token}", McLoginLoader.Output.AccessToken) GameArguments.Add("${auth_session}", McLoginLoader.Output.AccessToken) GameArguments.Add("${user_type}", "msa") '#1221 - GameArguments.Add("${primary_jar}", Version.Path & Version.Name & ".jar") '#6942 + GameArguments.Add("${primary_jar}", ShortenPath(Version.Path & Version.Name & ".jar")) '#6942 '窗口尺寸参数 Dim GameSize As Size @@ -1827,10 +1830,14 @@ NextVersion: ''' Private Function GetNativesFolder() As String Dim Result As String = McVersionCurrent.Path & McVersionCurrent.Name & "-natives" - If IsGBKEncoding OrElse Result.IsASCII() Then Return ShortenPath(Result) - Result = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\bin\natives" - If Result.IsASCII() Then Return ShortenPath(Result) - Return OsDrive & "ProgramData\PCL\natives" + If Not (IsGBKEncoding OrElse Result.IsASCII()) Then + Result = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\bin\natives" + If Not Result.IsASCII() Then + Result = OsDrive & "ProgramData\PCL\natives" + End If + End If + Directory.CreateDirectory(Result) '提前创建,这样 ShortenPath 才有结果(否则在长路径下首次启动 Forge 会崩溃) + Return ShortenPath(Result) End Function #End Region @@ -1981,7 +1988,7 @@ NextVersion: McLoginLoader.Input.Type = McLoginType.Legacy AndAlso '离线登录 (Setup.Get("LaunchSkinType") = 2 OrElse '强制 Alex (Setup.Get("LaunchSkinType") = 4 AndAlso Setup.Get("LaunchSkinSlim"))) Then '或选用 Alex 皮肤 - Hint("此 Minecraft 版本尚不支持 Alex 皮肤,你的皮肤可能会显示为 Steve!", HintType.Critical) + Hint("此 Minecraft 版本尚不支持 Alex 皮肤,你的皮肤可能会显示为 Steve!", HintType.Red) End If '离线皮肤资源包 @@ -2125,9 +2132,9 @@ IgnoreCustomSkin: '获取自定义命令 Dim CustomCommandGlobal As String = Setup.Get("LaunchAdvanceRun") - If CustomCommandGlobal <> "" Then CustomCommandGlobal = ArgumentReplace(CustomCommandGlobal, True) + If CustomCommandGlobal <> "" Then CustomCommandGlobal = ArgumentReplace(CustomCommandGlobal) Dim CustomCommandVersion As String = Setup.Get("VersionAdvanceRun", Version:=McVersionCurrent) - If CustomCommandVersion <> "" Then CustomCommandVersion = ArgumentReplace(CustomCommandVersion, True) + If CustomCommandVersion <> "" Then CustomCommandVersion = ArgumentReplace(CustomCommandVersion) '输出 bat Try @@ -2283,7 +2290,7 @@ IgnoreCustomSkin: '获取窗口标题 Dim WindowTitle As String = Setup.Get("VersionArgumentTitle", Version:=McVersionCurrent) If WindowTitle = "" Then WindowTitle = Setup.Get("LaunchArgumentTitle") - WindowTitle = ArgumentReplace(WindowTitle, False) + WindowTitle = ArgumentReplace(WindowTitle, ReplaceTime:=False) '初始化等待 Dim Watcher As New Watcher(Loader, McVersionCurrent, WindowTitle) @@ -2332,47 +2339,6 @@ IgnoreCustomSkin: End Sub - ''' - ''' 在启动结束时,对 PCL 约定的替换标记进行处理。 - ''' - Private Function ArgumentReplace(Raw As String, ReplaceTimeAndDate As Boolean) As String - If Raw Is Nothing Then Return Nothing - '路径替换 - Raw = Raw.Replace("{minecraft}", PathMcFolder) - Raw = Raw.Replace("{verpath}", McVersionCurrent.Path) - Raw = Raw.Replace("{verindie}", McVersionCurrent.PathIndie) - Raw = Raw.Replace("{java}", McLaunchJavaSelected.PathFolder) - '普通替换 - Raw = Raw.Replace("{user}", McLoginLoader.Output.Name) - Raw = Raw.Replace("{uuid}", McLoginLoader.Output.Uuid) - If ReplaceTimeAndDate Then '设置窗口标题时需要动态替换日期和时间 - Raw = Raw.Replace("{date}", Date.Now.ToString("yyyy/M/d")) - Raw = Raw.Replace("{time}", Date.Now.ToString("HH:mm:ss")) - End If - Select Case McLoginLoader.Input.Type - Case McLoginType.Legacy - If PageLinkHiper.HiperState = LoadState.Finished Then - Raw = Raw.Replace("{login}", "联机离线") - Else - Raw = Raw.Replace("{login}", "离线") - End If - Case McLoginType.Ms - Raw = Raw.Replace("{login}", "正版") - Case McLoginType.Nide - Raw = Raw.Replace("{login}", "统一通行证") - Case McLoginType.Auth - Raw = Raw.Replace("{login}", "Authlib-Injector") - End Select - Raw = Raw.Replace("{name}", McVersionCurrent.Name) - If {"unknown", "old", "pending"}.Contains(McVersionCurrent.Version.McName.ToLower) Then - Raw = Raw.Replace("{version}", McVersionCurrent.Name) - Else - Raw = Raw.Replace("{version}", McVersionCurrent.Version.McName) - End If - Raw = Raw.Replace("{path}", Path) - Return Raw - End Function - #End Region End Module diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb index 6a3a527..2382a0b 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb @@ -68,7 +68,7 @@ Public Module ModMinecraft For Each Folder As String In Setup.Get("LaunchFolders").Split("|") If Folder = "" Then Continue For If Not Folder.Contains(">") OrElse Not Folder.EndsWithF("\") Then - Hint("无效的 Minecraft 文件夹:" & Folder, HintType.Critical) + Hint("无效的 Minecraft 文件夹:" & Folder, HintType.Red) Continue For End If Dim Name As String = Folder.Split(">")(0) @@ -261,6 +261,12 @@ Public Module ModMinecraft ''' 显示的描述文本。 ''' Public Info As String = "该版本未被加载,请向作者反馈此问题" + Public ReadOnly Property HasCustomInfo As Boolean + Get + Return ReadIni(Path & "PCL\Setup.ini", "CustomInfo") <> "" + End Get + End Property + ''' ''' 该版本的列表检查原始结果,不受自定义影响。 ''' @@ -784,7 +790,17 @@ ExitDataLoad: End If '确定版本描述 Dim CustomInfo As String = ReadIni(Path & "PCL\Setup.ini", "CustomInfo") - Info = If(CustomInfo <> "", CustomInfo, GetDefaultDescription()) + If CustomInfo <> "" Then + Info = CustomInfo + Else + Info = GetVersionDescription() + If State = McVersionState.Fool Then + Info = GetMcFoolName(Version.McName) + ElseIf State <> McVersionState.Error Then + If Setup.Get("VersionServerLogin", Version:=Me) = 3 Then Info += ", 统一通行证验证" + If Setup.Get("VersionServerLogin", Version:=Me) = 4 Then Info += ", Authlib 验证" + End If + End If '确定版本收藏状态 IsStar = ReadIni(Path & "PCL\Setup.ini", "IsStar", False) '确定版本显示种类 @@ -817,11 +833,13 @@ ExitDataLoad: End Try Return Me End Function + Public IsLoaded As Boolean = False ''' - ''' 获取版本的默认描述。 + ''' 获取对该版本的简短描述。 + ''' 例如 “快照 16w01a”、“原版 1.12.2”、“愚人节版本 2.0”。 ''' - Public Function GetDefaultDescription() As String - Dim Info As String = "" + Public Function GetVersionDescription() As String + Dim Info As String Select Case State Case McVersionState.Snapshot If Version.McName.ContainsF("pre", True) Then @@ -838,21 +856,38 @@ ExitDataLoad: Case McVersionState.Original, McVersionState.Forge, McVersionState.NeoForge, McVersionState.Fabric, McVersionState.OptiFine, McVersionState.LiteLoader Info = Version.ToString Case McVersionState.Fool - Info = GetMcFoolName(Version.McName) + Info = "愚人节版本 " & Version.McName Case McVersionState.Error Return Me.Info '已有错误信息 Case Else Info = "发生了未知错误,请向作者反馈此问题" End Select - If Not State = McVersionState.Error Then - If Setup.Get("VersionServerLogin", Version:=Me) = 3 Then Info += ", 统一通行证验证" - If Setup.Get("VersionServerLogin", Version:=Me) = 4 Then Info += ", Authlib 验证" - End If Return Info End Function - Public IsLoaded As Boolean = False + Public Function ToListItem() As MyListItem + Dim NewItem As New MyListItem With {.Info = Info, .Height = 42, .Tag = Me, .SnapsToDevicePixels = True, .Type = MyListItem.CheckType.Clickable} + '标题 + NewItem.Inlines.Clear() + NewItem.Inlines.Add(New Run(Name)) + If HasCustomInfo Then '如果版本设置了自定义描述,在标题后面以淡灰色显示其版本号 + NewItem.Inlines.Add(New Run(" | " & GetVersionDescription()) With {.Foreground = New MyColor(215, 215, 215), .FontSize = 12}) + End If + 'Logo + Try + If Logo.EndsWith("PCL\Logo.png") Then + NewItem.Logo = Path & "PCL\Logo.png" '修复老版本中,存储的自定义 Logo 使用完整路径,导致移动后无法加载的 Bug + Else + NewItem.Logo = Logo + End If + Catch ex As Exception + Log(ex, "加载版本图标失败", LogLevel.Hint) + NewItem.Logo = "pack://application:,,,/images/Blocks/RedstoneBlock.png" + End Try + Return NewItem + End Function + '运算符支持 Public Overrides Function Equals(obj As Object) As Boolean Dim version = TryCast(obj, McVersion) Return version IsNot Nothing AndAlso Path = version.Path @@ -865,7 +900,6 @@ ExitDataLoad: Public Shared Operator <>(a As McVersion, b As McVersion) As Boolean Return Not (a = b) End Operator - End Class Public Enum McVersionState [Error] @@ -1567,12 +1601,12 @@ OnLoaded: Try Dim Image As New MyBitmap(FileName) If Image.Pic.Width <> 64 OrElse Not (Image.Pic.Height = 32 OrElse Image.Pic.Height = 64) Then - Hint("皮肤图片大小应为 64x32 像素或 64x64 像素!", HintType.Critical) + Hint("皮肤图片大小应为 64x32 像素或 64x64 像素!", HintType.Red) Return New McSkinInfo With {.IsVaild = False} End If Dim FileInfo As New FileInfo(FileName) If FileInfo.Length > 24 * 1024 Then - Hint("皮肤文件大小需小于 24 KB,而所选文件大小为 " & Math.Round(FileInfo.Length / 1024, 2) & " KB", HintType.Critical) + Hint("皮肤文件大小需小于 24 KB,而所选文件大小为 " & Math.Round(FileInfo.Length / 1024, 2) & " KB", HintType.Red) Return New McSkinInfo With {.IsVaild = False} End If Catch ex As Exception diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb index a2d7783..5769826 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb @@ -31,7 +31,7 @@ Public Module ModModpack Try '字符校验 Dim TargetFolder As String = $"{PathMcFolder}versions\{VersionName}\" - If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("游戏路径中不能含有感叹号或分号:" & TargetFolder, HintType.Critical) : Throw New CancelledException + If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("游戏路径中不能含有感叹号或分号:" & TargetFolder, HintType.Red) : Throw New CancelledException '获取整合包种类与关键 Json Dim PackType As Integer = -1 Try @@ -344,7 +344,7 @@ Retry: '重复任务检查 Dim LoaderName As String = "CurseForge 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then - Hint("该整合包正在安装中!", HintType.Critical) + Hint("该整合包正在安装中!", HintType.Red) Throw New CancelledException End If @@ -485,7 +485,7 @@ Retry: '重复任务检查 Dim LoaderName As String = $"Modrinth 整合包安装:{VersionName} " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then - Hint("该整合包正在安装中!", HintType.Critical) + Hint("该整合包正在安装中!", HintType.Red) Throw New CancelledException End If @@ -540,7 +540,7 @@ Retry: '重复任务检查 Dim LoaderName As String = "HMCL 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then - Hint("该整合包正在安装中!", HintType.Critical) + Hint("该整合包正在安装中!", HintType.Red) Throw New CancelledException End If '启动 @@ -639,8 +639,8 @@ Retry: '构造版本安装请求 If PackJson("components") Is Nothing Then Throw New Exception("该 MMC 整合包未提供游戏版本信息,无法安装!") Dim Request As New McInstallRequest With {.TargetVersionName = VersionName, .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\"} - For Each Component In PackJson("components") - If Not Component.Contains("uid") Then Continue For + For Each Component As JObject In PackJson("components") + If Not Component.ContainsKey("uid") Then Continue For Select Case Component("uid").ToString Case "org.lwjgl" Log("[ModPack] 已跳过 LWJGL 项") @@ -667,7 +667,7 @@ Retry: '重复任务检查 Dim LoaderName As String = "MMC 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then - Hint("该整合包正在安装中!", HintType.Critical) + Hint("该整合包正在安装中!", HintType.Red) Throw New CancelledException End If @@ -725,7 +725,7 @@ Retry: Next If Not Addons.ContainsKey("game") Then Throw New Exception("该 MCBBS 整合包未提供游戏版本信息,无法安装!") If Addons.ContainsKey("quilt") Then - Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Critical) + Hint("PCL 暂不支持安装需要 Quilt 的整合包!", HintType.Red) Throw New CancelledException End If Dim Request As New McInstallRequest With { @@ -746,7 +746,7 @@ Retry: '重复任务检查 Dim LoaderName As String = "MCBBS 整合包安装:" & VersionName & " " If LoaderTaskbar.Any(Function(l) l.Name = LoaderName) Then - Hint("该整合包正在安装中!", HintType.Critical) + Hint("该整合包正在安装中!", HintType.Red) Throw New CancelledException End If @@ -766,7 +766,7 @@ Retry: MyMsgBox("接下来请选择一个空文件夹,它会被安装到这个文件夹里。", "安装", "继续", ForceWait:=True) Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)") If String.IsNullOrEmpty(TargetFolder) Then Throw New CancelledException - If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Throw New CancelledException + If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Red) : Throw New CancelledException '解压 Dim Loader As New LoaderCombo(Of String)("解压压缩包", { New LoaderTask(Of String, Integer)("解压压缩包", @@ -843,8 +843,8 @@ Retry: MyMsgBox("接下来请选择一个空文件夹,它会被安装到这个文件夹里。", "安装", "继续", ForceWait:=True) Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)") If String.IsNullOrEmpty(TargetFolder) Then Throw New CancelledException - If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Throw New CancelledException - If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Critical) : Throw New CancelledException + If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Red) : Throw New CancelledException + If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Red) : Throw New CancelledException '解压 Dim Loader As New LoaderCombo(Of String)("解压压缩包", { New LoaderTask(Of String, Integer)("解压压缩包", diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb index c4f08a4..d6259a0 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb @@ -349,7 +349,7 @@ State = MinecraftState.Crashed '崩溃分析 WatcherLog("Minecraft 已崩溃,将在 2 秒后开始崩溃分析") - Hint("检测到 Minecraft 出现错误,错误分析已开始……", HintType.Critical) + Hint("检测到 Minecraft 出现错误,错误分析已开始……", HintType.Red) FeedbackInfo() RunInNewThread( Sub() diff --git a/Plain Craft Launcher 2/Modules/ModEvent.vb b/Plain Craft Launcher 2/Modules/ModEvent.vb index 615fcf7..02849de 100644 --- a/Plain Craft Launcher 2/Modules/ModEvent.vb +++ b/Plain Craft Launcher 2/Modules/ModEvent.vb @@ -1,181 +1,291 @@ -Imports System.Collections.ObjectModel + +#Region "附加属性" + +''' +''' 用于在 XAML 中初始化列表对象。 +''' 附加属性无法在 XAML 中为每个对象初始化独立的列表对象,因此需要一个包装类,然后在 XAML 中显式初始化。 +''' + +Public Class CustomEventCollection + Implements IEnumerable(Of CustomEvent) + Dim _Events As New List(Of CustomEvent) + Public ReadOnly Property Events As List(Of CustomEvent) + Get + Return _Events + End Get + End Property + Public Function GetEnumerator() As IEnumerator(Of CustomEvent) Implements IEnumerable(Of CustomEvent).GetEnumerator + Return DirectCast(Events, IEnumerable(Of CustomEvent)).GetEnumerator() + End Function + Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator + Return DirectCast(Events, IEnumerable).GetEnumerator() + End Function +End Class + +''' +''' 提供自定义事件的附加属性。 +''' +Public Class CustomEventService + + 'Events + Public Shared ReadOnly EventsProperty As DependencyProperty = + DependencyProperty.RegisterAttached("Events", GetType(CustomEventCollection), GetType(CustomEventService), New PropertyMetadata(Nothing)) + + Public Shared Sub SetEvents(d As DependencyObject, value As CustomEventCollection) + d.SetValue(EventsProperty, value) + End Sub + + Public Shared Function GetEvents(d As DependencyObject) As CustomEventCollection + If d.GetValue(EventsProperty) Is Nothing Then d.SetValue(EventsProperty, New CustomEventCollection) + Return d.GetValue(EventsProperty) + End Function + + 'EventType + Public Shared ReadOnly EventTypeProperty As DependencyProperty = + DependencyProperty.RegisterAttached("EventType", GetType(CustomEvent.EventType), GetType(CustomEventService), New PropertyMetadata(Nothing)) + + Public Shared Sub SetEventType(d As DependencyObject, value As CustomEvent.EventType) + d.SetValue(EventTypeProperty, value) + End Sub + + Public Shared Function GetEventType(d As DependencyObject) As CustomEvent.EventType + Return d.GetValue(EventTypeProperty) + End Function + + 'EventData + Public Shared ReadOnly EventDataProperty As DependencyProperty = + DependencyProperty.RegisterAttached("EventData", GetType(String), GetType(CustomEventService), New PropertyMetadata(Nothing)) + + Public Shared Sub SetEventData(d As DependencyObject, value As String) + d.SetValue(EventDataProperty, value) + End Sub + + Public Shared Function GetEventData(d As DependencyObject) As String + Return d.GetValue(EventDataProperty) + End Function + +End Class + +Partial Public Module ModMain -Public Module ModEvent -#Region "事件执行方法" ''' - ''' 供外部调用的自定义事件执行接口,会在新建工作线程中运行逻辑。 + ''' 触发该控件上的自定义事件。 + ''' 事件会在新线程中执行。 ''' - ''' xaml中的EventType - ''' xaml中的EventData - ''' xaml中的CustomEvents - Public Sub ProcessCustomEvents(SingleEventType As String, SingleEventData As String, EventCollection As CustomEventCollection) + + Public Sub RaiseCustomEvent(Control As DependencyObject) + '收集事件列表 + Dim Events = CustomEventService.GetEvents(Control).ToList + Dim EventType = CustomEventService.GetEventType(Control) + If EventType <> CustomEvent.EventType.None Then Events.Add(New CustomEvent(EventType, CustomEventService.GetEventData(Control))) + '执行事件 + If Not Events.Any Then Return RunInNewThread( - Sub() - Try - '先执行单个事件 - StartCustomEvent(SingleEventType, SingleEventData) - '再挨个执行事件集合中的事件 - If EventCollection IsNot Nothing Then - For Each AnEvent In RunInUiWait(Function() EventCollection.DeepCloneToStructureList()) - StartCustomEvent(AnEvent.EventType, AnEvent.EventData) - Next - End If - Catch ex As Exception - Log(ex, "自定义事件执行器发生异常", LogLevel.Feedback) - End Try - End Sub, "CustomEventProcessor " & GetUuid()) - End Sub - ''' - ''' 对当前线程阻塞地调用自定义事件处理器,接受来自 xaml 原始输入作为参数。 - ''' - Private Sub StartCustomEvent(Type As String, DataRaw As String) - If String.IsNullOrEmpty(Type) Then Exit Sub - Dim Data = If(DataRaw Is Nothing, {""}, DataRaw.Split("|")) - Log("[Control] 执行自定义事件:" & Type & ", " & Join(Data, ", ")) - '检测是否存在对应事件 - If Not CustomEventProcessorsDict.ContainsKey(Type) Then - MyMsgBox($"未知的事件类型:'{Type}'{vbCrLf}请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败", ForceWait:=True) - Exit Sub - End If - '调用事件处理器 - Try - CustomEventProcessorsDict(Type)(Data) - Catch ex As Exception - Log(ex, $"自定义事件执行失败:{Type}", LogLevel.Msgbox, "自定义主页事件执行失败") - End Try + Sub() + For Each e In Events + e.Raise() + Next + End Sub, "执行自定义事件 " & GetUuid()) End Sub - ''' - ''' 存储各个自定义事件处理器的字典,以 EventType 为键,执行自定义事件时在工作线程中调用 Action 并传入分割后的 EventData 。 - ''' Action 应当在事件逻辑结束后,即可以开始下一个事件时再结束;以便于挨个调用事件不打架。 - ''' - Private ReadOnly CustomEventProcessorsDict As New Dictionary(Of String, Action(Of String())) From { - {"打开网页", - Sub(Data As String()) - Data(0) = Data(0).Replace("\", "/") - If Not Data(0).Contains("://") OrElse Data(0).StartsWithF("file", True) Then '为了支持更多协议(#2200) - MyMsgBox("打开网页事件中,EventData 必须为一个网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败") - Exit Sub - End If - Hint("网页正在开启中,请稍候……") - OpenWebsite(Data(0)) - End Sub}, - {"打开文件", - Sub(Data As String()) - Dim ActualPaths = GetEventAbsoluteUrls(Data(0), "打开文件") - Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1) - Log($"[Control] 打开文件:路径:{Location},工作目录:{WorkingDir}") - If Not CommandRunUserConfirm(If(Data.Length < 2, Location, $"{Location} {Data(1)}")) Then Exit Sub - Dim Info As New ProcessStartInfo With { - .Arguments = If(Data.Length < 2, "", Data(1)), - .FileName = Location, - .WorkingDirectory = ShortenPath(WorkingDir) - } - Process.Start(Info) - End Sub}, - {"打开帮助", - Sub(Data As String()) - Dim ActualPaths = GetEventAbsoluteUrls(Data(0), "打开帮助") - Dim Location = ActualPaths(0) - Log($"[Control] 打开帮助:{Location}") - PageOtherHelp.EnterHelpPage(Location) - End Sub}, - {"执行命令", - Sub(Data As String()) - Dim ActualPaths = GetEventAbsoluteUrls(Data(0), "执行命令") - Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1) - Log($"[Control] 执行命令:路径:{Location},工作目录:{WorkingDir}") - If Not CommandRunUserConfirm(If(Data.Length < 2, Location, $"{Location} {Data(1)}")) Then Exit Sub - Dim Info As New ProcessStartInfo With { - .Arguments = If(Data.Length < 2, "", Data(1)), - .FileName = Location, - .WorkingDirectory = ShortenPath(WorkingDir) - } - Process.Start(Info) - End Sub}, - {"启动游戏", - Sub(Data As String()) - If Data(0) = "\current" Then - If McVersionCurrent Is Nothing Then - Hint("请先选择一个 Minecraft 版本!", HintType.Critical) - Exit Sub - Else - Data(0) = McVersionCurrent.Name - End If - End If - RunInUiWait( - Sub() - If McLaunchStart(New McLaunchOptions With {.Version = New McVersion(Data(0)), .ServerIp = If(Data.Length >= 2, Data(1), Nothing)}) Then - Hint("正在启动 " & Data(0) & "……") - End If - End Sub) - End Sub}, - {"复制文本", Sub(Data As String()) ClipboardSet(Join(Data, "|"))}, - {"刷新主页", - Sub(Data As String()) - RunInUiWait(Sub() FrmLaunchRight.ForceRefresh()) - If Data(0) = "" Then Hint("已刷新主页!", HintType.Finish) - End Sub}, - {"刷新帮助", Sub() RunInUi(Sub() PageOtherLeft.RefreshHelp())}, - {"今日人品", Sub() PageOtherTest.Jrrp()}, - {"内存优化", - Sub(Data As String()) - If Data.Length >= 1 AndAlso Data(0) = "前台运行" Then - PageOtherTest.MemoryOptimize(Data.Length >= 2 AndAlso Data(1) = "显示提示") - Else - RunInNewThread(Sub() PageOtherTest.MemoryOptimize(True)) - End If - End Sub}, - {"弹出窗口", Sub(Data As String()) MyMsgBox(Data(1).Replace("\n", vbCrLf), Data(0).Replace("\n", vbCrLf), ForceWait:=True)}, - {"切换页面", Sub(Data As String()) RunInUiWait(Sub() FrmMain.PageChange(Val(Data(0)), Val(Data(1))))}, - {"安装整合包", Sub() RunInUiWait(Sub() ModpackInstall())}, - {"导入整合包", Sub() RunInUiWait(Sub() ModpackInstall())}, - {"下载文件", - Sub(Data As String()) - Data(0) = Data(0).Replace("\", "/") - If Not (Data(0).StartsWithF("http://", True) OrElse Data(0).StartsWithF("https://", True)) Then - MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL 不支持其他乱七八糟的下载协议。", "事件执行失败") - Exit Sub - End If - Try - Select Case Data.Length - Case 1 - PageOtherTest.StartCustomDownload(Data(0), GetFileNameFromPath(Data(0))) - Case 2 - PageOtherTest.StartCustomDownload(Data(0), Data(1)) - Case Else - PageOtherTest.StartCustomDownload(Data(0), Data(1), Data(2)) - End Select - Catch - PageOtherTest.StartCustomDownload(Data(0), "未知") - End Try - End Sub} - } +End Module #End Region -#Region "工具方法" + +''' +''' 自定义事件。 +''' +Public Class CustomEvent + +#Region "属性与触发" + + Public Property Type As EventType = EventType.None + Public Property Data As String = Nothing + Public Sub New() + End Sub + Public Sub New(Type As EventType, Data As String) + Me.Type = Type + Me.Data = Data + End Sub + ''' - ''' 弹窗询问用户是否同意继续执行打开类事件。 + ''' 在当前线程中触发该自定义事件。 ''' - Private Function CommandRunUserConfirm(TextShowToUser As String) As Boolean - If Setup.Get("HintCustomCommand") Then Return True - Select Case MyMsgBox("即将执行:" & TextShowToUser & vbCrLf & "请在确认该操作没有安全隐患后继续。", "执行确认", "继续", "继续且今后不再要求确认", "取消") - Case 1 - Return True - Case 2 - Setup.Set("HintCustomCommand", True) - Return True - Case Else '3 - Log("[Control] 用户取消了打开类事件") - Return False - End Select - End Function + Public Sub Raise() + Raise(Type, Data) + End Sub + +#End Region + + Public Enum EventType + None = 0 + 打开网页 + 打开文件 + 打开帮助 + 执行命令 + 启动游戏 + 复制文本 + 刷新主页 + 刷新页面 + 刷新帮助 + 今日人品 + 内存优化 + 清理垃圾 + 弹出窗口 + 弹出提示 + 切换页面 + 导入整合包 + 安装整合包 + 下载文件 + 修改设置 + 写入设置 + 修改变量 + 写入变量 + End Enum + + ''' + ''' 在当前线程中触发一个自定义事件。 + ''' + Public Shared Sub Raise(Type As EventType, Arg As String) + If Type = EventType.None Then Return + Log($"[Control] 执行自定义事件:{Type}, {Arg}") + Try + Dim Args As String() = If(Arg?.Split("|"), {""}) + Select Case Type + + Case EventType.打开网页 + Arg = Arg.Replace("\", "/") + If Not Arg.Contains("://") OrElse Arg.StartsWithF("file", True) Then '为了支持更多协议(#2200) + MyMsgBox("EventData 必须为一个网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败") + Return + End If + Hint("正在开启中,请稍候:" & Arg) + RunInThread(Sub() OpenWebsite(Arg)) + + Case EventType.打开文件, EventType.打开帮助, EventType.执行命令 + RunInThread( + Sub() + Try + '确认实际路径 + Dim ActualPaths = GetAbsoluteUrls(Args(0), Type) + Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1) + Log($"[Control] 打开类自定义事件实际路径:{Location},工作目录:{WorkingDir}") + '执行 + If Type = EventType.打开帮助 Then + PageOtherHelp.EnterHelpPage(Location) + Else + If Not EventSafetyConfirm("即将执行:" & Location & If(Args.Length >= 2, " " & Args(1), "")) Then Return + Dim Info As New ProcessStartInfo With { + .Arguments = If(Args.Length >= 2, Args(1), ""), + .FileName = Location, + .WorkingDirectory = WorkingDir + } + StartProcess(Info) + End If + Catch ex As Exception + Log(ex, "执行打开类自定义事件失败", LogLevel.Msgbox) + End Try + End Sub) + + Case EventType.启动游戏 + If Args(0) = "\current" Then + If McVersionCurrent Is Nothing Then + Hint("请先选择一个 Minecraft 版本!", HintType.Red) + Return + Else + Args(0) = McVersionCurrent.Name + End If + End If + RunInUi( + Sub() + If McLaunchStart(New McLaunchOptions With + {.ServerIp = If(Args.Length >= 2, Args(1), Nothing), .Version = New McVersion(Args(0))}) Then + Hint($"正在启动 {Args(0)}……") + End If + End Sub) + + Case EventType.复制文本 + ClipboardSet(Arg) + + Case EventType.刷新主页, EventType.刷新页面 + If TypeOf FrmMain.PageRight Is IRefreshable Then + RunInUiWait(Sub() CType(FrmMain.PageRight, IRefreshable).Refresh()) + If String.IsNullOrEmpty(Arg) Then Hint("已刷新!", HintType.Green) + Else + Hint("当前页面不支持刷新操作!", HintType.Red) + End If + + Case EventType.刷新帮助 + RunInUiWait(Sub() PageOtherLeft.RefreshHelp()) + If String.IsNullOrEmpty(Arg) Then Hint("已刷新!", HintType.Green) + + Case EventType.今日人品 + PageOtherTest.Jrrp() + + Case EventType.内存优化 + RunInThread(Sub() PageOtherTest.MemoryOptimize(True)) + + Case EventType.清理垃圾 + RunInThread(Sub() PageOtherTest.RubbishClear()) + + Case EventType.弹出窗口 + If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 弹窗标题|弹窗内容") + MyMsgBox(Args(1).Replace("\n", vbCrLf), Args(0).Replace("\n", vbCrLf), If(Args.Length > 2, Args(2), "确定")) + + Case EventType.弹出提示 + Hint(Args(0).Replace("\n", vbCrLf), If(Args.Length = 1, HintType.Blue, Args(1).ParseToEnum(Of HintType))) + + Case EventType.切换页面 + RunInUi(Sub() FrmMain.PageChange( + Args(0).ParseToEnum(Of FormMain.PageType), + If(Args.Length = 1, FormMain.PageSubType.Default, Args(1).ParseToEnum(Of FormMain.PageSubType)))) + + Case EventType.导入整合包, EventType.安装整合包 + RunInUi(Sub() ModpackInstall()) + + Case EventType.下载文件 + Args(0) = Args(0).Replace("\", "/") + If Not (Args(0).StartsWithF("http://", True) OrElse Args(0).StartsWithF("https://", True)) Then + MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL 不支持其他乱七八糟的下载协议。", "事件执行失败") + Return + End If + If Not EventSafetyConfirm("即将从该网址下载文件:" & vbCrLf & Args(0)) Then Return + Try + Select Case Args.Length + Case 1 + PageOtherTest.StartCustomDownload(Args(0), GetFileNameFromPath(Args(0))) + Case 2 + PageOtherTest.StartCustomDownload(Args(0), Args(1)) + Case Else + PageOtherTest.StartCustomDownload(Args(0), Args(1), Args(2)) + End Select + Catch + PageOtherTest.StartCustomDownload(Args(0), "未知") + End Try + + Case EventType.修改设置, EventType.写入设置 + If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 UiLauncherTransparent|400") + Setup.SetSafe(Args(0), Args(1), Version:=McVersionCurrent) + If Args.Length = 2 Then Hint($"已写入设置:{Args(0)} → {Args(1)}", HintType.Green) + + Case EventType.修改变量, EventType.写入变量 + If Args.Length = 1 Then Throw New Exception($"EventType {Type} 需要至少 2 个以 | 分割的参数,例如 VariableName|SomeValue") + WriteReg("CustomEvent" & Args(0), Args(1)) + If Args.Length = 2 Then Hint($"已写入变量:{Args(0)} → {Args(1)}", HintType.Green) + + Case Else + MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败") + End Select + Catch ex As Exception + Log(ex, $"事件执行失败({Type}, {Arg})", LogLevel.Msgbox) + End Try + End Sub ''' ''' 返回自定义事件的绝对 Url。实际返回 {绝对 Url, WorkingDir}。 ''' 失败会抛出异常。 ''' - Public Function GetEventAbsoluteUrls(RelativeUrl As String, EventType As String) As String() + Public Shared Function GetAbsoluteUrls(RelativeUrl As String, Type As EventType) As String() '网页确认 If RelativeUrl.StartsWithF("http", True) Then @@ -216,25 +326,25 @@ Public Module ModEvent If RelativeUrl.Contains(":\") Then '绝对路径 Location = RelativeUrl - Log("[Control] 自定义事件中由绝对路径" & EventType & ":" & Location) + Log("[Control] 自定义事件中由绝对路径" & Type & ":" & Location) ElseIf File.Exists(Path & "PCL\" & RelativeUrl) Then '相对 PCL 文件夹的路径 Location = Path & "PCL\" & RelativeUrl - Log("[Control] 自定义事件中由相对 PCL 文件夹的路径" & EventType & ":" & Location) + Log("[Control] 自定义事件中由相对 PCL 文件夹的路径" & Type & ":" & Location) ElseIf File.Exists(Path & "PCL\Help\" & RelativeUrl) Then '相对 PCL 本地帮助文件夹的路径 Location = Path & "PCL\Help\" & RelativeUrl WorkingDir = Path & "PCL\Help\" - Log("[Control] 自定义事件中由相对 PCL 本地帮助文件夹的路径" & EventType & ":" & Location) - ElseIf EventType = "打开帮助" AndAlso File.Exists(PathTemp & "Help\" & RelativeUrl) Then + Log("[Control] 自定义事件中由相对 PCL 本地帮助文件夹的路径" & Type & ":" & Location) + ElseIf Type = EventType.打开帮助 AndAlso File.Exists(PathTemp & "Help\" & RelativeUrl) Then '相对 PCL 自带帮助文件夹的路径 Location = PathTemp & "Help\" & RelativeUrl WorkingDir = PathTemp & "Help\" - Log("[Control] 自定义事件中由相对 PCL 自带帮助文件夹的路径" & EventType & ":" & Location) - ElseIf EventType = "打开文件" OrElse EventType = "执行命令" Then + Log("[Control] 自定义事件中由相对 PCL 自带帮助文件夹的路径" & Type & ":" & Location) + ElseIf Type = EventType.打开文件 OrElse Type = EventType.执行命令 Then '直接使用原有路径启动程序 Location = RelativeUrl - Log("[Control] 自定义事件中直接" & EventType & ":" & Location) + Log("[Control] 自定义事件中直接" & Type & ":" & Location) Else '打开帮助,但是格式不对劲 Throw New FileNotFoundException("未找到 EventData 指向的本地 xaml 文件:" & RelativeUrl, RelativeUrl) @@ -243,42 +353,20 @@ Public Module ModEvent Return {Location, WorkingDir} End Function -#End Region -End Module -#Region "数据结构类声明" -Public Class CustomEventCollection - Inherits ObservableCollection(Of CustomEvent) - Public Function DeepCloneToStructureList() As IList(Of CustomEventStructure) - DeepCloneToStructureList = New List(Of CustomEventStructure) - For Each AnEvent In Me - DeepCloneToStructureList.Add(New CustomEventStructure With {.EventType = AnEvent.EventType, .EventData = AnEvent.EventData}) - Next + ''' + ''' 弹出安全确认弹窗。返回是否继续执行。 + ''' + Private Shared Function EventSafetyConfirm(Message As String) As Boolean + If Setup.Get("HintCustomCommand") Then Return True + Select Case MyMsgBox(Message & vbCrLf & "请在确认没有安全隐患后再继续。", "执行确认", "继续", "继续且今后不再要求确认", "取消") + Case 1 + Return True + Case 2 + Setup.Set("HintCustomCommand", True) + Return True + Case Else + Return False + End Select End Function -End Class -Public Class CustomEvent - Inherits DependencyObject - Public Property EventType As String - Get - Return GetValue(EventTypeProperty) - End Get - Set(value As String) - SetValue(EventTypeProperty, value) - End Set - End Property - Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(CustomEvent), New PropertyMetadata(Nothing)) - Public Property EventData As String - Get - Return GetValue(EventDataProperty) - End Get - Set(value As String) - SetValue(EventDataProperty, value) - End Set - End Property - Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(CustomEvent), New PropertyMetadata(Nothing)) -End Class -Public Structure CustomEventStructure - Public EventType As String - Public EventData As String -End Structure -#End Region \ No newline at end of file +End Class diff --git a/Plain Craft Launcher 2/Modules/ModMain.vb b/Plain Craft Launcher 2/Modules/ModMain.vb index 68aaebb..c7eb4c5 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.vb +++ b/Plain Craft Launcher 2/Modules/ModMain.vb @@ -7,23 +7,12 @@ Public Module ModMain ''' ''' 提示信息的种类。 + ''' 该枚举在自定义事件中使用,是公开 API 的一部分。 ''' Public Enum HintType - ''' - ''' 信息,通常是蓝色的“i”。 - ''' - ''' - Info - ''' - ''' 已完成,通常是绿色的“√”。 - ''' - ''' - Finish - ''' - ''' 错误,通常是红色的“×”。 - ''' - ''' - Critical + Blue + Green + Red End Enum Private Structure HintMessage Public Text As String @@ -38,7 +27,7 @@ Public Module ModMain ''' ''' 在窗口左下角弹出提示文本。 ''' - Public Sub Hint(Text As String, Optional Type As HintType = HintType.Info, Optional Log As Boolean = True) + Public Sub Hint(Text As String, Optional Type As HintType = HintType.Blue, Optional Log As Boolean = True) If HintWaiting Is Nothing Then HintWaiting = New SafeList(Of HintMessage) HintWaiting.Add(New HintMessage With {.Text = If(Text, ""), .Type = Type, .Log = Log}) End Sub @@ -68,13 +57,13 @@ Public Module ModMain Dim TargetColor0, TargetColor1 As MyColor Dim Percent As Double = 0.3 Select Case CurrentHint.Type - Case HintType.Info + Case HintType.Blue TargetColor0 = New MyColor(215, 37, 155, 252) TargetColor1 = New MyColor(215, 10, 142, 252) - Case HintType.Finish + Case HintType.Green TargetColor0 = New MyColor(215, 33, 177, 33) TargetColor1 = New MyColor(215, 29, 160, 29) - Case Else 'HintType.Critical + Case Else 'HintType.Red TargetColor0 = New MyColor(215, 255, 53, 11) TargetColor1 = New MyColor(215, 255, 43, 0) End Select @@ -490,7 +479,7 @@ EndHint: ''' 是否为 “执行事件”。 ''' Public IsEvent As Boolean - Public EventType As String + Public EventType As CustomEvent.EventType Public EventData As String ''' ''' 若非执行事件,其对应的 .xaml 本地文件内容。 @@ -504,7 +493,7 @@ EndHint: ''' Public Sub New(FilePath As String) RawPath = FilePath - Dim JsonData As JObject = GetJson(HelpArgumentReplace(ReadFile(FilePath))) + Dim JsonData As JObject = GetJson(ArgumentReplace(ReadFile(FilePath), AddressOf EscapeXML)) If JsonData Is Nothing Then Throw New FileNotFoundException("未找到帮助文件:" & FilePath, FilePath) '加载常规信息 If JsonData("Title") IsNot Nothing Then @@ -524,8 +513,7 @@ EndHint: Next '加载事件信息 If If(JsonData("IsEvent"), False) Then - EventType = JsonData("EventType") - If EventType Is Nothing Then Throw New ArgumentException("未找到 EventType 项") + EventType = [Enum].Parse(GetType(CustomEvent.EventType), JsonData("EventType").ToString) EventData = If(JsonData("EventData"), "") IsEvent = True Else @@ -550,7 +538,7 @@ EndHint: Public Function SetToListItem(Item As MyListItem) As MyListItem Dim Logo As String If IsEvent Then - If EventType = "弹出窗口" Then + If EventType = CustomEvent.EventType.弹出窗口 Then Logo = PathImage & "Blocks/GrassPath.png" Else Logo = PathImage & "Blocks/CommandBlock.png" @@ -567,9 +555,9 @@ EndHint: .Height = 42 .Type = MyListItem.CheckType.Clickable .Tag = Me - .EventType = Nothing - .EventData = Nothing End With + CustomEventService.SetEventType(Item, CustomEvent.EventType.None) '清空自定义事件属性,它们会被下面的点击事件处理 + CustomEventService.SetEventData(Item, Nothing) '项目的点击事件 AddHandler Item.Click, Sub(sender, e) PageOtherHelp.OnItemClick(sender.Tag) Return Item @@ -669,15 +657,6 @@ NextFile: Log("[Help] 已解压内置帮助文件,目前状态:" & File.Exists(PathTemp & "Help\启动器\备份设置.xaml"), LogLevel.Debug) End If End Sub - ''' - ''' 对帮助文件约定的替换标记进行处理,如果遇到需要转义的字符会进行转义。 - ''' - Public Function HelpArgumentReplace(Xaml As String) As String - Dim Result = Xaml.Replace("{path}", EscapeXML(Path)) - Result = Result.RegexReplaceEach("\{hint\}", Function() EscapeXML(PageOtherTest.GetRandomHint())) - Result = Result.RegexReplaceEach("\{cave\}", Function() EscapeXML(PageOtherTest.GetRandomCave())) - Return Result - End Function #End Region @@ -836,6 +815,78 @@ NextFile: End Using End Sub + ''' + ''' 对替换标记进行处理。会对替换内容使用 EscapeHandler 进行转义。 + ''' + Public Function ArgumentReplace(Text As String, Optional EscapeHandler As Func(Of String, String) = Nothing, Optional ReplaceTime As Boolean = True) As String + '预处理 + If Text Is Nothing Then Return Nothing + Dim Replacer = + Function(s As String) As String + If s Is Nothing Then Return "" + If EscapeHandler Is Nothing Then Return s + If s.Contains(":\") Then s = ShortenPath(s) + Return EscapeHandler(s) + End Function + '基础 + Text = Text.Replace("{pcl_version}", Replacer(VersionBaseName)) + Text = Text.Replace("{pcl_version_code}", Replacer(VersionCode)) + Text = Text.Replace("{pcl_version_branch}", Replacer(VersionBranchName)) + Text = Text.Replace("{pcl_branch}", Replacer(VersionBranchMain)) + Text = Text.Replace("{identify}", Replacer(Identify)) + Text = Text.Replace("{path}", Replacer(Path)) + Text = Text.Replace("{path_with_name}", Replacer(PathWithName)) + Text = Text.Replace("{path_temp}", Replacer(PathTemp)) + '时间 + If ReplaceTime Then '在窗口标题中,时间会被后续动态替换,所以此时不应该替换 + Text = Text.Replace("{date}", Replacer(Date.Now.ToString("yyyy/M/d"))) + Text = Text.Replace("{time}", Replacer(Date.Now.ToString("HH:mm:ss"))) + End If + 'Minecraft + Text = Text.Replace("{java}", Replacer(McLaunchJavaSelected?.PathFolder)) + Text = Text.Replace("{minecraft}", Replacer(PathMcFolder)) + If McVersionCurrent IsNot Nothing Then + Text = Text.Replace("{version_path}", Replacer(McVersionCurrent.Path)) : Text = Text.Replace("{verpath}", Replacer(McVersionCurrent.Path)) + Text = Text.Replace("{version_indie}", Replacer(McVersionCurrent.PathIndie)) : Text = Text.Replace("{verindie}", Replacer(McVersionCurrent.PathIndie)) + Text = Text.Replace("{name}", Replacer(McVersionCurrent.Name)) + If {"unknown", "old", "pending"}.Contains(McVersionCurrent.Version.McName.ToLower) Then + Text = Text.Replace("{version}", Replacer(McVersionCurrent.Name)) + Else + Text = Text.Replace("{version}", Replacer(McVersionCurrent.Version.McName)) + End If + Else + Text = Text.Replace("{version_path}", Replacer(Nothing)) : Text = Text.Replace("{verpath}", Replacer(Nothing)) + Text = Text.Replace("{version_indie}", Replacer(Nothing)) : Text = Text.Replace("{verindie}", Replacer(Nothing)) + Text = Text.Replace("{name}", Replacer(Nothing)) + Text = Text.Replace("{version}", Replacer(Nothing)) + End If + '登录信息 + If McLoginLoader.State = LoadState.Finished Then + Text = Text.Replace("{user}", Replacer(McLoginLoader.Output.Name)) + Text = Text.Replace("{uuid}", Replacer(McLoginLoader.Output.Uuid.ToLower)) + Select Case McLoginLoader.Input.Type + Case McLoginType.Legacy + Text = Text.Replace("{login}", Replacer("离线")) + Case McLoginType.Ms + Text = Text.Replace("{login}", Replacer("正版")) + Case McLoginType.Nide + Text = Text.Replace("{login}", Replacer("统一通行证")) + Case McLoginType.Auth + Text = Text.Replace("{login}", Replacer("Authlib-Injector")) + End Select + Else + Text = Text.Replace("{user}", Replacer(Nothing)) + Text = Text.Replace("{uuid}", Replacer(Nothing)) + Text = Text.Replace("{login}", Replacer(Nothing)) + End If + '高级 + Text = Text.RegexReplaceEach("\{hint\}", Function() Replacer(PageOtherTest.GetRandomHint())) + 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, McVersionCurrent))) + Text = Text.RegexReplaceEach("\{varible:([^\}]+)\}", Function(m) Replacer(ReadReg("CustomEvent" & m.Groups(1).Value, Nothing))) + Return Text + End Function + #End Region #Region "任务缓存" diff --git a/Plain Craft Launcher 2/Modules/ModMusic.vb b/Plain Craft Launcher 2/Modules/ModMusic.vb index 0476e89..403ceee 100644 --- a/Plain Craft Launcher 2/Modules/ModMusic.vb +++ b/Plain Craft Launcher 2/Modules/ModMusic.vb @@ -111,7 +111,7 @@ ''' Public Sub MusicControlPause() If MusicNAudio Is Nothing Then - Hint("音乐播放尚未开始!", HintType.Critical) + Hint("音乐播放尚未开始!", HintType.Red) Else Select Case MusicState Case MusicStates.Pause @@ -131,14 +131,14 @@ Public Sub MusicControlNext() If MusicAllList.Count = 1 Then MusicStartPlay(MusicCurrent) - Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Finish) + Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Green) Else Dim Address As String = DequeueNextMusicAddress() If Address Is Nothing Then - Hint("没有可以播放的音乐!", HintType.Critical) + Hint("没有可以播放的音乐!", HintType.Red) Else MusicStartPlay(Address) - Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish) + Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Green) End If End If MusicRefreshUI() @@ -182,19 +182,19 @@ MusicListInit(True) If Not MusicAllList.Any() Then If MusicNAudio Is Nothing Then - If ShowHint Then Hint("未检测到可用的背景音乐!", HintType.Critical) + If ShowHint Then Hint("未检测到可用的背景音乐!", HintType.Red) Else MusicNAudio = Nothing - If ShowHint Then Hint("背景音乐已清除!", HintType.Finish) + If ShowHint Then Hint("背景音乐已清除!", HintType.Green) End If Else Dim Address As String = DequeueNextMusicAddress() If Address Is Nothing Then - If ShowHint Then Hint("没有可以播放的音乐!", HintType.Critical) + If ShowHint Then Hint("没有可以播放的音乐!", HintType.Red) Else Try MusicStartPlay(Address, IsFirstLoad) - If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Finish, False) + If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Green, False) Catch End Try End If @@ -303,18 +303,18 @@ Catch ex As Exception Log(ex, "播放音乐出现内部错误(" & MusicCurrent & ")", LogLevel.Developer) If TypeOf ex Is NAudio.MmException AndAlso ex.Message.Contains("AlreadyAllocated") Then - Hint("你的音频设备正被其他程序占用。请在关闭占用的程序后重启 PCL,才能恢复音乐播放功能!", HintType.Critical) + Hint("你的音频设备正被其他程序占用。请在关闭占用的程序后重启 PCL,才能恢复音乐播放功能!", HintType.Red) Thread.Sleep(1000000000) End If If TypeOf ex Is NAudio.MmException AndAlso (ex.Message.Contains("NoDriver") OrElse ex.Message.Contains("BadDeviceId")) Then - Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Critical) + Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Red) Thread.Sleep(1000000000) End If If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then - Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 不支持播放音频属性在中途发生变化的音乐", HintType.Critical) + 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) - Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Critical) + Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Red) Else Log(ex, "播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & ")", LogLevel.Hint) End If diff --git a/Plain Craft Launcher 2/Modules/ModSecret.vb b/Plain Craft Launcher 2/Modules/ModSecret.vb index 672ea2a..f4bd63c 100644 --- a/Plain Craft Launcher 2/Modules/ModSecret.vb +++ b/Plain Craft Launcher 2/Modules/ModSecret.vb @@ -6,6 +6,8 @@ Friend Module ModSecret #Region "杂项" + '标注 PCL 的不同分支,仅用于替换标记 + Public Const VersionBranchMain As String = "OpenSource" '在开源版的注册表与常规版的注册表隔离,以防数据冲突 Public Const RegFolder As String = "PCLDebug" '用于微软登录的 ClientId @@ -56,13 +58,13 @@ Friend Module ModSecret ''' ''' 获取设备标识码。 ''' - Friend Function SecretGetUniqueAddress() As String + Friend Function SecretGetIdentify() As String Return "0000-0000-0000-0000" End Function Friend Sub SecretLaunchJvmArgs(ByRef DataList As List(Of String)) Dim DataJvmCustom As String = Setup.Get("VersionAdvanceJvm", Version:=McVersionCurrent) - DataList.Insert(0, If(DataJvmCustom = "", Setup.Get("LaunchAdvanceJvm"), DataJvmCustom)) '可变 JVM 参数 + 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(PageVersionSetup.GetRam(McVersionCurrent) * 1024 * 0.15) & "m") DataList.Add("-Xmx" & Math.Floor(PageVersionSetup.GetRam(McVersionCurrent) * 1024) & "m") diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb index ac15996..5813168 100644 --- a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb +++ b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb @@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 ' 方法是按如下所示使用“*” - - + + diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb index 9d2dae5..fda60b1 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb @@ -290,9 +290,9 @@ Sub(MyLoader) Select Case MyLoader.State Case LoadState.Failed - Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetBrief(), HintType.Critical) + Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetBrief(), HintType.Red) Case LoadState.Aborted - Hint(MyLoader.Name & "已取消!", HintType.Info) + Hint(MyLoader.Name & "已取消!", HintType.Blue) Case LoadState.Loading Return '不重新加载版本列表 End Select @@ -326,7 +326,7 @@ Dim DefaultFolder As String = Nothing If File.Type <> CompType.ModPack Then Dim SubFolder As String = Nothing - Select Case Project.Type + Select Case File.Type Case CompType.Mod : SubFolder = "mods\" Case CompType.ResourcePack : SubFolder = "resourcepacks\" Case CompType.Shader : SubFolder = "shaderpacks\" @@ -346,7 +346,7 @@ Function(Version) If Not Version.IsLoaded Then Version.Load() '只对 Mod 和数据包进行版本检测 - If Project.Type = CompType.Mod OrElse Project.Type = CompType.DataPack Then + If File.Type = CompType.Mod OrElse File.Type = CompType.DataPack Then If File.GameVersions.Any(Function(v) v.Contains(".")) AndAlso Not File.GameVersions.Any(Function(v) v.Contains(".") AndAlso v = Version.Version.McName) Then Return False End If @@ -359,8 +359,8 @@ Return False End Function '获取常规资源默认下载位置 - If CachedFolder.ContainsKey(Project.Type) Then - DefaultFolder = CachedFolder(Project.Type) + If CachedFolder.ContainsKey(File.Type) Then + DefaultFolder = CachedFolder(File.Type) Log($"[Comp] 使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}") ElseIf McVersionCurrent IsNot Nothing AndAlso IsVersionSuitable(McVersionCurrent) Then DefaultFolder = $"{McVersionCurrent.PathIndie}{SubFolder}" @@ -425,7 +425,7 @@ If Not Target.Contains("\") Then Return '构造步骤加载器 Dim LoaderName As String = Desc & "下载:" & IO.Path.GetFileNameWithoutExtension(Target) & " " - If Target <> DefaultFolder Then CachedFolder(Project.Type) = GetPathFromFullPath(Target) + If Target <> DefaultFolder Then CachedFolder(File.Type) = GetPathFromFullPath(Target) Dim Loaders As New List(Of LoaderBase) Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True}) '启动 diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb index a19a93c..6e1d801 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb @@ -32,7 +32,7 @@ Public Module ModDownloadLib For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"Minecraft {Id} 下载" Then Continue For If Behaviour = NetPreDownloadBehaviour.ExitWhileExistsOrDownloading Then Return OngoingLoader - Hint("该版本正在下载中!", HintType.Critical) + Hint("该版本正在下载中!", HintType.Red) Return OngoingLoader Next @@ -223,7 +223,7 @@ Public Module ModDownloadLib '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"Minecraft {Id} 服务端下载" Then Continue For - Hint("该服务端正在下载中!", HintType.Critical) + Hint("该服务端正在下载中!", HintType.Red) Return Next @@ -241,7 +241,7 @@ Public Module ModDownloadLib File.Delete(VersionFolder & Id & ".json") If Not New DirectoryInfo(VersionFolder).GetFileSystemInfos.Any() Then Directory.Delete(VersionFolder) Task.Output = New List(Of NetFile) - Hint($"Mojang 没有给 Minecraft {Id} 提供官方服务端下载,没法下,撤退!", HintType.Critical) + Hint($"Mojang 没有给 Minecraft {Id} 提供官方服务端下载,没法下,撤退!", HintType.Red) Thread.Sleep(2000) '等玩家把上一个提示看完 Task.Abort() Return @@ -300,7 +300,7 @@ pause" '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"Minecraft {Id} 下载" Then Continue For - Hint("该版本正在下载中!", HintType.Critical) + Hint("该版本正在下载中!", HintType.Red) Return Next @@ -401,7 +401,7 @@ pause" '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"OptiFine {DownloadInfo.NameDisplay} 下载" Then Continue For - Hint("该版本正在下载中!", HintType.Critical) + Hint("该版本正在下载中!", HintType.Red) Return Next @@ -832,7 +832,7 @@ Retry: '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"LiteLoader {Id} 下载" Then Continue For - Hint("该版本正在下载中!", HintType.Critical) + Hint("该版本正在下载中!", HintType.Red) Return Next @@ -866,7 +866,7 @@ Retry: '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"LiteLoader {Id} 下载" Then Continue For - Hint("该版本正在下载中!", HintType.Critical) + Hint("该版本正在下载中!", HintType.Red) Return Next @@ -1048,7 +1048,7 @@ Retry: '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"{DisplayName} 下载" Then Continue For - Hint("该版本正在下载中!", HintType.Critical) + Hint("该版本正在下载中!", HintType.Red) Return Next @@ -1803,7 +1803,7 @@ Retry: '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() If OngoingLoader.Name <> $"Fabric {Version} 安装器下载" Then Continue For - Hint("该版本正在下载中!", HintType.Critical) + Hint("该版本正在下载中!", HintType.Red) Return Next @@ -1986,28 +1986,28 @@ Retry: ''' 在加载器状态改变后显示一条提示。 ''' 不会进行任何其他操作。 ''' - Public Sub LoaderStateChangedHintOnly(Loader) + Public Sub LoaderStateChangedHintOnly(Loader As LoaderBase) Select Case Loader.State Case LoadState.Finished - Hint(Loader.Name & "成功!", HintType.Finish) + Hint(Loader.Name & "成功!", HintType.Green) Case LoadState.Failed - Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Critical) + Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red) Case LoadState.Aborted - Hint(Loader.Name & "已取消!", HintType.Info) + Hint(Loader.Name & "已取消!", HintType.Blue) End Select End Sub ''' ''' 安装加载器状态改变后进行提示和重载文件夹列表的方法。 ''' - Public Sub McInstallState(Loader) + Public Sub McInstallState(Loader As LoaderBase) Select Case Loader.State Case LoadState.Finished WriteIni(PathMcFolder & "PCL.ini", "VersionCache", "") '清空缓存(合并安装会先生成文件夹,这会在刷新时误判为可以使用缓存) - Hint(Loader.Name & "成功!", HintType.Finish) + Hint(Loader.Name & "成功!", HintType.Green) Case LoadState.Failed - Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Critical) + Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red) Case LoadState.Aborted - Hint(Loader.Name & "已取消!", HintType.Info) + Hint(Loader.Name & "已取消!", HintType.Blue) Case LoadState.Loading Return '不重新加载版本列表 End Select @@ -2108,7 +2108,7 @@ Retry: '重复版本检查 If File.Exists($"{VersionFolder}{Request.TargetVersionName}.json") Then - Hint("版本 " & Request.TargetVersionName & " 已经存在!", HintType.Critical) + Hint("版本 " & Request.TargetVersionName & " 已经存在!", HintType.Red) Throw New CancelledException End If diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml index 1144f09..83f5368 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml @@ -1,8 +1,8 @@  + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="clr-namespace:PCL" + RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25"> @@ -23,17 +23,17 @@ - - + - - - + + + diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb index dd48c06..576c6dc 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb @@ -89,14 +89,14 @@ $"登录网页将自动开启,请在网页中输入 {UserCode}(已自动复制)。" & vbCrLf & vbCrLf & $"如果网络环境不佳,网页可能一直加载不出来,届时请使用加速器或 VPN 改善网络环境。" & vbCrLf & $"你也可以用其他设备打开 {Website} 并输入上述代码。" - Btn1.EventData = Website - Btn2.EventData = UserCode + CustomEventService.SetEventData(Btn1, Website) + CustomEventService.SetEventData(Btn2, UserCode) '启动工作线程 RunInNewThread(AddressOf WorkThread, "MyMsgLogin") End Sub Private Sub WorkThread() - Thread.Sleep(3000) + Thread.Sleep(2000) If MyConverter.IsExited Then Return OpenWebsite(Website) ClipboardSet(UserCode) @@ -118,7 +118,7 @@ '获取结果 Dim ResultJson As JObject = GetJson(Result) McLaunchLog($"令牌过期时间:{ResultJson("expires_in")} 秒") - Hint("网页登录成功!", HintType.Finish) + Hint("网页登录成功!", HintType.Green) Finished({ResultJson("access_token").ToString, ResultJson("refresh_token").ToString}) Return Catch ex As Exception diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb index 352c69b..2715ec8 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb @@ -47,7 +47,7 @@ Public Shared Sub Save(Loader As LoaderTask(Of EqualableList(Of String), String)) Dim Address = Loader.Output If Not Loader.State = LoadState.Finished Then - Hint("皮肤正在获取中,请稍候!", HintType.Critical) + Hint("皮肤正在获取中,请稍候!", HintType.Red) If Not Loader.State = LoadState.Loading Then Loader.Start() Return End If @@ -61,7 +61,7 @@ Else CopyFile(Address, FileAddress) End If - Hint("皮肤保存成功!", HintType.Finish) + Hint("皮肤保存成功!", HintType.Green) End If Catch ex As Exception Log(ex, "保存皮肤失败", LogLevel.Hint) @@ -143,7 +143,7 @@ Next If FrmLaunchLeft IsNot Nothing AndAlso HasLoaderRunning Then '由于 Abort 不是实时的,暂时不会释放文件,会导致删除报错,故只能取消执行 - Hint("有正在获取中的皮肤,请稍后再试!", HintType.Info) + Hint("有正在获取中的皮肤,请稍后再试!", HintType.Blue) Else RunInThread( Sub() @@ -161,7 +161,7 @@ For Each SkinLoader In If(sender IsNot Nothing, {sender}, {PageLaunchLeft.SkinLegacy, PageLaunchLeft.SkinMs}) SkinLoader.WaitForExit(IsForceRestart:=True) Next - Hint("已刷新头像!", HintType.Finish) + Hint("已刷新头像!", HintType.Green) Catch ex As Exception Log(ex, "刷新皮肤缓存失败", LogLevel.Msgbox) End Try @@ -184,7 +184,7 @@ SkinLoader.WaitForExit(IsForceRestart:=True) Next '完成提示 - Hint("更改皮肤成功!", HintType.Finish) + Hint("更改皮肤成功!", HintType.Green) Catch ex As Exception Log(ex, "更改正版皮肤后刷新皮肤失败", LogLevel.Feedback) End Try @@ -212,7 +212,7 @@ Return End If If McLoginMsLoader.State = LoadState.Failed Then - Hint("登录失败,无法更改披风!", HintType.Critical) + Hint("登录失败,无法更改披风!", HintType.Red) Return End If Hint("正在获取披风列表,请稍候……") @@ -225,7 +225,7 @@ Retry: '获取登录信息 If McLoginMsLoader.State <> LoadState.Finished Then McLoginMsLoader.WaitForExit(PageLoginMsSkin.GetLoginData()) If McLoginMsLoader.State <> LoadState.Finished Then - Hint("登录失败,无法更改披风!", HintType.Critical) + Hint("登录失败,无法更改披风!", HintType.Red) Return End If Dim AccessToken As String = McLoginMsLoader.Output.AccessToken @@ -265,10 +265,10 @@ Retry: ContentType:="application/json", Headers:={{"Authorization", "Bearer " & AccessToken}}) If Result.Contains("""errorMessage""") Then - Hint("更改披风失败:" & GetJson(Result)("errorMessage").ToString, HintType.Critical) + Hint("更改披风失败:" & GetJson(Result)("errorMessage").ToString, HintType.Red) Return Else - Hint("更改披风成功!", HintType.Finish) + Hint("更改披风成功!", HintType.Green) End If Catch ex As Exception Log(ex, "更改披风失败", LogLevel.Hint) diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb index 65b5086..260fed3 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb @@ -134,6 +134,8 @@ Public Class PageLaunchRight Private Sub OnlineLoaderSub(Task As LoaderTask(Of String, Integer)) Dim Address As String = Task.Input '#3721 中连续触发两次导致内容变化 Try + '替换自定义变量与设置 + Address = ArgumentReplace(Address, AddressOf WebUtility.HtmlEncode) '获取版本校验地址 Dim VersionAddress As String If Address.Contains(".xaml") Then @@ -146,29 +148,27 @@ Public Class PageLaunchRight End If '校验版本 Dim Version As String = "" - Dim NeedDownload As Boolean = True Try Version = NetRequestByClientRetry(VersionAddress) If Version.Length > 1000 Then Throw New Exception($"获取的主页版本过长({Version.Length} 字符)") Dim CurrentVersion As String = Setup.Get("CacheSavedPageVersion") If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then Log($"[Page] 当前缓存的主页已为最新,当前版本:{Version},检查源:{VersionAddress}") - NeedDownload = False - Else - Log($"[Page] 需要下载联网主页,当前版本:{Version},检查源:{VersionAddress}") + Return End If + Log($"[Page] 需要下载联网主页,当前版本:{Version},检查源:{VersionAddress}") Catch exx As Exception Log(exx, $"联网获取主页版本失败", LogLevel.Developer) Log($"[Page] 无法检查联网主页版本,将直接下载,检查源:{VersionAddress}") End Try '实际下载 - If Not NeedDownload Then Return Dim FileContent As String = NetRequestByClientRetry(Address) Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}") Setup.Set("CacheSavedPageUrl", Address) Setup.Set("CacheSavedPageVersion", Version) WriteFile(PathTemp & "Cache\Custom.xaml", FileContent) - Refresh() '要求刷新 + '若内容变更则要求刷新 + If LoadedContentHash <> FileContent.GetHashCode() Then Refresh() Catch ex As Exception Log(ex, $"下载主页失败({Address})", If(ModeDebug, LogLevel.Msgbox, LogLevel.Hint)) End Try @@ -220,7 +220,7 @@ Public Class PageLaunchRight End If Dim LoadStartTime As Date = Date.Now '修改时应同时修改 PageOtherHelpDetail.Init - Content = HelpArgumentReplace(Content) + Content = ArgumentReplace(Content, AddressOf EscapeXML) Do While Content.Contains("xmlns") Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间 Loop diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb index 56970a4..a339893 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb @@ -50,7 +50,7 @@ If CType(McLoginLoader.Input, McLoginServer).ForceReselectProfile Then Hint("正在尝试更换,请稍候!") Else - Hint("正在登录中,请稍后再更换角色!", HintType.Critical) + Hint("正在登录中,请稍后再更换角色!", HintType.Red) End If Return End If diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb index 33cafbb..780d8d6 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb @@ -68,7 +68,7 @@ Public Class PageLoginLegacy End Sub Private Sub Skin_Click() Handles Skin.Click If (Setup.Get("UiHiddenPageSetup") OrElse Setup.Get("UiHiddenSetupLaunch")) AndAlso Not PageSetupUI.HiddenForceShow Then - Hint("启动设置已被禁用!", HintType.Critical) + Hint("启动设置已被禁用!", HintType.Red) Else FrmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupLaunch) '切换到皮肤设置页面 End If diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml index cf470d4..8364edd 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml @@ -27,9 +27,9 @@ - - diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb index ae823a7..0d5ed36 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb @@ -90,7 +90,7 @@ Catch ex As Exception If ex.Message = "$$" Then ElseIf ex.Message.StartsWith("$") Then - Hint(ex.Message.TrimStart("$"), HintType.Critical) + Hint(ex.Message.TrimStart("$"), HintType.Red) ElseIf TypeOf ex Is Security.Authentication.AuthenticationException AndAlso ex.Message.ContainsF("SSL/TLS") Then Log(ex, "正版登录验证失败,请考虑在 [设置 → 其他] 中关闭 [在正版登录时验证 SSL 证书],然后再试。" & vbCrLf & vbCrLf & "原始错误信息:", LogLevel.Msgbox) Else diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb index 4b808f9..7199516 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb @@ -77,7 +77,7 @@ Return End If If McLoginLoader.State = LoadState.Failed Then - Hint("登录失败,无法更改皮肤!", HintType.Critical) + Hint("登录失败,无法更改皮肤!", HintType.Red) Return End If Dim SkinInfo As McSkinInfo = McSkinSelect() @@ -106,7 +106,7 @@ Retry: McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True) GoTo Retry ElseIf Result.Contains("""error""") Then - Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Critical) + Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Red) Return End If '获取新皮肤地址 @@ -122,7 +122,7 @@ Retry: Throw New Exception("未知错误(" & Result & ")") Catch ex As Exception If TypeOf ex Is OperationCanceledException Then - Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Critical) + Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red) Else Log(ex, "更改皮肤失败", LogLevel.Hint) End If diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml b/Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml index a64acc2..143d253 100644 --- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml +++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkFeedback.xaml @@ -8,29 +8,10 @@ - - - - - - - diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkHiper.xaml b/Plain Craft Launcher 2/Pages/PageLink/PageLinkHiper.xaml index 9cf794e..fd4a3b0 100644 --- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkHiper.xaml +++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkHiper.xaml @@ -83,7 +83,7 @@ - + @@ -229,7 +229,6 @@ - diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml b/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml index cc093ec..7a63bb3 100644 --- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml +++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml @@ -44,7 +44,7 @@ - + diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb b/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb index f1e6312..b398ac3 100644 --- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkIoi.xaml.vb @@ -121,26 +121,7 @@ Public Class PageLinkIoi ''' 获取当前的玩家名。 ''' Public Shared Function GetPlayerName() As String - '自动生成玩家名 - If AutogenPlayerName Is Nothing Then - If IsPlayerNameValid(McLoginName) Then - AutogenPlayerName = McLoginName() - Else - AutogenPlayerName = "玩家 " & CType(GetHash(If(UniqueAddress, "")) Mod 1048576, Integer).ToString("x5").ToUpper - End If - End If - '获取玩家自定义的名称 - Dim CustomName As String = Setup.Get("LinkName").ToString.Trim() - If CustomName <> "" Then - If IsPlayerNameValid(CustomName) Then - Return CustomName.Trim - Else - Hint("你所设置的玩家名存在异常,已被重置!", HintType.Critical) - Setup.Set("LinkName", "") - End If - End If - '使用自动生成的玩家名 - Return AutogenPlayerName + Return "" End Function Private Shared AutogenPlayerName As String = Nothing '并非由玩家自定义,而是自动生成的玩家名 ''' diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml index 0f8afa1..7e3bf33 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml @@ -29,8 +29,10 @@ - - + + @@ -51,11 +53,11 @@ - + - + - + @@ -105,288 +107,217 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -395,7 +326,7 @@ - + @@ -410,8 +341,8 @@ - - + + @@ -443,49 +374,49 @@ + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/00ll00/java_launch_wrapper" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/00ll00/java_launch_wrapper?tab=MIT-1-ov-file#readme" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.newtonsoft.com/json" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://opensource.org/licenses/MIT" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/naudio/NAudio" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/naudio/NAudio/blob/master/license.txt" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.ookii.org/Software/Dialogs/" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/caioproiete/ookii-dialogs-wpf/blob/master/LICENSE" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://iconmonstr.com/" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://iconmonstr.com/license/" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/imazen/libwebp-net" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/imazen/libwebp-net/blob/master/LICENSE.txt" /> + local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.iconfont.cn/" /> diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml.vb index 13e7a3f..cbaec36 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml.vb @@ -18,8 +18,8 @@ End Sub - Public Shared Sub CopyUniqueAddress() Handles BtnDonateCopy.Click - ClipboardSet(UniqueAddress) + Public Shared Sub CopyIdentify() Handles BtnDonateCopy.Click + ClipboardSet(Identify) End Sub Private Sub BtnDonateCodeInput_Click() Handles BtnDonateInput.Click DonateCodeInput() diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb index 2802cd4..6fd927f 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb @@ -71,7 +71,7 @@ Public Shared Sub OnItemClick(Entry As HelpEntry) Try If Entry.IsEvent Then - ModEvent.ProcessCustomEvents(Entry.EventType, Entry.EventData, Nothing) + CustomEvent.Raise(Entry.EventType, Entry.EventData) Else EnterHelpPage(Entry) End If diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb index dafcd2e..9d6b223 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb @@ -18,8 +18,10 @@ If Content = "" Then Throw New Exception("帮助 xaml 文件为空") Try '修改时应同时修改 PageLaunchRight.LoadContent - Content = HelpArgumentReplace(Content) - If Content.Contains("xmlns") Then Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间 + Content = ArgumentReplace(Content, AddressOf EscapeXML) + Do While Content.Contains("xmlns") + Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间 + Loop Content = "" & Content & "" Me.Entry = Entry PanCustom.Children.Clear() diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb index 7d8d927..4469cc2 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb @@ -150,14 +150,14 @@ Dim NewFolder As String = "" '检查是否有下载任务 If HasDownloadingTask() Then - Hint("在下载任务进行时,无法添加游戏文件夹!", HintType.Critical) + Hint("在下载任务进行时,无法添加游戏文件夹!", HintType.Red) Return End If Try '获取输入 NewFolder = SelectFolder() If NewFolder = "" Then Return - If NewFolder.Contains("!") OrElse NewFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Critical) : Return + If NewFolder.Contains("!") OrElse NewFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Red) : Return '要求输入显示名称 Dim SplitedNames As String() = NewFolder.TrimEnd("\").Split("\") Dim DefaultName As String = If(SplitedNames.Last = ".minecraft", If(SplitedNames.Count >= 3, SplitedNames(SplitedNames.Count - 2), ""), SplitedNames.Last) @@ -182,7 +182,7 @@ '检查文件夹权限 If Not CheckPermission(FolderPath) Then If ShowHint Then - Hint("添加文件夹失败:PCL 没有访问该文件夹的权限!", HintType.Critical) + Hint("添加文件夹失败:PCL 没有访问该文件夹的权限!", HintType.Red) Return Else Throw New Exception("PCL 没有访问文件夹的权限:" & FolderPath) @@ -207,12 +207,12 @@ If Folder.Split(">")(1) = FolderPath Then IsAdded = True If Folder.Split(">")(0) = DisplayName Then - If ShowHint Then Hint("此文件夹已在列表中!", HintType.Info) + If ShowHint Then Hint("此文件夹已在列表中!", HintType.Blue) Return Else Folders(i) = DisplayName & ">" & FolderPath IsReplace = True - If ShowHint Then Hint("文件夹名称已更新为 " & DisplayName & " !", HintType.Finish) + If ShowHint Then Hint("文件夹名称已更新为 " & DisplayName & " !", HintType.Green) End If Exit For End If @@ -226,7 +226,7 @@ McFolderListLoader.Start(IsForceRestart:=True) '提示 If IsReplace Then Return - If ShowHint Then Hint("文件夹 " & DisplayName & " 已添加!", HintType.Finish) + If ShowHint Then Hint("文件夹 " & DisplayName & " 已添加!", HintType.Green) '检查是否为根目录整合包,自动关闭版本隔离 '1. 根目录中存在数个 Mod Dim ModFolder As New DirectoryInfo(FolderPath & "mods\") @@ -257,7 +257,7 @@ Public Sub Create_Click() '检查是否有下载任务 If HasDownloadingTask() Then - Hint("在下载任务进行时,无法创建游戏文件夹!", HintType.Critical) + Hint("在下载任务进行时,无法创建游戏文件夹!", HintType.Red) Return End If If Not Directory.Exists(Path & ".minecraft\") Then @@ -265,7 +265,7 @@ Directory.CreateDirectory(Path & ".minecraft\versions\") Setup.Set("LaunchFolderSelect", "$.minecraft\") McFolderLauncherProfilesJsonCreate(Path & ".minecraft\") - Hint("新建 .minecraft 文件夹成功!", HintType.Finish) + Hint("新建 .minecraft 文件夹成功!", HintType.Green) End If McFolderListLoader.Start(IsForceRestart:=True) End Sub @@ -307,7 +307,7 @@ Next '保存 Setup.Set("LaunchFolders", If(Not Folders.Any(), "", Join(Folders.ToArray, "|"))) - Hint(If(Folder.Type = McFolderType.Custom, "文件夹 " & Name & " 已从列表中移除!", "文件夹名称已复原!"), HintType.Finish) + Hint(If(Folder.Type = McFolderType.Custom, "文件夹 " & Name & " 已从列表中移除!", "文件夹名称已复原!"), HintType.Green) McFolderListLoader.Start(IsForceRestart:=True) Catch ex As Exception @@ -336,10 +336,10 @@ Sub() '删除文件夹 Try - Hint("正在" & DeleteText & "文件夹 " & Folder.Name & "!", HintType.Info) + Hint("正在" & DeleteText & "文件夹 " & Folder.Name & "!", HintType.Blue) DeleteDirectory(Folder.Path) If DeleteText = "清空" Then Directory.CreateDirectory(Folder.Path) - Hint("已" & DeleteText & "文件夹 " & Folder.Name & "!", HintType.Finish) + Hint("已" & DeleteText & "文件夹 " & Folder.Name & "!", HintType.Green) Catch ex As Exception Log(ex, DeleteText & "文件夹 " & Folder.Name & " 失败", LogLevel.Hint) Finally @@ -389,7 +389,7 @@ Next '如果没有添加过,则添加进去(因为修改了默认项的名称) If Not IsAdded Then Folders.Add(NewName & ">" & Folder.Path) - Hint("文件夹名称已更新为 " & NewName & " !", HintType.Finish) + Hint("文件夹名称已更新为 " & NewName & " !", HintType.Green) '保存 Setup.Set("LaunchFolders", Join(Folders.ToArray, "|")) McFolderListLoader.Start(IsForceRestart:=True) @@ -403,7 +403,7 @@ If Not e.RaiseByMouse OrElse Not sender.Checked Then Return '检查是否有下载任务 If HasDownloadingTask(True) Then - Hint("在下载任务进行时,无法切换游戏文件夹!", HintType.Critical) + Hint("在下载任务进行时,无法切换游戏文件夹!", HintType.Red) e.Handled = True Return End If diff --git a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb index e6e7d27..16bd2f8 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb @@ -114,22 +114,7 @@ Log(ex, "将版本列表转换显示时失败", LogLevel.Feedback) End Try End Sub - Public Shared Function McVersionListItem(Version As McVersion) As MyListItem - Dim NewItem As New MyListItem With {.Title = Version.Name, .Info = Version.Info, .Height = 42, .Tag = Version, .SnapsToDevicePixels = True, .Type = MyListItem.CheckType.Clickable} - Try - If Version.Logo.EndsWith("PCL\Logo.png") Then - NewItem.Logo = Version.Path & "PCL\Logo.png" '修复老版本中,存储的自定义 Logo 使用完整路径,导致移动后无法加载的 Bug - Else - NewItem.Logo = Version.Logo - End If - Catch ex As Exception - Log(ex, "加载版本图标失败", LogLevel.Hint) - NewItem.Logo = "pack://application:,,,/images/Blocks/RedstoneBlock.png" - End Try - NewItem.ContentHandler = AddressOf McVersionListContent - Return NewItem - End Function - Private Shared Sub McVersionListContent(sender As MyListItem, e As EventArgs) + Public Shared Sub McVersionListContent(sender As MyListItem, e As EventArgs) Dim Version As McVersion = sender.Tag '注册点击事件 AddHandler sender.Click, AddressOf Item_Click @@ -225,10 +210,10 @@ IniClearCache(Version.Path & "PCL\Setup.ini") If IsShiftPressed Then DeleteDirectory(Version.Path) - Hint("版本 " & Version.Name & " 已永久删除!", HintType.Finish) + Hint("版本 " & Version.Name & " 已永久删除!", HintType.Green) Else FileIO.FileSystem.DeleteDirectory(Version.Path, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin) - Hint("版本 " & Version.Name & " 已删除到回收站!", HintType.Finish) + Hint("版本 " & Version.Name & " 已删除!", HintType.Green) End If Case 2 Return diff --git a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb index 38dca35..b18c083 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb @@ -227,7 +227,7 @@ Me.Value = Value Me.Source = Source Me.Type = If(Value, New Object).GetType - Me.DefaultValueEncoded = If(Encoded, SecretEncrypt(Value, "PCL" & UniqueAddress), Value) + Me.DefaultValueEncoded = If(Encoded, SecretEncrypt(Value, "PCL" & Identify), Value) Catch ex As Exception Log(ex, "初始化 SetupEntry 失败", LogLevel.Feedback) '#5095 的 fallback End Try @@ -241,6 +241,14 @@ Public Sub [Set](Key As String, Value As Object, Optional ForceReload As Boolean = False, Optional Version As McVersion = Nothing) [Set](Key, Value, SetupDict(Key), ForceReload, Version) End Sub + ''' + ''' 写入某个未经加密的设置项。 + ''' 若该设置项经过了加密,则会抛出异常。 + ''' + Public Sub SetSafe(Key As String, Value As Object, Optional ForceReload As Boolean = False, Optional Version As McVersion = Nothing) + If SetupDict(Key).Encoded Then Throw New InvalidOperationException("禁止写入加密设置项:" & Key) + [Set](Key, Version, ForceReload, Version) + End Sub Private Sub [Set](Key As String, Value As Object, E As SetupEntry, ForceReload As Boolean, Version As McVersion) Try @@ -258,7 +266,7 @@ If E.Encoded Then Try If Value Is Nothing Then Value = "" - Value = SecretEncrypt(Value, "PCL" & UniqueAddress) + Value = SecretEncrypt(Value, "PCL" & Identify) Catch ex As Exception Log(ex, "加密设置失败:" & Key, LogLevel.Developer) End Try @@ -303,9 +311,17 @@ ''' 获取某个设置项的值。 ''' Public Function [Get](Key As String, Optional Version As McVersion = Nothing) - If Not SetupDict.ContainsKey(Key) Then Throw New KeyNotFoundException("未找到设置项:" & Key) With {.Source = Key} + If Not SetupDict.ContainsKey(Key) Then Throw New KeyNotFoundException("未找到设置项:" & Key) Return [Get](Key, SetupDict(Key), Version) End Function + ''' + ''' 获取某个未经加密的设置项的值。 + ''' 若该设置项经过了加密,则会抛出异常。 + ''' + Public Function GetSafe(Key As String, Optional Version As McVersion = Nothing) + If SetupDict(Key).Encoded Then Throw New InvalidOperationException("禁止读取加密设置项:" & Key) + Return [Get](Key, Version) + End Function Private Function [Get](Key As String, E As SetupEntry, Version As McVersion) '获取强制值 Dim Force As String = ForceValue(Key) @@ -383,7 +399,7 @@ SourceValue = E.DefaultValue Else Try - SourceValue = SecretDecrypt(SourceValue, "PCL" & UniqueAddress) + SourceValue = SecretDecrypt(SourceValue, "PCL" & Identify) Catch ex As Exception Log(ex, "解密设置失败:" & Key, LogLevel.Developer) SourceValue = E.DefaultValue @@ -601,8 +617,7 @@ FrmSetupUI.HintCustom.Visibility = Visibility.Visible FrmSetupUI.HintCustomWarn.Visibility = If(Setup.Get("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible) FrmSetupUI.HintCustom.Text = $"从 PCL 文件夹下的 Custom.xaml 读取主页内容。{vbCrLf}你可以手动编辑该文件,向主页添加文本、图片、常用网站、快捷启动等功能。" - FrmSetupUI.HintCustom.EventType = "" - FrmSetupUI.HintCustom.EventData = "" + CustomEventService.SetEventType(FrmSetupUI.HintCustom, CustomEvent.EventType.None) Case 2 '联网 FrmSetupUI.PanCustomPreset.Visibility = Visibility.Collapsed FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed @@ -610,8 +625,8 @@ FrmSetupUI.HintCustom.Visibility = Visibility.Visible FrmSetupUI.HintCustomWarn.Visibility = If(Setup.Get("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible) FrmSetupUI.HintCustom.Text = $"从指定网址联网获取主页内容。服主也可以用于动态更新服务器公告。{vbCrLf}如果你制作了稳定运行的联网主页,可以点击这条提示投稿,若合格即可加入预设!" - FrmSetupUI.HintCustom.EventType = "打开网页" - FrmSetupUI.HintCustom.EventData = "https://github.com/Meloong-Git/PCL/discussions/2528" + 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 diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml index f207a1d..8adb4fa 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml @@ -41,9 +41,9 @@ - + - + @@ -240,13 +240,13 @@ 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" /> - - + + ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。 你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如: · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件 涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。 执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" /> diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb index d194840..cf5f028 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb @@ -93,7 +93,7 @@ JavaSearchLoader.Start(IsForceRestart:=True) Log("[Setup] 已初始化启动设置") - Hint("已初始化启动设置!", HintType.Finish, False) + Hint("已初始化启动设置!", HintType.Green, False) Catch ex As Exception Log(ex, "初始化启动设置失败", LogLevel.Msgbox) End Try @@ -170,7 +170,7 @@ Try File.Delete(PathAppdata & "CustomSkin.png") RadioSkinType0.SetChecked(True, True) - Hint("离线皮肤已清空!", HintType.Finish) + Hint("离线皮肤已清空!", HintType.Green) Catch ex As Exception Log(ex, "清空离线皮肤失败", LogLevel.Msgbox) End Try @@ -468,7 +468,7 @@ PreFin: '手动选择 Private Sub BtnArgumentJavaSelect_Click(sender As Object, e As EventArgs) Handles BtnArgumentJavaSelect.Click If JavaSearchLoader.State = LoadState.Loading Then - Hint("正在搜索 Java,请稍候!", HintType.Critical) + Hint("正在搜索 Java,请稍候!", HintType.Red) Return End If '选择 Java @@ -489,7 +489,7 @@ PreFin: Setup.Set("LaunchArgumentJavaAll", JavaNewList.ToString(Newtonsoft.Json.Formatting.None)) '重新加载列表 JavaSearchLoader.Start(IsForceRestart:=True) - Hint("已将该 Java 加入 Java 列表!", HintType.Finish) + Hint("已将该 Java 加入 Java 列表!", HintType.Green) Catch ex As Exception Log(ex, "该 Java 存在异常,无法使用", LogLevel.Msgbox, "异常的 Java") Return @@ -498,7 +498,7 @@ PreFin: '自动查找 Private Sub BtnArgumentJavaSearch_Click(sender As Object, e As EventArgs) Handles BtnArgumentJavaSearch.Click If JavaSearchLoader.State = LoadState.Loading Then - Hint("正在搜索 Java,请稍候!", HintType.Critical) + Hint("正在搜索 Java,请稍候!", HintType.Red) Return End If RunInThread( @@ -506,9 +506,9 @@ PreFin: Hint("正在搜索 Java!") JavaSearchLoader.WaitForExit(IsForceRestart:=True) If Not JavaList.Any() Then - Hint("未找到可用的 Java!", HintType.Critical) + Hint("未找到可用的 Java!", HintType.Red) Else - Hint("已找到 " & JavaList.Count & " 个 Java,请检查下拉框查看列表!", HintType.Finish) + Hint("已找到 " & JavaList.Count & " 个 Java,请检查下拉框查看列表!", HintType.Green) End If End Sub) End Sub diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb index 3069a96..c4cc82e 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb @@ -28,7 +28,7 @@ Setup.Reset("LinkHiperCertWarn") Log("[Setup] 已初始化联机页设置") - Hint("已初始化联机页设置!", HintType.Finish, False) + Hint("已初始化联机页设置!", HintType.Green, False) Catch ex As Exception Log(ex, "初始化联机页设置失败", LogLevel.Msgbox) End Try diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb index 7ead8ef..766413a 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb @@ -85,7 +85,7 @@ Setup.Reset("SystemSystemTelemetry") Log("[Setup] 已初始化启动器页设置") - Hint("已初始化启动器页设置!", HintType.Finish, False) + Hint("已初始化启动器页设置!", HintType.Green, False) Catch ex As Exception Log(ex, "初始化启动器页设置失败", LogLevel.Msgbox) End Try @@ -136,7 +136,7 @@ '识别码/解锁码替代入口 Private Sub BtnSystemIdentify_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnSystemIdentify.Click - PageOtherAbout.CopyUniqueAddress() + PageOtherAbout.CopyIdentify() End Sub Private Sub BtnSystemUnlock_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnSystemUnlock.Click DonateCodeInput() diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml index b995ec8..06913f0 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml @@ -225,7 +225,8 @@ - + diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb index 92fe4e1..a992749 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb @@ -162,7 +162,7 @@ Setup.Reset("UiHiddenOtherTest") Log("[Setup] 已初始化个性化设置!") - Hint("已初始化个性化设置", HintType.Finish, False) + Hint("已初始化个性化设置", HintType.Green, False) Catch ex As Exception Log(ex, "初始化个性化设置失败", LogLevel.Msgbox) End Try @@ -215,7 +215,7 @@ If MyMsgBox("即将删除背景图片文件夹中的所有文件。" & vbCrLf & "此操作不可撤销,是否确定?", "警告",, "取消", IsWarn:=True) = 1 Then DeleteDirectory(Path & "PCL\Pictures") BackgroundRefresh(False, True) - Hint("背景图片已清空!", HintType.Finish) + Hint("背景图片已清空!", HintType.Green) End If End Sub ''' @@ -238,10 +238,10 @@ If Not Pic.Any() Then If Refresh Then If FrmMain.ImgBack.Visibility = Visibility.Collapsed Then - If IsHint Then Hint("未检测到可用背景图片!", HintType.Critical) + If IsHint Then Hint("未检测到可用背景图片!", HintType.Red) Else FrmMain.ImgBack.Visibility = Visibility.Collapsed - If IsHint Then Hint("背景图片已清除!", HintType.Finish) + If IsHint Then Hint("背景图片已清除!", HintType.Green) End If End If If Not IsNothing(FrmSetupUI) Then FrmSetupUI.BackgroundRefreshUI(False, 0) @@ -253,7 +253,7 @@ FrmMain.ImgBack.Background = New MyBitmap(Address) Setup.Load("UiBackgroundSuit", True) FrmMain.ImgBack.Visibility = Visibility.Visible - If IsHint Then Hint("背景图片已刷新:" & GetFileNameFromPath(Address), HintType.Finish, False) + If IsHint Then Hint("背景图片已刷新:" & GetFileNameFromPath(Address), HintType.Green, False) Catch ex As Exception If ex.Message.Contains("参数无效") Then Log("刷新背景图片失败,该图片文件可能并非标准格式。" & vbCrLf & @@ -338,7 +338,7 @@ Refresh: Try File.Delete(Path & "PCL\Logo.png") RadioLogoType1.SetChecked(True, True) - Hint("标题栏图片已清空!", HintType.Finish) + Hint("标题栏图片已清空!", HintType.Green) Catch ex As Exception Log(ex, "清空标题栏图片失败", LogLevel.Msgbox) End Try @@ -381,7 +381,7 @@ Refresh: '删除文件 Try DeleteDirectory(Path & "PCL\Musics") - Hint("背景音乐已删除!", HintType.Finish) + Hint("背景音乐已删除!", HintType.Green) Catch ex As Exception Log(ex, "删除背景音乐失败", LogLevel.Msgbox) End Try @@ -410,7 +410,7 @@ Refresh: If MyMsgBox("当前已存在布局文件,继续生成教学文件将会覆盖现有布局文件!", "覆盖确认", "继续", "取消", IsWarn:=True) = 2 Then Return End If WriteFile(Path & "PCL\Custom.xaml", GetResources("Custom")) - Hint("教学文件已生成!", HintType.Finish) + Hint("教学文件已生成!", HintType.Green) OpenExplorer(Path & "PCL\Custom.xaml") Catch ex As Exception Log(ex, "生成教学文件失败", LogLevel.Feedback) @@ -418,7 +418,7 @@ Refresh: End Sub Private Sub BtnCustomRefresh_Click() Handles BtnCustomRefresh.Click FrmLaunchRight.ForceRefresh() - Hint("已刷新主页!", HintType.Finish) + Hint("已刷新主页!", HintType.Green) End Sub Private Sub BtnCustomTutorial_Click(sender As Object, e As EventArgs) Handles BtnCustomTutorial.Click MyMsgBox("1. 点击 生成教学文件 按钮,这会在 PCL 文件夹下生成 Custom.xaml 布局文件。" & vbCrLf & diff --git a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb index 3796d42..785b928 100644 --- a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb @@ -96,7 +96,7 @@ Public Class PageSpeedLeft AddHandler Tb.MouseLeftButtonDown, Sub(sender As TextBlock, e As EventArgs) ClipboardSet(sender.Text, False) - Hint("已复制错误详情!", HintType.Finish) + Hint("已复制错误详情!", HintType.Green) End Sub Card.Children.Add(Tb) #End Region diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml index 3574f12..4eee204 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml @@ -262,7 +262,7 @@ + local:CustomEventService.EventType="打开帮助" /> diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml.vb index cdae17b..0ad29e3 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml.vb @@ -22,7 +22,8 @@ Public Class PageVersionExport Private Sub PageVersionExport_Loaded() Handles Me.Loaded AniControlEnabled += 1 If CurrentVersion <> PageVersionLeft.Version.Path Then RefreshAll() '切换到了另一个版本,重置页面 - BtnAdvancedHelp.EventData = If(VersionBranchName = "Release", "指南/整合包制作 - Public.json", "指南/整合包制作 - Snapshot.json") + CustomEventService.SetEventData(BtnAdvancedHelp, + If(VersionBranchName = "Release", "指南/整合包制作 - Public.json", "指南/整合包制作 - Snapshot.json")) AniControlEnabled -= 1 End Sub Public Sub RefreshAll() Implements IRefreshable.Refresh @@ -35,7 +36,7 @@ Public Class PageVersionExport TextExportVersion.HintText = "1.0.0" CheckAdvancedInclude.Checked = False CheckAdvancedModrinth.Checked = False - GetExportOption(CheckOptionsBasic).Description = PageVersionLeft.Version.GetDefaultDescription() + GetExportOption(CheckOptionsBasic).Description = PageVersionLeft.Version.GetVersionDescription() ResetConfigOverrides() ReloadAllSubOptions() RefreshAllOptionsUI() @@ -341,7 +342,7 @@ Public Class PageVersionExport ConfigLines.AddRange(GetExtraFileLines()) '结束 WriteFile(ConfigPath, ConfigLines.Join(vbCrLf)) - Hint("已保存配置文件:" & ConfigPath, HintType.Finish) + Hint("已保存配置文件:" & ConfigPath, HintType.Green) OpenExplorer(ConfigPath) Catch ex As Exception Log(ex, "保存配置失败", LogLevel.Msgbox) @@ -378,7 +379,7 @@ Public Class PageVersionExport ExtraFiles = Nothing End If '结束 - Hint("已读取配置文件:" & ConfigPath, HintType.Finish) + Hint("已读取配置文件:" & ConfigPath, HintType.Green) Catch ex As Exception Log(ex, "读取配置失败", LogLevel.Msgbox) End Try @@ -517,13 +518,13 @@ Public Class PageVersionExport If Directory.Exists(Line) Then CopyDirectory(Line, BaseFolder & GetFolderNameFromPath(Line) & "\") Else - Hint($"未找到配置文件中指定的文件夹:{Line}", HintType.Critical) + Hint($"未找到配置文件中指定的文件夹:{Line}", HintType.Red) End If Else If File.Exists(Line) Then CopyFile(Line, BaseFolder & GetFileNameFromPath(Line)) Else - Hint($"未找到配置文件中指定的单个文件:{Line}", HintType.Critical) + Hint($"未找到配置文件中指定的单个文件:{Line}", HintType.Red) End If End If Next diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb index 73c280c..a844d23 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb @@ -306,7 +306,7 @@ If Result.Any Then MyMsgBox(Join(Result, vbCrLf & vbCrLf), "Mod 检查结果") Else - Hint("Mod 检查完成,未发现任何问题!", HintType.Finish) + Hint("Mod 检查完成,未发现任何问题!", HintType.Green) End If Catch ex As Exception Log(ex, "进行 Mod 检查时出错", LogLevel.Feedback) @@ -340,7 +340,7 @@ Log("[System] 文件为 jar/litemod 格式,尝试作为 Mod 安装") '检查回收站:回收站中的文件有错误的文件名 If FilePathList.First.Contains(":\$RECYCLE.BIN\") Then - Hint("请先将文件从回收站还原,再尝试安装!", HintType.Critical) + Hint("请先将文件从回收站还原,再尝试安装!", HintType.Red) Return True End If '获取并检查目标版本 @@ -362,9 +362,9 @@ Install: CopyFile(ModFile, TargetVersion.PathIndie & "mods\" & NewFileName) Next If FilePathList.Count = 1 Then - Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Finish) + Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Green) Else - Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Finish) + Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Green) End If '刷新列表 If FrmMain.PageCurrent = FormMain.PageType.VersionSetup AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.VersionMod Then @@ -570,7 +570,7 @@ Install: If IsSuccessful Then RefreshBars() Else - Hint("由于文件被占用,Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical) + Hint("由于文件被占用,Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Red) ReloadModList(True) End If LoaderRun(LoaderFolderRunType.UpdateOnly) @@ -643,14 +643,14 @@ Install: Try For Each Entry As McMod In ModList If File.Exists(Entry.Path) Then - My.Computer.FileSystem.DeleteFile(Entry.Path, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin) + My.Computer.FileSystem.DeleteFile(Entry.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) Else Log($"[Mod] 未找到更新前的 Mod 文件,跳过对它的删除:{Entry.Path}", LogLevel.Debug) End If Next For Each Entry As KeyValuePair(Of String, String) In FileCopyList If File.Exists(Entry.Value) Then - My.Computer.FileSystem.DeleteFile(Entry.Value, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin) + My.Computer.FileSystem.DeleteFile(Entry.Value, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) Log($"[Mod] 更新后的 Mod 文件已存在,将会把它放入回收站:{Entry.Value}", LogLevel.Debug) End If If Directory.Exists(GetPathFromFullPath(Entry.Value)) Then @@ -676,14 +676,14 @@ Install: Case 0 '一般是由于 Mod 文件被占用,然后玩家主动取消 Log($"[Mod] 没有 Mod 被成功更新") Case 1 - Hint($"已成功更新 {FinishedFileNames.Single}!", HintType.Finish) + Hint($"已成功更新 {FinishedFileNames.Single}!", HintType.Green) Case Else - Hint($"已成功更新 {FinishedFileNames.Count} 个 Mod!", HintType.Finish) + Hint($"已成功更新 {FinishedFileNames.Count} 个 Mod!", HintType.Green) End Select Case LoadState.Failed - Hint("Mod 更新失败:" & Loader.Error.GetBrief(), HintType.Critical) + Hint("Mod 更新失败:" & Loader.Error.GetBrief(), HintType.Red) Case LoadState.Aborted - Hint("Mod 更新已中止!", HintType.Info) + Hint("Mod 更新已中止!", HintType.Blue) Case Else Return End Select @@ -739,7 +739,7 @@ Install: If IsShiftPressed Then File.Delete(ModEntity.Path) Else - My.Computer.FileSystem.DeleteFile(ModEntity.Path, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin) + My.Computer.FileSystem.DeleteFile(ModEntity.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) End If Catch ex As OperationCanceledException Log(ex, "删除 Mod 被主动取消") @@ -760,7 +760,7 @@ Install: Next RefreshBars() If Not IsSuccessful Then - Hint("由于文件被占用,Mod 删除失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical) + Hint("由于文件被占用,Mod 删除失败,请尝试关闭正在运行的游戏后再试!", HintType.Red) ReloadModList(True) ElseIf PanList.Children.Count = 0 Then ReloadModList(True) '删除了全部文件 @@ -771,15 +771,15 @@ Install: If Not IsSuccessful Then Return If IsShiftPressed Then If ModList.Count = 1 Then - Hint($"已彻底删除 {ModList.Single.FileName}!", HintType.Finish) + Hint($"已彻底删除 {ModList.Single.FileName}!", HintType.Green) Else - Hint($"已彻底删除 {ModList.Count} 个文件!", HintType.Finish) + Hint($"已彻底删除 {ModList.Count} 个文件!", HintType.Green) End If Else If ModList.Count = 1 Then - Hint($"已将 {ModList.Single.FileName} 删除到回收站!", HintType.Finish) + Hint($"已将 {ModList.Single.FileName} 删除到回收站!", HintType.Green) Else - Hint($"已将 {ModList.Count} 个文件删除到回收站!", HintType.Finish) + Hint($"已将 {ModList.Count} 个文件删除到回收站!", HintType.Green) End If End If Catch ex As OperationCanceledException diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml.vb index 294b486..3035e9f 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionOverall.xaml.vb @@ -30,7 +30,7 @@ BtnFolderMods.Visibility = If(PageVersionLeft.Version.Modable, Visibility.Visible, Visibility.Collapsed) '刷新版本显示 PanDisplayItem.Children.Clear() - ItemVersion = PageSelectRight.McVersionListItem(PageVersionLeft.Version) + ItemVersion = PageVersionLeft.Version.ToListItem ItemVersion.IsHitTestVisible = False PanDisplayItem.Children.Add(ItemVersion) FrmMain.PageNameRefresh() @@ -169,7 +169,7 @@ Log(ex, "重命名版本 json 失败") End Try '刷新与提示 - Hint("重命名成功!", HintType.Finish) + Hint("重命名成功!", HintType.Green) PageVersionLeft.Version = New McVersion(NewName).Load() If Not IsNothing(McVersionCurrent) AndAlso McVersionCurrent.Equals(PageVersionLeft.Version) Then WriteIni(PathMcFolder & "PCL.ini", "Version", NewName) Reload() @@ -263,7 +263,7 @@ If SavePath = "" Then Return '检查中断(等玩家选完弹窗指不定任务就结束了呢……) If McLaunchLoader.State = LoadState.Loading Then - Hint("请在当前启动任务结束后再试!", HintType.Critical) + Hint("请在当前启动任务结束后再试!", HintType.Red) Return End If '生成脚本 @@ -284,13 +284,13 @@ Try '忽略文件检查提示 If ShouldIgnoreFileCheck(PageVersionLeft.Version) Then - Hint("请先关闭 [版本设置 → 设置 → 高级启动选项 → 关闭文件校验],然后再尝试补全文件!", HintType.Info) + Hint("请先关闭 [版本设置 → 设置 → 高级启动选项 → 关闭文件校验],然后再尝试补全文件!", HintType.Blue) Return End If '重复任务检查 For Each OngoingLoader In LoaderTaskbar If OngoingLoader.Name <> PageVersionLeft.Version.Name & " 文件补全" Then Continue For - Hint("正在处理中,请稍候!", HintType.Critical) + Hint("正在处理中,请稍候!", HintType.Red) Return Next '启动 @@ -299,11 +299,11 @@ Sub() Select Case Loader.State Case LoadState.Finished - Hint(Loader.Name & "成功!", HintType.Finish) + Hint(Loader.Name & "成功!", HintType.Green) Case LoadState.Failed - Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Critical) + Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red) Case LoadState.Aborted - Hint(Loader.Name & "已取消!", HintType.Info) + Hint(Loader.Name & "已取消!", HintType.Blue) End Select End Sub Loader.Start(PageVersionLeft.Version.Name) @@ -329,10 +329,10 @@ IniClearCache(PageVersionLeft.Version.Path & "PCL\Setup.ini") If IsShiftPressed Then DeleteDirectory(PageVersionLeft.Version.Path) - Hint("版本 " & PageVersionLeft.Version.Name & " 已永久删除!", HintType.Finish) + Hint("版本 " & PageVersionLeft.Version.Name & " 已永久删除!", HintType.Green) Else - FileIO.FileSystem.DeleteDirectory(PageVersionLeft.Version.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) - Hint("版本 " & PageVersionLeft.Version.Name & " 已删除到回收站!", HintType.Finish) + FileIO.FileSystem.DeleteDirectory(PageVersionLeft.Version.Path, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin) + Hint("版本 " & PageVersionLeft.Version.Name & " 已删除到回收站!", HintType.Green) End If Case 2 Return diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml index b3a872c..7c1e11d 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml @@ -34,9 +34,9 @@ ToolTip="与其余关闭隔离的版本共享存档、Mod 等文件。 若存在多个安装了 Mod 的版本,可能会由于 Mod 冲突而导致崩溃。" ToolTipService.HorizontalOffset="100"/> - + - + @@ -209,13 +209,13 @@ - - + + ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。 在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。 你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如: · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件 涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。 执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" /> diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb index 414d5f0..b22e277 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionSetup.xaml.vb @@ -98,7 +98,7 @@ JavaSearchLoader.Start(IsForceRestart:=True) Log("[Setup] 已初始化版本独立设置") - Hint("已初始化版本独立设置!", HintType.Finish, False) + Hint("已初始化版本独立设置!", HintType.Green, False) Catch ex As Exception Log(ex, "初始化版本独立设置失败", LogLevel.Msgbox) End Try diff --git a/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj b/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj index b5eafff..e40bfb6 100644 --- a/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj +++ b/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj @@ -206,8 +206,8 @@ Designer - - + + diff --git a/Plain Craft Launcher 2/Resources/Custom.xaml b/Plain Craft Launcher 2/Resources/Custom.xaml index 07ed9a2..65c3675 100644 --- a/Plain Craft Launcher 2/Resources/Custom.xaml +++ b/Plain Craft Launcher 2/Resources/Custom.xaml @@ -53,114 +53,37 @@ - - - + + - - - - - - + + + + - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -198,7 +121,7 @@ Logo="pack://application:,,,/images/Blocks/Grass.png" EventType="打开帮助" EventData="帮助/自定义帮助.json" Type="Clickable" /> + Text="EventType、EventData 与按钮几乎一致。唯一不同的是,列表项不支持联网加载帮助文件。" /> @@ -261,17 +184,6 @@ - - - - - - - -