This commit is contained in:
龙腾猫跃
2025-10-07 04:57:14 +08:00
parent 86ed0e9ae0
commit a41579b1da
71 changed files with 1151 additions and 1340 deletions
+2 -3
View File
@@ -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})")
@@ -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()
+22 -15
View File
@@ -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
''' <summary>
''' 是否已被折叠。(已过时,请使用 IsSwapped)
''' </summary>
<Obsolete("IsSwaped 存在拼写错误,请换用 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
@@ -12,9 +12,6 @@ Public Class MyCheckBox
''' <param name="user">是否为用户手动改变的勾选状态。</param>
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
@@ -117,7 +117,7 @@
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
If SelectedItem Is Nothing OrElse Text = SelectedItem.ToString Then Return
Dim RawText As String = Text
Dim RawSelectionStart As Integer = TextBox.SelectionStart
IsTextChanging = True
@@ -125,7 +125,6 @@
Text = RawText
TextBox.SelectionStart = RawSelectionStart
IsTextChanging = False
End If
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
@@ -53,7 +53,8 @@
Set(value As Boolean)
If _Show = value Then Return
_Show = value
RunInUi(Sub()
RunInUi(
Sub()
If value Then
'有了
Visibility = Visibility.Visible
@@ -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,7 +201,8 @@
''' 发出一圈波浪效果提示。
''' </summary>
Public Sub Ribble()
RunInUi(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)
@@ -81,12 +81,12 @@ Public Class MyExtraTextButton
'触发点击事件
Private Sub Button_LeftMouseUp(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseLeftButtonUp
If IsLeftMouseHeld Then
If Not IsLeftMouseHeld Then Return
Log("[Control] 按下附加图标按钮:" & Text)
RaiseEvent Click(sender, e)
e.Handled = True
RaiseCustomEvent()
Button_LeftMouseUp()
End If
End Sub
'鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行)
+1 -31
View File
@@ -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
@@ -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
@@ -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
'动画
+16 -3
View File
@@ -46,7 +46,7 @@
Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyImage).Source = e.NewValue.ToString())))
''' <summary>
''' 若 Source 是一个网络图片,该地址将作为第二下载源。
''' 若 Source 是一个网络图片,该地址将作为第二图片源。
''' </summary>
Public Property FallbackSource As String
Get
@@ -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
@@ -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
@@ -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
@@ -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
'更改动画
@@ -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 属性。
''' </summary>
''' <param name="value">新的 Checked 属性。</param>
''' <param name="user">是否由用户引发。</param>
''' <param name="raiseByMouse">是否由用户引发。</param>
''' <param name="anime">是否执行动画。</param>
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)
@@ -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
@@ -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
@@ -22,14 +22,14 @@
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
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 If
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
If Not IsMouseDown Then Return
IsMouseDown = False
Log("[Control] 按下文本按钮:" & Text)
RaiseEvent Click(Me, Nothing)
ModEvent.ProcessCustomEvents(EventType, EventData, _CustomEvents)
RaiseCustomEvent()
e.Handled = True
End If
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
+23 -13
View File
@@ -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 的一部分
''' <summary>
''' 页面种类。
''' 该枚举在自定义事件中使用,是公开 API 的一部分。
''' </summary>
Public Enum PageType
''' <summary>
@@ -1043,6 +1052,7 @@ Public Class FormMain
End Enum
''' <summary>
''' 次要页面种类。其数值必须与 StackPanel 中的下标一致。
''' 该枚举在自定义事件中使用,是公开 API 的一部分。
''' </summary>
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
+37 -17
View File
@@ -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
''' <summary>
''' 识别码。
''' </summary>
Public UniqueAddress As String = SecretGetUniqueAddress()
Public Identify As String = SecretGetIdentify()
''' <summary>
''' 程序是否已结束。
''' </summary>
@@ -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
''' <summary>
@@ -1400,12 +1399,13 @@ RetryDir:
''' <summary>
''' 若路径长度大于指定值,则将长路径转换为短路径。
''' 如果路径不存在,则返回原始路径。
''' </summary>
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
''' <summary>
''' 将字符串转换为枚举类型,支持数字或原文两种格式,若为空字符串则返回 0。
''' 若转换失败会抛出异常。
''' </summary>
<Extension> 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
''' <summary>
''' 将文件大小转化为适合的文本形式,如“1.28 M”。
''' </summary>
''' <param name="FileSize">以字节为单位的大小表示。</param>
@@ -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 对象。
''' </summary>
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
+21 -19
View File
@@ -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
''' <summary>
''' 下载一系列文件的加载器。
''' </summary>
@@ -1890,7 +1893,6 @@ Retry:
Catch ex As Exception
Log(ex, "清理下载缓存失败")
End Try
Directory.CreateDirectory(PathTemp & "Download")
End If
IsDownloadCacheCleared = True
End SyncLock
@@ -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
@@ -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:
''' </summary>
Private Function GetNativesFolder() As String
Dim Result As String = McVersionCurrent.Path & McVersionCurrent.Name & "-natives"
If IsGBKEncoding OrElse Result.IsASCII() Then Return ShortenPath(Result)
If Not (IsGBKEncoding OrElse Result.IsASCII()) Then
Result = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\bin\natives"
If Result.IsASCII() Then Return ShortenPath(Result)
Return OsDrive & "ProgramData\PCL\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
''' <summary>
''' 在启动结束时,对 PCL 约定的替换标记进行处理。
''' </summary>
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
@@ -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
''' 显示的描述文本。
''' </summary>
Public Info As String = "该版本未被加载,请向作者反馈此问题"
Public ReadOnly Property HasCustomInfo As Boolean
Get
Return ReadIni(Path & "PCL\Setup.ini", "CustomInfo") <> ""
End Get
End Property
''' <summary>
''' 该版本的列表检查原始结果,不受自定义影响。
''' </summary>
@@ -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
''' <summary>
''' 获取版本的默认描述。
''' 获取对该版本的简短描述。
''' 例如 “快照 16w01a”、“原版 1.12.2”、“愚人节版本 2.0”。
''' </summary>
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
@@ -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)("解压压缩包",
@@ -349,7 +349,7 @@
State = MinecraftState.Crashed
'崩溃分析
WatcherLog("Minecraft 已崩溃,将在 2 秒后开始崩溃分析")
Hint("检测到 Minecraft 出现错误,错误分析已开始……", HintType.Critical)
Hint("检测到 Minecraft 出现错误,错误分析已开始……", HintType.Red)
FeedbackInfo()
RunInNewThread(
Sub()
+290 -202
View File
@@ -1,181 +1,291 @@
Imports System.Collections.ObjectModel

#Region "附加属性"
''' <summary>
''' 用于在 XAML 中初始化列表对象。
''' 附加属性无法在 XAML 中为每个对象初始化独立的列表对象,因此需要一个包装类,然后在 XAML 中显式初始化。
''' </summary>
<Markup.ContentProperty("Events")>
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
''' <summary>
''' 提供自定义事件的附加属性。
''' </summary>
Public Class CustomEventService
'Events
Public Shared ReadOnly EventsProperty As DependencyProperty =
DependencyProperty.RegisterAttached("Events", GetType(CustomEventCollection), GetType(CustomEventService), New PropertyMetadata(Nothing))
<AttachedPropertyBrowsableForType(GetType(DependencyObject))>
Public Shared Sub SetEvents(d As DependencyObject, value As CustomEventCollection)
d.SetValue(EventsProperty, value)
End Sub
<AttachedPropertyBrowsableForType(GetType(DependencyObject))>
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))
<AttachedPropertyBrowsableForType(GetType(DependencyObject))>
Public Shared Sub SetEventType(d As DependencyObject, value As CustomEvent.EventType)
d.SetValue(EventTypeProperty, value)
End Sub
<AttachedPropertyBrowsableForType(GetType(DependencyObject))>
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))
<AttachedPropertyBrowsableForType(GetType(DependencyObject))>
Public Shared Sub SetEventData(d As DependencyObject, value As String)
d.SetValue(EventDataProperty, value)
End Sub
<AttachedPropertyBrowsableForType(GetType(DependencyObject))>
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 "事件执行方法"
''' <summary>
''' 供外部调用的自定义事件执行接口,会在新建工作线程中运行逻辑。
''' 触发该控件上的自定义事件。
''' 事件会在新线程中执行。
''' </summary>
''' <param name="SingleEventType">xaml中的EventType</param>
''' <param name="SingleEventData">xaml中的EventData</param>
''' <param name="EventCollection">xaml中的CustomEvents</param>
Public Sub ProcessCustomEvents(SingleEventType As String, SingleEventData As String, EventCollection As CustomEventCollection)
<Runtime.CompilerServices.Extension>
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)
For Each e In Events
e.Raise()
Next
End If
Catch ex As Exception
Log(ex, "自定义事件执行器发生异常", LogLevel.Feedback)
End Try
End Sub, "CustomEventProcessor " & GetUuid())
End Sub
''' <summary>
''' 对当前线程阻塞地调用自定义事件处理器,接受来自 xaml 原始输入作为参数。
''' </summary>
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
End Sub, "执行自定义事件 " & GetUuid())
End Sub
''' <summary>
''' 存储各个自定义事件处理器的字典,以 EventType 为键,执行自定义事件时在工作线程中调用 Action 并传入分割后的 EventData 。
''' Action 应当在事件逻辑结束后,即可以开始下一个事件时再结束;以便于挨个调用事件不打架。
''' </summary>
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 "工具方法"
''' <summary>
''' 自定义事件。
''' </summary>
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
''' <summary>
''' 弹窗询问用户是否同意继续执行打开类事件。
''' 在当前线程中触发该自定义事件。
''' </summary>
Private Function CommandRunUserConfirm(TextShowToUser As String) As Boolean
If Setup.Get("HintCustomCommand") Then Return True
Select Case MyMsgBox("即将执行:" & TextShowToUser & vbCrLf & "请在确认该操作没有安全隐患后继续。", "执行确认", "继续", "继续且今后不再要求确认", "取消")
Public Sub Raise()
Raise(Type, Data)
End Sub
#End Region
Public Enum EventType
None = 0
打开网页
打开文件
打开帮助
执行命令
启动游戏
复制文本
刷新主页
刷新页面
刷新帮助
今日人品
内存优化
清理垃圾
弹出窗口
弹出提示
切换页面
导入整合包
安装整合包
下载文件
修改设置
写入设置
修改变量
写入变量
End Enum
''' <summary>
''' 在当前线程中触发一个自定义事件。
''' </summary>
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
Return True
PageOtherTest.StartCustomDownload(Args(0), GetFileNameFromPath(Args(0)))
Case 2
Setup.Set("HintCustomCommand", True)
Return True
Case Else '3
Log("[Control] 用户取消了打开类事件")
Return False
PageOtherTest.StartCustomDownload(Args(0), Args(1))
Case Else
PageOtherTest.StartCustomDownload(Args(0), Args(1), Args(2))
End Select
End Function
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
''' <summary>
''' 返回自定义事件的绝对 Url。实际返回 {绝对 Url, WorkingDir}。
''' 失败会抛出异常。
''' </summary>
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
''' <summary>
''' 弹出安全确认弹窗。返回是否继续执行。
''' </summary>
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
End Class
+86 -35
View File
@@ -7,23 +7,12 @@ Public Module ModMain
''' <summary>
''' 提示信息的种类。
''' 该枚举在自定义事件中使用,是公开 API 的一部分。
''' </summary>
Public Enum HintType
''' <summary>
''' 信息,通常是蓝色的“i”。
''' </summary>
''' <remarks></remarks>
Info
''' <summary>
''' 已完成,通常是绿色的“√”。
''' </summary>
''' <remarks></remarks>
Finish
''' <summary>
''' 错误,通常是红色的“×”。
''' </summary>
''' <remarks></remarks>
Critical
Blue
Green
Red
End Enum
Private Structure HintMessage
Public Text As String
@@ -38,7 +27,7 @@ Public Module ModMain
''' <summary>
''' 在窗口左下角弹出提示文本。
''' </summary>
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:
''' 是否为 “执行事件”。
''' </summary>
Public IsEvent As Boolean
Public EventType As String
Public EventType As CustomEvent.EventType
Public EventData As String
''' <summary>
''' 若非执行事件,其对应的 .xaml 本地文件内容。
@@ -504,7 +493,7 @@ EndHint:
''' </summary>
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
''' <summary>
''' 对帮助文件约定的替换标记进行处理,如果遇到需要转义的字符会进行转义。
''' </summary>
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
''' <summary>
''' 对替换标记进行处理。会对替换内容使用 EscapeHandler 进行转义。
''' </summary>
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 "任务缓存"
+12 -12
View File
@@ -111,7 +111,7 @@
''' </summary>
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
+4 -2
View File
@@ -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
''' <summary>
''' 获取设备标识码。
''' </summary>
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")
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*”
<Assembly: AssemblyVersion("2.10.8.0")>
<Assembly: AssemblyFileVersion("2.10.8.0")>
<Assembly: AssemblyVersion("2.10.9.0")>
<Assembly: AssemblyFileVersion("2.10.9.0")>
<Assembly: NeutralResourcesLanguage("")>
@@ -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})
'启动
@@ -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:
''' 在加载器状态改变后显示一条提示。
''' 不会进行任何其他操作。
''' </summary>
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
''' <summary>
''' 安装加载器状态改变后进行提示和重载文件夹列表的方法。
''' </summary>
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
@@ -1,7 +1,7 @@
<Grid x:Class="MyMsgLogin"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:PCL"
xmlns:local="clr-namespace:PCL"
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
<Grid.RenderTransform>
<TransformGroup>
@@ -23,17 +23,17 @@
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="7,-1,70,9" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle x:Name="ShapeLine" Grid.Row="1" Height="2" Fill="{Binding Foreground, ElementName=LabTitle}" />
<my:MyScrollViewer Grid.Row="3" VerticalAlignment="Top" x:Name="PanCaption" Margin="0,0,0,17" Padding="7,0,15,0"
<local:MyScrollViewer Grid.Row="3" VerticalAlignment="Top" x:Name="PanCaption" Margin="0,0,0,17" Padding="7,0,15,0"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMult="0.7">
<TextBlock VerticalAlignment="Top" TextTrimming="None" TextWrapping="Wrap" Name="LabCaption" FontSize="15" LineHeight="18"
Foreground="#FF5C5C5C" FontWeight="Normal" Padding="1" />
</my:MyScrollViewer>
</local:MyScrollViewer>
<StackPanel Grid.Row="4" Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,8,0" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="重新打开网页" x:Name="Btn1" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False"
EventType="打开网页" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="复制代码" x:Name="Btn2" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False"
EventType="复制文本" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="取消" x:Name="Btn3" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<local:MyButton ColorType="Normal" x:FieldModifier="public" Text="重新打开网页" x:Name="Btn1" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False"
local:CustomEventService.EventType="打开网页" />
<local:MyButton ColorType="Normal" x:FieldModifier="public" Text="复制代码" x:Name="Btn2" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False"
local:CustomEventService.EventType="复制文本" />
<local:MyButton ColorType="Normal" x:FieldModifier="public" Text="取消" x:Name="Btn3" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Border>
@@ -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
@@ -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)
@@ -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
@@ -50,7 +50,7 @@
If CType(McLoginLoader.Input, McLoginServer).ForceReselectProfile Then
Hint("正在尝试更换,请稍候!")
Else
Hint("正在登录中,请稍后再更换角色!", HintType.Critical)
Hint("正在登录中,请稍后再更换角色!", HintType.Red)
End If
Return
End If
@@ -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
@@ -27,9 +27,9 @@
<ColumnDefinition Width="30" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:MyTextButton Text="» 购买正版" EventType="打开网页" EventData="https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj"
<local:MyTextButton Text="» 购买正版" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj"
Grid.Column="0" />
<local:MyTextButton Text="» 前往官网" EventType="打开网页" EventData="https://www.minecraft.net/zh-hans"
<local:MyTextButton Text="» 前往官网" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.minecraft.net/zh-hans"
Grid.Column="2" />
</Grid>
</Grid>
@@ -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
@@ -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
@@ -8,29 +8,10 @@
<StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
<local:MyCard Title="关于" Margin="0,0,0,15">
<StackPanel Margin="20,40,18,18">
<TextBlock TextWrapping="Wrap" Text="多人联机服务由速聚授权提供,PCL 仅为速聚提供多人联机服务入口,使用中遇到的任何问题由速聚负责处理。你在使用多人联机服务过程中所遇到的任何问题与纠纷(包括其付费业务)均与 PCL 无关,应与速聚协商解决。"
Margin="0,0,0,3" />
<TextBlock TextWrapping="Wrap" Text="PCL 作者并不会从速聚的付费业务中获得任何分成、奖金等报酬,请不要瞎说。"
Margin="0,0,0,6" />
<local:MyListItem Title="速聚官网" Info="打开速聚的官方网站"
Type="Clickable" EventType="打开网页" EventData="https://www.the.bb/zh-CN.html"
Logo="pack://application:,,,/images/Blocks/Grass.png" />
<local:MyListItem Title="授权协议书" Info="查看速聚与 PCL 间的授权协议书"
Type="Clickable" EventType="打开网页" EventData="https://shimo.im/docs/0l3NVXYzeXhb903R"
Logo="pack://application:,,,/images/Blocks/Grass.png" />
<local:MyListItem Title="用户协议与隐私政策" Info="查看速聚的用户协议与隐私政策文档"
Type="Clickable" EventType="打开网页" EventData="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkxMTMyODk3Mg==&amp;action=getalbum&amp;album_id=2585385685407514625&amp;scene=173&amp;from_msgid=2247483720&amp;from_itemidx=1&amp;count=3&amp;nolastread=1#wechat_redirect"
Logo="pack://application:,,,/images/Blocks/Grass.png" />
</StackPanel>
</local:MyCard>
<local:MyCard Title="发送反馈" Margin="0,0,0,15">
<StackPanel Margin="20,40,18,18">
<local:MyListItem Title="联机反馈与交流" Info="加入联机模块官方 QQ 群反馈联机异常,或询问联机功能的使用方式"
Type="Clickable" Logo="pack://application:,,,/images/Blocks/RedstoneBlock.png"
EventType="打开网页" EventData="https://shimo.im/docs/KrkEVXz1K0frowAJ#anchor-7qQG" />
<local:MyListItem Title="违法违规举报" Info="投诉、举报联机使用者的各类违法违规行为"
Type="Clickable" EventType="打开网页" EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW#anchor-7x6P"
Logo="pack://application:,,,/images/Blocks/RedstoneBlock.png" />
</StackPanel>
</local:MyCard>
</StackPanel>
@@ -83,7 +83,7 @@
<local:ValidateRegex Regex="^[^\u4e00-\u9fa5]{6,}$" />
</local:MyTextBox.ValidateRules>
</local:MyTextBox>
<local:MyButton Grid.Column="4" Grid.Row="4" Margin="0,0,15,0" Text="获取索引码" Padding="13,8" EventType="打开网页" EventData="https://shimo.im/docs/KrkEVXz1K0frowAJ" />
<local:MyButton Grid.Column="4" Grid.Row="4" Margin="0,0,15,0" Text="获取索引码" Padding="13,8" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://shimo.im/docs/KrkEVXz1K0frowAJ" />
<local:MyButton x:Name="BtnCertDone" Grid.Column="5" Grid.Row="4" Text="确定" ColorType="Highlight" Padding="13,8" IsEnabled="False" />
</Grid>
</local:MyCard>
@@ -229,7 +229,6 @@
</Grid>
</Grid>
<Grid x:Name="PanAlways" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="15" Opacity="0.5">
<local:MyTextButton Text="联机服务由 速聚 授权提供" EventType="打开网页" EventData="https://www.the.bb/zh-CN.html" />
</Grid>
</Grid>
</local:MyPageRight>
@@ -44,7 +44,7 @@
<local:MyLoading Text="正在加载联机模块" Margin="20,20,20,17" x:Name="Load" ShowProgress="True" HorizontalAlignment="Center" VerticalAlignment="Center" />
</local:MyCard>
<Grid x:Name="PanAlways" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="15" Opacity="0.5">
<local:MyTextButton Text="联机服务由 速聚 授权提供" EventType="打开网页" EventData="https://www.the.bb/zh-CN.html" />
<local:MyTextButton Text="联机服务由 速聚 授权提供" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.the.bb/zh-CN.html" />
</Grid>
</Grid>
</local:MyPageRight>
@@ -121,26 +121,7 @@ Public Class PageLinkIoi
''' 获取当前的玩家名。
''' </summary>
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 '并非由玩家自定义,而是自动生成的玩家名
''' <summary>
@@ -29,8 +29,10 @@
<EllipseGeometry Center="17 17" RadiusX="17" RadiusY="17" />
</Image.Clip>
</Image>
<local:MyButton Text="赞助 PCL !" Grid.Column="2" Grid.Row="0" Height="35" EventType="打开网页" EventData="https://afdian.com/a/LTCat" ColorType="Highlight" />
<local:MyButton Text="查看源代码" Grid.Column="2" Grid.Row="1" Height="35" EventType="打开网页" EventData="https://github.com/Hex-Dragon/PCL2" />
<local:MyButton Text="赞助 PCL !" Grid.Column="2" Grid.Row="0" Height="35" ColorType="Highlight"
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://afdian.com/a/LTCat" />
<local:MyButton Text="查看源代码" Grid.Column="2" Grid.Row="1" Height="35"
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/Hex-Dragon/PCL2" />
</Grid>
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="特别鸣谢">
@@ -51,11 +53,11 @@
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<local:MyListItem Title="bangbang93" Margin="-5,0,15,0" IsHitTestVisible="False" Info="提供 BMCLAPI 镜像源和 Forge 安装工具,详见 https://bmclapi.bangbang93.com" Grid.Row="0" Grid.Column="1" />
<local:MyButton Text="赞助镜像源" Grid.Row="0" Grid.Column="2" Height="35" EventType="打开网页" EventData="https://afdian.com/a/bangbang93" />
<local:MyButton Text="赞助镜像源" Grid.Row="0" Grid.Column="2" Height="35" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://afdian.com/a/bangbang93" />
<local:MyListItem Title="MC 百科" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 Mod 名称的中文翻译和更多相关信息!" Grid.Row="1" Grid.Column="1" />
<local:MyButton Text="打开百科" Grid.Row="1" Grid.Column="2" Height="35" EventType="打开网页" EventData="https://www.mcmod.cn" />
<local:MyButton Text="打开百科" Grid.Row="1" Grid.Column="2" Height="35" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.mcmod.cn" />
<local:MyListItem Title="z0z0r4" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 MCIM 社区资源镜像源和帮助库图床!" Grid.Row="2" Grid.Column="1" />
<local:MyButton Text="MCIM 主页" Grid.Row="2" Grid.Column="2" Height="35" EventType="打开网页" EventData="https://github.com/mcmod-info-mirror" />
<local:MyButton Text="MCIM 主页" Grid.Row="2" Grid.Column="2" Height="35" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/mcmod-info-mirror" />
<local:MyListItem Title="00ll00" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="提供了 Java Launch Wrapper 和一些重要服务支持!" Grid.Row="3" Grid.Column="1" />
<local:MyListItem Title="Patrick" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="设计并制作了 PCL 图标,让我从做图标的水深火热中得到了解脱……" Grid.Row="4" Grid.Column="1" />
<local:MyListItem Title="Hao_Tian" Margin="-5,0,0,0" IsHitTestVisible="False" Grid.ColumnSpan="2" Info="在内测中找出了一大堆没人想得到的诡异 Bug,有非同寻常的 Bug 体质" Grid.Row="5" Grid.Column="1" />
@@ -105,288 +107,217 @@
</local:MyCard>
<local:MyCard Margin="0,0,0,15" Title="赞助者">
<StackPanel Margin="25,40,10,20">
<TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 8 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
<WrapPanel Margin="0,0,0,10"> <TextBlock Width="120" Margin="0,1.5" Text="粒子鹰" />
<TextBlock Width="120" Margin="0,1.5" Text="暮色黄昏" />
<TextBlock Width="120" Margin="0,1.5" Text="未殃" />
<TextBlock Width="120" Margin="0,1.5" Text="咸鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="Claud_9527" />
<TextBlock Width="120" Margin="0,1.5" Text="Qqsnd" />
<TextBlock Width="120" Margin="0,1.5" Text="☆Kiana☆" />
<TextBlock Width="120" Margin="0,1.5" Text="晓枫-橘味C" />
<TextBlock Width="120" Margin="0,1.5" Text="Ferderica" />
<TextBlock Width="120" Margin="0,1.5" Text="过路人" />
<TextBlock Width="120" Margin="0,1.5" Text="寒溪" />
<TextBlock Width="120" Margin="0,1.5" Text="小咪vv" />
<TextBlock Width="120" Margin="0,1.5" Text="容小狸" />
<TextBlock Width="120" Margin="0,1.5" Text="南宫流溪" />
<TextBlock Width="120" Margin="0,1.5" Text="懒包子" />
<TextBlock Width="120" Margin="0,1.5" Text="王家有政" />
<TextBlock Width="120" Margin="0,1.5" Text="??????" />
<TextBlock Width="120" Margin="0,1.5" Text="念念" />
<TextBlock Width="120" Margin="0,1.5" Text="启233" />
<TextBlock Width="120" Margin="0,1.5" Text="爱小黎" />
<TextBlock Width="120" Margin="0,1.5" Text="北笙T-T" />
<TextBlock Width="120" Margin="0,1.5" Text="listpmater" />
<TextBlock Width="120" Margin="0,1.5" Text="朝朝超级の好运" />
<TextBlock Width="120" Margin="0,1.5" Text="低调" />
<TextBlock Width="120" Margin="0,1.5" Text="老公" />
<TextBlock Width="120" Margin="0,1.5" Text="雍仕" />
<TextBlock Width="120" Margin="0,1.5" Text="AAboss" />
<TextBlock Width="120" Margin="0,1.5" Text="闲来无事" />
<TextBlock Width="120" Margin="0,1.5" Text="omgddcsl" />
<TextBlock Width="120" Margin="0,1.5" Text="轻舟" />
<TextBlock Width="120" Margin="0,1.5" Text="浮生Yui" />
<TextBlock Width="120" Margin="0,1.5" Text="YangFK" />
<TextBlock Width="120" Margin="0,1.5" Text="一曲勺" />
<TextBlock Width="120" Margin="0,1.5" Text="时白Herhilo" />
<TextBlock Width="120" Margin="0,1.5" Text="寒冬落雨" />
<TextBlock Width="120" Margin="0,1.5" Text="柯基0v0" />
<TextBlock Width="120" Margin="0,1.5" Text="月兔" />
<TextBlock Width="120" Margin="0,1.5" Text="qkowo" />
<TextBlock Width="120" Margin="0,1.5" Text="沐白" />
<TextBlock Width="120" Margin="0,1.5" Text="每雨天" />
<TextBlock Width="120" Margin="0,1.5" Text="AiNo" />
<TextBlock Width="120" Margin="0,1.5" Text="木叶飞舞之处" />
<TextBlock Width="120" Margin="0,1.5" Text="wilbert_laogao" />
<TextBlock Width="120" Margin="0,1.5" Text="悠芸" />
<TextBlock Width="120" Margin="0,1.5" Text="黑白盗贼" />
<TextBlock Width="120" Margin="0,1.5" Text="PotCatawa" />
<TextBlock Width="120" Margin="0,1.5" Text="小王" />
<TextBlock Width="120" Margin="0,1.5" Text="花还没开" />
<TextBlock Width="240" Margin="0,1.5" Text="PixelFrontier像素边界" />
<TextBlock Width="120" Margin="0,1.5" Text="坊之岬" />
<TextBlock Width="120" Margin="0,1.5" Text="HuTu" />
<TextBlock Width="120" Margin="0,1.5" Text="爱言叶ray" />
<TextBlock Width="120" Margin="0,1.5" Text="lenrin" />
<TextBlock Width="120" Margin="0,1.5" Text="." />
<TextBlock Width="120" Margin="0,1.5" Text="这是一头灯笼花" />
<TextBlock Width="120" Margin="0,1.5" Text="肖然星辰" />
<TextBlock Width="120" Margin="0,1.5" Text="QMX" />
<TextBlock Width="120" Margin="0,1.5" Text="山外诗" />
<TextBlock Width="120" Margin="0,1.5" Text="刘" />
<TextBlock Width="120" Margin="0,1.5" Text="萧风溪水" />
<TextBlock Width="120" Margin="0,1.5" Text="风落" />
<TextBlock Width="120" Margin="0,1.5" Text="星星绒绒" />
<TextBlock Width="120" Margin="0,1.5" Text="Ciallo~(∠?ω" />
<TextBlock Width="120" Margin="0,1.5" Text="九十九" />
<TextBlock Width="120" Margin="0,1.5" Text="Guuzen" />
<TextBlock Width="120" Margin="0,1.5" Text="极光" />
<TextBlock Width="120" Margin="0,1.5" Text="9331" />
<TextBlock Width="120" Margin="0,1.5" Text="钱程" />
<TextBlock Width="120" Margin="0,1.5" Text="杏坂和人" />
<TextBlock Width="120" Margin="0,1.5" Text="jinlijsbjaj" />
<TextBlock Width="120" Margin="0,1.5" Text="海豹" />
<TextBlock Width="120" Margin="0,1.5" Text="洛玉衡kale" />
<TextBlock Width="120" Margin="0,1.5" Text="柠乔" />
<TextBlock Width="120" Margin="0,1.5" Text="N0NiL" />
<TextBlock Width="120" Margin="0,1.5" Text="阿卡零" />
<TextBlock Width="120" Margin="0,1.5" Text="ADAA" />
<TextBlock Width="120" Margin="0,1.5" Text="岚瑬" />
<TextBlock Width="120" Margin="0,1.5" Text="爱料理的猫" />
<TextBlock Width="120" Margin="0,1.5" Text="01B8" />
<TextBlock Width="120" Margin="0,1.5" Text="MCDJ喜羊羊" />
<TextBlock Width="120" Margin="0,1.5" Text="hwch55" />
<TextBlock Width="120" Margin="0,1.5" Text="棉花糖十五" />
<TextBlock Width="120" Margin="0,1.5" Text="鱼头" />
<TextBlock Width="120" Margin="0,1.5" Text="拉普兰德天下第一" />
<TextBlock Width="120" Margin="0,1.5" Text="KGIKUY" />
<TextBlock Width="120" Margin="0,1.5" Text="初洛" />
<TextBlock Width="120" Margin="0,1.5" Text="z .e.r.o" />
<TextBlock Width="120" Margin="0,1.5" Text="独孤真菜" />
<TextBlock Width="120" Margin="0,1.5" Text="阿囊" />
<TextBlock Width="120" Margin="0,1.5" Text="rrrwcsza" />
<TextBlock Width="120" Margin="0,1.5" Text="守卫军的杂鱼兵" />
<TextBlock Width="120" Margin="0,1.5" Text="念安" />
<TextBlock Width="120" Margin="0,1.5" Text="叶" />
<TextBlock Width="120" Margin="0,1.5" Text="rreorr" />
<TextBlock Width="120" Margin="0,1.5" Text="星辰大海" />
<TextBlock Width="120" Margin="0,1.5" Text="随便" />
<TextBlock Width="120" Margin="0,1.5" Text="烤着吃的鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="大概是" />
<TextBlock Width="120" Margin="0,1.5" Text="闹山麻雀" />
<TextBlock Width="240" Margin="0,1.5" Text="我是(⊙o⊙)啥?笔" />
<TextBlock Width="120" Margin="0,1.5" Text="北纬44" />
<TextBlock Width="120" Margin="0,1.5" Text="呼呼呼" />
<TextBlock Width="120" Margin="0,1.5" Text="嘎嘎不咕咕" />
<TextBlock Width="120" Margin="0,1.5" Text="kronos" />
<TextBlock Width="120" Margin="0,1.5" Text="有个好梦,同志" />
<TextBlock Width="120" Margin="0,1.5" Text="Amojun" />
<TextBlock Width="120" Margin="0,1.5" Text="bat-744" />
<TextBlock Width="120" Margin="0,1.5" Text="那谁" />
<TextBlock Width="120" Margin="0,1.5" Text="AYOSO" />
<TextBlock Width="120" Margin="0,1.5" Text="抽抽" />
<TextBlock Width="120" Margin="0,1.5" Text="柚子皮皮皮" />
<TextBlock Width="120" Margin="0,1.5" Text="白玉京" />
<TextBlock Width="120" Margin="0,1.5" Text="ALPSL" />
<TextBlock Width="120" Margin="0,1.5" Text="我爱喝兽奶" />
<TextBlock Width="120" Margin="0,1.5" Text="wwq557" />
<TextBlock Width="120" Margin="0,1.5" Text="爱莉希雅" />
<TextBlock Width="120" Margin="0,1.5" Text="上善若水" />
<TextBlock HorizontalAlignment="Left" Text="以下是 2025 年 9 月的高级赞助者们!感谢各位对 PCL 和伟大的咕咕咕事业的支持!" Margin="0,0,25,5.5" TextTrimming="None" TextWrapping="WrapWithOverflow" />
<WrapPanel Margin="0,0,0,10"> <TextBlock Width="120" Margin="0,1.5" Text="lecoe" />
<TextBlock Width="120" Margin="0,1.5" Text="QIUQI" />
<TextBlock Width="120" Margin="0,1.5" Text="Aquadtr" />
<TextBlock Width="120" Margin="0,1.5" Text="stb" />
<TextBlock Width="120" Margin="0,1.5" Text="mco" />
<TextBlock Width="120" Margin="0,1.5" Text="楠" />
<TextBlock Width="120" Margin="0,1.5" Text="砂糖蜂蜜锡红茶" />
<TextBlock Width="120" Margin="0,1.5" Text="小宸老弟" />
<TextBlock Width="120" Margin="0,1.5" Text="Le Play" />
<TextBlock Width="120" Margin="0,1.5" Text="烨神" />
<TextBlock Width="240" Margin="0,1.5" Text="Kamazi_Yuka5201" />
<TextBlock Width="120" Margin="0,1.5" Text="滚动的拉布拉多" />
<TextBlock Width="120" Margin="0,1.5" Text="王牟" />
<TextBlock Width="120" Margin="0,1.5" Text="Lazarus" />
<TextBlock Width="120" Margin="0,1.5" Text="幻觉" />
<TextBlock Width="120" Margin="0,1.5" Text="凌天" />
<TextBlock Width="120" Margin="0,1.5" Text="lIIIllIIllIIl" />
<TextBlock Width="120" Margin="0,1.5" Text="Zsol" />
<TextBlock Width="120" Margin="0,1.5" Text="榴莲" />
<TextBlock Width="120" Margin="0,1.5" Text="Night Voyager" />
<TextBlock Width="120" Margin="0,1.5" Text="JOHNJIANG" />
<TextBlock Width="120" Margin="0,1.5" Text="柒月" />
<TextBlock Width="120" Margin="0,1.5" Text="不温柔先森" />
<TextBlock Width="120" Margin="0,1.5" Text="Freewind" />
<TextBlock Width="120" Margin="0,1.5" Text="纯萧子" />
<TextBlock Width="120" Margin="0,1.5" Text="扇" />
<TextBlock Width="120" Margin="0,1.5" Text="Amturester" />
<TextBlock Width="120" Margin="0,1.5" Text="maigm" />
<TextBlock Width="120" Margin="0,1.5" Text="JO23" />
<TextBlock Width="120" Margin="0,1.5" Text="JCNB" />
<TextBlock Width="120" Margin="0,1.5" Text="星尘" />
<TextBlock Width="120" Margin="0,1.5" Text="姜桐桐233" />
<TextBlock Width="120" Margin="0,1.5" Text="AkaneRyoba" />
<TextBlock Width="120" Margin="0,1.5" Text="南山必胜客" />
<TextBlock Width="120" Margin="0,1.5" Text="57" />
<TextBlock Width="120" Margin="0,1.5" Text="咸菜萝卜煲" />
<TextBlock Width="120" Margin="0,1.5" Text="shawnlong" />
<TextBlock Width="120" Margin="0,1.5" Text="DDNGSZX1" />
<TextBlock Width="120" Margin="0,1.5" Text="KaguraZaka" />
<TextBlock Width="120" Margin="0,1.5" Text="谶纛" />
<TextBlock Width="120" Margin="0,1.5" Text="666" />
<TextBlock Width="120" Margin="0,1.5" Text="betwangzai" />
<TextBlock Width="120" Margin="0,1.5" Text="卑微小林" />
<TextBlock Width="120" Margin="0,1.5" Text="fjvg" />
<TextBlock Width="120" Margin="0,1.5" Text="TH-x" />
<TextBlock Width="120" Margin="0,1.5" Text="Q" />
<TextBlock Width="120" Margin="0,1.5" Text="清鸢" />
<TextBlock Width="120" Margin="0,1.5" Text="P·咕·D·咕咕·F" />
<TextBlock Width="120" Margin="0,1.5" Text="顾木" />
<TextBlock Width="120" Margin="0,1.5" Text="LAZY" />
<TextBlock Width="120" Margin="0,1.5" Text="沙发上的沙发" />
<TextBlock Width="120" Margin="0,1.5" Text="有熊子来" />
<TextBlock Width="240" Margin="0,1.5" Text="月下誓约,予爱以心" />
<TextBlock Width="120" Margin="0,1.5" Text="超级白给马" />
<TextBlock Width="120" Margin="0,1.5" Text="fwlqpalzmd" />
<TextBlock Width="120" Margin="0,1.5" Text="安执妄dying" />
<TextBlock Width="120" Margin="0,1.5" Text="黄开心" />
<TextBlock Width="120" Margin="0,1.5" Text="于是" />
<TextBlock Width="120" Margin="0,1.5" Text="荆槐序" />
<TextBlock Width="120" Margin="0,1.5" Text="三千游魂" />
<TextBlock Width="120" Margin="0,1.5" Text="^ ^" />
<TextBlock Width="120" Margin="0,1.5" Text="zz" />
<TextBlock Width="120" Margin="0,1.5" Text="爱炫鱼的猫" />
<TextBlock Width="120" Margin="0,1.5" Text="玄月" />
<TextBlock Width="120" Margin="0,1.5" Text="BRfake" />
<TextBlock Width="120" Margin="0,1.5" Text="Lucien_Liu" />
<TextBlock Width="120" Margin="0,1.5" Text="煎bingo子" />
<TextBlock Width="120" Margin="0,1.5" Text="对方正在输入..." />
<TextBlock Width="120" Margin="0,1.5" Text="hakureireimu" />
<TextBlock Width="120" Margin="0,1.5" Text="wwxa2019" />
<TextBlock Width="120" Margin="0,1.5" Text="TAIGA" />
<TextBlock Width="120" Margin="0,1.5" Text="墨玉" />
<TextBlock Width="120" Margin="0,1.5" Text="Jane" />
<TextBlock Width="120" Margin="0,1.5" Text="雪下丨残影" />
<TextBlock Width="120" Margin="0,1.5" Text="未命名3742" />
<TextBlock Width="120" Margin="0,1.5" Text="烧冻鸡翅" />
<TextBlock Width="120" Margin="0,1.5" Text="嘟嘟可" />
<TextBlock Width="120" Margin="0,1.5" Text="利姆露" />
<TextBlock Width="120" Margin="0,1.5" Text="ATH9" />
<TextBlock Width="120" Margin="0,1.5" Text="教主" />
<TextBlock Width="120" Margin="0,1.5" Text="落雪有声" />
<TextBlock Width="120" Margin="0,1.5" Text="苏子霄" />
<TextBlock Width="120" Margin="0,1.5" Text="一握砂" />
<TextBlock Width="120" Margin="0,1.5" Text="马春明" />
<TextBlock Width="120" Margin="0,1.5" Text="远力高" />
<TextBlock Width="120" Margin="0,1.5" Text="玉米片" />
<TextBlock Width="120" Margin="0,1.5" Text="sun次方" />
<TextBlock Width="120" Margin="0,1.5" Text="憨憨橙子" />
<TextBlock Width="120" Margin="0,1.5" Text="染年" />
<TextBlock Width="120" Margin="0,1.5" Text="准江月" />
<TextBlock Width="120" Margin="0,1.5" Text="蓝叶" />
<TextBlock Width="120" Margin="0,1.5" Text="ELUCIDATE" />
<TextBlock Width="120" Margin="0,1.5" Text="兔饼干哈哈" />
<TextBlock Width="120" Margin="0,1.5" Text="Styx誓约" />
<TextBlock Width="120" Margin="0,1.5" Text="V" />
<TextBlock Width="120" Margin="0,1.5" Text="月芸柔" />
<TextBlock Width="120" Margin="0,1.5" Text="灯火鬼魂" />
<TextBlock Width="120" Margin="0,1.5" Text="A" />
<TextBlock Width="120" Margin="0,1.5" Text="项刀关志" />
<TextBlock Width="120" Margin="0,1.5" Text="剑鱼776" />
<TextBlock Width="120" Margin="0,1.5" Text="叶明心" />
<TextBlock Width="120" Margin="0,1.5" Text="Ashlxy" />
<TextBlock Width="120" Margin="0,1.5" Text="小时" />
<TextBlock Width="120" Margin="0,1.5" Text="fisher426" />
<TextBlock Width="120" Margin="0,1.5" Text="老罗" />
<TextBlock Width="120" Margin="0,1.5" Text="百忧解" />
<TextBlock Width="120" Margin="0,1.5" Text="杨三海" />
<TextBlock Width="120" Margin="0,1.5" Text="锂化氩" />
<TextBlock Width="120" Margin="0,1.5" Text="饺子川" />
<TextBlock Width="120" Margin="0,1.5" Text="流年遥想" />
<TextBlock Width="120" Margin="0,1.5" Text="基围虾" />
<TextBlock Width="120" Margin="0,1.5" Text="山有木兮325" />
<TextBlock Width="120" Margin="0,1.5" Text="37号村民" />
<TextBlock Width="120" Margin="0,1.5" Text="白承宣" />
<TextBlock Width="240" Margin="0,1.5" Text="某蓝毛借钱不还的贝斯手" />
<TextBlock Width="120" Margin="0,1.5" Text="白狼" />
<TextBlock Width="120" Margin="0,1.5" Text="工蜂" />
<TextBlock Width="120" Margin="0,1.5" Text="封不觉" />
<TextBlock Width="120" Margin="0,1.5" Text="南樵鱼子" />
<TextBlock Width="120" Margin="0,1.5" Text="寂-御神幻狐" />
<TextBlock Width="120" Margin="0,1.5" Text="好" />
<TextBlock Width="120" Margin="0,1.5" Text="NeonSoda" />
<TextBlock Width="120" Margin="0,1.5" Text="UNICORN" />
<TextBlock Width="120" Margin="0,1.5" Text="红石beaker" />
<TextBlock Width="120" Margin="0,1.5" Text="EliasLSK" />
<TextBlock Width="120" Margin="0,1.5" Text="思考人生" />
<TextBlock Width="120" Margin="0,1.5" Text="L" />
<TextBlock Width="120" Margin="0,1.5" Text="起床了" />
<TextBlock Width="120" Margin="0,1.5" Text="服群" />
<TextBlock Width="120" Margin="0,1.5" Text="云符爱睡觉" />
<TextBlock Width="120" Margin="0,1.5" Text="幽幽秋" />
<TextBlock Width="120" Margin="0,1.5" Text="FAMS" />
<TextBlock Width="120" Margin="0,1.5" Text="会变身的栖仔" />
<TextBlock Width="120" Margin="0,1.5" Text="baka王" />
<TextBlock Width="120" Margin="0,1.5" Text="深海带鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="四戒梨子" />
<TextBlock Width="120" Margin="0,1.5" Text="无限" />
<TextBlock Width="120" Margin="0,1.5" Text="Xc_AcE" />
<TextBlock Width="120" Margin="0,1.5" Text="@6#" />
<TextBlock Width="120" Margin="0,1.5" Text="molFish" />
<TextBlock Width="120" Margin="0,1.5" Text="雪见" />
<TextBlock Width="120" Margin="0,1.5" Text="AAALLLAAANNN" />
<TextBlock Width="120" Margin="0,1.5" Text="华氏451" />
<TextBlock Width="120" Margin="0,1.5" Text="纸不好" />
<TextBlock Width="120" Margin="0,1.5" Text="博衍" />
<TextBlock Width="120" Margin="0,1.5" Text="志摩凛" />
<TextBlock Width="120" Margin="0,1.5" Text="八云蓝LIN" />
<TextBlock Width="120" Margin="0,1.5" Text="LittleBlue" />
<TextBlock Width="120" Margin="0,1.5" Text="老梦" />
<TextBlock Width="120" Margin="0,1.5" Text="动漫男主" />
<TextBlock Width="120" Margin="0,1.5" Text="Red_橙子" />
<TextBlock Width="120" Margin="0,1.5" Text="Junmucheng" />
<TextBlock Width="120" Margin="0,1.5" Text="无印" />
<TextBlock Width="120" Margin="0,1.5" Text="窗前露" />
<TextBlock Width="120" Margin="0,1.5" Text="1111111" />
<TextBlock Width="120" Margin="0,1.5" Text="什雨" />
<TextBlock Width="120" Margin="0,1.5" Text="七日 SEVENDAYS" />
<TextBlock Width="120" Margin="0,1.5" Text="Gǔdù" />
<TextBlock Width="120" Margin="0,1.5" Text="白吃白喝" />
<TextBlock Width="120" Margin="0,1.5" Text="路明非" />
<TextBlock Width="120" Margin="0,1.5" Text="子不语" />
<TextBlock Width="120" Margin="0,1.5" Text="王璟" />
<TextBlock Width="120" Margin="0,1.5" Text="阿星" />
<TextBlock Width="240" Margin="0,1.5" Text="小狗很担心你有没有好好喝水" />
<TextBlock Width="120" Margin="0,1.5" Text="hjhmeibao" />
<TextBlock Width="120" Margin="0,1.5" Text="网络白字话事人" />
<TextBlock Width="120" Margin="0,1.5" Text="想要点好运" />
<TextBlock Width="120" Margin="0,1.5" Text="Timmy1950" />
<TextBlock Width="120" Margin="0,1.5" Text="栩" />
<TextBlock Width="120" Margin="0,1.5" Text="玛卡巴卡" />
<TextBlock Width="120" Margin="0,1.5" Text="楞可" />
<TextBlock Width="120" Margin="0,1.5" Text="顶级牛板筋收藏家" />
<TextBlock Width="120" Margin="0,1.5" Text="HansOffice" />
<TextBlock Width="120" Margin="0,1.5" Text="466某某某" />
<TextBlock Width="120" Margin="0,1.5" Text="zztzzy" />
<TextBlock Width="120" Margin="0,1.5" Text="SHiao_Yui" />
<TextBlock Width="120" Margin="0,1.5" Text="一只花生" />
<TextBlock Width="120" Margin="0,1.5" Text="黑凤梨熊?" />
<TextBlock Width="120" Margin="0,1.5" Text="sdad" />
<TextBlock Width="120" Margin="0,1.5" Text="BLONG" />
<TextBlock Width="120" Margin="0,1.5" Text="787878" />
<TextBlock Width="120" Margin="0,1.5" Text="myry668" />
<TextBlock Width="120" Margin="0,1.5" Text="f三文鱼f" />
<TextBlock Width="120" Margin="0,1.5" Text="apqow" />
<TextBlock Width="120" Margin="0,1.5" Text="懒梦棉花糖" />
<TextBlock Width="120" Margin="0,1.5" Text="HaiMing" />
<TextBlock Width="120" Margin="0,1.5" Text="Evernight" />
<TextBlock Width="120" Margin="0,1.5" Text="CieloNeet" />
<TextBlock Width="120" Margin="0,1.5" Text="不青盆" />
<TextBlock Width="120" Margin="0,1.5" Text="Purelimiter" />
<TextBlock Width="120" Margin="0,1.5" Text="丨白丨" />
<TextBlock Width="120" Margin="0,1.5" Text="喵" />
<TextBlock Width="120" Margin="0,1.5" Text="雨过山秋" />
<TextBlock Width="120" Margin="0,1.5" Text="急了" />
<TextBlock Width="120" Margin="0,1.5" Text="歌斐木" />
<TextBlock Width="120" Margin="0,1.5" Text="公子天邪" />
<TextBlock Width="120" Margin="0,1.5" Text="爱发癫" />
<TextBlock Width="120" Margin="0,1.5" Text="洪某某" />
<TextBlock Width="120" Margin="0,1.5" Text="漫卡洛樱" />
<TextBlock Width="120" Margin="0,1.5" Text="云与海" />
<TextBlock Width="120" Margin="0,1.5" Text="子曰" />
<TextBlock Width="120" Margin="0,1.5" Text="CyrilZ" />
<TextBlock Width="120" Margin="0,1.5" Text="笑颜如花兮" />
<TextBlock Width="120" Margin="0,1.5" Text="咸鱼超人FF酱!" />
<TextBlock Width="120" Margin="0,1.5" Text="达达利鸭" />
<TextBlock Width="120" Margin="0,1.5" Text="TFofN" />
<TextBlock Width="120" Margin="0,1.5" Text="Kumo" />
<TextBlock Width="120" Margin="0,1.5" Text="江俞白" />
<TextBlock Width="120" Margin="0,1.5" Text="聆风忘年" />
<TextBlock Width="120" Margin="0,1.5" Text="五符临门" />
<TextBlock Width="120" Margin="0,1.5" Text="亭书浅墨" />
<TextBlock Width="120" Margin="0,1.5" Text="翀归滉" />
<TextBlock Width="120" Margin="0,1.5" Text="Anmuer" />
<TextBlock Width="120" Margin="0,1.5" Text="青天揽明月" />
<TextBlock Width="120" Margin="0,1.5" Text="鲫鱼崽" />
<TextBlock Width="120" Margin="0,1.5" Text="PPTNPC" />
<TextBlock Width="120" Margin="0,1.5" Text="vIccvI" />
<TextBlock Width="120" Margin="0,1.5" Text="GOOD" />
<TextBlock Width="120" Margin="0,1.5" Text="归零之诗" />
<TextBlock Width="120" Margin="0,1.5" Text="ppp" />
<TextBlock Width="120" Margin="0,1.5" Text="Ethanhmm1234" />
<TextBlock Width="120" Margin="0,1.5" Text="库里斯库拉" />
<TextBlock Width="240" Margin="0,1.5" Text="被伪安全软件坑害的普通人" />
<TextBlock Width="120" Margin="0,1.5" Text="无元亓" />
<TextBlock Width="120" Margin="0,1.5" Text="Raven" />
<TextBlock Width="120" Margin="0,1.5" Text="看看你的jjp" />
<TextBlock Width="120" Margin="0,1.5" Text="日月皆如水" />
<TextBlock Width="120" Margin="0,1.5" Text="gzwmmm" />
<TextBlock Width="120" Margin="0,1.5" Text="早上鸥" />
<TextBlock Width="120" Margin="0,1.5" Text="CJT" />
<TextBlock Width="120" Margin="0,1.5" Text="幽永森" />
<TextBlock Width="120" Margin="0,1.5" Text="东海帝皇" />
<TextBlock Width="120" Margin="0,1.5" Text="三岁" />
<TextBlock Width="120" Margin="0,1.5" Text="shui12dkhigl" />
<TextBlock Width="120" Margin="0,1.5" Text="豪猪" />
<TextBlock Width="120" Margin="0,1.5" Text="再相遇" />
<TextBlock Width="120" Margin="0,1.5" Text="?白樱Hakura" />
<TextBlock Width="120" Margin="0,1.5" Text="IssacPyromaniac" />
<TextBlock Width="120" Margin="0,1.5" Text="纯真丁一郎" />
<TextBlock Width="120" Margin="0,1.5" Text="岩之龙" />
<TextBlock Width="120" Margin="0,1.5" Text="星之金白" />
<TextBlock Width="120" Margin="0,1.5" Text="laocao" />
<TextBlock Width="120" Margin="0,1.5" Text="DLC...是什么" />
<TextBlock Width="120" Margin="0,1.5" Text="我家老米" />
<TextBlock Width="120" Margin="0,1.5" Text="TINY" />
<TextBlock Width="240" Margin="0,1.5" Text="只会coding的农民工" />
<TextBlock Width="120" Margin="0,1.5" Text="明月一行" />
<TextBlock Width="120" Margin="0,1.5" Text="nanako" />
<TextBlock Width="120" Margin="0,1.5" Text="辛霏Aiwx" />
<TextBlock Width="120" Margin="0,1.5" Text="奇妙的白给之旅" />
<TextBlock Width="120" Margin="0,1.5" Text="你咋不上天呢^_^" />
<TextBlock Width="120" Margin="0,1.5" Text="冰糕" />
<TextBlock Width="120" Margin="0,1.5" Text="sadas" />
<TextBlock Width="120" Margin="0,1.5" Text="小叮当搞快点" />
<TextBlock Width="120" Margin="0,1.5" Text="leu" />
<TextBlock Width="240" Margin="0,1.5" Text="休伯利安本来的舰长" />
<TextBlock Width="120" Margin="0,1.5" Text="天诺一字号仓鼠" />
<TextBlock Width="120" Margin="0,1.5" Text="真爱粉只因龙" />
<TextBlock Width="120" Margin="0,1.5" Text="绝望的温度" />
<TextBlock Width="120" Margin="0,1.5" Text="busituteng" />
<TextBlock Width="120" Margin="0,1.5" Text="SiC" />
<TextBlock Width="120" Margin="0,1.5" Text="契特卡拉概念机" />
<TextBlock Width="240" Margin="0,1.5" Text="我还能再在死线挣扎一会" />
<TextBlock Width="120" Margin="0,1.5" Text="02_G1nTonic" />
<TextBlock Width="120" Margin="0,1.5" Text="渊" />
<TextBlock Width="120" Margin="0,1.5" Text="1" />
<TextBlock Width="120" Margin="0,1.5" Text="小楠" />
<TextBlock Width="120" Margin="0,1.5" Text="阿冰" />
<TextBlock Width="120" Margin="0,1.5" Text="EliasG" />
<TextBlock Width="120" Margin="0,1.5" Text="jhx" />
<TextBlock Width="120" Margin="0,1.5" Text="zyccmyk" />
<TextBlock Width="120" Margin="0,1.5" Text="luxin" />
<TextBlock Width="120" Margin="0,1.5" Text="我是我" />
<TextBlock Width="120" Margin="0,1.5" Text="13462738215" />
<TextBlock Width="120" Margin="0,1.5" Text="minecraft java" />
<TextBlock Width="120" Margin="0,1.5" Text="那是小林吖" />
<TextBlock Width="120" Margin="0,1.5" Text="GITATIG" />
<TextBlock Width="120" Margin="0,1.5" Text="Musketeer" />
<TextBlock Width="120" Margin="0,1.5" Text="AuraSpeedJerry" />
<TextBlock Width="120" Margin="0,1.5" Text="luckymore" />
<TextBlock Width="120" Margin="0,1.5" Text="hcrmhj" />
<TextBlock Width="120" Margin="0,1.5" Text="我好焦灼啊" />
<TextBlock Width="120" Margin="0,1.5" Text="小王同学" />
<TextBlock Width="120" Margin="0,1.5" Text="MoDust2131" />
<TextBlock Width="120" Margin="0,1.5" Text="啊超" />
<TextBlock Width="120" Margin="0,1.5" Text="Ander·Les" />
<TextBlock Width="120" Margin="0,1.5" Text="Niko" />
<TextBlock Width="120" Margin="0,1.5" Text="五个麦卷" />
<TextBlock Width="120" Margin="0,1.5" Text="b0Ard" />
<TextBlock Width="120" Margin="0,1.5" Text="龙猫的专属粉丝" />
<TextBlock Width="120" Margin="0,1.5" Text="雾念~" />
<TextBlock Width="120" Margin="0,1.5" Text="烬灵梦" />
<TextBlock Width="120" Margin="0,1.5" Text="蝶落染花香" />
<TextBlock Width="120" Margin="0,1.5" Text="照井黎Terui_Rei" />
<TextBlock Width="120" Margin="0,1.5" Text="???狼??王?" />
<TextBlock Width="120" Margin="0,1.5" Text="辉光离子管" />
<TextBlock Width="120" Margin="0,1.5" Text="联开开" />
<TextBlock Width="120" Margin="0,1.5" Text="XIAOSHUAI" />
<TextBlock Width="120" Margin="0,1.5" Text="KMYLS" />
<TextBlock Width="120" Margin="0,1.5" Text="聽音" />
<TextBlock Width="120" Margin="0,1.5" Text="oPzPo" />
<TextBlock Width="120" Margin="0,1.5" Text="dream" />
<TextBlock Width="120" Margin="0,1.5" Text="123" />
<TextBlock Width="120" Margin="0,1.5" Text="Zik yeung" />
<TextBlock Width="120" Margin="0,1.5" Text="Coco" />
<TextBlock Width="120" Margin="0,1.5" Text="Ricardo" />
<TextBlock Width="120" Margin="0,1.5" Text="2969307002" />
<TextBlock Width="120" Margin="0,1.5" Text="鬼卿" />
<TextBlock Width="120" Margin="0,1.5" Text="wihz" />
<TextBlock Width="120" Margin="0,1.5" Text="九平" />
<TextBlock Width="120" Margin="0,1.5" Text="liu" />
<TextBlock Width="120" Margin="0,1.5" Text="PickStars" />
<TextBlock Width="240" Margin="0,1.5" Text="我真的事仁济啊(恼)" />
<TextBlock Width="120" Margin="0,1.5" Text="李白" />
<TextBlock Width="120" Margin="0,1.5" Text="霜木翔凤" />
<TextBlock Width="120" Margin="0,1.5" Text="岽龙" />
<TextBlock Width="120" Margin="0,1.5" Text="joksqp" />
<TextBlock Width="240" Margin="0,1.5" Text="what are you 说啥嘞?" />
<TextBlock Width="120" Margin="0,1.5" Text="木得爱_没人疼" />
<TextBlock Width="120" Margin="0,1.5" Text="小黑子?" />
<TextBlock Width="240" Margin="0,1.5" Text="删除线Strikethrough" />
<TextBlock Width="120" Margin="0,1.5" Text="REMOTE" />
<TextBlock Width="120" Margin="0,1.5" Text="H" />
<TextBlock Width="120" Margin="0,1.5" Text="Parapha" />
<TextBlock Width="120" Margin="0,1.5" Text="南吕十三" />
<TextBlock Width="120" Margin="0,1.5" Text="米帝" />
<TextBlock Width="120" Margin="0,1.5" Text="zdxff" />
<TextBlock Width="120" Margin="0,1.5" Text="蔚空" />
<TextBlock Width="120" Margin="0,1.5" Text="cleverboy1066" />
<TextBlock Width="120" Margin="0,1.5" Text="烤老鼠" />
<TextBlock Width="120" Margin="0,1.5" Text="TS彦祖" />
<TextBlock Width="120" Margin="0,1.5" Text="狮某人" />
<TextBlock Width="120" Margin="0,1.5" Text="lmst_myh" />
<TextBlock Width="120" Margin="0,1.5" Text="耐·若何" />
<TextBlock Width="120" Margin="0,1.5" Text="qvq" />
<TextBlock Width="120" Margin="0,1.5" Text="刀客塔" />
<TextBlock Width="120" Margin="0,1.5" Text="mika" />
<TextBlock Width="120" Margin="0,1.5" Text="金尘" />
<TextBlock Width="120" Margin="0,1.5" Text="喜之狼与灰太羊" />
<TextBlock Width="120" Margin="0,1.5" Text="天才小宋" />
<TextBlock Width="120" Margin="0,1.5" Text="MdsR" />
<TextBlock Width="120" Margin="0,1.5" Text="诗和雨夜" />
<TextBlock Width="120" Margin="0,1.5" Text="Samueldong" />
<TextBlock Width="120" Margin="0,1.5" Text="BBK" />
<TextBlock Width="120" Margin="0,1.5" Text="雪枫Sople" />
<TextBlock Width="120" Margin="0,1.5" Text="一坨灰" />
<TextBlock Width="120" Margin="0,1.5" Text="RI_CK" />
<TextBlock Width="120" Margin="0,1.5" Text="ximeng22" />
<TextBlock Width="120" Margin="0,1.5" Text="天天122_" />
<TextBlock Width="120" Margin="0,1.5" Text="李小浩&amp;mod" />
<TextBlock Width="120" Margin="0,1.5" Text="Southsheng" />
<TextBlock Width="120" Margin="0,1.5" Text="HurgerLiPy" />
<TextBlock Width="120" Margin="0,1.5" Text="Crishen70400" />
<TextBlock Width="120" Margin="0,1.5" Text="孤独" />
<TextBlock Width="120" Margin="0,1.5" Text="夏末彡微凉" />
<TextBlock Width="120" Margin="0,1.5" Text="山本樱桃不是df" />
<TextBlock Width="120" Margin="0,1.5" Text="陶牧馆长" />
<TextBlock Width="120" Margin="0,1.5" Text="一二三四" />
<TextBlock Width="120" Margin="0,1.5" Text="17382073935" />
<TextBlock Width="120" Margin="0,1.5" Text="不知道" />
<TextBlock Width="120" Margin="0,1.5" Text="重庆你周哥" />
<TextBlock Width="120" Margin="0,1.5" Text="熳ai" />
<TextBlock Width="120" Margin="0,1.5" Text="Rainbow Stars" />
<TextBlock Width="120" Margin="0,1.5" Text="无名岩" />
<TextBlock Width="120" Margin="0,1.5" Text="快乐小子" />
<TextBlock Width="120" Margin="0,1.5" Text="沙西凯" />
<TextBlock Width="120" Margin="0,1.5" Text="一只小孽QAQ" />
<TextBlock Width="120" Margin="0,1.5" Text="五度左右" />
<TextBlock Width="120" Margin="0,1.5" Text="咖喱鱼" />
<TextBlock Width="120" Margin="0,1.5" Text="千叶GG" />
<TextBlock Width="120" Margin="0,1.5" Text="泽木_Zemu" />
</WrapPanel>
<Grid Height="35">
<Grid.ColumnDefinitions>
@@ -395,7 +326,7 @@
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
</Grid.ColumnDefinitions>
<local:MyButton x:Name="BtnDonateOutput" Grid.Column="0" MinWidth="140" Text="生成解锁码" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" Visibility="Collapsed" />
<local:MyButton x:Name="BtnDonateDonate" Grid.Column="0" MinWidth="140" Text="赞助作者" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" EventType="打开网页" EventData="https://afdian.com/a/LTCat" />
<local:MyButton x:Name="BtnDonateDonate" Grid.Column="0" MinWidth="140" Text="赞助作者" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://afdian.com/a/LTCat" />
<local:MyButton x:Name="BtnDonateCopy" Grid.Column="1" MinWidth="140" Text="复制识别码" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
<local:MyButton x:Name="BtnDonateInput" Grid.Column="2" MinWidth="140" Text="输入解锁码" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
</Grid>
@@ -410,8 +341,8 @@
<TextBlock Text="其他信息" TextWrapping="Wrap" Margin="0,10,0,4" FontWeight="Bold" />
<TextBlock Margin="0,0,0,2" LineHeight="17" Text="Copyright © 龙腾猫跃 2016. All Rights Reserved.&#13;计算机软件著作权登记号:2020SR0875133&#13;违法违规行为举报投诉邮箱:hexdragon@vip.qq.com&#13;非 MINECRAFT 官方产品。未经 MOJANG 或 MICROSOFT 批准,也不与 MOJANG 或 MICROSOFT 关联。" TextWrapping="Wrap" />
<StackPanel Orientation="Horizontal" Height="35" HorizontalAlignment="Left" Margin="0,12,0,0">
<local:MyButton Text="用户协议与免责声明" Width="170" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" EventType="打开网页" EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW" />
<local:MyButton Text="开源代码" Width="140" Padding="13,0" EventType="打开网页" EventData="https://github.com/Hex-Dragon/PCL2" />
<local:MyButton Text="用户协议与免责声明" Width="170" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://shimo.im/docs/rGrd8pY8xWkt6ryW" />
<local:MyButton Text="开源代码" Width="140" Padding="13,0" local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/Hex-Dragon/PCL2" />
</StackPanel>
</StackPanel>
</local:MyCard>
@@ -443,49 +374,49 @@
<TextBlock Grid.Row="0" Grid.Column="0" Text="Java Launch Wrapper" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="2" Text="Copyright © 2022 00ll00&#xa;Licensed under the MIT License." TextWrapping="Wrap" />
<local:MyButton Grid.Row="1" Grid.Column="2" MinWidth="140" Text="查看来源网站" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://github.com/00ll00/java_launch_wrapper" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/00ll00/java_launch_wrapper" />
<local:MyButton Grid.Row="1" Grid.Column="3" MinWidth="140" Text="查看许可文档" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://github.com/00ll00/java_launch_wrapper?tab=MIT-1-ov-file#readme" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/00ll00/java_launch_wrapper?tab=MIT-1-ov-file#readme" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Newtonsoft.Json" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" Text="Copyright © 2007 James Newton-King&#xa;Licensed under the MIT License." TextWrapping="Wrap" />
<local:MyButton Grid.Row="3" Grid.Column="2" MinWidth="140" Text="查看来源网站" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://www.newtonsoft.com/json" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.newtonsoft.com/json" />
<local:MyButton Grid.Row="3" Grid.Column="3" MinWidth="140" Text="查看许可文档" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://opensource.org/licenses/MIT" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://opensource.org/licenses/MIT" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="NAudio" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Grid.Row="4" Grid.Column="2" Grid.ColumnSpan="2" Text="Copyright © 2015 Mark Heath (mark.heath@gmail.com)&#xa;Licensed under the MIT License." TextWrapping="Wrap" />
<local:MyButton Grid.Row="5" Grid.Column="2" MinWidth="140" Text="查看来源网站" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://github.com/naudio/NAudio" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/naudio/NAudio" />
<local:MyButton Grid.Row="5" Grid.Column="3" MinWidth="140" Text="查看许可文档" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://github.com/naudio/NAudio/blob/master/license.txt" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/naudio/NAudio/blob/master/license.txt" />
<TextBlock Grid.Row="6" Grid.Column="0" Text="Ookii.Dialogs" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Grid.Row="6" Grid.Column="2" Grid.ColumnSpan="2" Text="Copyright © 2009 Sven Groot (Ookii.org)" TextWrapping="Wrap" />
<local:MyButton Grid.Row="7" Grid.Column="2" MinWidth="140" Text="查看来源网站" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://www.ookii.org/Software/Dialogs/" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.ookii.org/Software/Dialogs/" />
<local:MyButton Grid.Row="7" Grid.Column="3" MinWidth="140" Text="查看许可文档" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://github.com/caioproiete/ookii-dialogs-wpf/blob/master/LICENSE" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/caioproiete/ookii-dialogs-wpf/blob/master/LICENSE" />
<TextBlock Grid.Row="8" Grid.Column="0" Text="Iconmonstr" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Grid.Row="8" Grid.Column="2" Grid.ColumnSpan="2" Text="Copyright © 2019 iconmonstr (Alexander Kahlkopf)" TextWrapping="Wrap" />
<local:MyButton Grid.Row="9" Grid.Column="2" MinWidth="140" Text="查看来源网站" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://iconmonstr.com/" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://iconmonstr.com/" />
<local:MyButton Grid.Row="9" Grid.Column="3" MinWidth="140" Text="查看许可文档" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://iconmonstr.com/license/" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://iconmonstr.com/license/" />
<TextBlock Grid.Row="10" Grid.Column="0" Text="libwebp wrapper for .NET" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Grid.Row="10" Grid.Column="2" Grid.ColumnSpan="2" Text="Copyright © 2012 Imazen&#xa;Licensed under the MIT License." TextWrapping="Wrap" />
<local:MyButton Grid.Row="11" Grid.Column="2" MinWidth="140" Text="查看来源网站" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://github.com/imazen/libwebp-net" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/imazen/libwebp-net" />
<local:MyButton Grid.Row="11" Grid.Column="3" MinWidth="140" Text="查看许可文档" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://github.com/imazen/libwebp-net/blob/master/LICENSE.txt" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://github.com/imazen/libwebp-net/blob/master/LICENSE.txt" />
<TextBlock Grid.Row="12" Grid.Column="0" Text="Iconfont" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Grid.Row="12" Grid.Column="2" Grid.ColumnSpan="2" Text="Copyright © ALIMAMA MUX, powered by alimama THX." TextWrapping="Wrap" />
<local:MyButton Grid.Row="13" Grid.Column="2" MinWidth="140" Text="查看原网站" Padding="13,0" Margin="0,7,20,18" HorizontalAlignment="Left"
EventType="打开网页" EventData="https://www.iconfont.cn/" />
local:CustomEventService.EventType="打开网页" local:CustomEventService.EventData="https://www.iconfont.cn/" />
</Grid>
</local:MyCard>
@@ -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()
@@ -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
@@ -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 = "<StackPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:sys=""clr-namespace:System;assembly=mscorlib"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xmlns:local=""clr-namespace:PCL;assembly=Plain Craft Launcher 2"">" & Content & "</StackPanel>"
Me.Entry = Entry
PanCustom.Children.Clear()
@@ -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
@@ -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
@@ -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
''' <summary>
''' 写入某个未经加密的设置项。
''' 若该设置项经过了加密,则会抛出异常。
''' </summary>
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 @@
''' 获取某个设置项的值。
''' </summary>
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
''' <summary>
''' 获取某个未经加密的设置项的值。
''' 若该设置项经过了加密,则会抛出异常。
''' </summary>
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
@@ -41,9 +41,9 @@
<local:MyComboBoxItem Content="隔离所有版本" ToolTip="不同版本之间的存档、Mod、资源包等均不互通。&#xa;这会导致不同原版版本间的存档不能共用,所以一般不推荐。" />
</local:MyComboBox>
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏窗口标题" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则不进行更改。&#xa;支持以下替换标记:&#xa; · {user}:玩家名字&#xa; · {login}:玩家的登录方式&#xa; · {name}:游戏版本名&#xa; · {date}、{time}:当前的系统时间&#xa; · {version}:游戏对应的原版版本号" HintText="默认" MaxLength="100" />
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则不进行更改。&#xa;你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" HintText="默认" MaxLength="100" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义信息" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchArgumentInfo" Text="PCL" Grid.Column="1" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角">
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchArgumentInfo" Text="PCL" Grid.Column="1" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。&#xa;你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。">
<local:MyTextBox.ValidateRules>
<local:ValidateExcept>
<local:ValidateExcept.Excepts>
@@ -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" />
</StackPanel>
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Tag="LaunchAdvanceJvm" Grid.Column="1" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,除非有确定把握,否则请不要修改。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。" MaxLength="4000"
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Tag="LaunchAdvanceJvm" Grid.Column="1" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,除非有确定把握,否则请不要修改。&#xa;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" MaxLength="4000"
Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="LaunchAdvanceRun" Grid.Column="1" HintText=""
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;可以使用以下替换标记实现相对路径(路径均以 \ 结尾):&#xa; · {path}:PCL 的 exe 文件所在的文件夹&#xa; · {minecraft}:.minecraft 文件夹&#xa; · {verpath}:版本文件夹(.minecraft\versions\版本名\)&#xa; · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹&#xa; · {java}:游戏运行时的 Java 文件夹&#xa;&#xa;除此之外,也支持以下替换标记:&#xa; · {user}:玩家名字&#xa; · {login}:玩家的登录方式&#xa; · {uuid}:玩家的 UUID&#xa; · {name}:游戏版本名&#xa; · {date}、{time}:当前的系统时间&#xa; · {version}:游戏对应的原版版本号&#xa;&#xa;例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="LaunchAdvanceRunWait" Visibility="Collapsed"
Text="等待命令执行完成后再继续启动" Margin="0,8,0,7" />
<StackPanel Margin="0,12,0,4" Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Left">
@@ -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
@@ -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
@@ -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()
@@ -225,7 +225,8 @@
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" Text="下载地址" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextCustomNet" Tag="UiCustomNet" Grid.Column="1" MaxHeight="28">
<local:MyTextBox x:Name="TextCustomNet" Tag="UiCustomNet" Grid.Column="1" MaxHeight="28"
ToolTip="你可以用替换标记动态改变网址,以传入参数或变量。&#xa;在 更多 → 帮助 中搜索 “替换标记” 以了解用法。">
<local:MyTextBox.ValidateRules>
<local:ValidateNullable />
<local:ValidateHttp />
@@ -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
''' <summary>
@@ -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 &
@@ -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
@@ -262,7 +262,7 @@
<local:MyButton Grid.Column="0" x:Name="BtnAdvancedImport" MinWidth="140" Text="读取配置" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
<local:MyButton Grid.Column="1" x:Name="BtnAdvancedExport" MinWidth="140" Text="保存配置" Padding="13,0" Margin="0,0,20,0" />
<local:MyButton Grid.Column="2" MinWidth="140" Text="整合包制作指南" Padding="13,0" Margin="0,0,20,0" x:Name="BtnAdvancedHelp"
EventType="打开帮助" />
local:CustomEventService.EventType="打开帮助" />
</Grid>
</StackPanel>
</local:MyCard>
@@ -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
@@ -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
@@ -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
@@ -34,9 +34,9 @@
ToolTip="与其余关闭隔离的版本共享存档、Mod 等文件。&#xa;若存在多个安装了 Mod 的版本,可能会由于 Mod 冲突而导致崩溃。" ToolTipService.HorizontalOffset="100"/>
</local:MyComboBox>
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏窗口标题" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则跟随全局设置的值。&#xa;支持以下替换标记:&#xa; · {user}:玩家名字&#xa; · {login}:玩家的登录方式&#xa; · {name}:游戏版本名&#xa; · {date}、{time}:当前的系统时间&#xa; · {version}:游戏对应的原版版本号" HintText="跟随全局设置" MaxLength="100" />
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则跟随全局设置的值。&#xa;你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" HintText="跟随全局设置" MaxLength="100" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="自定义信息" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionArgumentInfo" Grid.Column="1" HintText="跟随全局设置" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。&#xa;若留空,则跟随全局设置的值。">
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionArgumentInfo" Grid.Column="1" HintText="跟随全局设置" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。&#xa;若留空,则跟随全局设置的值。&#xa;&#xa;你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。">
<local:MyTextBox.ValidateRules>
<local:ValidateExcept>
<local:ValidateExcept.Excepts>
@@ -209,13 +209,13 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="Java 虚拟机参数" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.Row="0" Grid.ColumnSpan="2" Tag="VersionAdvanceJvm" Grid.Column="1" MaxLength="4000" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,在没有确定把握的情况下请不要尝试修改。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置"
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.Row="0" Grid.ColumnSpan="2" Tag="VersionAdvanceJvm" Grid.Column="1" MaxLength="4000" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,在没有确定把握的情况下请不要尝试修改。&#xa;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置"
Height="100" AcceptsReturn="True" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" VerticalScrollBarVisibility="Auto" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="游戏参数" Margin="0,0,25,0" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。&#xa;例如,输入 --demo 则会以试玩模式启动游戏。&#xa;&#xa;支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。&#xa;也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。&#xa;&#xa;若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="启动前执行命令" Margin="0,0,25,3" />
<local:MyTextBox x:Name="TextAdvanceRun" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionAdvanceRun" Grid.Column="1" HintText="" Margin="0,0,0,3"
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。&#xa;&#xa;在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;可以使用以下替换标记实现相对路径(路径均以 \ 结尾):&#xa; · {path}:PCL 的 exe 文件所在的文件夹&#xa; · {minecraft}:.minecraft 文件夹&#xa; · {verpath}:版本文件夹(.minecraft\versions\版本名\)&#xa; · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹&#xa; · {java}:游戏运行时的 Java 文件夹&#xa;&#xa;除此之外,也支持以下替换标记:&#xa; · {user}:玩家名字&#xa; · {login}:玩家的登录方式&#xa; · {uuid}:玩家的 UUID&#xa; · {name}:游戏版本名&#xa; · {date}、{time}:当前的系统时间&#xa; · {version}:游戏对应的原版版本号&#xa;&#xa;例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。&#xa;&#xa;在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。&#xa;&#xa;你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:&#xa; · &quot;{verpath}test.exe&quot; :运行版本文件夹下的 test.exe 程序&#xa; · &quot;{java}java.exe&quot; -jar &quot;{verpath}test.jar&quot; :用 Java 运行版本文件夹下的 test.jar&#xa; · notepad &quot;{verindie}options.txt&quot; :使用记事本打开该版本的设置文件&#xa;&#xa;涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。&#xa;执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
<local:MyCheckBox Grid.Row="5" Grid.Column="1" x:Name="CheckAdvanceRunWait" Tag="VersionAdvanceRunWait" Visibility="Collapsed"
Text="等待命令执行完成后再继续启动" Margin="0,5,0,0" />
<StackPanel Margin="0,12,0,4" Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Left">
@@ -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
@@ -206,8 +206,8 @@
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Controls\Behaviors\ClipboardInterceptor.vb" />
<Compile Include="Controls\IMyRadio.vb" />
<Compile Include="Controls\Interfaces.vb" />
<Compile Include="Controls\Behaviors\IMyRadio.vb" />
<Compile Include="Controls\Behaviors\Interfaces.vb" />
<Compile Include="Controls\MyComboBox.vb" />
<Compile Include="Controls\MyComboBoxItem.vb" />
<Compile Include="Controls\MyCard.vb" />
+18 -106
View File
@@ -53,114 +53,37 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="事件 1:打开网页、弹出窗口" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<local:MyCard Title="自定义事件" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
<TextBlock Margin="0,0,0,10"
Text="将按钮的 EventType 属性设为 打开网页,然后在 EventData 属性中写入网址,即可通过点击按钮打开网页。" />
<local:MyButton Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
<local:MyButton Height="35" HorizontalAlignment="Left" Padding="20,0,20,0"
Text="打开 Minecraft Wiki" EventType="打开网页" EventData="https://zh.minecraft.wiki/" />
<TextBlock TextWrapping="Wrap" Margin="0,10,0,10"
<TextBlock Margin="0,10,0,10"
Text="或者将 EventType 属性改为 弹出窗口,然后在 EventData 属性中写入弹窗的标题与内容……" />
<local:MyButton Width="140" Height="35" HorizontalAlignment="Left" Padding="13,0,13,0"
Text="显示一个弹窗" EventType="弹出窗口" EventData="这是标题|标题与内容以竖线间隔。\n你也可以直接在其中换行。" />
<TextBlock TextWrapping="Wrap" Margin="0,10,0,0"
<TextBlock Margin="0,10,0,0"
Text="local:MyTextButton 同样可以设置 EventType 与 EventData 让它具有特定功能。" />
<local:MyTextButton Margin="0,8,0,0" HorizontalAlignment="Center"
Text="点击打开知乎" EventType="打开网页" EventData="https://www.zhihu.com/" />
Text="点击打开哔哩哔哩" EventType="打开网页" EventData="https://www.bilibili.com/" />
<TextBlock Margin="0,30,0,0"
Text="你也可以让一个控件触发多个事件。自定义事件的详细用法请参考下方的 Wiki。" />
<local:MyListItem Margin="-5,8,-5,5"
Title="自定义事件 - PCL Wiki" Info="点击查看自定义事件的完整列表与说明"
Logo="pack://application:,,,/images/Blocks/CommandBlock.png" Type="Clickable"
EventType="打开网页" EventData="https://github.com/Meloong-Git/PCL/wiki/自定义事件" />
</StackPanel>
</local:MyCard>
<local:MyCard Title="事件 2:启动游戏" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="将 EventType 设置为 启动游戏,EventData 设置为具体的游戏版本,即可通过点击按钮启动游戏。如果当前游戏文件夹没有该版本,则无法启动。" />
<local:MyButton Margin="0,4,0,10" Width="250" Height="35"
Text="启动 Minecraft 1.12.2" EventType="启动游戏" EventData="1.12.2" />
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="在 EventData 后面添加一条竖线(|),竖线后填写服务器 IP,即可在启动该版本的同时自动进入服务器。" />
<local:MyButton Margin="0,4,0,0" Width="250" Height="35"
Text="启动 1.20.1 并进入 Hypixel" EventType="启动游戏" EventData="1.20.1|mc.hypixel.net" ToolTip="服务器 IP:mc.hypixel.net" />
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="在 EventData 中填写 \current,表示启动当前被选中的游戏版本,同样可以在后面填写服务器 IP。" />
<local:MyButton Margin="0,4,0,10" Width="250" Height="35"
Text="启动当前选中版本并进入 Hypixel" EventType="启动游戏" EventData="\current|mc.hypixel.net" ToolTip="启动当前版本" />
<local:MyCard Title="替换标记" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,10">
<local:MyListItem Margin="-5,0,-5,8"
EventType="打开帮助" EventData="个性化/替换标记.json" />
</StackPanel>
</local:MyCard>
<local:MyCard Title="事件 3:执行命令" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="将 EventType 设置为 执行命令(或 打开文件),EventData 设置为文件路径,即可点击打开特定文件或启动程序。" />
<local:MyButton Margin="0,4,0,8" Width="200" Height="35"
Text="打开记事本" EventType="执行命令" EventData="notepad.exe" />
<TextBlock TextWrapping="Wrap" Margin="0,4,0,0"
Text="如果能在 PCL 文件夹中找到该文件,则会优先打开 PCL 文件夹中的文件。当然,你可以使用例如 C:\ 开头的绝对路径。" />
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="此外,PCL 会将文件中的 “花括号 path” 替换为 PCL 可执行文件所在文件夹({path}),可以用于执行特定程序或加载图片。" />
<local:MyButton Margin="0,4,0,10" Width="200" Height="35"
Text="打开 PCL 日志" EventType="执行命令" EventData="Log1.txt" ToolTip="PCL 的日志文件就在 PCL 文件夹内,且名为 Log1.txt" />
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="就像为游戏指定服务器 IP 一样,你也可以在 EventData 的竖线后为程序添加启动参数。" />
<local:MyButton Margin="0,4,0,0" Width="200" Height="35"
Text="定位游戏启动脚本" EventType="执行命令" EventData="explorer.exe|/select,LatestLaunch.bat" ToolTip="PCL 会将上一次启动 MC 的脚本保存在 PCL 文件夹内,且名为 LatestLaunch.bat。&#xA;点击按钮会打开文件管理器,并且借助参数要求它选中这个文件。" />
</StackPanel>
</local:MyCard>
<local:MyCard Title="事件 4:其他事件类型" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock Margin="0,4,0,6" FontWeight="Bold"
Text="EventType 共有以下种类:" />
<TextBlock Margin="0,0,0,4"
Text="· 打开网页、启动游戏、打开文件:已在上方的卡片中介绍" />
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="查看 PCL 源代码" EventType="打开网页" EventData="https://github.com/Meloong-Git/PCL/blob/main/Plain%20Craft%20Launcher%202/FormMain.xaml.vb"/>
<TextBlock Margin="0,0,0,4"
Text="· 今日人品、清理垃圾、内存优化、安装整合包:触发对应功能" />
<TextBlock Margin="0,0,0,4"
Text="· 复制文本:将 EventData 中的内容复制到剪贴板" />
<TextBlock Margin="0,0,0,4"
Text="· 刷新主页:点击重新加载主页。如果主页文件为联网更新,这会重新下载主页内容" />
<TextBlock Margin="0,0,0,4"
Text="· 下载文件:在点击时要求选择文件保存位置,并且下载 EventData 的链接中的文件&#xa;      EventData 中也能可选地指定文件名或目标文件夹,格式为:链接|文件名|文件夹" />
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="下载百度的 Logo" EventType="下载文件" EventData="https://www.baidu.com/img/flexible/logo/pc/result.png" />
<TextBlock Margin="0,4,0,4"
Text="· 打开帮助:跳转到 EventData 对应的帮助文件(输入相对 Help 文件夹的路径)"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="打开自定义帮助页面" EventType="打开帮助" EventData="帮助/自定义帮助.json"/>
<TextBlock Margin="0,4,0,4"
Text="· 切换页面:强制切换到 PCL 的某一页面(尝试切换到不太对头的页面会出现不可预知的 Bug)&#xa;      EventData 为 页面种类|次要页面种类(PageType|PageSubType,例如 1|1)&#xa;      点击上方的 查看 PCL 源代码 按钮,在 1000 行左右的位置即可查找到对应数值"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="切换到下载页面" EventType="切换页面" EventData="1|1"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="切换到启动器设置" EventType="切换页面" EventData="3|2"/>
<TextBlock Margin="0,4,0,4"
Text="· 下载版本:切换到 EventData 对应的 Minecraft 下载页面"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="下载 Minecraft 1.12.2" EventType="下载版本" EventData="1.12.2"/>
<TextBlock Margin="0,4,0,4"
Text="· 修改设置:将 PCL 的特定设置修改为特定值"/>
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
Text="将窗口改为半透明" EventType="修改设置" EventData="UiLauncherTransparent|400"/>
</StackPanel>
</local:MyCard>
<local:MyCard Title="在单个按钮中执行多个事件" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock Margin="0,4,0,6"
Text="通过按钮的 CustomEvents 属性来指定多个事件,它们将挨个运行" />
<local:MyButton Margin="0,5,0,6" Width="400" Height="35"
Text="打开 Minecraft Wiki,显示一个弹窗,然后打开知乎">
<local:MyButton.CustomEvents>
<local:CustomEvent EventType="打开网页" EventData="https://zh.minecraft.wiki/" />
<local:CustomEvent EventType="弹出窗口" EventData="刚刚打开了 Wiki|该弹窗关闭后将打开知乎" />
<local:CustomEvent EventType="打开网页" EventData="https://www.zhihu.com/" />
</local:MyButton.CustomEvents>
</local:MyButton>
</StackPanel>
</local:MyCard>
<local:MyCard Title="StackPanel 横向布局" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<local:MyCard Title="横向布局" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
Text="你需要使用 StackPanel 在一行里塞下多个按钮。你可以仅在这个教学卡片的基础上稍作调整,来实现自己的按钮布局。" />
@@ -198,7 +121,7 @@
Logo="pack://application:,,,/images/Blocks/Grass.png"
EventType="打开帮助" EventData="帮助/自定义帮助.json" Type="Clickable" />
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="EventType、EventData 与按钮几乎一致,唯一不同的是,列表项不支持联网加载帮助文件。" />
Text="EventType、EventData 与按钮几乎一致。唯一不同的是,列表项不支持联网加载帮助文件。" />
</StackPanel>
</local:MyCard>
@@ -261,17 +184,6 @@
</StackPanel>
</local:MyCard>
<local:MyCard Title="替换标记" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="在花括号 {} 中写入特定内容,PCL 会在加载时对其进行替换。&#xa;例如,path 会被替换为 PCL 可执行文件所在文件夹({path}),用于在 EventData 中指定特定文件,或是加载图片。" />
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Text="你也可以使用替换标记来获取随机内容:cave 会被替换为一条随机的回声洞内容,hint 则是 “你知道吗” 的内容。" />
<TextBlock TextWrapping="Wrap" Margin="10,6,0,5" Foreground="{DynamicResource ColorBrush3}"
Text="你知道吗:{hint}" />
</StackPanel>
</local:MyCard>
<local:MyCard Title="进阶:Grid 布局" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
<StackPanel Margin="25,40,23,15">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
Binary file not shown.