Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a41579b1da | ||
|
|
86ed0e9ae0 | ||
|
|
ab697054c8 | ||
|
|
0ba2fd1edb | ||
|
|
49984a2913 | ||
|
|
6f6744dfd2 | ||
|
|
08e5e64ca4 | ||
|
|
cd736be212 |
No files matched your search
@@ -19,6 +19,9 @@ Public Class Application
|
||||
'开始
|
||||
Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
|
||||
Try
|
||||
'动态 DLL 调用(必须尽量在前面,否则模块加载 CacheCow 等 DLL 就可能导致崩溃)
|
||||
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf AssemblyResolve
|
||||
'开始
|
||||
SecretOnApplicationStart()
|
||||
'检查参数调用
|
||||
If e.Args.Length > 0 Then
|
||||
@@ -75,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
|
||||
@@ -116,16 +118,14 @@ WaitRetry:
|
||||
FrmStart = New SplashScreen("Images\icon.ico")
|
||||
FrmStart.Show(False, True)
|
||||
End If
|
||||
'动态 DLL 调用
|
||||
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf AssemblyResolve
|
||||
'日志初始化
|
||||
LogStart()
|
||||
'添加日志
|
||||
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})")
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -140,39 +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.TryStartEvent(EventType, EventData)
|
||||
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))
|
||||
|
||||
'鼠标点击判定(务必放在点击事件之后,以使得 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()
|
||||
|
||||
@@ -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,15 +117,14 @@
|
||||
Private IsTextChanging As Boolean = False
|
||||
Private Sub MyComboBox_TextChanged(sender As Object, e As TextChangedEventArgs) Handles Me.TextChanged
|
||||
If IsTextChanging OrElse Not IsEditable Then Return
|
||||
If SelectedItem IsNot Nothing AndAlso Text <> SelectedItem.ToString Then
|
||||
Dim RawText As String = Text
|
||||
Dim RawSelectionStart As Integer = TextBox.SelectionStart
|
||||
IsTextChanging = True
|
||||
SelectedItem = Nothing
|
||||
Text = RawText
|
||||
TextBox.SelectionStart = RawSelectionStart
|
||||
IsTextChanging = False
|
||||
End If
|
||||
If SelectedItem Is Nothing OrElse Text = SelectedItem.ToString Then Return
|
||||
Dim RawText As String = Text
|
||||
Dim RawSelectionStart As Integer = TextBox.SelectionStart
|
||||
IsTextChanging = True
|
||||
SelectedItem = Nothing
|
||||
Text = RawText
|
||||
TextBox.SelectionStart = RawSelectionStart
|
||||
IsTextChanging = False
|
||||
End Sub
|
||||
|
||||
Public ReadOnly Property ContentPresenter As ContentPresenter
|
||||
@@ -134,4 +133,8 @@
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Private Sub MyComboBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles Me.SelectionChanged
|
||||
If IsLoaded AndAlso AniControlEnabled = 0 Then RaiseCustomEvent()
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
@@ -53,25 +53,26 @@
|
||||
Set(value As Boolean)
|
||||
If _Show = value Then Return
|
||||
_Show = value
|
||||
RunInUi(Sub()
|
||||
If value Then
|
||||
'有了
|
||||
Visibility = Visibility.Visible
|
||||
AniStart({
|
||||
AaScaleTransform(Me, 0.3 - CType(RenderTransform, ScaleTransform).ScaleX, 500, 60, New AniEaseOutFluent(AniEasePower.Weak)),
|
||||
AaScaleTransform(Me, 0.7, 500, 60, New AniEaseOutBack(AniEasePower.Weak)),
|
||||
AaHeight(Me, 50 - Height, 200,, New AniEaseOutFluent(AniEasePower.Weak))
|
||||
}, "MyExtraButton MainScale " & Uuid)
|
||||
Else
|
||||
'没了
|
||||
AniStart({
|
||||
AaScaleTransform(Me, -CType(RenderTransform, ScaleTransform).ScaleX, 100,, New AniEaseInFluent(AniEasePower.Weak)),
|
||||
AaHeight(Me, -Height, 400, 100, New AniEaseOutFluent()),
|
||||
AaCode(Sub() Visibility = Visibility.Collapsed,, True)
|
||||
}, "MyExtraButton MainScale " & Uuid)
|
||||
End If
|
||||
IsHitTestVisible = value '防止缩放动画中依然可以点进去
|
||||
End Sub)
|
||||
RunInUi(
|
||||
Sub()
|
||||
If value Then
|
||||
'有了
|
||||
Visibility = Visibility.Visible
|
||||
AniStart({
|
||||
AaScaleTransform(Me, 0.3 - CType(RenderTransform, ScaleTransform).ScaleX, 500, 60, New AniEaseOutFluent(AniEasePower.Weak)),
|
||||
AaScaleTransform(Me, 0.7, 500, 60, New AniEaseOutBack(AniEasePower.Weak)),
|
||||
AaHeight(Me, 50 - Height, 200,, New AniEaseOutFluent(AniEasePower.Weak))
|
||||
}, "MyExtraButton MainScale " & Uuid)
|
||||
Else
|
||||
'没了
|
||||
AniStart({
|
||||
AaScaleTransform(Me, -CType(RenderTransform, ScaleTransform).ScaleX, 100,, New AniEaseInFluent(AniEasePower.Weak)),
|
||||
AaHeight(Me, -Height, 400, 100, New AniEaseOutFluent()),
|
||||
AaCode(Sub() Visibility = Visibility.Collapsed,, True)
|
||||
}, "MyExtraButton MainScale " & Uuid)
|
||||
End If
|
||||
IsHitTestVisible = value '防止缩放动画中依然可以点进去
|
||||
End Sub)
|
||||
End Set
|
||||
End Property
|
||||
Public Delegate Function ShowCheckDelegate() As Boolean
|
||||
@@ -137,6 +138,7 @@
|
||||
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 300,, New AniEaseOutBack)
|
||||
}, "MyExtraButton Scale " & Uuid)
|
||||
End If
|
||||
If IsLeftMouseHeld Then RaiseCustomEvent()
|
||||
IsLeftMouseHeld = False
|
||||
RefreshColor() '直接刷新颜色以判断是否已触发 MouseLeave
|
||||
End Sub
|
||||
@@ -199,16 +201,17 @@
|
||||
''' 发出一圈波浪效果提示。
|
||||
''' </summary>
|
||||
Public Sub Ribble()
|
||||
RunInUi(Sub()
|
||||
Dim Shape As New Border With {.CornerRadius = New CornerRadius(1000), .BorderThickness = New Thickness(0.001), .Opacity = 0.5, .RenderTransformOrigin = New Point(0.5, 0.5), .RenderTransform = New ScaleTransform()}
|
||||
Shape.SetResourceReference(Border.BackgroundProperty, "ColorBrush5")
|
||||
PanScale.Children.Insert(0, Shape)
|
||||
AniStart({
|
||||
AaScaleTransform(Shape, 13, 1000, Ease:=New AniEaseInoutFluent(AniEasePower.Strong, 0.3)),
|
||||
AaOpacity(Shape, -Shape.Opacity, 1000),
|
||||
AaCode(Sub() PanScale.Children.Remove(Shape), After:=True)
|
||||
}, "ExtraButton Ribble " & GetUuid())
|
||||
End Sub)
|
||||
RunInUi(
|
||||
Sub()
|
||||
Dim Shape As New Border With {.CornerRadius = New CornerRadius(1000), .BorderThickness = New Thickness(0.001), .Opacity = 0.5, .RenderTransformOrigin = New Point(0.5, 0.5), .RenderTransform = New ScaleTransform()}
|
||||
Shape.SetResourceReference(Border.BackgroundProperty, "ColorBrush5")
|
||||
PanScale.Children.Insert(0, Shape)
|
||||
AniStart({
|
||||
AaScaleTransform(Shape, 13, 1000, Ease:=New AniEaseInoutFluent(AniEasePower.Strong, 0.3)),
|
||||
AaOpacity(Shape, -Shape.Opacity, 1000),
|
||||
AaCode(Sub() PanScale.Children.Remove(Shape), After:=True)
|
||||
}, "ExtraButton Ribble " & GetUuid())
|
||||
End Sub)
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
@@ -81,12 +81,12 @@ Public Class MyExtraTextButton
|
||||
|
||||
'触发点击事件
|
||||
Private Sub Button_LeftMouseUp(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseLeftButtonUp
|
||||
If IsLeftMouseHeld Then
|
||||
Log("[Control] 按下附加图标按钮:" & Text)
|
||||
RaiseEvent Click(sender, e)
|
||||
e.Handled = True
|
||||
Button_LeftMouseUp()
|
||||
End If
|
||||
If Not IsLeftMouseHeld Then Return
|
||||
Log("[Control] 按下附加图标按钮:" & Text)
|
||||
RaiseEvent Click(sender, e)
|
||||
e.Handled = True
|
||||
RaiseCustomEvent()
|
||||
Button_LeftMouseUp()
|
||||
End Sub
|
||||
|
||||
'鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行)
|
||||
|
||||
@@ -113,7 +113,7 @@ Public Class MyHint
|
||||
IsMouseDown = False
|
||||
Log("[Control] 按下提示条" & If(String.IsNullOrEmpty(Name), "", ":" & Name))
|
||||
e.Handled = True
|
||||
ModEvent.TryStartEvent(EventType, EventData)
|
||||
RaiseCustomEvent() '自定义事件
|
||||
End Sub
|
||||
Private Sub MyHint_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
|
||||
IsMouseDown = True
|
||||
@@ -121,24 +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))
|
||||
|
||||
End Class
|
||||
Partial Public Module ModAnimation
|
||||
|
||||
@@ -48,36 +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.TryStartEvent(EventType, EventData)
|
||||
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))
|
||||
|
||||
'鼠标点击判定(务必放在点击事件之后,以使得 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()
|
||||
@@ -102,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.TryStartEvent(EventType, EventData)
|
||||
RaiseCustomEvent() '自定义事件
|
||||
RefreshColor()
|
||||
End Sub
|
||||
Private Sub MyIconTextButton_MouseDown() Handles Me.MouseLeftButtonDown
|
||||
@@ -87,24 +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))
|
||||
|
||||
'动画
|
||||
|
||||
|
||||
@@ -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,12 +120,12 @@
|
||||
End If
|
||||
RunInNewThread(
|
||||
Sub()
|
||||
Dim IsLocalFallback As Boolean = FallbackSource IsNot Nothing AndAlso Not FallbackSource.StartsWithF("http")
|
||||
Try
|
||||
RetryStart:
|
||||
'下载
|
||||
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
|
||||
'保存缓存并显示
|
||||
@@ -140,7 +140,19 @@ RetryStart:
|
||||
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.TryStartEvent(EventType, EventData)
|
||||
If CustomEventService.GetEventType(sender) <> CustomEvent.EventType.None Then
|
||||
RaiseCustomEvent()
|
||||
e.Handled = True
|
||||
End If
|
||||
If e.Handled Then Return
|
||||
@@ -537,26 +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))
|
||||
|
||||
#End Region
|
||||
|
||||
Private StateLast As String
|
||||
@@ -657,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,15 +22,15 @@
|
||||
End Set
|
||||
End Property
|
||||
Public Shared ReadOnly TextProperty As DependencyProperty =
|
||||
DependencyProperty.Register("Text", GetType(String), GetType(MyTextButton), New PropertyMetadata("", Sub(sender As MyTextButton, e As DependencyPropertyChangedEventArgs)
|
||||
If Not e.OldValue = e.NewValue Then
|
||||
AniStart({
|
||||
AaOpacity(sender, -sender.Opacity, 50),
|
||||
AaCode(Sub() sender.Content = e.NewValue,, True),
|
||||
AaOpacity(sender, 1, 170)
|
||||
}, "MyTextButton Text " & sender.Uuid)
|
||||
End If
|
||||
End Sub))
|
||||
DependencyProperty.Register("Text", GetType(String), GetType(MyTextButton), New PropertyMetadata("",
|
||||
Sub(sender As MyTextButton, e As DependencyPropertyChangedEventArgs)
|
||||
If e.OldValue = e.NewValue Then Return
|
||||
AniStart({
|
||||
AaOpacity(sender, -sender.Opacity, 50),
|
||||
AaCode(Sub() sender.Content = e.NewValue,, True),
|
||||
AaOpacity(sender, 1, 170)
|
||||
}, "MyTextButton Text " & sender.Uuid)
|
||||
End Sub))
|
||||
|
||||
'鼠标事件
|
||||
|
||||
@@ -43,13 +43,12 @@
|
||||
IsMouseDown = False
|
||||
End Sub
|
||||
Private Sub MyTextButton_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
|
||||
If IsMouseDown Then
|
||||
IsMouseDown = False
|
||||
Log("[Control] 按下文本按钮:" & Text)
|
||||
RaiseEvent Click(Me, Nothing)
|
||||
ModEvent.TryStartEvent(EventType, EventData)
|
||||
e.Handled = True
|
||||
End If
|
||||
If Not IsMouseDown Then Return
|
||||
IsMouseDown = False
|
||||
Log("[Control] 按下文本按钮:" & Text)
|
||||
RaiseEvent Click(Me, Nothing)
|
||||
RaiseCustomEvent()
|
||||
e.Handled = True
|
||||
End Sub
|
||||
|
||||
'指向动画
|
||||
@@ -85,26 +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))
|
||||
|
||||
End Class
|
||||
@@ -11,6 +11,14 @@ Public Class FormMain
|
||||
Dim FeatureList As New List(Of KeyValuePair(Of Integer, String))
|
||||
'统计更新日志条目
|
||||
#If BETA Then
|
||||
If LastVersion < 369 Then 'Release 2.10.8
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "新增:允许在版本设置中设置禁止更新 Mod,以防整合包玩家误操作"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:若整合包需要 PCL 不兼容的加载器,允许选择跳过它的安装"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "删除:由于已不再需要,删除手动安装包下载功能"))
|
||||
FeatureCount += 21
|
||||
BugCount += 32
|
||||
End If
|
||||
If LastVersion < 367 Then 'Release 2.10.6
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:启用 MCIM 社区资源镜像源,以缓解社区资源难以下载的问题"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:正版登录出错时无法给出正确的错误信息"))
|
||||
@@ -96,6 +104,20 @@ 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
|
||||
BugCount += 4
|
||||
End If
|
||||
If LastVersion < 368 Then 'Snapshot 2.10.7
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "新增:允许在版本设置中设置禁止更新 Mod,以防整合包玩家误操作"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化"))
|
||||
@@ -305,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 正以调试模式运行,这可能会导致性能下降,若无必要请不要开启!")
|
||||
'尽早执行的加载池
|
||||
@@ -590,7 +612,7 @@ Public Class FormMain
|
||||
FeedbackInfo()
|
||||
Log("请在 https://github.com/Meloong-Git/PCL/issues 提交错误报告,以便于作者解决此问题!")
|
||||
IsLogShown = True
|
||||
ShellOnly(Path & "PCL\Log1.txt")
|
||||
StartProcess(Path & "PCL\Log1.txt")
|
||||
End If
|
||||
Thread.Sleep(500) '防止 PCL 在记事本打开前就被掐掉
|
||||
End If
|
||||
@@ -674,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
|
||||
@@ -772,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
|
||||
@@ -824,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
|
||||
@@ -842,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
|
||||
'多文件拖拽
|
||||
@@ -853,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
|
||||
@@ -872,7 +894,7 @@ Public Class FormMain
|
||||
Sub()
|
||||
Setup.Set("UiCustomType", 1)
|
||||
FrmLaunchRight.ForceRefresh()
|
||||
Hint("已加载主页自定义文件!", HintType.Finish)
|
||||
Hint("已加载主页自定义文件!", HintType.Green)
|
||||
End Sub)
|
||||
Return
|
||||
End If
|
||||
@@ -982,9 +1004,9 @@ Public Class FormMain
|
||||
#Region "切换页面"
|
||||
|
||||
'页面种类与属性
|
||||
'注意,这一枚举在 “切换页面” EventType 中调用,应视作公开 API 的一部分
|
||||
''' <summary>
|
||||
''' 页面种类。
|
||||
''' 该枚举在自定义事件中使用,是公开 API 的一部分。
|
||||
''' </summary>
|
||||
Public Enum PageType
|
||||
''' <summary>
|
||||
@@ -1030,6 +1052,7 @@ Public Class FormMain
|
||||
End Enum
|
||||
''' <summary>
|
||||
''' 次要页面种类。其数值必须与 StackPanel 中的下标一致。
|
||||
''' 该枚举在自定义事件中使用,是公开 API 的一部分。
|
||||
''' </summary>
|
||||
Public Enum PageSubType
|
||||
[Default] = 0
|
||||
@@ -1472,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
|
||||
@@ -1490,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
|
||||
|
||||
@@ -13,13 +13,13 @@ Public Module ModBase
|
||||
#Region "声明"
|
||||
|
||||
'下列版本信息由更新器自动修改
|
||||
Public Const VersionBaseName As String = "2.10.7" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.10.7." & 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 = 368 '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,21 +761,9 @@ 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>
|
||||
''' 从文件路径或者 Url 获取不包含路径与扩展名的文件名。不包含文件名将会抛出异常。
|
||||
''' </summary>
|
||||
Public Function GetFileNameWithoutExtentionFromPath(FilePath As String) As String
|
||||
Dim Name As String = GetFileNameFromPath(FilePath)
|
||||
If Name.Contains(".") Then
|
||||
Return Name.Substring(0, Name.LastIndexOfF("."))
|
||||
Else
|
||||
Return Name
|
||||
End If
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 从文件夹路径获取文件夹名。
|
||||
''' </summary>
|
||||
Public Function GetFolderNameFromPath(FolderPath As String) As String
|
||||
@@ -791,8 +779,8 @@ Public Module ModBase
|
||||
Public Sub CopyFile(FromPath As String, ToPath As String)
|
||||
Try
|
||||
'还原文件路径
|
||||
FromPath = ShortenPath(If(FromPath.Contains(":\"), FromPath, Path & FromPath))
|
||||
ToPath = ShortenPath(If(ToPath.Contains(":\"), ToPath, Path & ToPath))
|
||||
FromPath = If(FromPath.Contains(":\"), FromPath, Path & FromPath)
|
||||
ToPath = If(ToPath.Contains(":\"), ToPath, Path & ToPath)
|
||||
'如果复制同一个文件则跳过
|
||||
If FromPath = ToPath Then Return
|
||||
'确保目录存在
|
||||
@@ -861,7 +849,7 @@ Public Module ModBase
|
||||
''' <param name="Append">是否将文件内容追加到当前文件,而不是覆盖它。</param>
|
||||
Public Sub WriteFile(FilePath As String, Text As String, Optional Append As Boolean = False, Optional Encoding As Encoding = Nothing)
|
||||
'处理相对路径
|
||||
FilePath = ShortenPath(If(FilePath.Contains(":\"), FilePath, Path & FilePath))
|
||||
FilePath = If(FilePath.Contains(":\"), FilePath, Path & FilePath)
|
||||
'确保目录存在
|
||||
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
|
||||
'写入文件
|
||||
@@ -886,7 +874,7 @@ Public Module ModBase
|
||||
''' <param name="Append">是否将文件内容追加到当前文件,而不是覆盖它。</param>
|
||||
Public Sub WriteFile(FilePath As String, Content As Byte(), Optional Append As Boolean = False)
|
||||
'处理相对路径
|
||||
FilePath = ShortenPath(If(FilePath.Contains(":\"), FilePath, Path & FilePath))
|
||||
FilePath = If(FilePath.Contains(":\"), FilePath, Path & FilePath)
|
||||
'确保目录存在
|
||||
Directory.CreateDirectory(GetPathFromFullPath(FilePath))
|
||||
'写入文件
|
||||
@@ -1294,11 +1282,11 @@ Re:
|
||||
''' </summary>
|
||||
Public Sub ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing,
|
||||
Optional ProgressIncrementHandler As Action(Of Double) = Nothing)
|
||||
Directory.CreateDirectory(ShortenPath(DestDirectory))
|
||||
Directory.CreateDirectory(DestDirectory)
|
||||
If CompressFilePath.EndsWithF(".gz", True) Then
|
||||
'以 gz 方式解压
|
||||
Dim stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.ReadWrite), CompressionMode.Decompress)
|
||||
Dim decompressedFile As New FileStream(ShortenPath(DestDirectory & GetFileNameFromPath(CompressFilePath).ToLower.Replace(".tar", "").Replace(".gz", "")), FileMode.OpenOrCreate, FileAccess.Write)
|
||||
Dim decompressedFile As New FileStream(DestDirectory & GetFileNameFromPath(CompressFilePath).ToLower.Replace(".tar", "").Replace(".gz", ""), FileMode.OpenOrCreate, FileAccess.Write)
|
||||
Dim data As Integer = stream.ReadByte()
|
||||
While data <> -1
|
||||
decompressedFile.WriteByte(data)
|
||||
@@ -1312,13 +1300,10 @@ Re:
|
||||
Dim TotalCount As Long = Archive.Entries.Count
|
||||
For Each Entry As ZipArchiveEntry In Archive.Entries
|
||||
If ProgressIncrementHandler IsNot Nothing AndAlso TotalCount > 0 Then ProgressIncrementHandler(1 / TotalCount)
|
||||
Dim DestinationPath As String = ShortenPath(IO.Path.Combine(DestDirectory, Entry.FullName))
|
||||
If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then
|
||||
Continue For '不创建空文件夹
|
||||
Else
|
||||
Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
|
||||
Entry.ExtractToFile(DestinationPath, True)
|
||||
End If
|
||||
Dim DestinationPath As String = IO.Path.Combine(DestDirectory, Entry.FullName)
|
||||
If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then Continue For '不创建空文件夹
|
||||
Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
|
||||
Entry.ExtractToFile(DestinationPath, True)
|
||||
Next
|
||||
End Using
|
||||
End If
|
||||
@@ -1342,6 +1327,7 @@ Re:
|
||||
Try
|
||||
Files = Directory.GetFiles(Path)
|
||||
Catch ex As DirectoryNotFoundException '#4549
|
||||
If Not Directory.Exists(Path) Then Return 0 '可能已被其他线程删除
|
||||
Log(ex, $"疑似为孤立符号链接,尝试直接删除({Path})", LogLevel.Developer)
|
||||
Directory.Delete(Path)
|
||||
Return 0
|
||||
@@ -1406,21 +1392,24 @@ RetryDir:
|
||||
''' 遍历文件夹中的所有文件。
|
||||
''' </summary>
|
||||
Public Function EnumerateFiles(Directory As String) As IEnumerable(Of FileInfo)
|
||||
Dim Info As New DirectoryInfo(ShortenPath(Directory))
|
||||
Dim Info As New DirectoryInfo(Directory)
|
||||
If Not Info.Exists Then Return New List(Of FileInfo)
|
||||
Return Info.EnumerateFiles("*", SearchOption.AllDirectories)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' 若路径长度大于指定值,则将长路径转换为短路径。
|
||||
''' 如果路径不存在,则返回原始路径。
|
||||
''' </summary>
|
||||
Public Function ShortenPath(LongPath As String, Optional ShortenThreshold As Integer = 247) As String
|
||||
If LongPath.Length <= ShortenThreshold Then Return LongPath
|
||||
Public Function ShortenPath(LongPath As String) As String
|
||||
If LongPath.Length <= 200 OrElse LongPath.StartsWithF("http", True) Then Return LongPath
|
||||
If Not Directory.Exists(LongPath) AndAlso Not File.Exists(LongPath) Then Return LongPath
|
||||
Dim ShortPath As New StringBuilder(260)
|
||||
GetShortPathName(LongPath, ShortPath, 260)
|
||||
Return ShortPath.ToString
|
||||
GetShortPathName(LongPath.Replace("/", "\"), ShortPath, 260) '第一个参数也会在调用后被修改,使用 Replace 后不会影响原始字符串
|
||||
ShortenPath = ShortPath.ToString
|
||||
If String.IsNullOrEmpty(ShortenPath) Then Return LongPath
|
||||
End Function
|
||||
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (ByVal lpszLongPath As String, ByVal lpszShortPath As StringBuilder, ByVal cchBuffer As Integer) As Integer
|
||||
Private Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (lpszLongPath As String, lpszShortPath As StringBuilder, cchBuffer As Integer) As Integer
|
||||
|
||||
#End Region
|
||||
|
||||
@@ -1500,7 +1489,7 @@ RetryDir:
|
||||
If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is BadImageFormatException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then
|
||||
Return "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。"
|
||||
ElseIf TypeOf InnerEx Is UnauthorizedAccessException Then
|
||||
Return "PCL 的权限不足。请尝试右键 PCL 选择以管理员身份运行,或将目标从 C 盘或桌面挪到其他硬盘。"
|
||||
Return "PCL 的权限不足。请尝试右键 PCL 选择以管理员身份运行。"
|
||||
ElseIf TypeOf InnerEx Is OutOfMemoryException Then
|
||||
Return "你的电脑运行内存不足,导致 PCL 无法继续运行。请在关闭一部分不需要的程序后再试。"
|
||||
ElseIf TypeOf InnerEx Is Runtime.InteropServices.COMException Then
|
||||
@@ -1522,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>
|
||||
@@ -2027,8 +2029,8 @@ RetryDir:
|
||||
'构造函数
|
||||
Public Sub New()
|
||||
End Sub
|
||||
Public Sub New(data As IEnumerable(Of KeyValuePair(Of TKey, TValue)))
|
||||
For Each DataItem In data
|
||||
Public Sub New(Data As IEnumerable(Of KeyValuePair(Of TKey, TValue)))
|
||||
For Each DataItem In Data
|
||||
_Dictionary.Add(DataItem.Key, DataItem.Value)
|
||||
Next
|
||||
End Sub
|
||||
@@ -2184,7 +2186,7 @@ RetryDir:
|
||||
''' 返回程序的返回代码,如果运行失败将抛出异常。
|
||||
''' </summary>
|
||||
Public Function RunAsAdmin(Argument As String) As Integer
|
||||
Dim NewProcess = Process.Start(New ProcessStartInfo(PathWithName) With {.Verb = "runas", .Arguments = Argument})
|
||||
Dim NewProcess = StartProcess(New ProcessStartInfo(PathWithName) With {.Verb = "runas", .Arguments = Argument})
|
||||
NewProcess.WaitForExit()
|
||||
Return NewProcess.ExitCode
|
||||
End Function
|
||||
@@ -2343,46 +2345,21 @@ NextElement:
|
||||
End Class
|
||||
|
||||
''' <summary>
|
||||
''' 前台运行文件。
|
||||
''' 启动进程并返回进程实例,若失败则抛出异常。
|
||||
''' 会自动进行长路径处理。
|
||||
''' </summary>
|
||||
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
|
||||
''' <param name="Arguments">运行参数。</param>
|
||||
Public Sub ShellOnly(FileName As String, Optional Arguments As String = "")
|
||||
Try
|
||||
FileName = ShortenPath(FileName)
|
||||
Using Program As New Process
|
||||
Program.StartInfo.Arguments = Arguments
|
||||
Program.StartInfo.FileName = FileName
|
||||
Log("[System] 执行外部命令:" & FileName & " " & Arguments)
|
||||
Program.Start()
|
||||
End Using
|
||||
Catch ex As Exception
|
||||
Log(ex, "打开文件或程序失败:" & FileName, LogLevel.Msgbox)
|
||||
End Try
|
||||
End Sub
|
||||
Public Function StartProcess(FileName As String, Optional Arguments As String = "") As Process
|
||||
Return StartProcess(New ProcessStartInfo With {.FileName = FileName, .Arguments = Arguments})
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 前台运行文件并返回返回值。
|
||||
''' 启动进程并返回进程实例,若失败则抛出异常。
|
||||
''' 会自动进行长路径处理。
|
||||
''' </summary>
|
||||
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
|
||||
''' <param name="Arguments">运行参数。</param>
|
||||
''' <param name="Timeout">等待该程序结束的最长时间(毫秒)。超时会返回 Result.Timeout。</param>
|
||||
Public Function ShellAndGetExitCode(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000) As ProcessReturnValues
|
||||
Try
|
||||
Using Program As New Process
|
||||
Program.StartInfo.Arguments = Arguments
|
||||
Program.StartInfo.FileName = FileName
|
||||
Log("[System] 执行外部命令并等待返回码:" & FileName & " " & Arguments)
|
||||
Program.Start()
|
||||
If Program.WaitForExit(Timeout) Then
|
||||
Return Program.ExitCode
|
||||
Else
|
||||
Return ProcessReturnValues.Timeout
|
||||
End If
|
||||
End Using
|
||||
Catch ex As Exception
|
||||
Log(ex, "执行命令失败:" & FileName, LogLevel.Msgbox)
|
||||
Return ProcessReturnValues.Fail
|
||||
End Try
|
||||
Public Function StartProcess(StartInfo As ProcessStartInfo) As Process
|
||||
StartInfo.FileName = ShortenPath(StartInfo.FileName)
|
||||
If Not String.IsNullOrEmpty(StartInfo.WorkingDirectory) Then StartInfo.WorkingDirectory = ShortenPath(StartInfo.WorkingDirectory)
|
||||
Log("[System] 启动进程:" & StartInfo.FileName & " " & StartInfo.Arguments)
|
||||
Return Process.Start(StartInfo)
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 静默运行文件并返回输出流字符串。执行失败会抛出异常。
|
||||
@@ -2390,10 +2367,11 @@ NextElement:
|
||||
''' <param name="FileName">文件名。可以为“notepad”等缩写。</param>
|
||||
''' <param name="Arguments">运行参数。</param>
|
||||
''' <param name="Timeout">等待该程序结束的最长时间(毫秒)。超时会抛出错误。</param>
|
||||
Public Function ShellAndGetOutput(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000, Optional WorkingDirectory As String = Nothing) As String
|
||||
Public Function StartProcessAndGetOutput(FileName As String, Optional Arguments As String = "", Optional Timeout As Integer = 1000000,
|
||||
Optional WorkingDirectory As String = Nothing) As String
|
||||
Dim Info = New ProcessStartInfo With {
|
||||
.Arguments = Arguments,
|
||||
.FileName = FileName,
|
||||
.FileName = ShortenPath(FileName),
|
||||
.UseShellExecute = False,
|
||||
.CreateNoWindow = True,
|
||||
.RedirectStandardError = True,
|
||||
@@ -2408,7 +2386,7 @@ NextElement:
|
||||
End If
|
||||
End If
|
||||
Log("[System] 执行外部命令并等待返回结果:" & FileName & " " & Arguments)
|
||||
Using Program As New Process() With {.StartInfo = Info}
|
||||
Using Program As New Process With {.StartInfo = Info}
|
||||
Program.Start()
|
||||
Dim Result As String = Program.StandardOutput.ReadToEnd & Program.StandardError.ReadToEnd
|
||||
Program.WaitForExit(Timeout)
|
||||
@@ -2510,17 +2488,14 @@ NextElement:
|
||||
''' <summary>
|
||||
''' 尝试从字典中获取某项,如果该项不存在,则返回默认值。
|
||||
''' </summary>
|
||||
<Extension> Public Function GetOrDefault(Of TKey, TValue)(Dict As Dictionary(Of TKey, TValue), Key As TKey, Optional DefaultValue As TValue = Nothing) As TValue
|
||||
If Dict.ContainsKey(Key) Then
|
||||
Return Dict(Key)
|
||||
Else
|
||||
Return DefaultValue
|
||||
End If
|
||||
<Extension> Public Function GetOrDefault(Of TKey, TValue)(Dict As IDictionary(Of TKey, TValue), Key As TKey, Optional DefaultValue As TValue = Nothing) As TValue
|
||||
Dim Result As TValue
|
||||
Return If(Dict.TryGetValue(Key, Result), Result, DefaultValue)
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 将某项添加到以列表作为值的字典中。
|
||||
''' </summary>
|
||||
<Extension> Public Sub AddToList(Of TKey, TValue)(Dict As Dictionary(Of TKey, List(Of TValue)), Key As TKey, Value As TValue)
|
||||
<Extension> Public Sub AddToList(Of TKey, TValue)(Dict As IDictionary(Of TKey, List(Of TValue)), Key As TKey, Value As TValue)
|
||||
If Dict.ContainsKey(Key) Then
|
||||
Dict(Key).Add(Value)
|
||||
Else
|
||||
@@ -2568,7 +2543,7 @@ NextElement:
|
||||
Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!")
|
||||
End If
|
||||
Log("[System] 正在打开网页:" & Url)
|
||||
Process.Start(Url)
|
||||
StartProcess(Url)
|
||||
Catch ex As Exception
|
||||
Log(ex, "无法打开网页(" & Url & ")")
|
||||
ClipboardSet(Url, False)
|
||||
@@ -2582,12 +2557,12 @@ NextElement:
|
||||
''' </summary>
|
||||
Public Sub OpenExplorer(Location As String)
|
||||
Try
|
||||
Location = ShortenPath(Location.Replace("/", "\").Trim(" "c, """"c))
|
||||
Location = Location.Replace("/", "\").Trim(" "c, """"c)
|
||||
Log("[System] 正在打开资源管理器:" & Location)
|
||||
If Location.EndsWith("\") Then
|
||||
ShellOnly(Location)
|
||||
StartProcess(Location)
|
||||
Else
|
||||
ShellOnly("explorer", $"/select,""{Location}""")
|
||||
StartProcess("explorer", $"/select,""{Location}""")
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", LogLevel.Msgbox)
|
||||
@@ -2617,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
|
||||
|
||||
@@ -2754,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)
|
||||
@@ -2869,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
|
||||
@@ -2922,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)
|
||||
@@ -2941,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
|
||||
@@ -2993,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)
|
||||
@@ -3011,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
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
Imports System.Net.Http.Headers
|
||||
Imports System.Net.Sockets
|
||||
Imports System.Runtime.CompilerServices
|
||||
Imports System.Security.Policy
|
||||
Imports System.Threading.Tasks
|
||||
Imports CacheCow.Client
|
||||
|
||||
Public Module ModNet
|
||||
|
||||
@@ -75,6 +73,11 @@ Retry:
|
||||
Catch ex As ThreadInterruptedException
|
||||
Throw
|
||||
Catch ex As Exception
|
||||
If TypeOf ex Is ResponsedWebException Then
|
||||
If CType(ex, ResponsedWebException).StatusCode = HttpStatusCode.Forbidden Then Throw
|
||||
If CType(ex, ResponsedWebException).StatusCode = 429 Then Thread.Sleep(10000) 'Too Many Requests
|
||||
End If
|
||||
'重试
|
||||
Select Case RetryCount
|
||||
Case 0
|
||||
RetryException = ex
|
||||
@@ -245,8 +248,20 @@ RequestFinished:
|
||||
SecretHeadersSign(Url, Request, SimulateBrowserHeaders)
|
||||
'DNS 解析
|
||||
CancelToken = New CancellationTokenSource(Timeout)
|
||||
HostIp = DnsLookup(Request, CancelToken)
|
||||
HostIp = DNSLookup(Request, CancelToken)
|
||||
If HostIp IsNot Nothing AndAlso Not IPReliability.ContainsKey(HostIp) Then
|
||||
IPReliability(HostIp) = -0.01 '预先降低一点,这样快速的重复请求会使用不同的 IP 以提高成功率
|
||||
End If
|
||||
'发送请求
|
||||
SyncLock RequestClientLock
|
||||
'延迟初始化,以避免在程序启动前加载 CacheCow 导致 DLL 加载失败
|
||||
If RequestClient Is Nothing Then
|
||||
RequestClient = CacheCow.Client.ClientExtensions.CreateClient(New CacheCow.Client.FileCacheStore.FileStore(PathTemp & "Cache/Http/"), New HttpClientHandler With {
|
||||
.AutomaticDecompression = DecompressionMethods.Deflate Or DecompressionMethods.GZip Or DecompressionMethods.None,
|
||||
.UseCookies = False '不设为 False 就不能从 Header 手动传入 Cookies
|
||||
})
|
||||
End If
|
||||
End SyncLock
|
||||
Response = RequestClient.SendAsync(Request, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetAwaiter().GetResult()
|
||||
Dim ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult()
|
||||
Dim ResponseBytes As Byte()
|
||||
@@ -263,18 +278,18 @@ RequestFinished:
|
||||
Dim ResponseMessage = If(Encoding, Encoding.UTF8).GetString(ResponseBytes)
|
||||
Throw New ResponsedWebException(
|
||||
$"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Method},{Url},{HostIp}" &
|
||||
If(String.IsNullOrEmpty(ResponseMessage), "", vbCrLf & ResponseMessage), ResponseMessage)
|
||||
If(String.IsNullOrEmpty(ResponseMessage), "", vbCrLf & ResponseMessage), Response.StatusCode, ResponseMessage)
|
||||
End If
|
||||
Catch ex As ThreadInterruptedException
|
||||
Throw
|
||||
Catch ex As ResponsedWebException
|
||||
Throw
|
||||
Catch ex As DnsLookupException
|
||||
Throw
|
||||
Catch ex As Exception
|
||||
RecordIPReliability(HostIp, -1)
|
||||
If TypeOf ex Is OperationCanceledException Then 'CancellationToken 超时
|
||||
Throw New WebException($"连接服务器超时,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},{HostIp})", WebExceptionStatus.Timeout)
|
||||
Throw New WebException($"连接服务器超时,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout)
|
||||
ElseIf ex.IsNetworkRelated Then
|
||||
Throw New WebException($"网络请求失败,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout)
|
||||
Else
|
||||
Throw New Exception($"网络请求出现意外异常({Method}, {Url},{HostIp})", ex)
|
||||
End If
|
||||
@@ -284,17 +299,15 @@ RequestFinished:
|
||||
Response?.Dispose()
|
||||
End Try
|
||||
End Function
|
||||
Private RequestClient As HttpClient = ClientExtensions.CreateClient(New FileCacheStore.FileStore(PathTemp & "Cache/Http/"), New HttpClientHandler With {
|
||||
.AutomaticDecompression = DecompressionMethods.Deflate Or DecompressionMethods.GZip Or DecompressionMethods.None,
|
||||
.UseCookies = False '不设为 False 就不能从 Header 手动传入 Cookies
|
||||
})
|
||||
Private RequestClient As HttpClient = Nothing
|
||||
Private RequestClientLock As New Object
|
||||
|
||||
''' <summary>
|
||||
''' 进行 DNS 解析。它仅在选择的 IP 与系统默认的不一致时才对 URL 中的 Host 进行替换。
|
||||
''' 返回请求时应使用的 IP;若为 IPv6,则加上了方括号。
|
||||
''' 若解析失败,则返回 Nothing。
|
||||
''' </summary>
|
||||
''' <exception cref="DnsLookupException"></exception>
|
||||
Private Function DnsLookup(Request As HttpRequestMessage, CancelToken As CancellationTokenSource) As String
|
||||
Private Function DNSLookup(Request As HttpRequestMessage, CancelToken As CancellationTokenSource) As String
|
||||
Dim GetIPReliability = Function(Key) IPReliability.GetOrDefault(Key.ToString, 0)
|
||||
'初步 DNS 解析
|
||||
Dim Host = Request.RequestUri.Host
|
||||
@@ -303,10 +316,14 @@ RequestFinished:
|
||||
DnsTask = Dns.GetHostAddressesAsync(Host)
|
||||
DnsTask.Wait(CancelToken.Token)
|
||||
Catch ex As Exception
|
||||
Throw New DnsLookupException($"DNS 解析失败,请检查你的网络连接({Host})", ex)
|
||||
Log(ex, $"DNS 解析失败({Host})")
|
||||
Return Nothing
|
||||
End Try
|
||||
Dim Candidates As IPAddress() = DnsTask.Result.ToArray
|
||||
If Not Candidates.Any Then Throw New DnsLookupException($"DNS 解析无结果,请检查你的网络连接({Host})")
|
||||
If Not Candidates.Any Then
|
||||
Log($"[Net] DNS 解析无结果({Host})")
|
||||
Return Nothing
|
||||
End If
|
||||
'若同时存在 IPv4 和 IPv6 地址,仅选择其中一类(因为 GFW 可能只屏蔽了 IPv4 或 IPv6)
|
||||
Dim IPv4Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetwork).ToArray
|
||||
Dim IPv6Targets = Candidates.Where(Function(i) i.AddressFamily = AddressFamily.InterNetworkV6).ToArray
|
||||
@@ -322,20 +339,19 @@ RequestFinished:
|
||||
Dim TargetIp As String = If(Target.AddressFamily = AddressFamily.InterNetworkV6, $"[{Target}]", Target.ToString)
|
||||
If Target IsNot Candidates.First Then
|
||||
'优选结果与系统默认 IP 不一致,替换域名并设置 Host 头
|
||||
If ModeDebug Then Log($"[Net] DNS 结果:{Host} → {Target},所有可能的 IP 与可靠度:{DnsTask.Result.Select(Function(i) $"{i} → {GetIPReliability(i):0.000}").Join(";")}")
|
||||
If ModeDebug Then Log($"[Net] DNS 解析结果:{Host} → {Target},所有可能的 IP 与可靠度:{DnsTask.Result.Select(Function(i) $"{i} → {GetIPReliability(i):0.000}").Join(";")}")
|
||||
Request.Headers.Host = Host
|
||||
Dim Builder As New UriBuilder(Request.RequestUri)
|
||||
Builder.Host = TargetIp
|
||||
Request.RequestUri = Builder.Uri
|
||||
End If
|
||||
If Not IPReliability.ContainsKey(TargetIp) Then IPReliability(TargetIp) = -0.01 '预先降低一点,这样快速的重复请求会使用不同的 IP 以提高成功率
|
||||
Return TargetIp
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 记录每个 IP 地址的请求可靠度。
|
||||
''' 通常取值 -1 ~ +0.5,越高越好。未尝试过的 IP 应视为 0。
|
||||
''' </summary>
|
||||
Private IPReliability As New Dictionary(Of String, Double)
|
||||
Private IPReliability As New SafeDictionary(Of String, Double)
|
||||
''' <summary>
|
||||
''' 根据请求结果,记录 IP 地址的可靠度。
|
||||
''' </summary>
|
||||
@@ -346,29 +362,22 @@ RequestFinished:
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' DNS 解析失败引发的异常。
|
||||
''' </summary>
|
||||
Private Class DnsLookupException
|
||||
Inherits Exception
|
||||
Public Sub New(Message As String, Optional InnerException As Exception = Nothing)
|
||||
MyBase.New(Message, InnerException)
|
||||
End Sub
|
||||
Public Sub New(Message As String)
|
||||
MyBase.New(Message)
|
||||
End Sub
|
||||
End Class
|
||||
''' <summary>
|
||||
''' 当网络请求失败时引发的异常。
|
||||
''' 附带 Response 属性,可用于获取远程服务器给予的回复。
|
||||
''' 当 HTTP 状态码不指示成功时引发的异常。
|
||||
''' 附带额外属性,可用于获取远程服务器给予的回复以及 HTTP 状态码。
|
||||
''' </summary>
|
||||
Public Class ResponsedWebException
|
||||
Inherits WebException
|
||||
''' <summary>
|
||||
''' HTTP 状态码。
|
||||
''' </summary>
|
||||
Public StatusCode As HttpStatusCode
|
||||
''' <summary>
|
||||
''' 远程服务器给予的回复。
|
||||
''' </summary>
|
||||
Public Overloads Property Response As String
|
||||
Public Sub New(Message As String, Response As String)
|
||||
Public Sub New(Message As String, StatusCode As HttpStatusCode, Response As String)
|
||||
MyBase.New(Message)
|
||||
Me.StatusCode = StatusCode
|
||||
Me.Response = Response
|
||||
End Sub
|
||||
End Class
|
||||
@@ -750,7 +759,7 @@ RequestFinished:
|
||||
''' </summary>
|
||||
Public Check As FileChecker
|
||||
''' <summary>
|
||||
''' 下载时是否添加浏览器 UA。
|
||||
''' 是否模拟浏览器的 UserAgent 和 Referer。
|
||||
''' </summary>
|
||||
Public SimulateBrowserHeaders As Boolean
|
||||
|
||||
@@ -969,7 +978,7 @@ StartThread:
|
||||
If ModeDebug OrElse Th.DownloadStart = 0 Then Log($"[Download] {LocalName}:开始,起始点 {Th.DownloadStart},{Th.Source.Url}")
|
||||
Dim ResultStream As Stream = Nothing, HttpRequest As HttpRequestMessage = Nothing,
|
||||
Response As HttpResponseMessage = Nothing, ResponseStream As Stream = Nothing,
|
||||
CancelToken As CancellationTokenSource = Nothing, HostIp As String = ""
|
||||
CancelToken As CancellationTokenSource = Nothing, HostIp As String = Nothing
|
||||
'部分下载源真的特别慢,并且只需要一个请求,例如 Ping 为 20s,如果增长太慢,就会造成类似 2.5s 5s 7.5s 10s 12.5s... 的极大延迟
|
||||
'延迟过长会导致某些特别慢的链接迟迟不被掐死
|
||||
Dim Timeout As Integer = Math.Min(Math.Max(ConnectAverage, 6000) * (1 + Th.Source.FailCount), 30000)
|
||||
@@ -980,7 +989,7 @@ StartThread:
|
||||
HttpRequest = New HttpRequestMessage(HttpMethod.Get, Th.Source.Url)
|
||||
SecretHeadersSign(Th.Source.Url, HttpRequest, SimulateBrowserHeaders)
|
||||
CancelToken = New CancellationTokenSource(Timeout)
|
||||
HostIp = DnsLookup(HttpRequest, CancelToken) 'DNS 预解析
|
||||
HostIp = DNSLookup(HttpRequest, CancelToken) 'DNS 预解析
|
||||
If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New RangeHeaderValue(Th.DownloadStart, Nothing)
|
||||
Dim ContentLength As Long = 0
|
||||
Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetAwaiter().GetResult()
|
||||
@@ -989,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
|
||||
@@ -1031,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
|
||||
@@ -1052,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
|
||||
@@ -1126,7 +1130,7 @@ SourceBreak:
|
||||
RecordIPReliability(HostIp, 0.5)
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log($"[Download] {LocalName}:出错,{If(TypeOf ex Is OperationCanceledException, $"已超时({Timeout}ms)", ex.GetDetail())},{HostIp}")
|
||||
Log($"[Download] {LocalName}:出错,{If(TypeOf ex Is OperationCanceledException, $"已超时({Timeout}ms)", ex.GetDetail())},IP:{HostIp}")
|
||||
RecordIPReliability(HostIp, -0.7)
|
||||
SourceFail(Th, ex, False)
|
||||
Finally
|
||||
@@ -1156,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
|
||||
'当一个下载源有多个线程在下载时,只选择其中一个线程进行后续处理
|
||||
@@ -1171,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
|
||||
@@ -1182,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()
|
||||
@@ -1379,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>
|
||||
@@ -1864,7 +1876,7 @@ Retry:
|
||||
End Sub
|
||||
Private IsManagerStarted As Boolean = False
|
||||
|
||||
'Public FileRemainList As New List(Of String)
|
||||
Private DownloadCacheLock As New Object
|
||||
Private IsDownloadCacheCleared As Boolean = False
|
||||
''' <summary>
|
||||
''' 开始一个下载任务。
|
||||
@@ -1872,15 +1884,18 @@ Retry:
|
||||
Public Sub Start(Task As LoaderDownload)
|
||||
StartManager()
|
||||
'清理缓存
|
||||
If Not IsDownloadCacheCleared Then
|
||||
Try
|
||||
DeleteDirectory(PathTemp & "Download")
|
||||
Catch ex As Exception
|
||||
Log(ex, "清理下载缓存失败")
|
||||
End Try
|
||||
SyncLock DownloadCacheLock '防止同时开启多个下载任务时重复清理
|
||||
If Not IsDownloadCacheCleared Then
|
||||
Try
|
||||
Log("[Net] 开始清理下载缓存")
|
||||
DeleteDirectory(PathTemp & "Download")
|
||||
Log("[Net] 下载缓存已清理")
|
||||
Catch ex As Exception
|
||||
Log(ex, "清理下载缓存失败")
|
||||
End Try
|
||||
End If
|
||||
IsDownloadCacheCleared = True
|
||||
End If
|
||||
Directory.CreateDirectory(PathTemp & "Download")
|
||||
End SyncLock
|
||||
'文件处理
|
||||
SyncLock LockFiles
|
||||
'添加每个文件
|
||||
@@ -1959,11 +1974,12 @@ Retry:
|
||||
''' 判断某个 Exception 是否为网络问题所导致。
|
||||
''' </summary>
|
||||
<Extension> Public Function IsNetworkRelated(Ex As Exception) As Boolean
|
||||
If TypeOf Ex Is DnsLookupException Then Return True
|
||||
Dim Detail = Ex.GetDetail()
|
||||
If Detail.Contains("(403)") Then Return False
|
||||
Return {"(408)", "超时", "timeout", "网络请求失败", "连接尝试失败", "远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝"}.
|
||||
Any(Function(k) Detail.ContainsF(k, True))
|
||||
Return {
|
||||
"(408)", "超时", "timeout", "网络请求失败", "连接尝试失败", "远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称",
|
||||
"由于目标计算机积极拒绝", "基础连接已经关闭"
|
||||
}.Any(Function(k) Detail.ContainsF(k, True))
|
||||
End Function
|
||||
|
||||
End Module
|
||||
@@ -148,7 +148,7 @@ End Class
|
||||
''' </summary>
|
||||
Public Class ValidateExcept
|
||||
Inherits Validate
|
||||
Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
|
||||
Public Property Excepts As New ObjectModel.Collection(Of String)
|
||||
Public Property ErrorMessage As String
|
||||
Public Sub New()
|
||||
ErrorMessage = "输入内容不能包含 %"
|
||||
@@ -157,12 +157,15 @@ Public Class ValidateExcept
|
||||
Me.Excepts = Excepts
|
||||
Me.ErrorMessage = ErrorMessage
|
||||
End Sub
|
||||
Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能包含 %")
|
||||
Me.Excepts = New ObjectModel.Collection(Of String)
|
||||
Me.ErrorMessage = ErrorMessage
|
||||
For Each Data As String In Excepts
|
||||
Me.Excepts.Add(Data)
|
||||
Next
|
||||
Public Sub New(Excepts As IEnumerable(Of String), Optional ErrorMessage As String = "输入内容不能包含 %")
|
||||
Me.New(
|
||||
New ObjectModel.Collection(Of String)(New List(Of String)(Excepts)),
|
||||
ErrorMessage)
|
||||
End Sub
|
||||
Public Sub New(Excepts As IEnumerable(Of Char), Optional ErrorMessage As String = "输入内容不能包含 %")
|
||||
Me.New(
|
||||
New ObjectModel.Collection(Of String)(Excepts.Select(Function(c) c.ToString).ToList),
|
||||
ErrorMessage)
|
||||
End Sub
|
||||
Public Overrides Function Validate(Str As String) As String
|
||||
For Each Ch As String In Excepts
|
||||
@@ -181,7 +184,7 @@ End Class
|
||||
''' </summary>
|
||||
Public Class ValidateExceptSame
|
||||
Inherits Validate
|
||||
Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
|
||||
Public Property Excepts As New ObjectModel.Collection(Of String)
|
||||
Public Property ErrorMessage As String
|
||||
Public Property IgnoreCase As Boolean = False
|
||||
Public Sub New()
|
||||
@@ -192,17 +195,14 @@ Public Class ValidateExceptSame
|
||||
Me.IgnoreCase = IgnoreCase
|
||||
End Sub
|
||||
Public Sub New(Excepts As IEnumerable(Of String), Optional ErrorMessage As String = "输入内容不能为 %", Optional IgnoreCase As Boolean = False)
|
||||
Me.Excepts = New ObjectModel.Collection(Of String)
|
||||
For Each Data As String In Excepts
|
||||
Me.Excepts.Add(Data)
|
||||
Next
|
||||
Me.ErrorMessage = ErrorMessage
|
||||
Me.IgnoreCase = IgnoreCase
|
||||
Me.New(
|
||||
New ObjectModel.Collection(Of String)(New List(Of String)(Excepts)),
|
||||
ErrorMessage, IgnoreCase)
|
||||
End Sub
|
||||
Public Sub New(Except As String, Optional ErrorMessage As String = "输入内容不能为 %", Optional IgnoreCase As Boolean = False)
|
||||
Me.Excepts = New ObjectModel.Collection(Of String) From {Except}
|
||||
Me.ErrorMessage = ErrorMessage
|
||||
Me.IgnoreCase = IgnoreCase
|
||||
Me.New(
|
||||
New ObjectModel.Collection(Of String) From {Except},
|
||||
ErrorMessage, IgnoreCase)
|
||||
End Sub
|
||||
Public Overrides Function Validate(Str As String) As String
|
||||
If Str Is Nothing Then Return ErrorMessage.Replace("%", "null")
|
||||
|
||||
@@ -871,11 +871,11 @@ NextStack:
|
||||
Sub()
|
||||
'弹窗选择:查看日志
|
||||
If File.Exists(DirectFile.Value.Key) Then
|
||||
ShellOnly(DirectFile.Value.Key)
|
||||
StartProcess(DirectFile.Value.Key)
|
||||
Else
|
||||
Dim FilePath As String = PathTemp & "Crash.txt"
|
||||
WriteFile(FilePath, Join(DirectFile.Value.Value, vbCrLf))
|
||||
ShellOnly(FilePath)
|
||||
StartProcess(FilePath)
|
||||
End If
|
||||
End Sub))
|
||||
Case 3
|
||||
@@ -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
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
If File.Exists(PathFolder & "pdf-bookmark") Then Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326
|
||||
IsJre = Not File.Exists(PathFolder & "javac.exe")
|
||||
'运行 -version
|
||||
Output = ShellAndGetOutput(PathJava, "-version", 15000).ToLower
|
||||
Output = StartProcessAndGetOutput(PathJava, "-version", 15000).ToLower
|
||||
If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败")
|
||||
If ModeDebug Then Log("[Java] Java 检查输出:" & PathJava & vbCrLf & Output)
|
||||
If Output.Contains("/lib/ext exists") Then Throw New ApplicationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试")
|
||||
@@ -445,8 +445,8 @@ NoUserJava:
|
||||
''' 将 Java 按照适用性排序。
|
||||
''' </summary>
|
||||
Public Function JavaSorter(Left As JavaEntry, Right As JavaEntry) As Boolean
|
||||
Dim PathInfo As New DirectoryInfo(ShortenPath(Path))
|
||||
Dim PathMcInfo As New DirectoryInfo(ShortenPath(PathMcFolder))
|
||||
Dim PathInfo As New DirectoryInfo(Path)
|
||||
Dim PathMcInfo As New DirectoryInfo(PathMcFolder)
|
||||
'1. 尽量在当前文件夹或当前 Minecraft 文件夹
|
||||
Dim ProgramPathParent As String, MinecraftPathParent As String = ""
|
||||
ProgramPathParent = If(PathInfo.Parent, PathInfo).FullName
|
||||
@@ -646,7 +646,7 @@ Wait:
|
||||
Private Sub JavaSearchFolder(OriginalPath As String, ByRef Results As Dictionary(Of String, Boolean), Source As Boolean, Optional IsFullSearch As Boolean = False)
|
||||
Try
|
||||
Log("[Java] 开始" & If(IsFullSearch, "完全", "部分") & "遍历查找:" & OriginalPath)
|
||||
JavaSearchFolder(New DirectoryInfo(ShortenPath(OriginalPath)), Results, Source, IsFullSearch)
|
||||
JavaSearchFolder(New DirectoryInfo(OriginalPath), Results, Source, IsFullSearch)
|
||||
Catch ex As UnauthorizedAccessException
|
||||
Log("[Java] 遍历查找 Java 时遭遇无权限的文件夹:" & OriginalPath)
|
||||
Catch ex As Exception
|
||||
|
||||
@@ -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("$$")
|
||||
@@ -695,7 +695,7 @@ LoginFinish:
|
||||
'发送登录请求
|
||||
Dim RequestData As New JObject(
|
||||
New JProperty("accessToken", AccessToken), New JProperty("clientToken", ClientToken), New JProperty("requestUser", True))
|
||||
NetRequestByClient(
|
||||
NetRequestByClientRetry(
|
||||
Data.Input.BaseUrl & "/validate", HttpMethod.Post,
|
||||
Content:=RequestData.ToString(Newtonsoft.Json.Formatting.None),
|
||||
Headers:={{"Accept-Language", "zh-CN"}},
|
||||
@@ -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 Result
|
||||
Result = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\bin\natives"
|
||||
If Result.IsASCII() Then Return Result
|
||||
Return OsDrive & "ProgramData\PCL\natives"
|
||||
If Not (IsGBKEncoding OrElse Result.IsASCII()) Then
|
||||
Result = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\bin\natives"
|
||||
If Not Result.IsASCII() Then
|
||||
Result = OsDrive & "ProgramData\PCL\natives"
|
||||
End If
|
||||
End If
|
||||
Directory.CreateDirectory(Result) '提前创建,这样 ShortenPath 才有结果(否则在长路径下首次启动 Forge 会崩溃)
|
||||
Return ShortenPath(Result)
|
||||
End Function
|
||||
|
||||
#End Region
|
||||
@@ -1981,7 +1988,7 @@ NextVersion:
|
||||
McLoginLoader.Input.Type = McLoginType.Legacy AndAlso '离线登录
|
||||
(Setup.Get("LaunchSkinType") = 2 OrElse '强制 Alex
|
||||
(Setup.Get("LaunchSkinType") = 4 AndAlso Setup.Get("LaunchSkinSlim"))) Then '或选用 Alex 皮肤
|
||||
Hint("此 Minecraft 版本尚不支持 Alex 皮肤,你的皮肤可能会显示为 Steve!", HintType.Critical)
|
||||
Hint("此 Minecraft 版本尚不支持 Alex 皮肤,你的皮肤可能会显示为 Steve!", HintType.Red)
|
||||
End If
|
||||
|
||||
'离线皮肤资源包
|
||||
@@ -2125,9 +2132,9 @@ IgnoreCustomSkin:
|
||||
|
||||
'获取自定义命令
|
||||
Dim CustomCommandGlobal As String = Setup.Get("LaunchAdvanceRun")
|
||||
If CustomCommandGlobal <> "" Then CustomCommandGlobal = ArgumentReplace(CustomCommandGlobal, True)
|
||||
If CustomCommandGlobal <> "" Then CustomCommandGlobal = ArgumentReplace(CustomCommandGlobal)
|
||||
Dim CustomCommandVersion As String = Setup.Get("VersionAdvanceRun", Version:=McVersionCurrent)
|
||||
If CustomCommandVersion <> "" Then CustomCommandVersion = ArgumentReplace(CustomCommandVersion, True)
|
||||
If CustomCommandVersion <> "" Then CustomCommandVersion = ArgumentReplace(CustomCommandVersion)
|
||||
|
||||
'输出 bat
|
||||
Try
|
||||
@@ -2159,14 +2166,15 @@ IgnoreCustomSkin:
|
||||
'执行自定义命令
|
||||
If CustomCommandGlobal <> "" Then
|
||||
McLaunchLog("正在执行全局自定义命令:" & CustomCommandGlobal)
|
||||
Dim CustomProcess As New Process
|
||||
Dim CustomProcess As Process = Nothing
|
||||
Try
|
||||
CustomProcess.StartInfo.FileName = "cmd.exe"
|
||||
CustomProcess.StartInfo.Arguments = "/c """ & CustomCommandGlobal & """"
|
||||
CustomProcess.StartInfo.WorkingDirectory = ShortenPath(PathMcFolder)
|
||||
CustomProcess.StartInfo.UseShellExecute = False
|
||||
CustomProcess.StartInfo.CreateNoWindow = True
|
||||
CustomProcess.Start()
|
||||
CustomProcess = StartProcess(New ProcessStartInfo With {
|
||||
.FileName = "cmd.exe",
|
||||
.Arguments = $"/c ""{CustomCommandGlobal}""",
|
||||
.WorkingDirectory = PathMcFolder,
|
||||
.UseShellExecute = False,
|
||||
.CreateNoWindow = True
|
||||
})
|
||||
If Setup.Get("LaunchAdvanceRunWait") Then
|
||||
Do Until CustomProcess.HasExited OrElse Loader.IsAborted
|
||||
Thread.Sleep(10)
|
||||
@@ -2175,7 +2183,7 @@ IgnoreCustomSkin:
|
||||
Catch ex As Exception
|
||||
Log(ex, "执行全局自定义命令失败", LogLevel.Hint)
|
||||
Finally
|
||||
If Not CustomProcess.HasExited AndAlso Loader.IsAborted Then
|
||||
If CustomProcess IsNot Nothing AndAlso Not CustomProcess.HasExited AndAlso Loader.IsAborted Then
|
||||
McLaunchLog("由于取消启动,已强制结束自定义命令 CMD 进程") '#1183
|
||||
CustomProcess.Kill()
|
||||
End If
|
||||
@@ -2183,14 +2191,15 @@ IgnoreCustomSkin:
|
||||
End If
|
||||
If CustomCommandVersion <> "" Then
|
||||
McLaunchLog("正在执行版本自定义命令:" & CustomCommandVersion)
|
||||
Dim CustomProcess As New Process
|
||||
Dim CustomProcess As Process = Nothing
|
||||
Try
|
||||
CustomProcess.StartInfo.FileName = "cmd.exe"
|
||||
CustomProcess.StartInfo.Arguments = "/c """ & CustomCommandVersion & """"
|
||||
CustomProcess.StartInfo.WorkingDirectory = ShortenPath(PathMcFolder)
|
||||
CustomProcess.StartInfo.UseShellExecute = False
|
||||
CustomProcess.StartInfo.CreateNoWindow = True
|
||||
CustomProcess.Start()
|
||||
CustomProcess = StartProcess(New ProcessStartInfo With {
|
||||
.FileName = "cmd.exe",
|
||||
.Arguments = $"/c ""{CustomCommandVersion}""",
|
||||
.WorkingDirectory = PathMcFolder,
|
||||
.UseShellExecute = False,
|
||||
.CreateNoWindow = True
|
||||
})
|
||||
If Setup.Get("VersionAdvanceRunWait", Version:=McVersionCurrent) Then
|
||||
Do Until CustomProcess.HasExited OrElse Loader.IsAborted
|
||||
Thread.Sleep(10)
|
||||
@@ -2199,7 +2208,7 @@ IgnoreCustomSkin:
|
||||
Catch ex As Exception
|
||||
Log(ex, "执行版本自定义命令失败", LogLevel.Hint)
|
||||
Finally
|
||||
If Not CustomProcess.HasExited AndAlso Loader.IsAborted Then
|
||||
If CustomProcess IsNot Nothing AndAlso Not CustomProcess.HasExited AndAlso Loader.IsAborted Then
|
||||
McLaunchLog("由于取消启动,已强制结束自定义命令 CMD 进程") '#1183
|
||||
CustomProcess.Kill()
|
||||
End If
|
||||
@@ -2210,7 +2219,6 @@ IgnoreCustomSkin:
|
||||
Private Sub McLaunchRun(Loader As LoaderTask(Of Integer, Process))
|
||||
|
||||
'启动信息
|
||||
Dim GameProcess = New Process()
|
||||
Dim StartInfo As New ProcessStartInfo(McLaunchJavaSelected.PathJava) '使用 javaw.exe 会导致 #6263
|
||||
|
||||
'设置环境变量
|
||||
@@ -2220,16 +2228,15 @@ IgnoreCustomSkin:
|
||||
StartInfo.EnvironmentVariables("appdata") = ShortenPath(PathMcFolder)
|
||||
|
||||
'设置其他参数
|
||||
StartInfo.WorkingDirectory = ShortenPath(McVersionCurrent.PathIndie)
|
||||
StartInfo.WorkingDirectory = McVersionCurrent.PathIndie
|
||||
StartInfo.UseShellExecute = False
|
||||
StartInfo.RedirectStandardOutput = True
|
||||
StartInfo.RedirectStandardError = True
|
||||
StartInfo.CreateNoWindow = True
|
||||
StartInfo.Arguments = McLaunchArgument
|
||||
GameProcess.StartInfo = StartInfo
|
||||
|
||||
'开始进程
|
||||
GameProcess.Start()
|
||||
Dim GameProcess = StartProcess(StartInfo)
|
||||
McLaunchLog("已启动游戏进程:" & McLaunchJavaSelected.PathJava)
|
||||
If Loader.IsAborted Then
|
||||
McLaunchLog("由于取消启动,已强制结束游戏进程") '#1631
|
||||
@@ -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
|
||||
|
||||
@@ -73,7 +73,7 @@ Public Module ModMod
|
||||
Get
|
||||
If _Name Is Nothing Then Load()
|
||||
If _Name Is Nothing Then _Name = _ModId
|
||||
If _Name Is Nothing Then _Name = GetFileNameWithoutExtentionFromPath(Path)
|
||||
If _Name Is Nothing Then _Name = IO.Path.GetFileNameWithoutExtension(Path)
|
||||
Return _Name
|
||||
End Get
|
||||
Set(value As String)
|
||||
|
||||
@@ -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
|
||||
@@ -335,7 +335,7 @@ Retry:
|
||||
File.Delete(Target)
|
||||
End If
|
||||
Next
|
||||
If File.Exists(FileAddress) AndAlso GetFileNameWithoutExtentionFromPath(FileAddress) = "modpack" Then
|
||||
If File.Exists(FileAddress) AndAlso IO.Path.GetFileNameWithoutExtension(FileAddress) = "modpack" Then
|
||||
Log("[ModPack] 删除安装整合包文件:" & FileAddress)
|
||||
File.Delete(FileAddress)
|
||||
End If
|
||||
@@ -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
|
||||
|
||||
@@ -476,7 +476,7 @@ Retry:
|
||||
File.Delete(Target)
|
||||
End If
|
||||
Next
|
||||
If File.Exists(FileAddress) AndAlso GetFileNameWithoutExtentionFromPath(FileAddress) = "modpack" Then
|
||||
If File.Exists(FileAddress) AndAlso IO.Path.GetFileNameWithoutExtension(FileAddress) = "modpack" Then
|
||||
Log("[ModPack] 删除安装整合包文件:" & FileAddress)
|
||||
File.Delete(FileAddress)
|
||||
End If
|
||||
@@ -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)("解压压缩包",
|
||||
@@ -795,7 +795,7 @@ Retry:
|
||||
Log("[Modpack] 找到压缩包中附带的启动器:" & Launcher)
|
||||
If MyMsgBox($"整合包里似乎自带了启动器,是否换用它继续安装?{vbCrLf}即将打开:{Launcher}", "换用整合包启动器?", "换用", "不换用") = 1 Then
|
||||
OpenExplorer(TargetFolder)
|
||||
ShellOnly(Launcher, "--wait") '要求等待已有的 PCL 退出
|
||||
StartProcess(Launcher, "--wait") '要求等待已有的 PCL 退出
|
||||
Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序")
|
||||
FrmMain.EndProgram(False)
|
||||
Return
|
||||
@@ -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()
|
||||
|
||||
@@ -1,129 +1,283 @@
|
||||
Public Module ModEvent
|
||||
|
||||
#Region "附加属性"
|
||||
|
||||
Public Sub TryStartEvent(Type As String, Data As String)
|
||||
If String.IsNullOrWhiteSpace(Type) Then Return
|
||||
Dim RealData As String() = {""}
|
||||
If Data IsNot Nothing Then RealData = Data.Split("|")
|
||||
StartEvent(Type, RealData)
|
||||
''' <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
|
||||
Public Sub StartEvent(Type As String, Data As String())
|
||||
<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
|
||||
|
||||
''' <summary>
|
||||
''' 触发该控件上的自定义事件。
|
||||
''' 事件会在新线程中执行。
|
||||
''' </summary>
|
||||
<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()
|
||||
For Each e In Events
|
||||
e.Raise()
|
||||
Next
|
||||
End Sub, "执行自定义事件 " & GetUuid())
|
||||
End Sub
|
||||
|
||||
End Module
|
||||
|
||||
#End 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>
|
||||
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
|
||||
Log("[Control] 执行自定义事件:" & Type & ", " & Join(Data, ", "))
|
||||
Dim Args As String() = If(Arg?.Split("|"), {""})
|
||||
Select Case Type
|
||||
|
||||
Case "打开网页"
|
||||
Data(0) = Data(0).Replace("\", "/")
|
||||
If Not Data(0).Contains("://") OrElse Data(0).StartsWithF("file", True) Then '为了支持更多协议(#2200)
|
||||
Case EventType.打开网页
|
||||
Arg = Arg.Replace("\", "/")
|
||||
If Not Arg.Contains("://") OrElse Arg.StartsWithF("file", True) Then '为了支持更多协议(#2200)
|
||||
MyMsgBox("EventData 必须为一个网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败")
|
||||
Return
|
||||
End If
|
||||
Hint("正在开启中,请稍候……")
|
||||
OpenWebsite(Data(0))
|
||||
Hint("正在开启中,请稍候:" & Arg)
|
||||
RunInThread(Sub() OpenWebsite(Arg))
|
||||
|
||||
Case "打开文件", "打开帮助", "执行命令"
|
||||
Case EventType.打开文件, EventType.打开帮助, EventType.执行命令
|
||||
RunInThread(
|
||||
Sub()
|
||||
Try
|
||||
'确认实际路径
|
||||
Dim ActualPaths = GetEventAbsoluteUrls(Data(0), Type)
|
||||
Dim ActualPaths = GetAbsoluteUrls(Args(0), Type)
|
||||
Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1)
|
||||
Log($"[Control] 打开类自定义事件实际路径:{Location},工作目录:{WorkingDir}")
|
||||
'执行
|
||||
If Type = "打开帮助" Then
|
||||
If Type = EventType.打开帮助 Then
|
||||
PageOtherHelp.EnterHelpPage(Location)
|
||||
Else
|
||||
If Not Setup.Get("HintCustomCommand") Then
|
||||
Select Case MyMsgBox(
|
||||
"即将执行:" & Location & If(Data.Length >= 2, " " & Data(1), "") & vbCrLf &
|
||||
"请在确认该操作没有安全隐患后继续。", "执行确认", "继续", "继续且今后不再要求确认", "取消")
|
||||
Case 2
|
||||
Setup.Set("HintCustomCommand", True)
|
||||
Case 3
|
||||
Return
|
||||
End Select
|
||||
End If
|
||||
If Not EventSafetyConfirm("即将执行:" & Location & If(Args.Length >= 2, " " & Args(1), "")) Then Return
|
||||
Dim Info As New ProcessStartInfo With {
|
||||
.Arguments = If(Data.Length >= 2, Data(1), ""),
|
||||
.Arguments = If(Args.Length >= 2, Args(1), ""),
|
||||
.FileName = Location,
|
||||
.WorkingDirectory = ShortenPath(WorkingDir)
|
||||
.WorkingDirectory = WorkingDir
|
||||
}
|
||||
Process.Start(Info)
|
||||
StartProcess(Info)
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "执行打开类自定义事件失败", LogLevel.Msgbox)
|
||||
End Try
|
||||
End Sub)
|
||||
|
||||
Case "启动游戏"
|
||||
If Data(0) = "\current" Then
|
||||
Case EventType.启动游戏
|
||||
If Args(0) = "\current" Then
|
||||
If McVersionCurrent Is Nothing Then
|
||||
Hint("请先选择一个 Minecraft 版本!", HintType.Critical)
|
||||
Hint("请先选择一个 Minecraft 版本!", HintType.Red)
|
||||
Return
|
||||
Else
|
||||
Data(0) = McVersionCurrent.Name
|
||||
Args(0) = McVersionCurrent.Name
|
||||
End If
|
||||
End If
|
||||
If McLaunchStart(New McLaunchOptions With
|
||||
{.ServerIp = If(Data.Length >= 2, Data(1), Nothing), .Version = New McVersion(Data(0))}) Then
|
||||
Hint("正在启动 " & Data(0) & "……")
|
||||
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 "复制文本"
|
||||
ClipboardSet(Join(Data, "|"))
|
||||
Case EventType.刷新帮助
|
||||
RunInUiWait(Sub() PageOtherLeft.RefreshHelp())
|
||||
If String.IsNullOrEmpty(Arg) Then Hint("已刷新!", HintType.Green)
|
||||
|
||||
Case "刷新主页"
|
||||
FrmLaunchRight.ForceRefresh()
|
||||
If Data(0) = "" Then Hint("已刷新主页!", HintType.Finish)
|
||||
|
||||
Case "刷新帮助"
|
||||
PageOtherLeft.RefreshHelp()
|
||||
|
||||
Case "今日人品"
|
||||
Case EventType.今日人品
|
||||
PageOtherTest.Jrrp()
|
||||
|
||||
Case "内存优化"
|
||||
Case EventType.内存优化
|
||||
RunInThread(Sub() PageOtherTest.MemoryOptimize(True))
|
||||
|
||||
Case "清理垃圾"
|
||||
Case EventType.清理垃圾
|
||||
RunInThread(Sub() PageOtherTest.RubbishClear())
|
||||
|
||||
Case "弹出窗口"
|
||||
MyMsgBox(Data(1).Replace("\n", vbCrLf), Data(0).Replace("\n", vbCrLf))
|
||||
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 "切换页面"
|
||||
FrmMain.PageChange(Val(Data(0)), Val(Data(1)))
|
||||
Case EventType.弹出提示
|
||||
Hint(Args(0).Replace("\n", vbCrLf), If(Args.Length = 1, HintType.Blue, Args(1).ParseToEnum(Of HintType)))
|
||||
|
||||
Case "导入整合包", "安装整合包"
|
||||
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 "下载文件"
|
||||
Data(0) = Data(0).Replace("\", "/")
|
||||
If Not (Data(0).StartsWithF("http://", True) OrElse Data(0).StartsWithF("https://", True)) Then
|
||||
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 Data.Length
|
||||
Select Case Args.Length
|
||||
Case 1
|
||||
PageOtherTest.StartCustomDownload(Data(0), GetFileNameFromPath(Data(0)))
|
||||
PageOtherTest.StartCustomDownload(Args(0), GetFileNameFromPath(Args(0)))
|
||||
Case 2
|
||||
PageOtherTest.StartCustomDownload(Data(0), Data(1))
|
||||
PageOtherTest.StartCustomDownload(Args(0), Args(1))
|
||||
Case Else
|
||||
PageOtherTest.StartCustomDownload(Data(0), Data(1), Data(2))
|
||||
PageOtherTest.StartCustomDownload(Args(0), Args(1), Args(2))
|
||||
End Select
|
||||
Catch
|
||||
PageOtherTest.StartCustomDownload(Data(0), "未知")
|
||||
PageOtherTest.StartCustomDownload(Args(0), "未知")
|
||||
End Try
|
||||
|
||||
Case "修改设置"
|
||||
Setup.Set(Data(0), Data(1))
|
||||
Hint($"已写入设置:{Data(0)} → {Data(1)}", HintType.Finish)
|
||||
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, "事件执行失败", LogLevel.Msgbox)
|
||||
Log(ex, $"事件执行失败({Type}, {Arg})", LogLevel.Msgbox)
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
@@ -131,7 +285,7 @@
|
||||
''' 返回自定义事件的绝对 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
|
||||
@@ -172,25 +326,25 @@
|
||||
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)
|
||||
@@ -199,4 +353,20 @@
|
||||
Return {Location, WorkingDir}
|
||||
End Function
|
||||
|
||||
End Module
|
||||
''' <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
|
||||
@@ -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 "任务缓存"
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
If MusicState = MusicStates.Pause Then
|
||||
FrmMain.BtnExtraMusic.Logo = Logo.IconPlay
|
||||
FrmMain.BtnExtraMusic.LogoScale = 0.8
|
||||
ToolTipText = "已暂停:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
|
||||
ToolTipText = "已暂停:" & IO.Path.GetFileNameWithoutExtension(MusicCurrent)
|
||||
If MusicAllList.Count > 1 Then
|
||||
ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。"
|
||||
Else
|
||||
@@ -88,7 +88,7 @@
|
||||
Else
|
||||
FrmMain.BtnExtraMusic.Logo = Logo.IconMusic
|
||||
FrmMain.BtnExtraMusic.LogoScale = 1
|
||||
ToolTipText = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
|
||||
ToolTipText = "正在播放:" & IO.Path.GetFileNameWithoutExtension(MusicCurrent)
|
||||
If MusicAllList.Count > 1 Then
|
||||
ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。"
|
||||
Else
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
@@ -81,13 +83,14 @@ Friend Module ModSecret
|
||||
''' 设置 Headers 的 UA、Referer。
|
||||
''' </summary>
|
||||
Friend Sub SecretHeadersSign(Url As String, ByRef Req As HttpRequestMessage, Optional SimulateBrowserHeaders As Boolean = False)
|
||||
If Req.Headers.UserAgent.Any Then Return
|
||||
If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then
|
||||
Req.Headers.Add("User-Agent", "LogStatistic") '#4951
|
||||
ElseIf SimulateBrowserHeaders Then
|
||||
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36")
|
||||
Else
|
||||
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode}")
|
||||
If Not Req.Headers.UserAgent.Any Then
|
||||
If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then
|
||||
Req.Headers.Add("User-Agent", "LogStatistic") '#4951
|
||||
ElseIf SimulateBrowserHeaders Then
|
||||
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36")
|
||||
Else
|
||||
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode}")
|
||||
End If
|
||||
End If
|
||||
If Not SimulateBrowserHeaders Then Req.Headers.Add("Referer", $"http://{VersionCode}.open.pcl2.server/")
|
||||
If Url.Contains("api.curseforge.com") Then Req.Headers.Add("x-api-key", CurseForgeAPIKey)
|
||||
|
||||
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
|
||||
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
||||
' 方法是按如下所示使用“*”
|
||||
|
||||
<Assembly: AssemblyVersion("2.10.7.0")>
|
||||
<Assembly: AssemblyFileVersion("2.10.7.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}"
|
||||
@@ -424,8 +424,8 @@
|
||||
If(File.FileName.EndsWith(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder)
|
||||
If Not Target.Contains("\") Then Return
|
||||
'构造步骤加载器
|
||||
Dim LoaderName As String = Desc & "下载:" & GetFileNameWithoutExtentionFromPath(Target) & " "
|
||||
If Target <> DefaultFolder Then CachedFolder(Project.Type) = GetPathFromFullPath(Target)
|
||||
Dim LoaderName As String = Desc & "下载:" & IO.Path.GetFileNameWithoutExtension(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,8 +1,8 @@
|
||||
<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"
|
||||
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:PCL"
|
||||
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
|
||||
<Grid.RenderTransform>
|
||||
<TransformGroup>
|
||||
<RotateTransform x:Name="TransformRotate" Angle="-4" />
|
||||
@@ -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==&action=getalbum&album_id=2585385685407514625&scene=173&from_msgid=2247483720&from_itemidx=1&count=3&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,287 +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="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="李小浩&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>
|
||||
@@ -394,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>
|
||||
@@ -409,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. 计算机软件著作权登记号:2020SR0875133 违法违规行为举报投诉邮箱:[email protected] 非 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>
|
||||
@@ -442,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
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
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 ([email protected])
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
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.TryStartEvent(Entry.EventType, Entry.EventData)
|
||||
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、资源包等均不互通。
这会导致不同原版版本间的存档不能共用,所以一般不推荐。" />
|
||||
</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="自定义游戏窗口的标题,若留空则不进行更改。
支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {name}:游戏版本名
 · {date}、{time}:当前的系统时间
 · {version}:游戏对应的原版版本号" HintText="默认" MaxLength="100" />
|
||||
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则不进行更改。
你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" 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 调试页面的左上角。
你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。">
|
||||
<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 参数,除非有确定把握,否则请不要修改。
支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。" MaxLength="4000"
|
||||
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.ColumnSpan="2" Tag="LaunchAdvanceJvm" Grid.Column="1" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,除非有确定把握,否则请不要修改。

支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。
也支持使用 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="文本框中的内容将会被直接拼合在启动参数的末尾。
例如,输入 --demo 则会以试玩模式启动游戏。
支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。" />
|
||||
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="LaunchAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。
例如,输入 --demo 则会以试玩模式启动游戏。

支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。
也支持使用 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 的命令提示符一致。

可以使用以下替换标记实现相对路径(路径均以 \ 结尾):
 · {path}:PCL 的 exe 文件所在的文件夹
 · {minecraft}:.minecraft 文件夹
 · {verpath}:版本文件夹(.minecraft\versions\版本名\)
 · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹
 · {java}:游戏运行时的 Java 文件夹

除此之外,也支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {uuid}:玩家的 UUID
 · {name}:游戏版本名
 · {date}、{time}:当前的系统时间
 · {version}:游戏对应的原版版本号

例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
|
||||
ToolTip="在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .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="你可以用替换标记动态改变网址,以传入参数或变量。
在 更多 → 帮助 中搜索 “替换标记” 以了解用法。">
|
||||
<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
|
||||
|
||||
@@ -344,14 +344,11 @@ Public Class MyLocalModItem
|
||||
End If
|
||||
'标题与描述
|
||||
Dim DescFileName As String
|
||||
Select Case Entry.State
|
||||
Case McMod.McModState.Fine
|
||||
DescFileName = GetFileNameWithoutExtentionFromPath(Entry.Path)
|
||||
Case McMod.McModState.Disabled
|
||||
DescFileName = GetFileNameWithoutExtentionFromPath(Entry.Path.Replace(".disabled", "").Replace(".old", ""))
|
||||
Case Else 'McMod.McModState.Unavailable
|
||||
DescFileName = GetFileNameFromPath(Entry.Path)
|
||||
End Select
|
||||
If Entry.State = McMod.McModState.Fine OrElse Entry.State = McMod.McModState.Disabled Then
|
||||
DescFileName = IO.Path.GetFileNameWithoutExtension(Entry.Path)
|
||||
Else
|
||||
DescFileName = GetFileNameFromPath(Entry.Path)
|
||||
End If
|
||||
Dim NewDescription As String
|
||||
If Setup.Get("ToolModLocalNameStyle") = 1 Then
|
||||
'标题显示文件名,详情显示译名
|
||||
|
||||
@@ -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.AllDialogs, FileIO.RecycleOption.SendToRecycleBin)
|
||||
Hint("版本 " & PageVersionLeft.Version.Name & " 已删除到回收站!", HintType.Finish)
|
||||
Hint("版本 " & PageVersionLeft.Version.Name & " 已删除到回收站!", HintType.Green)
|
||||
End If
|
||||
Case 2
|
||||
Return
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
ToolTip="与其余关闭隔离的版本共享存档、Mod 等文件。
若存在多个安装了 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="自定义游戏窗口的标题,若留空则跟随全局设置的值。
支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {name}:游戏版本名
 · {date}、{time}:当前的系统时间
 · {version}:游戏对应的原版版本号" HintText="跟随全局设置" MaxLength="100" />
|
||||
<local:MyTextBox x:Name="TextArgumentTitle" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionArgumentTitle" Grid.Column="1" ToolTip="自定义游戏窗口的标题,若留空则跟随全局设置的值。
你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。" 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 调试页面的左上角。
若留空,则跟随全局设置的值。">
|
||||
<local:MyTextBox x:Name="TextArgumentInfo" Grid.Row="4" Grid.ColumnSpan="2" Tag="VersionArgumentInfo" Grid.Column="1" HintText="跟随全局设置" ToolTip="该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。
若留空,则跟随全局设置的值。

你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。">
|
||||
<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 参数,在没有确定把握的情况下请不要尝试修改。
支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。

若留空,则跟随全局设置的值。" HintText="跟随全局设置"
|
||||
<local:MyTextBox x:Name="TextAdvanceJvm" Grid.Row="0" Grid.ColumnSpan="2" Tag="VersionAdvanceJvm" Grid.Column="1" MaxLength="4000" ToolTip="启动 Minecraft 时使用的额外 JVM 参数,在没有确定把握的情况下请不要尝试修改。

支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。
也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。

若留空,则跟随全局设置的值。" 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="文本框中的内容将会被直接拼合在启动参数的末尾。
例如,输入 --demo 则会以试玩模式启动游戏。
支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。

若留空,则跟随全局设置的值。" HintText="跟随全局设置" />
|
||||
<local:MyTextBox x:Name="TextAdvanceGame" Grid.Row="2" Grid.ColumnSpan="2" Tag="VersionAdvanceGame" Grid.Column="1" ToolTip="文本框中的内容将会被直接拼合在启动参数的末尾。
例如,输入 --demo 则会以试玩模式启动游戏。

支持 Minecraft 版本 JSON 中的字符串替换标记,例如 ${library_directory}。
也支持使用 PCL 的替换标记,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。

若留空,则跟随全局设置的值。" 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="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。

在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

可以使用以下替换标记实现相对路径(路径均以 \ 结尾):
 · {path}:PCL 的 exe 文件所在的文件夹
 · {minecraft}:.minecraft 文件夹
 · {verpath}:版本文件夹(.minecraft\versions\版本名\)
 · {verindie}:开启版本隔离时等同版本文件夹,未开启时等同 .minecraft 文件夹
 · {java}:游戏运行时的 Java 文件夹

除此之外,也支持以下替换标记:
 · {user}:玩家名字
 · {login}:玩家的登录方式
 · {uuid}:玩家的 UUID
 · {name}:游戏版本名
 · {date}、{time}:当前的系统时间
 · {version}:游戏对应的原版版本号

例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .minecraft 文件夹。" />
|
||||
ToolTip="该项不会覆盖全局设置:启动时会先执行全局设置的命令,再执行版本设置的命令。

在 MC 启动前执行特定命令或程序,语法与 Windows 的命令提示符一致。

你可以用替换标记来动态改变其内容或实现相对路径,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。例如:
 · "{verpath}test.exe" :运行版本文件夹下的 test.exe 程序
 · "{java}java.exe" -jar "{verpath}test.jar" :用 Java 运行版本文件夹下的 test.jar
 · notepad "{verindie}options.txt" :使用记事本打开该版本的设置文件

涉及路径的操作最好都打上双引号,以避免路径中的空格导致运行失败。
执行命令时,命令行所在的目录是当前的 .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" />
|
||||
|
||||
@@ -53,99 +53,37 @@
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
|
||||
<local:MyCard Title="事件 1:打开网页、弹出窗口" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
|
||||
<StackPanel Margin="25,40,23,15">
|
||||
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10"
|
||||
<local:MyCard Title="自定义事件" Margin="0,0,0,15" CanSwap="True" IsSwapped="True">
|
||||
<StackPanel Margin="25,40,23,15">
|
||||
<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"
|
||||
<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/" />
|
||||
</StackPanel>
|
||||
<local:MyTextButton Margin="0,8,0,0" HorizontalAlignment="Center"
|
||||
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="启动当前版本" />
|
||||
</StackPanel>
|
||||
<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。
点击按钮会打开文件管理器,并且借助参数要求它选中这个文件。" />
|
||||
</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 的链接中的文件
 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)
 EventData 为 页面种类|次要页面种类(PageType|PageSubType,例如 1|1)
 点击上方的 查看 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="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 在一行里塞下多个按钮。你可以仅在这个教学卡片的基础上稍作调整,来实现自己的按钮布局。" />
|
||||
@@ -183,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>
|
||||
|
||||
@@ -246,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 会在加载时对其进行替换。
例如,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.
Reference in new issue
Block a user