2.6.4
This commit is contained in:
@@ -41,8 +41,11 @@ Public Class Application
|
||||
MsgBox(ex.Message, MsgBoxStyle.Critical, "内存优化失败")
|
||||
Environment.Exit(-1)
|
||||
End Try
|
||||
Ram = My.Computer.Info.AvailablePhysicalMemory - Ram
|
||||
Environment.Exit(Math.Max(0, Ram / 1024)) '返回清理的内存量(K)
|
||||
If My.Computer.Info.AvailablePhysicalMemory < Ram Then '避免 ULong 相减出现负数
|
||||
Environment.Exit(0)
|
||||
Else
|
||||
Environment.Exit((My.Computer.Info.AvailablePhysicalMemory - Ram) / 1024) '返回清理的内存量(K)
|
||||
End If
|
||||
#If DEBUG Then
|
||||
ElseIf e.Args(0) = "--make" Then
|
||||
'制作更新包
|
||||
@@ -71,7 +74,8 @@ Public Class Application
|
||||
Directory.CreateDirectory(PathAppdata)
|
||||
'检测单例
|
||||
#If Not DEBUG Then
|
||||
Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher 2 ")
|
||||
Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher ")
|
||||
If WindowHwnd = IntPtr.Zero Then FindWindow(Nothing, "Plain Craft Launcher 2 ")
|
||||
If WindowHwnd <> IntPtr.Zero Then
|
||||
'将已有的 PCL 窗口拖出来
|
||||
ShowWindowToTop(WindowHwnd)
|
||||
|
||||
@@ -134,23 +134,21 @@
|
||||
|
||||
'实现自定义事件
|
||||
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
|
||||
If IsMouseDown Then
|
||||
Log("[Control] 按下按钮:" & Text)
|
||||
RaiseEvent Click(sender, e)
|
||||
If Not String.IsNullOrEmpty(Tag) Then
|
||||
If Tag.ToString.StartsWith("链接-") OrElse Tag.ToString.StartsWith("启动-") Then
|
||||
Hint("主页自定义按钮语法已更新,且不再兼容老版本语法,请查看新的自定义示例!")
|
||||
End If
|
||||
If Not IsMouseDown Then Exit Sub
|
||||
Log("[Control] 按下按钮:" & Text)
|
||||
RaiseEvent Click(sender, e)
|
||||
If Not String.IsNullOrEmpty(Tag) Then
|
||||
If Tag.ToString.StartsWith("链接-") OrElse Tag.ToString.StartsWith("启动-") Then
|
||||
Hint("主页自定义按钮语法已更新,且不再兼容老版本语法,请查看新的自定义示例!")
|
||||
End If
|
||||
ModEvent.TryStartEvent(EventType, EventData)
|
||||
End If
|
||||
ModEvent.TryStartEvent(EventType, EventData)
|
||||
End Sub
|
||||
Public Property EventType As String
|
||||
Get
|
||||
Return GetValue(EventTypeProperty)
|
||||
End Get
|
||||
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
SetValue(EventTypeProperty, value)
|
||||
End Set
|
||||
End Property
|
||||
@@ -159,8 +157,7 @@
|
||||
Get
|
||||
Return GetValue(EventDataProperty)
|
||||
End Get
|
||||
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
SetValue(EventDataProperty, value)
|
||||
End Set
|
||||
End Property
|
||||
|
||||
@@ -166,7 +166,9 @@
|
||||
End Sub
|
||||
|
||||
'事件
|
||||
Public Property HasMouseAnimation As Boolean = True
|
||||
Private Sub MyCard_MouseEnter(sender As Object, e As MouseEventArgs) Handles Me.MouseEnter
|
||||
If Not HasMouseAnimation Then Exit Sub
|
||||
Dim AniList As New List(Of AniData)
|
||||
If Not IsNothing(MainTextBlock) Then AniList.Add(AaColor(MainTextBlock, TextBlock.ForegroundProperty, "ColorBrush2", 150))
|
||||
If Not IsNothing(MainSwap) Then AniList.Add(AaColor(MainSwap, Shapes.Path.FillProperty, "ColorBrush2", 150))
|
||||
@@ -178,6 +180,7 @@
|
||||
AniStart(AniList, "MyCard Mouse " & Uuid)
|
||||
End Sub
|
||||
Private Sub MyCard_MouseLeave(sender As Object, e As MouseEventArgs) Handles Me.MouseLeave
|
||||
If Not HasMouseAnimation Then Exit Sub
|
||||
Dim AniList As New List(Of AniData)
|
||||
If Not IsNothing(MainTextBlock) Then AniList.Add(AaColor(MainTextBlock, TextBlock.ForegroundProperty, "ColorBrush1", 250))
|
||||
If Not IsNothing(MainSwap) Then AniList.Add(AaColor(MainSwap, Shapes.Path.FillProperty, "ColorBrush1", 250))
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
Get
|
||||
Return _CanRightClick
|
||||
End Get
|
||||
Set(ByVal value As Boolean)
|
||||
Set(value As Boolean)
|
||||
_CanRightClick = value
|
||||
End Set
|
||||
End Property
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
Get
|
||||
Return LabText.Text
|
||||
End Get
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
LabText.Text = value
|
||||
End Set
|
||||
End Property
|
||||
@@ -43,7 +43,7 @@
|
||||
Get
|
||||
Return BtnClose.Visibility = Visibility.Visible
|
||||
End Get
|
||||
Set(ByVal value As Boolean)
|
||||
Set(value As Boolean)
|
||||
BtnClose.Visibility = If(value, Visibility.Visible, Visibility.Collapsed)
|
||||
End Set
|
||||
End Property
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<Border x:Name="PanBack" x:Class="MyIconTextButton"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path x:Name="ShapeLogo" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="White" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center" />
|
||||
<TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="7,0,12,1" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
@@ -0,0 +1,180 @@
|
||||
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 事件
|
||||
|
||||
'自定义属性
|
||||
|
||||
Public Property Logo As String
|
||||
Get
|
||||
Return ShapeLogo.Data.ToString
|
||||
End Get
|
||||
Set(value As String)
|
||||
ShapeLogo.Data = (New GeometryConverter).ConvertFromString(value)
|
||||
End Set
|
||||
End Property
|
||||
Private _LogoScale As Double = 1
|
||||
Public Property LogoScale() As Double
|
||||
Get
|
||||
Return _LogoScale
|
||||
End Get
|
||||
Set(value As Double)
|
||||
_LogoScale = value
|
||||
If Not IsNothing(ShapeLogo) Then ShapeLogo.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale}
|
||||
End Set
|
||||
End Property
|
||||
|
||||
Public Property Text As String
|
||||
Get
|
||||
Return GetValue(TextProperty)
|
||||
End Get
|
||||
Set(value As String)
|
||||
SetValue(TextProperty, value)
|
||||
End Set
|
||||
End Property '内容
|
||||
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(New PropertyChangedCallback(
|
||||
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
|
||||
If Not IsNothing(sender) Then CType(sender, MyIconTextButton).LabText.Text = e.NewValue
|
||||
End Sub)))
|
||||
Public Enum ColorState
|
||||
Black
|
||||
Highlight
|
||||
End Enum
|
||||
Private _ColorType As ColorState = ColorState.Black
|
||||
Public Property ColorType As ColorState
|
||||
Get
|
||||
Return _ColorType
|
||||
End Get
|
||||
Set(value As ColorState)
|
||||
_ColorType = value
|
||||
RefreshColor()
|
||||
End Set
|
||||
End Property '颜色类别
|
||||
|
||||
'点击事件
|
||||
|
||||
Public Event Click(sender As Object, e As RouteEventArgs)
|
||||
Private IsMouseDown As Boolean = False
|
||||
Private Sub MyIconTextButton_MouseUp() Handles Me.MouseLeftButtonUp
|
||||
If Not IsMouseDown Then Exit Sub
|
||||
Log("[Control] 按下带图标按钮:" & Text)
|
||||
IsMouseDown = False
|
||||
RaiseEvent Click(Me, New RouteEventArgs(True))
|
||||
ModEvent.TryStartEvent(EventType, EventData)
|
||||
RefreshColor()
|
||||
End Sub
|
||||
Private Sub MyIconTextButton_MouseDown() Handles Me.MouseLeftButtonDown
|
||||
IsMouseDown = True
|
||||
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))
|
||||
|
||||
'动画
|
||||
|
||||
Private Const AnimationTimeOfMouseIn As Integer = 100 '鼠标指向动画长度
|
||||
Private Const AnimationTimeOfMouseOut As Integer = 150 '鼠标移出动画长度
|
||||
Private Sub RefreshColor(Optional obj = Nothing, Optional e = Nothing) Handles Me.MouseEnter, Me.MouseLeave, Me.Loaded, Me.IsEnabledChanged
|
||||
Try
|
||||
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not False.Equals(e) Then '防止默认属性变更触发动画,若强制不执行动画,则 e 为 False
|
||||
|
||||
Select Case ColorType
|
||||
Case ColorState.Black
|
||||
If IsMouseDown Then
|
||||
'按下
|
||||
AniStart(AaColor(Me, BackgroundProperty, "ColorBrush6", 70), "MyIconTextButton Color " & Uuid)
|
||||
ElseIf IsMouseOver Then
|
||||
'指向
|
||||
AniStart({
|
||||
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseIn),
|
||||
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn)
|
||||
}, "MyIconTextButton Checked " & Uuid)
|
||||
AniStart(AaColor(Me, BackgroundProperty, "ColorBrushBg1", AnimationTimeOfMouseIn), "MyIconTextButton Color " & Uuid)
|
||||
ElseIf IsEnabled Then
|
||||
'正常
|
||||
AniStart({
|
||||
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush1", AnimationTimeOfMouseOut),
|
||||
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush1", AnimationTimeOfMouseOut)
|
||||
}, "MyIconTextButton Checked " & Uuid)
|
||||
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
|
||||
Else
|
||||
'禁用
|
||||
AniStart({
|
||||
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrushGray5", 100),
|
||||
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrushGray5", 100)
|
||||
}, "MyIconTextButton Checked " & Uuid)
|
||||
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
|
||||
End If
|
||||
Case ColorState.Highlight
|
||||
If IsMouseDown Then
|
||||
'按下
|
||||
AniStart(AaColor(Me, BackgroundProperty, "ColorBrush6", 70), "MyIconTextButton Color " & Uuid)
|
||||
ElseIf IsMouseOver Then
|
||||
'指向
|
||||
AniStart({
|
||||
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseIn),
|
||||
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn)
|
||||
}, "MyIconTextButton Checked " & Uuid)
|
||||
AniStart(AaColor(Me, BackgroundProperty, "ColorBrushBg1", AnimationTimeOfMouseIn), "MyIconTextButton Color " & Uuid)
|
||||
ElseIf IsEnabled Then
|
||||
'正常
|
||||
AniStart({
|
||||
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseOut),
|
||||
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseOut)
|
||||
}, "MyIconTextButton Checked " & Uuid)
|
||||
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
|
||||
Else
|
||||
'禁用
|
||||
AniStart({
|
||||
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrushGray5", 100),
|
||||
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrushGray5", 100)
|
||||
}, "MyIconTextButton Checked " & Uuid)
|
||||
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
|
||||
End If
|
||||
End Select
|
||||
|
||||
Else
|
||||
|
||||
'不使用动画
|
||||
AniStop("MyIconTextButton Checked " & Uuid)
|
||||
AniStop("MyIconTextButton Color " & Uuid)
|
||||
Select Case ColorType
|
||||
Case ColorState.Black
|
||||
Background = ColorSemiTransparent
|
||||
ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
|
||||
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
|
||||
Case ColorState.Highlight
|
||||
Background = ColorSemiTransparent
|
||||
ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, If(IsEnabled, "ColorBrush3", "ColorBrushGray5"))
|
||||
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush3", "ColorBrushGray5"))
|
||||
End Select
|
||||
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "刷新按钮颜色出错")
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
End Class
|
||||
@@ -15,7 +15,7 @@
|
||||
If _RectBack Is Nothing Then
|
||||
Dim Rect As New Border With {
|
||||
.Name = "RectBack",
|
||||
.CornerRadius = New CornerRadius(If(IsScaleAnimationEnabled, 6, 0)),
|
||||
.CornerRadius = New CornerRadius(If(IsScaleAnimationEnabled OrElse Height > 40, 6, 0)),
|
||||
.RenderTransform = If(IsScaleAnimationEnabled, New ScaleTransform(0.8, 0.8), Nothing),
|
||||
.RenderTransformOrigin = New Point(0.5, 0.5),
|
||||
.BorderThickness = New Thickness(GetWPFSize(1)),
|
||||
@@ -225,6 +225,7 @@
|
||||
If _Logo.ToLower.StartsWith("http") Then
|
||||
'网络图片
|
||||
PathLogo = New Image With {
|
||||
.Tag = Me,
|
||||
.IsHitTestVisible = LogoClickable,
|
||||
.Source = New ImageSourceConverter().ConvertFromString(_Logo),
|
||||
.RenderTransformOrigin = New Point(0.5, 0.5),
|
||||
@@ -235,6 +236,7 @@
|
||||
'位图
|
||||
Dim Bitmap = New MyBitmap(_Logo)
|
||||
PathLogo = New Canvas With {
|
||||
.Tag = Me,
|
||||
.IsHitTestVisible = LogoClickable,
|
||||
.Background = Bitmap,
|
||||
.RenderTransformOrigin = New Point(0.5, 0.5),
|
||||
@@ -252,6 +254,7 @@
|
||||
Else
|
||||
'矢量图
|
||||
PathLogo = New Shapes.Path With {
|
||||
.Tag = Me,
|
||||
.IsHitTestVisible = LogoClickable, .HorizontalAlignment = HorizontalAlignment.Center, .VerticalAlignment = VerticalAlignment.Center, .Stretch = Stretch.Uniform,
|
||||
.Data = (New GeometryConverter).ConvertFromString(_Logo),
|
||||
.RenderTransformOrigin = New Point(0.5, 0.5),
|
||||
@@ -267,7 +270,7 @@
|
||||
If LogoClickable Then
|
||||
AddHandler PathLogo.MouseLeave, Sub(sender, e) IsLogoDown = False
|
||||
AddHandler PathLogo.MouseLeftButtonDown, Sub(sender, e) IsLogoDown = True
|
||||
AddHandler PathLogo.MouseLeftButtonUp, Sub(sender, e) If IsLogoDown Then IsLogoDown = False : RaiseEvent LogoClick(sender, e)
|
||||
AddHandler PathLogo.MouseLeftButtonUp, Sub(sender, e) If IsLogoDown Then IsLogoDown = False : RaiseEvent LogoClick(sender.Tag, e)
|
||||
End If
|
||||
End If
|
||||
'改变行距
|
||||
@@ -286,6 +289,9 @@
|
||||
End Property
|
||||
|
||||
'图标的点击
|
||||
''' <summary>
|
||||
''' 该 Logo 是否可用点击触发事件。需要在 Logo 属性之前设置。
|
||||
''' </summary>
|
||||
Public Property LogoClickable As Boolean = False
|
||||
Private IsLogoDown As Boolean = False
|
||||
|
||||
@@ -447,7 +453,7 @@
|
||||
RectCheck.VerticalAlignment = VerticalAlignment.Center
|
||||
RectCheck.Margin = New Thickness(-1, 0, 0, 0)
|
||||
End If
|
||||
Anim.Add(AaColor(Me, ForegroundProperty, "ColorBrush3", 200))
|
||||
Anim.Add(AaColor(Me, ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"), 200))
|
||||
Else
|
||||
'由有变无
|
||||
If Not IsNothing(RectCheck) Then
|
||||
@@ -469,7 +475,7 @@
|
||||
RectCheck.Opacity = 1
|
||||
RectCheck.VerticalAlignment = VerticalAlignment.Stretch
|
||||
End If
|
||||
SetResourceReference(ForegroundProperty, "ColorBrush3")
|
||||
SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
|
||||
Else
|
||||
If Not IsNothing(RectCheck) Then
|
||||
RectCheck.Height = 0
|
||||
@@ -615,12 +621,14 @@
|
||||
Else
|
||||
If ButtonStack IsNot Nothing Then Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.5))
|
||||
Ani.Add(AaOpacity(RectBack, -RectBack.Opacity, Time))
|
||||
If IsScaleAnimationEnabled Then Ani.AddRange({
|
||||
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
|
||||
AaScaleTransform(Me, 1 - CType(Me.RenderTransform, ScaleTransform).ScaleX, Time * 3,, New AniEaseOutFluent),
|
||||
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
|
||||
AaScaleTransform(RectBack, -0.246, 1,,, True)
|
||||
})
|
||||
If IsScaleAnimationEnabled Then
|
||||
Ani.AddRange({
|
||||
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
|
||||
AaScaleTransform(Me, 1 - CType(RenderTransform, ScaleTransform).ScaleX, Time * 3,, New AniEaseOutFluent),
|
||||
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
|
||||
AaScaleTransform(RectBack, -0.246, 1,,, True)
|
||||
})
|
||||
End If
|
||||
End If
|
||||
AniStart(Ani, "ListItem Color " & Uuid)
|
||||
Else
|
||||
@@ -647,7 +655,7 @@
|
||||
|
||||
Private Sub MyListItem_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
|
||||
If Checked Then
|
||||
SetResourceReference(ForegroundProperty, "ColorBrush3")
|
||||
SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
|
||||
Else
|
||||
SetResourceReference(ForegroundProperty, "ColorBrush1")
|
||||
End If
|
||||
|
||||
@@ -46,7 +46,7 @@ Public Class MyLoading
|
||||
Get
|
||||
Return _Text
|
||||
End Get
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
_Text = value
|
||||
RefreshText()
|
||||
End Set
|
||||
@@ -57,7 +57,7 @@ Public Class MyLoading
|
||||
Get
|
||||
Return _TextError
|
||||
End Get
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
_TextError = value
|
||||
RefreshText()
|
||||
End Set
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path x:Name="ShapeLogo" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="White" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center" />
|
||||
<TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="8,0,12,0" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
|
||||
<TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="8,0,12,1" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Class MySearchBox
|
||||
Inherits MyCard
|
||||
|
||||
Public Event TextChanged(ByVal sender As Object, ByVal e As EventArgs)
|
||||
Public Event TextChanged(sender As Object, e As EventArgs)
|
||||
Private Sub MySearchBox_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
|
||||
TextBox.Focus()
|
||||
End Sub
|
||||
@@ -11,7 +11,7 @@
|
||||
Get
|
||||
Return TextBox.HintText
|
||||
End Get
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
TextBox.HintText = value
|
||||
End Set
|
||||
End Property
|
||||
@@ -19,7 +19,7 @@
|
||||
Get
|
||||
Return TextBox.Text
|
||||
End Get
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
TextBox.Text = value
|
||||
End Set
|
||||
End Property
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
Return GetValue(EventTypeProperty)
|
||||
End Get
|
||||
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
SetValue(EventTypeProperty, value)
|
||||
End Set
|
||||
End Property
|
||||
@@ -101,7 +101,7 @@
|
||||
Return GetValue(EventDataProperty)
|
||||
End Get
|
||||
|
||||
Set(ByVal value As String)
|
||||
Set(value As String)
|
||||
SetValue(EventDataProperty, value)
|
||||
End Set
|
||||
End Property
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
xmlns:local="clr-namespace:PCL"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
|
||||
x:Name="WindMain" x:Class="FormMain" Style="{StaticResource MyWindow}"
|
||||
AllowDrop="True" Topmost="True" Title="Plain Craft Launcher 2 " AllowsTransparency="True" MinHeight="470" MinWidth="810" ScrollViewer.VerticalScrollBarVisibility="Disabled" Icon="/Plain Craft Launcher 2;component/Images/icon.ico" WindowStyle="None" ResizeMode="CanMinimize" Background="{x:Null}" d:DesignWidth="870" d:DesignHeight="520" Width="850" Height="500" RenderTransformOrigin="0.5,0.5">
|
||||
AllowDrop="True" Topmost="True" Title="Plain Craft Launcher " AllowsTransparency="True" MinHeight="470" MinWidth="810" ScrollViewer.VerticalScrollBarVisibility="Disabled" Icon="/Plain Craft Launcher 2;component/Images/icon.ico" WindowStyle="None" ResizeMode="CanMinimize" Background="{x:Null}" d:DesignWidth="870" d:DesignHeight="520" Width="850" Height="500" RenderTransformOrigin="0.5,0.5">
|
||||
<Window.TaskbarItemInfo>
|
||||
<TaskbarItemInfo ThumbnailClipMargin="{Binding Margin, ElementName=PanForm}" />
|
||||
</Window.TaskbarItemInfo>
|
||||
|
||||
@@ -116,8 +116,13 @@ Public Class FormMain
|
||||
'3:BUG+ IMP* FEAT-
|
||||
'2:BUG* IMP-
|
||||
'1:BUG-
|
||||
If LastVersion < 297 Then 'Snapshot 2.6.3
|
||||
If LastVersion < 298 Then 'Snapshot 2.6.4
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "Mod 管理中允许多选 Mod 进行批量操作"))
|
||||
FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化崩溃分析,添加多种崩溃情况的判断"))
|
||||
FeatureCount += 18
|
||||
BugCount += 19
|
||||
End If
|
||||
If LastVersion < 297 Then 'Snapshot 2.6.3
|
||||
FeatureCount += 12
|
||||
BugCount += 14
|
||||
End If
|
||||
@@ -744,31 +749,32 @@ Public Class FormMain
|
||||
Hint($"输入的 Authlib 验证服务器不符合网址格式({AuthlibServer})!", HintType.Critical)
|
||||
Exit Sub
|
||||
End If
|
||||
If McVersionCurrent Is Nothing Then
|
||||
Dim TargetVersion = If(PageCurrent = PageType.VersionSetup, PageVersionLeft.Version, McVersionCurrent)
|
||||
If TargetVersion Is Nothing Then
|
||||
Hint("请先下载游戏,再设置第三方登录!", HintType.Critical)
|
||||
Exit Sub
|
||||
End If
|
||||
If AuthlibServer = "https://littleskin.cn/api/yggdrasil" Then
|
||||
'LittleSkin
|
||||
If MyMsgBox($"是否要在版本 {McVersionCurrent.Name} 中开启 LittleSkin 登录?" & vbCrLf &
|
||||
If MyMsgBox($"是否要在版本 {TargetVersion.Name} 中开启 LittleSkin 登录?" & vbCrLf &
|
||||
"你可以在 版本设置 → 设置 → 服务器选项 中修改登录方式。", "第三方登录开启确认", "确定", "取消") = 2 Then
|
||||
Exit Sub
|
||||
End If
|
||||
Setup.Set("VersionServerLogin", 4, Version:=McVersionCurrent)
|
||||
Setup.Set("VersionServerAuthServer", "https://littleskin.cn/api/yggdrasil", Version:=McVersionCurrent)
|
||||
Setup.Set("VersionServerAuthRegister", "https://littleskin.cn/auth/register", Version:=McVersionCurrent)
|
||||
Setup.Set("VersionServerAuthName", "LittleSkin 登录", Version:=McVersionCurrent)
|
||||
Setup.Set("VersionServerLogin", 4, Version:=TargetVersion)
|
||||
Setup.Set("VersionServerAuthServer", "https://littleskin.cn/api/yggdrasil", Version:=TargetVersion)
|
||||
Setup.Set("VersionServerAuthRegister", "https://littleskin.cn/auth/register", Version:=TargetVersion)
|
||||
Setup.Set("VersionServerAuthName", "LittleSkin 登录", Version:=TargetVersion)
|
||||
Else
|
||||
'第三方 Authlib 服务器
|
||||
If MyMsgBox($"是否要在版本 {McVersionCurrent.Name} 中开启第三方登录?" & vbCrLf &
|
||||
If MyMsgBox($"是否要在版本 {TargetVersion.Name} 中开启第三方登录?" & vbCrLf &
|
||||
$"登录服务器:{AuthlibServer}" & vbCrLf & vbCrLf &
|
||||
"你可以在 版本设置 → 设置 → 服务器选项 中修改登录方式。", "第三方登录开启确认", "确定", "取消") = 2 Then
|
||||
Exit Sub
|
||||
End If
|
||||
Setup.Set("VersionServerLogin", 4, Version:=McVersionCurrent)
|
||||
Setup.Set("VersionServerAuthServer", AuthlibServer, Version:=McVersionCurrent)
|
||||
Setup.Set("VersionServerAuthRegister", AuthlibServer.Replace("api/yggdrasil", "auth/register"), Version:=McVersionCurrent)
|
||||
Setup.Set("VersionServerAuthName", "", Version:=McVersionCurrent)
|
||||
Setup.Set("VersionServerLogin", 4, Version:=TargetVersion)
|
||||
Setup.Set("VersionServerAuthServer", AuthlibServer, Version:=TargetVersion)
|
||||
Setup.Set("VersionServerAuthRegister", AuthlibServer.Replace("api/yggdrasil", "auth/register"), Version:=TargetVersion)
|
||||
Setup.Set("VersionServerAuthName", "", Version:=TargetVersion)
|
||||
End If
|
||||
If PageCurrent = PageType.VersionSetup AndAlso PageCurrentSub = PageSubType.VersionSetup Then
|
||||
'正在服务器选项页,需要刷新设置项显示
|
||||
@@ -916,7 +922,7 @@ Install:
|
||||
Get
|
||||
Return _Hidden
|
||||
End Get
|
||||
Set(ByVal value As Boolean)
|
||||
Set(value As Boolean)
|
||||
If _Hidden = value Then Exit Property
|
||||
_Hidden = value
|
||||
If value Then
|
||||
@@ -963,6 +969,7 @@ Install:
|
||||
#Region "切换页面"
|
||||
|
||||
'页面种类与属性
|
||||
'注意,这一枚举在 “切换页面” EventType 中调用,应视作公开 API 的一部分
|
||||
''' <summary>
|
||||
''' 页面种类。
|
||||
''' </summary>
|
||||
@@ -970,43 +977,43 @@ Install:
|
||||
''' <summary>
|
||||
''' 启动。
|
||||
''' </summary>
|
||||
Launch
|
||||
Launch = 0
|
||||
''' <summary>
|
||||
''' 下载。
|
||||
''' </summary>
|
||||
Download
|
||||
Download = 1
|
||||
''' <summary>
|
||||
''' 联机。
|
||||
''' </summary>
|
||||
Link
|
||||
Link = 2
|
||||
''' <summary>
|
||||
''' 设置。
|
||||
''' </summary>
|
||||
Setup
|
||||
Setup = 3
|
||||
''' <summary>
|
||||
''' 更多。
|
||||
''' </summary>
|
||||
Other
|
||||
Other = 4
|
||||
''' <summary>
|
||||
''' 版本选择。这是一个副页面。
|
||||
''' </summary>
|
||||
VersionSelect
|
||||
VersionSelect = 5
|
||||
''' <summary>
|
||||
''' 下载管理。这是一个副页面。
|
||||
''' </summary>
|
||||
DownloadManager
|
||||
DownloadManager = 6
|
||||
''' <summary>
|
||||
''' 版本设置。这是一个副页面。
|
||||
''' </summary>
|
||||
VersionSetup
|
||||
VersionSetup = 7
|
||||
''' <summary>
|
||||
''' 资源工程详情。这是一个副页面。
|
||||
''' </summary>
|
||||
CompDetail
|
||||
CompDetail = 8
|
||||
''' <summary>
|
||||
''' 帮助详情。这是一个副页面。
|
||||
''' </summary>
|
||||
HelpDetail
|
||||
HelpDetail = 9
|
||||
End Enum
|
||||
''' <summary>
|
||||
''' 次要页面种类。其数值必须与 StackPanel 中的下标一致。
|
||||
|
||||
@@ -11,12 +11,12 @@ Public Module ModBase
|
||||
#Region "声明"
|
||||
|
||||
'下列版本信息由更新器自动修改
|
||||
Public Const VersionBaseName As String = "2.6.3" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.6.3." & VersionBranchCode '标准格式的四段式版本号
|
||||
Public Const VersionBaseName As String = "2.6.4" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.6.4." & VersionBranchCode '标准格式的四段式版本号
|
||||
#If BETA Then
|
||||
Public Const VersionCode As Integer = 293 'Release
|
||||
Public Const VersionCode As Integer = 296 'Release
|
||||
#Else
|
||||
Public Const VersionCode As Integer = 297 'Snapshot
|
||||
Public Const VersionCode As Integer = 298 'Snapshot
|
||||
#End If
|
||||
'自动生成的版本信息
|
||||
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
||||
|
||||
@@ -73,10 +73,10 @@ Public Class MyBitmap
|
||||
Pic = My.Application.TryFindResource(FilePathOrResourceName)
|
||||
If Pic Is Nothing Then
|
||||
Pic = New System.Drawing.Bitmap(1, 1)
|
||||
Log(ex, "加载位图失败(" & FilePathOrResourceName & ")")
|
||||
Log(ex, $"加载位图失败({FilePathOrResourceName})")
|
||||
Throw
|
||||
Else
|
||||
Log(ex, "指定类型有误的位图加载(" & FilePathOrResourceName & ")", LogLevel.Developer)
|
||||
Log(ex, $"指定类型有误的位图加载({FilePathOrResourceName})", LogLevel.Developer)
|
||||
Exit Try
|
||||
End If
|
||||
End Try
|
||||
|
||||
@@ -375,6 +375,7 @@
|
||||
End Select
|
||||
Next
|
||||
If Tags.Count = 0 Then Tags.Add("杂项")
|
||||
Tags.Sort()
|
||||
ModLoaders.Sort()
|
||||
#End Region
|
||||
End If
|
||||
@@ -424,15 +425,32 @@
|
||||
Dim ExNameList As List(Of String)
|
||||
If TranslatedName = RawName Then
|
||||
'没有中文翻译
|
||||
FinalName = TranslatedName.Split(" | ").First.Split(" - ").First.Split("(").First.Split("[").First
|
||||
ExNameList = TranslatedName.Split({" | ", " - ", "(", ")", "[", "]", "{", "}"}, StringSplitOptions.RemoveEmptyEntries).
|
||||
Select(Function(s) s.Trim(" /".ToCharArray)).Where(Function(w) Not String.IsNullOrEmpty(w)).ToList
|
||||
ExNameList.RemoveAt(0)
|
||||
If Not ExNameList.Any(Function(s) s.ToLower.Contains("forge") OrElse s.ToLower.Contains("fabric") OrElse s.ToLower.Contains("quilt")) AndAlso '不是标注 XX 版
|
||||
Not (ExNameList.Count = 1 AndAlso ExNameList.First.ToUpper = ExNameList.First) Then '不是缩写
|
||||
FinalName = RawName '使用原名
|
||||
ExNameList.Clear()
|
||||
End If
|
||||
'将所有名称分段
|
||||
Dim NameLists = TranslatedName.Split({" | ", " - ", "(", ")", "[", "]", "{", "}"}, StringSplitOptions.RemoveEmptyEntries).
|
||||
Select(Function(s) s.Trim(" /\".ToCharArray)).Where(Function(w) Not String.IsNullOrEmpty(w)).ToList
|
||||
If NameLists.Count = 1 Then GoTo NoExName
|
||||
'查找其中的缩写、Forge/Fabric 等版本标记
|
||||
ExNameList = New List(Of String)
|
||||
Dim NormalNameList = New List(Of String)
|
||||
For Each Name In NameLists
|
||||
Dim LowerName As String = Name.ToLower
|
||||
If Name.ToUpper = Name Then
|
||||
'缩写
|
||||
ExNameList.Add(Name)
|
||||
ElseIf (LowerName.Contains("forge") OrElse LowerName.Contains("fabric") OrElse LowerName.Contains("quilt")) AndAlso
|
||||
Not RegexCheck(LowerName.Replace("forge", "").Replace("fabric", "").Replace("quilt", ""), "[a-z]+") Then '去掉关键词后没有其他字母
|
||||
'Forge/Fabric 等版本标记
|
||||
ExNameList.Add(Name)
|
||||
Else
|
||||
'其他部分
|
||||
NormalNameList.Add(Name)
|
||||
End If
|
||||
Next
|
||||
'根据分类后的结果处理
|
||||
If NormalNameList.Count = 0 OrElse ExNameList.Count = 0 Then GoTo NoExName
|
||||
'同时包含 NormalName 和 ExName
|
||||
FinalName = NormalNameList.Join(" - ")
|
||||
ExNameList = ExNameList
|
||||
Else
|
||||
'有中文翻译
|
||||
'尝试将文本分为三段:FinalName (EnglishName) - Suffix
|
||||
@@ -452,21 +470,20 @@
|
||||
ExNameList = New List(Of String) From {EnglishName} '使用原名
|
||||
End If
|
||||
'添加后缀
|
||||
If Suffix <> "" Then
|
||||
ExNameList.Add(Suffix)
|
||||
ExNameList = ExNameList.Distinct().ToList()
|
||||
End If
|
||||
If Suffix <> "" Then ExNameList.Add(Suffix)
|
||||
End If
|
||||
ExNameList = ExNameList.Distinct().ToList()
|
||||
'显示 FinalName 与 ExNameList
|
||||
NewItem.LabTitle.Text = FinalName
|
||||
If ExNameList.Count = 0 Then
|
||||
NoExName:
|
||||
NewItem.LabTitle.Text = RawName
|
||||
CType(NewItem.LabTitleRaw.Parent, StackPanel).Children.Remove(NewItem.LabTitleRaw)
|
||||
Else
|
||||
NewItem.LabTitle.Text = FinalName
|
||||
Dim ExName As String = ""
|
||||
For Each Ex In ExNameList
|
||||
'去除 “Forge/Fabric” 这一无意义提示
|
||||
If Ex.Length < 19 AndAlso Ex.ToLower.Contains("fabric") AndAlso Ex.ToLower.Contains("forge") Then Continue For
|
||||
If Ex.Length < 16 AndAlso Ex.ToLower.Contains("fabric") AndAlso Ex.ToLower.Contains("forge") Then Continue For
|
||||
'将 “Forge” 等提示改为 “Forge 版”
|
||||
If (Ex.ToLower.Contains("forge") OrElse Ex.ToLower.Contains("fabric") OrElse Ex.ToLower.Contains("quilt")) AndAlso Not Ex.Contains("版") AndAlso
|
||||
Ex.ToLower.Replace("forge", "").Replace("fabric", "").Replace("quilt", "").Length <= 3 Then
|
||||
|
||||
@@ -365,7 +365,7 @@
|
||||
ShadersMod与Optifine同时安装
|
||||
Forge安装不完整
|
||||
Mod需要Java11
|
||||
Mod依赖项未完善
|
||||
Mod缺少前置或MC版本错误
|
||||
End Enum
|
||||
''' <summary>
|
||||
''' 根据 AnalyzeLogs 与可能的版本信息分析崩溃原因。
|
||||
@@ -374,9 +374,11 @@
|
||||
Log("[Crash] 步骤 3:分析崩溃原因")
|
||||
LogAll = (If(LogMc, "") & If(LogHs, "") & If(LogCrash, "")).ToLower
|
||||
|
||||
'1. 精准日志匹配 1
|
||||
'1. 精准日志匹配,中/高优先级
|
||||
AnalyzeCrit1()
|
||||
If CrashReasons.Count > 0 Then GoTo Done
|
||||
AnalyzeCrit2()
|
||||
If CrashReasons.Count > 0 Then GoTo Done
|
||||
|
||||
'2. 堆栈分析
|
||||
If LogAll.Contains("forge") OrElse LogAll.Contains("fabric") OrElse LogAll.Contains("liteloader") Then
|
||||
@@ -414,8 +416,8 @@
|
||||
Log("[Crash] 可能并未安装 Mod,不进行堆栈分析")
|
||||
End If
|
||||
|
||||
'3. 精准日志匹配 2
|
||||
AnalyzeCrit2()
|
||||
'3. 精准日志匹配,低优先级
|
||||
AnalyzeCrit3()
|
||||
|
||||
'输出到日志
|
||||
Done:
|
||||
@@ -470,13 +472,12 @@ Done:
|
||||
If LogMc.Contains("java.lang.ClassCastException: java.base/jdk") Then AppendReason(CrashReason.使用JDK)
|
||||
If LogMc.Contains("java.lang.ClassCastException: class jdk.") Then AppendReason(CrashReason.使用JDK)
|
||||
If LogMc.Contains("TRANSFORMER/net.optifine/net.optifine.reflect.Reflector.<clinit>(Reflector.java") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.client.renderer.texture.SpriteContents.<init>(net.minecraft.resources.ResourceLocation, ") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.client.renderer.texture.SpriteContents.<init>") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'java.lang.String com.mojang.blaze3d.systems.RenderSystem.getBackendDescription") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.client.renderer.block.model.BakedQuad.<init>(int[], int, net.minecraft.core.Direction, net.minecraft.client.renderer.texture.TextureAtlasSprite, boolean, boolean)'") Then AppendReason(CrashReason.OptiFine与Forge不兼容)'1.19.2 Optifine HD_U_H9 Forge 43.2.17
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.server.level.DistanceManager.addRegionTicket(net.minecraft.server.level.TicketType, net.minecraft.world.level.ChunkPos, int, java.lang.Object, boolean)'") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.server.level.DistanceManager.removeRegionTicket(net.minecraft.server.level.TicketType, net.minecraft.world.level.ChunkPos, int, java.lang.Object, boolean)'") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'net.minecraft.network.chat.FormattedText net.minecraft.client.gui.Font.ellipsize(net.minecraft.network.chat.FormattedText, int)'") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraftforge.client.gui.overlay.ForgeGui.renderSelectedItemName(net.minecraft.client.gui.GuiGraphics, int)'") Then AppendReason(CrashReason.OptiFine与Forge不兼容)'1.20.1 OptiFine HD_U_I5 Forge 47.1.28/47.1.14 , 1.20.1 OptiFine_I6_pre1 Forge 47.1.14
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.client.renderer.block.model.BakedQuad.<init>") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraftforge.client.gui.overlay.ForgeGui.renderSelectedItemName") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.server.level.DistanceManager") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("java.lang.NoSuchMethodError: 'net.minecraft.network.chat.FormattedText net.minecraft.client.gui.Font.ellipsize") Then AppendReason(CrashReason.OptiFine与Forge不兼容)
|
||||
If LogMc.Contains("Open J9 is not supported") OrElse LogMc.Contains("OpenJ9 is incompatible") OrElse LogMc.Contains(".J9VMInternals.") Then AppendReason(CrashReason.使用OpenJ9)
|
||||
If LogMc.Contains("java.lang.NoSuchFieldException: ucp") Then AppendReason(CrashReason.Java版本过高)
|
||||
If LogMc.Contains("because module java.base does not export") Then AppendReason(CrashReason.Java版本过高)
|
||||
@@ -498,7 +499,7 @@ Done:
|
||||
If LogMc.Contains("Invalid module name: '' is not a Java identifier") Then AppendReason(CrashReason.Mod名称包含特殊字符)
|
||||
If LogMc.Contains("has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to") Then AppendReason(CrashReason.Mod需要Java11)
|
||||
If LogMc.Contains("java.lang.RuntimeException: java.lang.NoSuchMethodException: no such method: sun.misc.Unsafe.defineAnonymousClass(Class,byte[],Object[])Class/invokeVirtual") Then AppendReason(CrashReason.Mod需要Java11)
|
||||
If LogMc.Contains("java.lang.UnsupportedClassVersionError: net/fabricmc/loader/impl/launch/knot/KnotClient : Unsupported major.minor version") Then AppendReason(CrashReason.Java版本不兼容)
|
||||
If LogMc.Contains("Unsupported major.minor version") Then AppendReason(CrashReason.Java版本不兼容)
|
||||
If LogMc.Contains("Invalid maximum heap size") Then AppendReason(CrashReason.使用32位Java导致JVM无法分配足够多的内存)
|
||||
If LogMc.Contains("Could not reserve enough space") Then
|
||||
If LogMc.Contains("for 1048576KB object heap") Then
|
||||
@@ -507,34 +508,17 @@ Done:
|
||||
AppendReason(CrashReason.内存不足)
|
||||
End If
|
||||
End If
|
||||
'确定的 Mod 导致崩溃
|
||||
If LogMc.Contains("Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(RegexSeek(LogMc, "(?<=Caught exception from )[^\n]+?")?.TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
'Mod 重复安装
|
||||
If LogMc.Contains("DuplicateModsFoundException") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(LogMc, "(?<=\n\t[\w]+ : [A-Z]{1}:[^\n]+(/|\\))[^/\\\n]+?.jar", RegularExpressions.RegexOptions.IgnoreCase))
|
||||
If LogMc.Contains("Found a duplicate mod") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(If(RegexSeek(LogMc, "Found a duplicate mod[^\n]+"), ""), "[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase))
|
||||
If LogMc.Contains("ModResolutionException: Duplicate") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(If(RegexSeek(LogMc, "ModResolutionException: Duplicate[^\n]+"), ""), "[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase))
|
||||
'Mod 导致的崩溃
|
||||
If LogMc.Contains("Mixin prepare failed ") OrElse LogMc.Contains("Mixin apply failed ") OrElse LogMc.Contains("MixinApplyError") OrElse
|
||||
LogMc.Contains("mixin.injection.throwables.") OrElse LogMc.Contains(".mixins.json] FAILED during )") Then
|
||||
Dim ModId As String = RegexSeek(LogMc, "(?<=in )[^./ ]+(?=.mixins.json.+failed injection check)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=in mixins.)[^./ ]+(?=.json.+failed injection check)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in )[^./ ]+(?=.mixins.json)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in mixins.)[^./ ]+(?=.json)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[)[^./ ]+(?=.mixins.json\] FAILED during )")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[mixins.)[^./ ]+(?=.json\] FAILED during )")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=from mod )[^./ ]+(?=\] from)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=for mod )[^./ ]+(?= failed)")
|
||||
'兜底名称判断
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "[^./ \]]+(?=.mixins.json")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=mixins.)[^./ \]]+(?=.json")
|
||||
AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(If(ModId, "").TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
'Mod 依赖项未完善
|
||||
If LogCrash.Contains("Missing or unsupported mandatory dependencies:") Then
|
||||
AppendReason(CrashReason.Mod依赖项未完善, RegexSearch(LogMc, "(?<=Missing or unsupported mandatory dependencies:)[\n\r]*(\t(.*)[\n\r]*)+"), "").TrimEnd((vbCrLf & " ").ToCharArray)
|
||||
End If
|
||||
If LogMc.Contains("Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(RegexSeek(LogMc, "(?<=Caught exception from )[^\n]+?")?.TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
'仅当没有其他分析结果时显示
|
||||
If CrashReasons.Count = 0 Then
|
||||
If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf))
|
||||
If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf))
|
||||
'Mod 缺少前置
|
||||
If LogMc.Contains("Missing or unsupported mandatory dependencies:") Then
|
||||
AppendReason(CrashReason.Mod缺少前置或MC版本错误,
|
||||
RegexSearch(LogMc, "(?<=Missing or unsupported mandatory dependencies:)([\n\r]+\t(.*))+", RegularExpressions.RegexOptions.IgnoreCase).
|
||||
Select(Function(s) s.Trim((vbCrLf & vbTab & " ").ToCharArray)).Distinct().ToList())
|
||||
End If
|
||||
End If
|
||||
|
||||
@@ -572,14 +556,43 @@ Done:
|
||||
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 进行精准日志匹配。匹配优先级低于堆栈分析的崩溃。
|
||||
''' 进行精准日志匹配。匹配优先级高于堆栈分析的崩溃,但低于上面的。
|
||||
''' 如果第一步已经找到了原因则不执行该检测。
|
||||
''' </summary>
|
||||
Private Sub AnalyzeCrit2()
|
||||
|
||||
'游戏日志分析
|
||||
If LogMc IsNot Nothing Then
|
||||
If Not (LogMc.Contains("at net.") OrElse LogMc.Contains("INFO]")) AndAlso
|
||||
LogHs Is Nothing AndAlso LogCrash Is Nothing AndAlso LogMc.Length < 100 Then
|
||||
'Mixin 崩溃
|
||||
If LogMc.Contains("Mixin prepare failed ") OrElse LogMc.Contains("Mixin apply failed ") OrElse LogMc.Contains("MixinApplyError") OrElse
|
||||
LogMc.Contains("mixin.injection.throwables.") OrElse LogMc.Contains(".mixins.json] FAILED during )") Then
|
||||
Dim ModId As String = RegexSeek(LogMc, "(?<=in )[^./ ]+(?=.mixins.json.+failed injection check)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=in mixins.)[^./ ]+(?=.json.+failed injection check)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in )[^./ ]+(?=.mixins.json)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= failed .+ in mixins.)[^./ ]+(?=.json)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[)[^./ ]+(?=.mixins.json\] FAILED during )")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<= in config \[mixins.)[^./ ]+(?=.json\] FAILED during )")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=from mod )[^./ ]+(?=\] from)")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=for mod )[^./ ]+(?= failed)")
|
||||
'兜底名称判断
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "[^./ \]]+(?=.mixins.json")
|
||||
If ModId Is Nothing Then ModId = RegexSeek(LogMc, "(?<=mixins.)[^./ \]]+(?=.json")
|
||||
AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(If(ModId, "").TrimEnd((vbCrLf & " ").ToCharArray)))
|
||||
End If
|
||||
'常规信息
|
||||
If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf))
|
||||
If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, Join(RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)((\t)+ - [^\n]+\n)+"), ""), "(?<=(\t)+)[^\n]+"), vbLf))
|
||||
End If
|
||||
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 进行精准日志匹配。匹配优先级低于堆栈分析的崩溃。
|
||||
''' </summary>
|
||||
Private Sub AnalyzeCrit3()
|
||||
|
||||
'游戏日志分析
|
||||
If LogMc IsNot Nothing Then
|
||||
If Not (LogMc.Contains("at net.") OrElse LogMc.Contains("INFO]")) AndAlso LogHs Is Nothing AndAlso LogCrash Is Nothing AndAlso LogMc.Length < 100 Then
|
||||
AppendReason(CrashReason.极短的程序输出, LogMc)
|
||||
End If
|
||||
'Mixin 失败可以导致大量 Mod 实例创建失败
|
||||
@@ -814,7 +827,7 @@ NextStack:
|
||||
Case CrashReason.Mod文件被解压
|
||||
Results.Add("由于 Mod 文件被解压了,导致游戏无法继续运行。\n直接把整个 Mod 文件放进 Mod 文件夹中即可,若解压就会导致游戏出错。\n\n请删除 Mod 文件夹中已被解压的 Mod,然后再启动游戏。")
|
||||
Case CrashReason.内存不足
|
||||
Results.Add("Minecraft 内存不足,导致其无法继续运行。\n这很可能是由于你为游戏分配的内存不足,或是游戏的配置要求过高。\n\n你可以在启动设置中增加为游戏分配的内存,删除配置要求较高的材质、Mod、光影。\n如果这依然不奏效,请在开始游戏前尽量关闭其他软件,或者……换台电脑?\h")
|
||||
Results.Add("Minecraft 内存不足,导致其无法继续运行。\n这很可能是因为电脑内存不足、游戏分配的内存不足,或是配置要求过高。\n\n你可以尝试在 更多 → 百宝箱 中选择 内存优化,然后再启动游戏。\n如果还是不行,请在启动设置中增加为游戏分配的内存,并删除配置要求较高的材质、Mod、光影。\n如果依然不奏效,请在开始游戏前尽量关闭其他软件,或者……换台电脑?\h")
|
||||
Case CrashReason.使用OpenJ9
|
||||
Results.Add("游戏因为使用 Open J9 而崩溃了。\n请在启动设置的 Java 选择一项中改用非 OpenJ9 的 Java,然后再启动游戏。")
|
||||
Case CrashReason.使用JDK
|
||||
@@ -837,6 +850,12 @@ NextStack:
|
||||
Else
|
||||
Results.Add("你的游戏遇到了一些问题,这可能是某些 Mod 所引起的,PCL 找到了以下可疑的关键词:\n - " & Join(Additional, ", ") & "\n\n如果你知道这些关键词对应的 Mod,那么有可能就是它引起的错误,你也可以查看错误报告获取详情。\h")
|
||||
End If
|
||||
Case CrashReason.Mod缺少前置或MC版本错误
|
||||
If Additional.Count > 0 Then
|
||||
Results.Add("由于未满足 Mod 的依赖项,导致游戏退出。\n未满足的依赖项:\n - " & Join(Additional, "\n - ") & "\n\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
|
||||
Else
|
||||
Results.Add("由于未满足 Mod 的依赖项,导致游戏退出。\n请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\h")
|
||||
End If
|
||||
Case CrashReason.崩溃日志堆栈分析发现Mod名称
|
||||
If Additional.Count = 1 Then
|
||||
Results.Add("名为 " & Additional.First & " 的 Mod 可能导致了游戏出错。\n\e\h")
|
||||
@@ -943,12 +962,6 @@ NextStack:
|
||||
Else
|
||||
Results.Add("Forge 可能已经提供了错误信息,请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h")
|
||||
End If
|
||||
Case CrashReason.Mod依赖项未完善
|
||||
If Additional.Count = 1 Then
|
||||
Results.Add("由于 Mod 缺少或不受支持的必备依赖项,导致了游戏退出。\n以下是未满足条件的必备依赖项:" & Additional.First & "\n请根据上述信息进行对应处理,如果看不懂英文可以使用翻译软件。")
|
||||
Else
|
||||
Results.Add("由于 Mod 缺少或不受支持的强制依赖项,导致了游戏退出。请根据错误报告中的日志信息进行对应处理,如果看不懂英文可以使用翻译软件。\n如果没有看到报错信息,可以查看错误报告了解错误具体是如何发生的。\h")
|
||||
End If
|
||||
Case CrashReason.没有可用的分析文件
|
||||
Results.Add("你的游戏出现了一些问题,但 PCL 未能找到相关记录文件,因此无法进行分析。\h")
|
||||
Case Else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Public Module ModJava
|
||||
Public JavaListCacheVersion As Integer = 4
|
||||
Public JavaListCacheVersion As Integer = 5
|
||||
|
||||
''' <summary>
|
||||
''' 目前所有可用的 Java。
|
||||
@@ -129,8 +129,10 @@
|
||||
End If
|
||||
Is64Bit = Output.Contains("64-bit")
|
||||
If Version.Minor <= 4 OrElse Version.Minor >= 25 Then Throw New Exception("分析详细信息失败,获取的版本为 " & Version.ToString)
|
||||
'无论如何不允许使用 JRE 16,它完全是炸的,安 OptiFine、Forge 和启动 MC 都会炸
|
||||
If IsJre AndAlso VersionCode = 16 Then Throw New Exception("由于 JRE 16 对 Minecraft 的兼容性很差,因此不再允许使用")
|
||||
'基于 #2249 发现的 JRE 17 似乎也导致了 Forge 安装失败,干脆禁用更多版本的 JRE
|
||||
If IsJre AndAlso VersionCode >= 16 Then Throw New Exception("由于高版本 JRE 对 Minecraft 的兼容性很差,因此不再允许使用")
|
||||
''无论如何不允许使用 JRE 16,它完全是炸的,安 OptiFine、Forge 和启动 MC 都会炸
|
||||
'If IsJre AndAlso VersionCode = 16 Then Throw New Exception("由于 JRE 16 对 Minecraft 的兼容性很差,因此不再允许使用")
|
||||
Catch ex As Exception
|
||||
Log("[Java] 检查失败的 Java 输出:" & PathFolder & "java.exe" & vbCrLf & If(Output, "无程序输出"))
|
||||
Throw New Exception("检查 Java 失败(" & If(PathJavaw, "Nothing") & ")", ex)
|
||||
@@ -230,6 +232,8 @@
|
||||
Try
|
||||
UserJava = JavaEntry.FromJson(GetJson(Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion)))
|
||||
UserJava.Check()
|
||||
Catch ex As ThreadInterruptedException
|
||||
Throw
|
||||
Catch ex As Exception
|
||||
UserJava = Nothing
|
||||
Setup.Reset("VersionArgumentJavaSelect", Version:=RelatedVersion)
|
||||
@@ -242,6 +246,8 @@
|
||||
Try
|
||||
UserJava = JavaEntry.FromJson(GetJson(Setup.Get("LaunchArgumentJavaSelect")))
|
||||
UserJava.Check()
|
||||
Catch ex As ThreadInterruptedException
|
||||
Throw
|
||||
Catch ex As Exception
|
||||
UserJava = Nothing
|
||||
Setup.Reset("LaunchArgumentJavaSelect")
|
||||
@@ -450,7 +456,7 @@ NoUserJava:
|
||||
'4. Java 大版本
|
||||
If Left.VersionCode <> Right.VersionCode Then
|
||||
' Java 7 8 9 10 11 12 13 14 15 16 17 18 19 20...
|
||||
Dim Weight = {0, 1, 2, 3, 4, 5, 6, 14, 29, 10, 12, 15, 13, 9, 8, 7, 11, 31, 30, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}
|
||||
Dim Weight = {0, 1, 2, 3, 4, 5, 6, 14, 30, 10, 12, 15, 13, 9, 8, 7, 11, 31, 29, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28}
|
||||
Return Weight.ElementAtOrDefault(Left.VersionCode) >= Weight.ElementAtOrDefault(Right.VersionCode)
|
||||
End If
|
||||
'5. 最次级版本号更接近 51
|
||||
@@ -530,10 +536,10 @@ NoUserJava:
|
||||
For Each Pair In JavaPreList
|
||||
If Pair.Key.Contains("javapath_target_") OrElse Pair.Key.Contains("javatmp") Then
|
||||
Log("[Java] 位于 " & Pair.Key & " 的 Java 包含特殊引用")
|
||||
Continue For
|
||||
Else
|
||||
Log("[Java] 位于 " & Pair.Key & " 的 Java 不含特殊引用")
|
||||
JavaWithoutInherit.Add(Pair.Key, Pair.Value)
|
||||
End If
|
||||
Log("[Java] 位于 " & Pair.Key & " 的 Java 不含特殊引用")
|
||||
JavaWithoutInherit.Add(Pair.Key, Pair.Value)
|
||||
Next
|
||||
If JavaWithoutInherit.Count > 0 Then JavaPreList = JavaWithoutInherit
|
||||
|
||||
@@ -688,18 +694,17 @@ Wait:
|
||||
|
||||
''' <summary>
|
||||
''' 提示 Java 缺失,并弹窗确认是否自动下载。返回玩家选择是否下载。
|
||||
''' 支持下载 Java 8、14、17,输入其他 VersionCode 会要求玩家自行下载。
|
||||
''' </summary>
|
||||
Public Function JavaDownloadConfirm(VersionCode As String) As Boolean
|
||||
If VersionCode = 8 OrElse VersionCode = 14 OrElse VersionCode = 17 Then
|
||||
Return MyMsgBox($"PCL 未找到 Java {VersionCode},是否需要 PCL 自动下载?" & vbCrLf &
|
||||
$"如果你已经安装了 Java {VersionCode},请在 设置 → 启动选项 → 游戏 Java 中手动导入。",
|
||||
"未找到 Java", "自动下载", "取消") = 1
|
||||
Else
|
||||
MyMsgBox($"PCL 未找到 Java {VersionCode}。" & vbCrLf &
|
||||
$"请自行搜索并安装 Java {VersionCode},安装后在 设置 → 启动选项 → 游戏 Java 中重新搜索或导入。",
|
||||
Public Function JavaDownloadConfirm(VersionDescription As String, Optional ForcedManualDownload As Boolean = False) As Boolean
|
||||
If ForcedManualDownload Then
|
||||
MyMsgBox($"PCL 未找到 {VersionDescription}。" & vbCrLf &
|
||||
$"请自行搜索并安装 {VersionDescription},安装后在 设置 → 启动选项 → 游戏 Java 中重新搜索或导入。",
|
||||
"未找到 Java")
|
||||
Return False
|
||||
Else
|
||||
Return MyMsgBox($"PCL 未找到 {VersionDescription},是否需要 PCL 自动下载?" & vbCrLf &
|
||||
$"如果你已经安装了 {VersionDescription},请在 设置 → 启动选项 → 游戏 Java 中手动导入。",
|
||||
"未找到 Java", "自动下载", "取消") = 1
|
||||
End If
|
||||
End Function
|
||||
|
||||
|
||||
@@ -1131,11 +1131,11 @@ SystemBrowser:
|
||||
If McVersionCurrent.Version.McName = "1.7.2" Then
|
||||
'1.7.2:必须 Java 7
|
||||
MinVer = New Version(1, 7, 0, 0) : MaxVer = New Version(1, 7, 999, 999)
|
||||
ElseIf McVersionCurrent.Version.McCodeMain <= 12 AndAlso McVersionCurrent.Version.McCodeMain > 0 AndAlso VersionSortBoolean("14.23.5.2855", McVersionCurrent.Version.ForgeVersion) Then
|
||||
'<=1.12,Forge 14.23.5.2855 及更低:Java 8
|
||||
ElseIf McVersionCurrent.Version.McCodeMain <= 12 AndAlso McVersionCurrent.Version.McCodeMain > 0 Then
|
||||
'<=1.12:Java 8
|
||||
MaxVer = New Version(1, 8, 999, 999)
|
||||
ElseIf McVersionCurrent.Version.McCodeMain <= 14 AndAlso McVersionCurrent.Version.McCodeMain >= 13 AndAlso VersionSortBoolean("28.2.23", McVersionCurrent.Version.ForgeVersion) Then
|
||||
'1.13 - 1.14,Forge 28.2.23 及更低:Java 8 - 10
|
||||
ElseIf McVersionCurrent.Version.McCodeMain <= 14 AndAlso McVersionCurrent.Version.McCodeMain >= 13 Then
|
||||
'1.13 - 1.14:Java 8 - 10
|
||||
MinVer = New Version(1, 8, 0, 0) : MaxVer = New Version(1, 10, 999, 999)
|
||||
ElseIf McVersionCurrent.Version.McCodeMain = 15 Then
|
||||
'1.15:Java 8 - 15
|
||||
@@ -1182,17 +1182,27 @@ SystemBrowser:
|
||||
If Task.IsAborted Then Exit Sub '中断加载会导致 JavaSelect 异常地返回空值,误判找不到 Java
|
||||
McLaunchLog("无合适的 Java,需要确认是否自动下载")
|
||||
Dim JavaCode As String
|
||||
If MinVer >= New Version(1, 16, 0, 0) Then
|
||||
If MinVer >= New Version(1, 9, 0, 0) Then
|
||||
JavaCode = 17
|
||||
If Not JavaDownloadConfirm("Java 17") Then Throw New Exception("$$")
|
||||
ElseIf MaxVer < New Version(1, 8, 0, 0) Then
|
||||
JavaCode = 7
|
||||
ElseIf MinVer > New Version(1, 8, 0, 52) Then
|
||||
'缺少 Java 8 较新版(统一通行证)
|
||||
If Not JavaDownloadConfirm("Java 7") Then Throw New Exception("$$")
|
||||
ElseIf MinVer > New Version(1, 8, 0, 100) AndAlso MaxVer < New Version(1, 8, 0, 321) Then
|
||||
JavaCode = "8u101"
|
||||
JavaDownloadConfirm("Java 8.0.101 ~ 8.0.320", True)
|
||||
Throw New Exception("$$")
|
||||
ElseIf MinVer > New Version(1, 8, 0, 100) Then
|
||||
JavaCode = "8u101"
|
||||
JavaDownloadConfirm("Java 8.0.101 或更高版本的 Java 8", True)
|
||||
Throw New Exception("$$")
|
||||
ElseIf MaxVer < New Version(1, 8, 0, 321) Then
|
||||
JavaCode = 8
|
||||
If Not JavaDownloadConfirm("Java 8.0.320 或更低版本的 Java 8") Then Throw New Exception("$$")
|
||||
Else
|
||||
JavaCode = 8
|
||||
If Not JavaDownloadConfirm("Java 8") Then Throw New Exception("$$")
|
||||
End If
|
||||
If Not JavaDownloadConfirm(JavaCode) Then Throw New Exception("$$")
|
||||
|
||||
'开始自动下载
|
||||
Dim JavaLoader = JavaFixLoaders(JavaCode)
|
||||
@@ -1350,7 +1360,7 @@ SystemBrowser:
|
||||
|
||||
'添加 Java Wrapper 作为主 Jar
|
||||
If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
|
||||
DataList.Insert(0, "-Doolloo.jlw.tmpdir=""" & GetJavaWrapperDir() & """")
|
||||
DataList.Add("-Doolloo.jlw.tmpdir=""" & GetJavaWrapperDir() & """")
|
||||
DataList.Add("-jar """ & ExtractJavaWrapper() & """")
|
||||
|
||||
'添加 MainClass
|
||||
@@ -1417,7 +1427,7 @@ NextVersion:
|
||||
|
||||
'添加 Java Wrapper 作为主 Jar
|
||||
If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED")
|
||||
DataList.Insert(0, "-Doolloo.jlw.tmpdir=""" & GetJavaWrapperDir() & """")
|
||||
DataList.Add("-Doolloo.jlw.tmpdir=""" & GetJavaWrapperDir() & """")
|
||||
DataList.Add("-jar """ & ExtractJavaWrapper() & """")
|
||||
|
||||
'将 "-XXX" 与后面 "XXX" 合并到一起
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,903 @@
|
||||
Imports System.IO.Compression
|
||||
|
||||
Public Module ModMod
|
||||
|
||||
Public Class McMod
|
||||
|
||||
#Region "基础"
|
||||
|
||||
''' <summary>
|
||||
''' Mod 文件的地址。
|
||||
''' </summary>
|
||||
Public ReadOnly Path As String
|
||||
Public Sub New(Path As String)
|
||||
Me.Path = If(Path, "")
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Mod 的完整文件名。
|
||||
''' </summary>
|
||||
Public ReadOnly Property FileName As String
|
||||
Get
|
||||
Return GetFileNameFromPath(Path)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <summary>
|
||||
''' Mod 的完整文件名,去除最后的 .disabled。
|
||||
''' </summary>
|
||||
Public ReadOnly Property RawFileName As String
|
||||
Get
|
||||
Return FileName.Replace(".disabled", "")
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <summary>
|
||||
''' Mod 的状态。
|
||||
''' </summary>
|
||||
Public ReadOnly Property State As McModState
|
||||
Get
|
||||
Load()
|
||||
If Not IsFileAvailable Then
|
||||
Return McModState.Unavaliable
|
||||
ElseIf Path.EndsWith(".disabled") Then
|
||||
Return McModState.Disabled
|
||||
Else
|
||||
Return McModState.Fine
|
||||
End If
|
||||
End Get
|
||||
End Property
|
||||
Public Enum McModState As Integer
|
||||
Fine = 0
|
||||
Disabled = 1
|
||||
Unavaliable = 2
|
||||
End Enum
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "信息项"
|
||||
|
||||
''' <summary>
|
||||
''' Mod 的名称。若不可用则为 ModID 或无扩展的文件名。
|
||||
''' </summary>
|
||||
Public Property Name As String
|
||||
Get
|
||||
If _Name Is Nothing Then Load()
|
||||
If _Name Is Nothing Then _Name = _ModId
|
||||
If _Name Is Nothing Then _Name = GetFileNameWithoutExtentionFromPath(Path)
|
||||
Return _Name
|
||||
End Get
|
||||
Set(value As String)
|
||||
If _Name Is Nothing AndAlso value IsNot Nothing AndAlso
|
||||
value.ToLower <> "name" AndAlso value.Count > 1 AndAlso Val(value).ToString <> value Then
|
||||
_Name = value
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
Private _Name As String = Nothing
|
||||
|
||||
''' <summary>
|
||||
''' Mod 的描述信息。
|
||||
''' </summary>
|
||||
Public Property Description As String
|
||||
Get
|
||||
If _Description Is Nothing Then Load()
|
||||
If _Description Is Nothing AndAlso FileUnavailableReason IsNot Nothing Then _Description = FileUnavailableReason.Message
|
||||
'If _Description Is Nothing Then _Description = Path
|
||||
Return _Description
|
||||
End Get
|
||||
Set(value As String)
|
||||
If _Description Is Nothing AndAlso value IsNot Nothing AndAlso value.Count > 2 Then
|
||||
_Description = value.ToString.Trim(vbLf)
|
||||
'优化显示:若以 [a-zA-Z0-9] 结尾,加上小数点句号
|
||||
If _Description.ToLower.LastIndexOfAny("qwertyuiopasdfghjklzxcvbnm0123456789") = _Description.Count - 1 Then _Description += "."
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
Private _Description As String = Nothing
|
||||
|
||||
''' <summary>
|
||||
''' Mod 的版本,不保证符合版本格式规范。
|
||||
''' </summary>
|
||||
Public Property Version As String
|
||||
Get
|
||||
If _Version Is Nothing Then Load()
|
||||
Return _Version
|
||||
End Get
|
||||
Set(value As String)
|
||||
If _Version IsNot Nothing AndAlso (_Version.Contains(".") OrElse _Version.Contains("-")) Then Exit Property
|
||||
If value IsNot Nothing AndAlso value.ToLower.Contains("version") Then value = "version" '需要修改的标识
|
||||
_Version = value
|
||||
End Set
|
||||
End Property
|
||||
Private _Version As String = Nothing
|
||||
|
||||
''' <summary>
|
||||
''' 用于依赖检查的 ModID。
|
||||
''' </summary>
|
||||
Public Property ModId As String
|
||||
Get
|
||||
If _ModId Is Nothing Then Load()
|
||||
Return _ModId
|
||||
End Get
|
||||
Set(value As String)
|
||||
If value Is Nothing Then Exit Property
|
||||
value = RegexSeek(value.ToLower, "[0-9a-z_-]+")
|
||||
If value IsNot Nothing AndAlso value.ToLower <> "name" AndAlso value.Count > 1 AndAlso Val(value).ToString <> value Then
|
||||
If Not PossibleModId.Contains(value) Then PossibleModId.Add(value)
|
||||
If _ModId Is Nothing Then _ModId = value
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
Private _ModId As String = Nothing
|
||||
''' <summary>
|
||||
''' 其他可能的 ModID。
|
||||
''' </summary>
|
||||
Public PossibleModId As New List(Of String)
|
||||
|
||||
''' <summary>
|
||||
''' Mod 的主页。
|
||||
''' </summary>
|
||||
Public Property Url As String
|
||||
Get
|
||||
If _Url Is Nothing Then Load()
|
||||
Return _Url
|
||||
End Get
|
||||
Set(value As String)
|
||||
If _Url Is Nothing AndAlso value IsNot Nothing AndAlso value.StartsWith("http") Then
|
||||
_Url = value
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
Private _Url As String = Nothing
|
||||
|
||||
''' <summary>
|
||||
''' Mod 的作者列表。
|
||||
''' </summary>
|
||||
Public Property Authors As String
|
||||
Get
|
||||
If _Authors Is Nothing Then Load()
|
||||
Return _Authors
|
||||
End Get
|
||||
Set(value As String)
|
||||
If _Authors Is Nothing AndAlso Not String.IsNullOrWhiteSpace(value) Then
|
||||
_Authors = value
|
||||
End If
|
||||
End Set
|
||||
End Property
|
||||
Private _Authors As String = Nothing
|
||||
|
||||
''' <summary>
|
||||
''' 依赖项,其中包括了 Minecraft 的版本要求。格式为 ModID - VersionRequirement,若无版本要求则为 Nothing。
|
||||
''' </summary>
|
||||
Public ReadOnly Property Dependencies As Dictionary(Of String, String)
|
||||
Get
|
||||
Load()
|
||||
Return _Dependencies
|
||||
End Get
|
||||
End Property
|
||||
Private _Dependencies As New Dictionary(Of String, String)
|
||||
Private Sub AddDependency(ModID As String, Optional VersionRequirement As String = Nothing)
|
||||
'确保信息正确
|
||||
If ModID Is Nothing OrElse ModID.Count < 2 Then Exit Sub
|
||||
ModID = ModID.ToLower
|
||||
If ModID = "name" OrElse Val(ModID).ToString = ModID Then Exit Sub '跳过 name 与纯数字 id
|
||||
If VersionRequirement Is Nothing OrElse ((Not VersionRequirement.Contains(".")) AndAlso (Not VersionRequirement.Contains("-"))) OrElse VersionRequirement.Contains("$") Then
|
||||
VersionRequirement = Nothing
|
||||
Else
|
||||
If (Not VersionRequirement.StartsWith("[")) AndAlso (Not VersionRequirement.StartsWith("(")) AndAlso (Not VersionRequirement.EndsWith("]")) AndAlso (Not VersionRequirement.EndsWith(")")) Then VersionRequirement = "[" & VersionRequirement & ",)"
|
||||
End If
|
||||
'向依赖项中添加
|
||||
If _Dependencies.ContainsKey(ModID) Then
|
||||
If _Dependencies(ModID) Is Nothing Then _Dependencies(ModID) = VersionRequirement
|
||||
Else
|
||||
_Dependencies.Add(ModID, VersionRequirement)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "加载步骤标记"
|
||||
|
||||
'1. 进行文件可用性检查
|
||||
' 成功:继续第二步。
|
||||
' 失败:标记 FileUnavailableReason, 并停止后续加载。
|
||||
''' <summary>
|
||||
''' 是否已进行 Mod 文件的基础加载。(这包括第一步和第二步)
|
||||
''' </summary>
|
||||
Private IsLoaded As Boolean = False
|
||||
''' <summary>
|
||||
''' Mod 文件是否可被正常读取。
|
||||
''' </summary>
|
||||
Public ReadOnly Property IsFileAvailable As Boolean
|
||||
Get
|
||||
Load()
|
||||
Return FileUnavailableReason Is Nothing
|
||||
End Get
|
||||
End Property
|
||||
''' <summary>
|
||||
''' Mod 文件出错的原因。若无错误,则为 Nothing。
|
||||
''' </summary>
|
||||
Public ReadOnly Property FileUnavailableReason As Exception
|
||||
Get
|
||||
Load()
|
||||
Return _FileUnavailableReason
|
||||
End Get
|
||||
End Property
|
||||
Private _FileUnavailableReason As Exception = Nothing
|
||||
|
||||
'2. 进行 .class 以外的信息获取
|
||||
' 成功:标记 IsInfoWithoutClassAvailable。
|
||||
' 失败:什么也不干。如果需要补充信息的话,检测到 IsInfoWithoutClassAvailable 为 False,会自动继续加载。
|
||||
''' <summary>
|
||||
''' 是否已在不获取 .class 文件的前提下完成了所需信息的加载。
|
||||
''' </summary>
|
||||
Private IsInfoWithoutClassAvailable As Boolean = False
|
||||
|
||||
'3. 尝试从 .class 文件中获取信息
|
||||
' 成功:标记 IsInfoWithClassAvailable。
|
||||
' 失败:什么也不干。
|
||||
''' <summary>
|
||||
''' 是否已进行 .class 文件的信息获取。
|
||||
''' </summary>
|
||||
Private IsInfoWithClassLoaded As Boolean = False
|
||||
''' <summary>
|
||||
''' 是否已在 .class 文件中完成了所需信息的加载。
|
||||
''' </summary>
|
||||
Private IsInfoWithClassAvailable As Boolean = False
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "加载"
|
||||
|
||||
''' <summary>
|
||||
''' 初始化所有数据。
|
||||
''' </summary>
|
||||
Private Sub Init()
|
||||
_Name = Nothing
|
||||
_Description = Nothing
|
||||
_Version = Nothing
|
||||
_ModId = Nothing
|
||||
PossibleModId = New List(Of String)
|
||||
_Dependencies = New Dictionary(Of String, String)
|
||||
IsLoaded = False
|
||||
_FileUnavailableReason = Nothing
|
||||
IsInfoWithoutClassAvailable = False
|
||||
IsInfoWithClassLoaded = False
|
||||
IsInfoWithClassAvailable = False
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 进行文件可用性检查与 .class 以外的信息获取。
|
||||
''' </summary>
|
||||
Public Sub Load(Optional ForceReload As Boolean = False)
|
||||
If IsLoaded AndAlso Not ForceReload Then Exit Sub
|
||||
'初始化
|
||||
Init()
|
||||
'阶段 1:基础可用性检查
|
||||
Dim Jar As ZipArchive
|
||||
Try
|
||||
'打开 Jar 文件
|
||||
If Path.Length < 2 Then Throw New FileNotFoundException("错误的 Mod 文件路径(" & If(Path, "null") & ")")
|
||||
If Not File.Exists(Path) Then Throw New FileNotFoundException("未找到 Mod 文件(" & Path & ")")
|
||||
Jar = New ZipArchive(New FileStream(Path, FileMode.Open))
|
||||
If Jar.Entries.Count = 0 Then Throw New FileFormatException("文件内容为空")
|
||||
Catch ex As UnauthorizedAccessException
|
||||
Log(ex, "Mod 文件由于无权限无法打开(" & Path & ")", LogLevel.Developer)
|
||||
_FileUnavailableReason = New UnauthorizedAccessException("没有读取此文件的权限,请尝试右键以管理员身份运行 PCL", ex)
|
||||
Jar = Nothing
|
||||
Catch ex As Exception
|
||||
Log(ex, "Mod 文件无法打开(" & Path & ")", LogLevel.Developer)
|
||||
_FileUnavailableReason = ex
|
||||
Jar = Nothing
|
||||
End Try
|
||||
'阶段 2:信息获取
|
||||
If Jar IsNot Nothing Then LoadWithoutClass(Jar)
|
||||
'阶段 3: Class 信息获取
|
||||
If Jar IsNot Nothing AndAlso Not IsInfoWithoutClassAvailable Then LoadWithClass(Jar)
|
||||
'释放文件
|
||||
Try
|
||||
If Jar IsNot Nothing Then Jar.Dispose()
|
||||
Catch
|
||||
End Try
|
||||
'完成标记
|
||||
IsLoaded = True
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 进行不使用 .class 文件的信息获取。
|
||||
''' </summary>
|
||||
Private Sub LoadWithoutClass(Jar As ZipArchive)
|
||||
|
||||
#Region "尝试使用 mcmod.info"
|
||||
Try
|
||||
'获取信息文件
|
||||
Dim InfoEntry As ZipArchiveEntry = Jar.GetEntry("mcmod.info")
|
||||
Dim InfoString As String = Nothing
|
||||
If InfoEntry IsNot Nothing Then
|
||||
InfoString = ReadFile(InfoEntry.Open())
|
||||
If InfoString.Length < 15 Then InfoString = Nothing
|
||||
End If
|
||||
If InfoString Is Nothing Then Exit Try
|
||||
'获取可用 Json 项
|
||||
Dim InfoObject As JObject
|
||||
Dim JsonObject = GetJson(InfoString)
|
||||
If JsonObject.Type = JTokenType.Array Then
|
||||
InfoObject = JsonObject(0)
|
||||
Else
|
||||
InfoObject = JsonObject("modList")(0)
|
||||
End If
|
||||
'从文件中获取 Mod 信息项
|
||||
Name = InfoObject("name")
|
||||
Description = InfoObject("description")
|
||||
Version = InfoObject("version")
|
||||
Url = InfoObject("url")
|
||||
ModId = InfoObject("modid")
|
||||
Dim AuthorJson As JArray = InfoObject("authorList")
|
||||
If AuthorJson IsNot Nothing Then
|
||||
Dim Author As New List(Of String)
|
||||
For Each Token In AuthorJson
|
||||
Author.Add(Token.ToString)
|
||||
Next
|
||||
If Author.Count > 0 Then Authors = Join(Author, ", ")
|
||||
End If
|
||||
Dim Reqs As JArray = InfoObject("requiredMods")
|
||||
If Reqs IsNot Nothing Then
|
||||
For Each Token As String In Reqs
|
||||
If Not String.IsNullOrEmpty(Token) Then
|
||||
Token = Token.Substring(Token.IndexOf(":") + 1)
|
||||
If Token.Contains("@") Then
|
||||
AddDependency(Token.Split("@")(0), Token.Split("@")(1))
|
||||
Else
|
||||
AddDependency(Token)
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
Reqs = InfoObject("dependancies")
|
||||
If Reqs IsNot Nothing Then
|
||||
For Each Token As String In Reqs
|
||||
If Not String.IsNullOrEmpty(Token) Then
|
||||
Token = Token.Substring(Token.IndexOf(":") + 1)
|
||||
If Token.Contains("@") Then
|
||||
AddDependency(Token.Split("@")(0), Token.Split("@")(1))
|
||||
Else
|
||||
AddDependency(Token)
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "读取 mcmod.info 时出现未知错误(" & Path & ")", LogLevel.Developer)
|
||||
End Try
|
||||
#End Region
|
||||
#Region "尝试使用 mods.toml"
|
||||
Try
|
||||
'获取 mods.toml 文件
|
||||
Dim TomlEntry As ZipArchiveEntry = Jar.GetEntry("META-INF/mods.toml")
|
||||
Dim TomlText As String = Nothing
|
||||
If TomlEntry IsNot Nothing Then
|
||||
TomlText = ReadFile(TomlEntry.Open())
|
||||
If TomlText.Length < 15 Then TomlText = Nothing
|
||||
End If
|
||||
If TomlText Is Nothing Then Exit Try
|
||||
'文件标准化:统一换行符为 vbLf,去除注释、头尾的空格、空行
|
||||
Dim Lines As New List(Of String)
|
||||
For Each Line In TomlText.Replace(vbCrLf, vbLf).Replace(vbCr, vbLf).Split(vbLf) '统一换行符
|
||||
If Line.StartsWith("#") Then '去除注释
|
||||
Continue For
|
||||
ElseIf Line.Contains("#") Then
|
||||
Line = Line.Substring(0, Line.IndexOf("#"))
|
||||
End If
|
||||
Line = Line.Trim(New Char() {" "c, " "c, " "c}) '去除头尾的空格
|
||||
If Line.Count > 0 Then Lines.Add(Line) '去除空行
|
||||
Next
|
||||
'读取文件数据
|
||||
Dim TomlData As New List(Of KeyValuePair(Of String, Dictionary(Of String, Object))) From {New KeyValuePair(Of String, Dictionary(Of String, Object))("", New Dictionary(Of String, Object))}
|
||||
For i = 0 To Lines.Count - 1
|
||||
Dim Line As String = Lines(i)
|
||||
If Line.StartsWith("[") AndAlso Line.EndsWith("]") Then
|
||||
'段落标记
|
||||
Dim Header = Line.Trim("[]".ToCharArray)
|
||||
TomlData.Add(New KeyValuePair(Of String, Dictionary(Of String, Object))(Header, New Dictionary(Of String, Object)))
|
||||
ElseIf Line.Contains("=") Then
|
||||
'字段标记
|
||||
Dim Key As String = Line.Substring(0, Line.IndexOf("=")).TrimEnd(New Char() {" "c, " "c, " "c})
|
||||
Dim RawValue As String = Line.Substring(Line.IndexOf("=") + 1).TrimStart(New Char() {" "c, " "c, " "c})
|
||||
Dim Value As Object
|
||||
If RawValue.StartsWith("""") AndAlso RawValue.EndsWith("""") Then
|
||||
'单行字符串
|
||||
Value = RawValue.Trim("""")
|
||||
ElseIf RawValue.StartsWith("'''") Then
|
||||
'多行字符串
|
||||
Dim ValueLines As New List(Of String) From {RawValue.TrimStart("'")}
|
||||
Do Until i >= Lines.Count - 1
|
||||
i += 1
|
||||
Dim ValueLine As String = Lines(i)
|
||||
If ValueLine.EndsWith("'''") Then
|
||||
ValueLines.Add(ValueLine.TrimEnd("'"))
|
||||
Exit Do
|
||||
Else
|
||||
ValueLines.Add(ValueLine)
|
||||
End If
|
||||
Loop
|
||||
Value = Join(ValueLines, vbLf).Trim(vbLf).Replace(vbLf, vbCrLf)
|
||||
ElseIf RawValue.ToLower = "true" OrElse RawValue.ToLower = "false" Then
|
||||
'布尔型
|
||||
Value = (RawValue.ToLower = "true")
|
||||
ElseIf Val(RawValue).ToString = RawValue Then
|
||||
'数字型
|
||||
Value = Val(RawValue)
|
||||
Else
|
||||
'不知道是个啥玩意儿,直接存储
|
||||
Value = RawValue
|
||||
End If
|
||||
TomlData.Last.Value(Key) = Value
|
||||
Else
|
||||
'不知道是个啥玩意儿
|
||||
Exit Try
|
||||
End If
|
||||
Next
|
||||
'从文件数据中获取信息
|
||||
Dim ModEntry As Dictionary(Of String, Object) = Nothing
|
||||
For Each TomlSubData In TomlData
|
||||
If TomlSubData.Key = "mods" Then
|
||||
ModEntry = TomlSubData.Value
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
If ModEntry Is Nothing OrElse Not ModEntry.ContainsKey("modId") Then Exit Try
|
||||
ModId = ModEntry("modId")
|
||||
If _ModId Is Nothing Then Exit Try '设置了无效的 ModID
|
||||
If ModEntry.ContainsKey("displayName") Then Name = ModEntry("displayName")
|
||||
If ModEntry.ContainsKey("description") Then Description = ModEntry("description")
|
||||
If ModEntry.ContainsKey("version") Then Version = ModEntry("version")
|
||||
If TomlData(0).Value.ContainsKey("displayURL") Then Url = TomlData(0).Value("displayURL")
|
||||
If TomlData(0).Value.ContainsKey("authors") Then Authors = TomlData(0).Value("authors")
|
||||
For Each TomlSubData In TomlData
|
||||
If TomlSubData.Key.ToLower = $"dependencies.{ModId.ToLower}" Then
|
||||
Dim DepEntry As Dictionary(Of String, Object) = TomlSubData.Value
|
||||
If DepEntry.ContainsKey("modId") AndAlso DepEntry.ContainsKey("mandatory") AndAlso DepEntry("mandatory") AndAlso
|
||||
DepEntry.ContainsKey("side") AndAlso Not DepEntry("side").ToString.ToLower = "server" Then
|
||||
AddDependency(DepEntry("modId"), If(DepEntry.ContainsKey("versionRange"), DepEntry("versionRange"), Nothing))
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
'加载成功
|
||||
GoTo Finished
|
||||
Catch ex As Exception
|
||||
Log(ex, "读取 mods.toml 时出现未知错误(" & Path & ")", LogLevel.Developer)
|
||||
End Try
|
||||
#End Region
|
||||
#Region "尝试使用 fabric.mod.json"
|
||||
Try
|
||||
'获取 fabric.mod.json 文件
|
||||
Dim FabricEntry As ZipArchiveEntry = Jar.GetEntry("fabric.mod.json")
|
||||
Dim FabricText As String = Nothing
|
||||
If FabricEntry IsNot Nothing Then
|
||||
FabricText = ReadFile(FabricEntry.Open(), Encoding.UTF8)
|
||||
If Not FabricText.Contains("schemaVersion") Then FabricText = Nothing
|
||||
End If
|
||||
If FabricText Is Nothing Then Exit Try
|
||||
Dim FabricObject As JObject = GetJson(FabricText)
|
||||
GotFabric:
|
||||
'从文件中获取 Mod 信息项
|
||||
If FabricObject.ContainsKey("name") Then Name = FabricObject("name")
|
||||
If FabricObject.ContainsKey("version") Then Version = FabricObject("version")
|
||||
If FabricObject.ContainsKey("description") Then Description = FabricObject("description")
|
||||
If FabricObject.ContainsKey("id") Then ModId = FabricObject("id")
|
||||
If FabricObject.ContainsKey("contact") Then Url = If(FabricObject("contact")("homepage"), "")
|
||||
Dim AuthorJson As JArray = FabricObject("authors")
|
||||
If AuthorJson IsNot Nothing Then
|
||||
Dim Author As New List(Of String)
|
||||
For Each Token In AuthorJson
|
||||
Author.Add(Token.ToString)
|
||||
Next
|
||||
If Author.Count > 0 Then Authors = Join(Author, ", ")
|
||||
End If
|
||||
'If (Not FabricObject.ContainsKey("serverSideOnly")) OrElse FabricObject("serverSideOnly")("value").ToObject(Of Boolean) = False Then
|
||||
' '添加 Minecraft 依赖
|
||||
' Dim DepMinecraft As String = If(If(FabricObject("acceptedMinecraftVersions") IsNot Nothing, FabricObject("acceptedMinecraftVersions")("value"), ""), "")
|
||||
' If DepMinecraft <> "" Then AddDependency("minecraft", DepMinecraft)
|
||||
' '添加其他依赖
|
||||
' Dim Deps As String = If(If(FabricObject("dependencies") IsNot Nothing, FabricObject("dependencies")("value"), ""), "")
|
||||
' If Deps <> "" Then
|
||||
' For Each Dep In Deps.Split(";")
|
||||
' If Dep = "" OrElse Not Dep.StartsWith("required-") Then Continue For
|
||||
' Dep = Dep.Substring(Dep.IndexOf(":") + 1)
|
||||
' If Dep.Contains("@") Then
|
||||
' AddDependency(Dep.Split("@")(0), Dep.Split("@")(1))
|
||||
' Else
|
||||
' AddDependency(Dep)
|
||||
' End If
|
||||
' Next
|
||||
' End If
|
||||
'End If
|
||||
'加载成功
|
||||
GoTo Finished
|
||||
Catch ex As Exception
|
||||
Log(ex, "读取 fabric.mod.json 时出现未知错误(" & Path & ")", LogLevel.Developer)
|
||||
End Try
|
||||
#End Region
|
||||
#Region "尝试使用 fml_cache_annotation.json"
|
||||
Try
|
||||
'获取 fml_cache_annotation.json 文件
|
||||
Dim FmlEntry As ZipArchiveEntry = Jar.GetEntry("META-INF/fml_cache_annotation.json")
|
||||
Dim FmlText As String = Nothing
|
||||
If FmlEntry IsNot Nothing Then
|
||||
FmlText = ReadFile(FmlEntry.Open(), Encoding.UTF8)
|
||||
If Not FmlText.Contains("Lnet/minecraftforge/fml/common/Mod;") Then FmlText = Nothing
|
||||
End If
|
||||
If FmlText Is Nothing Then Exit Try
|
||||
Dim FmlJson As JObject = GetJson(FmlText)
|
||||
'获取可用 Json 项
|
||||
Dim FmlObject As JObject = Nothing
|
||||
For Each ModFilePair In FmlJson
|
||||
Dim ModFileAnnos As JArray = ModFilePair.Value("annotations")
|
||||
If ModFileAnnos IsNot Nothing Then
|
||||
'先获取 Mod
|
||||
For Each ModFileAnno In ModFileAnnos
|
||||
Dim Name As String = If(ModFileAnno("name"), "")
|
||||
If Name = "Lnet/minecraftforge/fml/common/Mod;" Then
|
||||
FmlObject = ModFileAnno("values")
|
||||
GoTo Got
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
Next
|
||||
Exit Try
|
||||
Got:
|
||||
'从文件中获取 Mod 信息项
|
||||
If FmlObject.ContainsKey("useMetadata") AndAlso If(FmlObject("useMetadata")("value"), "").ToString.ToLower = "true" Then
|
||||
'要求使用 mcmod.info 中的信息
|
||||
Dim value As String = FmlObject("modid")("value")
|
||||
If value Is Nothing Then Exit Try
|
||||
value = RegexSeek(value.ToLower, "[0-9a-z_]+")
|
||||
If value IsNot Nothing AndAlso value.ToLower <> "name" AndAlso value.Count > 1 AndAlso Val(value).ToString <> value Then
|
||||
If Not PossibleModId.Contains(value) Then PossibleModId.Add(value)
|
||||
End If
|
||||
Exit Try
|
||||
End If
|
||||
If FmlObject.ContainsKey("name") Then Name = FmlObject("name")("value")
|
||||
If FmlObject.ContainsKey("version") Then Version = FmlObject("version")("value")
|
||||
If FmlObject.ContainsKey("modid") Then ModId = FmlObject("modid")("value")
|
||||
If (Not FmlObject.ContainsKey("serverSideOnly")) OrElse FmlObject("serverSideOnly")("value").ToObject(Of Boolean) = False Then
|
||||
'添加 Minecraft 依赖
|
||||
Dim DepMinecraft As String = If(If(FmlObject("acceptedMinecraftVersions") IsNot Nothing, FmlObject("acceptedMinecraftVersions")("value"), ""), "")
|
||||
If DepMinecraft <> "" Then AddDependency("minecraft", DepMinecraft)
|
||||
'添加其他依赖
|
||||
Dim Deps As String = If(If(FmlObject("dependencies") IsNot Nothing, FmlObject("dependencies")("value"), ""), "")
|
||||
If Deps <> "" Then
|
||||
For Each Dep In Deps.Split(";")
|
||||
If Dep = "" OrElse Not Dep.StartsWith("required-") Then Continue For
|
||||
Dep = Dep.Substring(Dep.IndexOf(":") + 1)
|
||||
If Dep.Contains("@") Then
|
||||
AddDependency(Dep.Split("@")(0), Dep.Split("@")(1))
|
||||
Else
|
||||
AddDependency(Dep)
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "读取 fml_cache_annotation.json 时出现未知错误(" & Path & ")", LogLevel.Developer)
|
||||
End Try
|
||||
#End Region
|
||||
Finished:
|
||||
#Region "将 Version 代号转换为 META-INF 中的版本"
|
||||
If _Version = "version" Then
|
||||
Try
|
||||
Dim MetaEntry As ZipArchiveEntry = Jar.GetEntry("META-INF/MANIFEST.MF")
|
||||
If MetaEntry IsNot Nothing Then
|
||||
Dim MetaString As String = ReadFile(MetaEntry.Open()).Replace(" :", ":").Replace(": ", ":")
|
||||
If MetaString.Contains("Implementation-Version:") Then
|
||||
MetaString = MetaString.Substring(MetaString.IndexOf("Implementation-Version:") + "Implementation-Version:".Count)
|
||||
MetaString = MetaString.Substring(0, MetaString.IndexOfAny(vbCrLf.ToCharArray)).Trim
|
||||
Version = MetaString
|
||||
End If
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log("获取 META-INF 中的版本信息失败(" & Path & ")", LogLevel.Developer)
|
||||
Version = Nothing
|
||||
End Try
|
||||
End If
|
||||
If _Version IsNot Nothing AndAlso Not (_Version.Contains(".") OrElse _Version.Contains("-")) Then Version = Nothing
|
||||
#End Region
|
||||
|
||||
IsInfoWithoutClassAvailable = _ModId IsNot Nothing AndAlso _Version IsNot Nothing
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' 进行使用 .class 文件的信息获取。
|
||||
''' </summary>
|
||||
Private Sub LoadWithClass(Jar As ZipArchive)
|
||||
Try
|
||||
'查找入口点文件
|
||||
Dim ModClass As String = Nothing
|
||||
Dim ModClassNotBest As String = Nothing '非完美匹配
|
||||
For Each Entry In Jar.Entries
|
||||
If Entry.Name.EndsWith(".class") Then
|
||||
Dim Temp As String = ReadFile(Entry.Open()).ToLower
|
||||
If Temp.Contains("#lnet/minecraftforge/fml/common/mod;") Then
|
||||
ModClass = Temp
|
||||
Exit For
|
||||
ElseIf Temp.Contains("modid") Then
|
||||
ModClassNotBest = Temp
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
If ModClass Is Nothing Then ModClass = ModClassNotBest
|
||||
If ModClass Is Nothing Then Throw New FileNotFoundException("未找到 Mod 入口点")
|
||||
ModClass = ModClass.Replace("ljava/lang/string;", "")
|
||||
If ModClass.Count > 3000 Then ModClass = ModClass.Substring(0, 3000) '如果文件过大,截取前 3000 Byte
|
||||
Dim IndexHead As Integer, IndexTail As Integer, IncreaseCount As Integer
|
||||
'获取 ModID
|
||||
If _ModId Is Nothing Then
|
||||
IndexHead = ModClass.IndexOf("modid") + "modid".Length + 1
|
||||
IncreaseCount = 0
|
||||
Do While Convert.ToInt32(ModClass(IndexHead)) < 32
|
||||
IndexHead += 1
|
||||
IncreaseCount += 1
|
||||
If IncreaseCount > 10 Then Throw New Exception("ModID 头匹配失败")
|
||||
Loop
|
||||
IndexTail = IndexHead + 1
|
||||
IncreaseCount = 0
|
||||
Do Until Convert.ToInt32(ModClass(IndexTail)) < 32
|
||||
IndexTail += 1
|
||||
IncreaseCount += 1
|
||||
If IncreaseCount > 50 Then Throw New Exception("ModID 尾匹配失败")
|
||||
Loop
|
||||
ModId = ModClass.Substring(IndexHead, IndexTail - IndexHead)
|
||||
End If
|
||||
'获取 Version
|
||||
If _Version Is Nothing AndAlso ModClass.Contains("version") Then
|
||||
IndexHead = ModClass.IndexOf("version") + "version".Length + 1
|
||||
IncreaseCount = 0
|
||||
Do While Convert.ToInt32(ModClass(IndexHead)) < 32
|
||||
IndexHead += 1
|
||||
IncreaseCount += 1
|
||||
If IncreaseCount > 10 Then GoTo VersionFindFail
|
||||
Loop
|
||||
IndexTail = IndexHead + 1
|
||||
IncreaseCount = 0
|
||||
Do While ModClass(IndexTail) = "."c OrElse ModClass(IndexTail) = "-"c OrElse
|
||||
(ModClass(IndexTail) >= "0"c AndAlso ModClass(IndexTail) <= "9"c) OrElse
|
||||
(ModClass(IndexTail) >= "a"c AndAlso ModClass(IndexTail) <= "z"c)
|
||||
IndexTail += 1
|
||||
IncreaseCount += 1
|
||||
If IncreaseCount > 50 Then GoTo VersionFindFail
|
||||
Loop
|
||||
_Version = ModClass.Substring(IndexHead, IndexTail - IndexHead)
|
||||
End If
|
||||
VersionFindFail:
|
||||
'获取 Dependencies
|
||||
IndexHead = ModClass.IndexOf("dependencies")
|
||||
If IndexHead > 0 Then
|
||||
If ModClass.Count >= IndexHead + 300 Then ModClass = ModClass.Substring(IndexHead, 299)
|
||||
Dim Deps As List(Of String) = RegexSearch(ModClass, "(?<=required-((before|after|before-client|after-client)?):)[0-9a-z]+(@[\(\[]{1}[0-9.,]+[\)\]]{1})?")
|
||||
For Each Token As String In Deps
|
||||
If Not String.IsNullOrEmpty(Token) Then
|
||||
If Token.Contains("@") Then
|
||||
AddDependency(Token.Split("@")(0), Token.Split("@")(1))
|
||||
Else
|
||||
AddDependency(Token)
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Log(ex, "Mod Class 信息不可用(" & If(Path, "null") & ")", LogLevel.Normal)
|
||||
End Try
|
||||
IsInfoWithClassAvailable = _ModId IsNot Nothing AndAlso _Version IsNot Nothing
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
''' <summary>
|
||||
''' 是否可能为前置 Mod。
|
||||
''' </summary>
|
||||
Public Function IsPresetMod() As Boolean
|
||||
Return Dependencies.Count = 0 AndAlso (Name IsNot Nothing) AndAlso (Name.ToLower.Contains("core") OrElse Name.ToLower.Contains("lib"))
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' 根据完整文件路径的文件扩展名判断是否为 Mod 文件。
|
||||
''' </summary>
|
||||
Public Shared Function IsModFile(Path As String)
|
||||
If Path Is Nothing OrElse Not Path.Contains(".") Then Return False
|
||||
Path = Path.ToLower
|
||||
If Path.EndsWith(".jar") OrElse Path.EndsWith(".zip") OrElse Path.EndsWith(".litemod") OrElse
|
||||
Path.EndsWith(".jar.disabled") OrElse Path.EndsWith(".zip.disabled") OrElse Path.EndsWith(".litemod.disabled") Then Return True
|
||||
Return False
|
||||
End Function
|
||||
|
||||
End Class
|
||||
|
||||
'加载 Mod 列表
|
||||
Public McModLoader As New LoaderTask(Of String, List(Of McMod))("Mod List Loader", AddressOf McModLoad)
|
||||
Private Sub McModLoad(Loader As LoaderTask(Of String, List(Of McMod)))
|
||||
Try
|
||||
RunInUiWait(Sub() If FrmVersionMod IsNot Nothing Then FrmVersionMod.Load.ShowProgress = False)
|
||||
|
||||
'获取 Mod 文件夹下的可用文件列表
|
||||
Dim ModFileList As New List(Of FileInfo)
|
||||
If Directory.Exists(Loader.Input) Then
|
||||
Dim RawName As String = Loader.Input.ToLower
|
||||
For Each File As FileInfo In EnumerateFiles(Loader.Input)
|
||||
If File.DirectoryName.ToLower & "\" <> RawName Then
|
||||
'仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod
|
||||
If Not (PageVersionLeft.Version IsNot Nothing AndAlso PageVersionLeft.Version.Version.HasForge AndAlso
|
||||
PageVersionLeft.Version.Version.McCodeMain < 13 AndAlso
|
||||
File.Directory.Name = "1." & PageVersionLeft.Version.Version.McCodeMain & "." & PageVersionLeft.Version.Version.McCodeSub) Then
|
||||
Continue For
|
||||
End If
|
||||
End If
|
||||
If McMod.IsModFile(File.FullName) Then ModFileList.Add(File)
|
||||
Next
|
||||
End If
|
||||
|
||||
'确定是否显示进度
|
||||
Loader.Progress = 0.03
|
||||
If ModFileList.Count > 100 Then RunInUi(Sub() If FrmVersionMod IsNot Nothing Then FrmVersionMod.Load.ShowProgress = True)
|
||||
|
||||
'加载为 Mod 列表
|
||||
Dim ModList As New List(Of McMod)
|
||||
For Each ModFile As FileInfo In ModFileList
|
||||
Dim ModEntity As New McMod(ModFile.FullName)
|
||||
ModEntity.Load()
|
||||
ModList.Add(ModEntity)
|
||||
Loader.Progress += 0.9 / ModFileList.Count
|
||||
Next
|
||||
Loader.Progress = 0.93
|
||||
|
||||
'排序
|
||||
ModList = Sort(ModList, Function(Left As McMod, Right As McMod) As Boolean
|
||||
If (Left.State = McMod.McModState.Unavaliable) <> (Right.State = McMod.McModState.Unavaliable) Then
|
||||
Return Left.State = McMod.McModState.Unavaliable
|
||||
Else
|
||||
Return Not Right.FileName.CompareTo(Left.FileName)
|
||||
End If
|
||||
End Function)
|
||||
Loader.Progress = 0.98
|
||||
|
||||
'回设
|
||||
If Loader.IsAborted Then Exit Sub
|
||||
Loader.Output = ModList
|
||||
|
||||
Catch ex As Exception
|
||||
Log(ex, "Mod 列表加载失败", LogLevel.Debug)
|
||||
Throw
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
#If DEBUG Then
|
||||
''' <summary>
|
||||
''' 检查 Mod 列表中存在的错误,返回错误信息的集合。
|
||||
''' </summary>
|
||||
Public Function McModCheck(Version As McVersion, Mods As List(Of McMod)) As List(Of String)
|
||||
Dim Result As New List(Of String)
|
||||
'令所有 Mod 进行基础检查,并归纳需要检查的 Mod
|
||||
Dim CurrentModList As New List(Of McMod)
|
||||
For Each ModEntity In Mods
|
||||
If Not ModEntity.IsFileAvailable Then
|
||||
Result.Add("无法读取的 Mod 文件。" & vbCrLf & " - " & ModEntity.Path)
|
||||
Continue For
|
||||
End If
|
||||
If ModEntity.State = McMod.McModState.Fine AndAlso ModEntity.ModId IsNot Nothing Then CurrentModList.Add(ModEntity)
|
||||
Next
|
||||
'添加默认依赖
|
||||
Dim CurrentDependencies As New Dictionary(Of String, String()) '{DependencyVersion, Path}
|
||||
If Version.State = McVersionState.Forge Then CurrentDependencies.Add("forge", {Version.Version.ForgeVersion, "Forge"})
|
||||
CurrentDependencies.Add("minecraft", {Version.Version.McName, "Minecraft"})
|
||||
'检查重复的 Mod,并添加对应的依赖
|
||||
For Each ModEntity In CurrentModList
|
||||
For Each PossibleModId In ModEntity.PossibleModId
|
||||
If CurrentDependencies.ContainsKey(PossibleModId) Then
|
||||
If CurrentDependencies(PossibleModId)(2) = 1 Then
|
||||
Result.Add("重复添加了相同的 Mod,请尝试删除其中一个(ModID:" & PossibleModId & ")。" & vbCrLf &
|
||||
" - " & ModEntity.FileName & vbCrLf &
|
||||
" - " & CurrentDependencies(PossibleModId)(1))
|
||||
Else
|
||||
Log("[Minecraft] 由于可能有多个 ModID,跳过疑似的重复项(ModID:" & PossibleModId & ")。" & vbCrLf &
|
||||
" - " & ModEntity.FileName & vbCrLf &
|
||||
" - " & CurrentDependencies(PossibleModId)(1), LogLevel.Developer)
|
||||
End If
|
||||
Else
|
||||
CurrentDependencies.Add(PossibleModId, {ModEntity.Version, ModEntity.FileName, ModEntity.PossibleModId.Count})
|
||||
End If
|
||||
Next
|
||||
Next
|
||||
'检查依赖
|
||||
For Each ModEntity In CurrentModList
|
||||
Try
|
||||
For Each Dependency In ModEntity.Dependencies
|
||||
Dim ReqId As String = Dependency.Key
|
||||
If ReqId.Count < 2 Then Continue For '确保正常
|
||||
If ReqId = ModEntity.ModId Then Continue For '跳过自体引用
|
||||
If ReqId = "forgemultipartcbe" Then Continue For '跳过莫名其妙的引用
|
||||
If Dependency.Value IsNot Nothing Then
|
||||
'获取分段后的详细版本信息
|
||||
Dim ReqVersion As String = Dependency.Value
|
||||
Dim ReqVersionHeadCanEqual As Boolean = ReqVersion.StartsWith("[")
|
||||
Dim ReqVersionTailCanEqual As Boolean = ReqVersion.EndsWith("]")
|
||||
Dim ReqVersionHead As String
|
||||
Dim ReqVersionTail As String
|
||||
If ReqVersion.Contains(",") Then
|
||||
ReqVersionHead = ReqVersion.Split(",")(0).Trim("([ ".ToCharArray())
|
||||
ReqVersionTail = ReqVersion.Split(",")(1).Trim("]) ".ToCharArray())
|
||||
Else
|
||||
ReqVersionHead = ReqVersion.Trim("([]) ".ToCharArray())
|
||||
ReqVersionTail = ReqVersionHead
|
||||
If ReqId = "minecraft" AndAlso ReqVersionHead.Split(".").Count = 2 Then
|
||||
ReqVersionTail = ReqVersionHead.Split(".")(0) & "." & (Val(ReqVersionHead.Split(".")(1)) + 1)
|
||||
ReqVersionTailCanEqual = False
|
||||
End If
|
||||
End If
|
||||
If ReqVersionHead.StartsWith("1.") AndAlso ReqVersionHead.Contains("-") Then ReqVersionHead = ReqVersionHead.Substring(ReqVersionHead.LastIndexOf("-") + 1)
|
||||
If ReqVersionTail.StartsWith("1.") AndAlso ReqVersionTail.Contains("-") Then ReqVersionTail = ReqVersionTail.Substring(ReqVersionTail.LastIndexOf("-") + 1)
|
||||
'获取报错描述文本
|
||||
Dim VersionRequire As String
|
||||
If ReqVersionHead = ReqVersionTail Then
|
||||
VersionRequire = "应为 " & ReqVersionHead
|
||||
ElseIf ReqVersionHead.Contains(".") AndAlso ReqVersionTail.Contains(".") Then
|
||||
VersionRequire = "应为 " & ReqVersionHead & " 至 " & ReqVersionTail
|
||||
ElseIf ReqVersionHead.Contains(".") Then
|
||||
If ReqVersionHeadCanEqual Then
|
||||
VersionRequire = "最低应为 " & ReqVersionHead
|
||||
Else
|
||||
VersionRequire = "应高于 " & ReqVersionHead
|
||||
End If
|
||||
ElseIf ReqVersionTail.Contains(".") Then
|
||||
If ReqVersionTailCanEqual Then
|
||||
VersionRequire = "最高应为 " & ReqVersionHead
|
||||
Else
|
||||
VersionRequire = "应低于 " & ReqVersionHead
|
||||
End If
|
||||
Else
|
||||
VersionRequire = ""
|
||||
End If
|
||||
'检查前置 Mod 是否存在,并获取其版本
|
||||
If Not CurrentDependencies.ContainsKey(ReqId) Then
|
||||
Result.Add("缺少前置 Mod:" & ReqId & If(VersionRequire = "", "", ",其版本" & VersionRequire) & "。" & vbCrLf & " - " & ModEntity.FileName)
|
||||
Continue For
|
||||
End If
|
||||
Dim CurrentVersion As String = If(CurrentDependencies(ReqId)(0), "0.0")
|
||||
If CurrentVersion.StartsWith("1.") AndAlso CurrentVersion.Contains("-") Then CurrentVersion = CurrentVersion.Substring(CurrentVersion.LastIndexOf("-") + 1)
|
||||
'对比前置 Mod 头部版本
|
||||
If ReqVersionHead.Contains(".") Then
|
||||
If VersionSortInteger(ReqVersionHead, CurrentVersion) > If(ReqVersionHeadCanEqual, 0, -1) Then
|
||||
Result.Add(ReqId.Substring(0, 1).ToUpper & ReqId.Substring(1) & " 版本过低,其版本" & VersionRequire & ",而当前版本为 " & CurrentVersion & "。" & vbCrLf &
|
||||
" - " & ModEntity.FileName & If(ReqId <> "minecraft" AndAlso ReqId <> "forge", vbCrLf & " - 前置:" & CurrentDependencies(ReqId)(1), ""))
|
||||
Continue For
|
||||
End If
|
||||
End If
|
||||
'对比前置 Mod 尾部版本
|
||||
If ReqVersionTail.Contains(".") Then
|
||||
If VersionSortInteger(CurrentVersion, ReqVersionTail) > If(ReqVersionTailCanEqual, 0, -1) Then
|
||||
Result.Add(ReqId.Substring(0, 1).ToUpper & ReqId.Substring(1) & " 版本过高,其版本" & VersionRequire & ",而当前版本为 " & CurrentVersion & "。" & vbCrLf &
|
||||
" - " & ModEntity.FileName & If(ReqId <> "minecraft" AndAlso ReqId <> "forge", vbCrLf & " - 前置:" & CurrentDependencies(ReqId)(1), ""))
|
||||
Continue For
|
||||
End If
|
||||
End If
|
||||
Else
|
||||
If Not CurrentDependencies.ContainsKey(Dependency.Key) Then
|
||||
Result.Add("缺少前置 Mod:" & Dependency.Key & "。" & vbCrLf & " - " & ModEntity.FileName)
|
||||
Continue For
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
Catch ex As Exception
|
||||
Result.Add("检查 Mod 时出错:" & GetExceptionSummary(ex) & vbCrLf & " - " & ModEntity.FileName)
|
||||
Log(ex, "检查 Mod 时出错")
|
||||
End Try
|
||||
Next
|
||||
If Result.Count = 0 Then
|
||||
Log("[Minecraft] Mod 检查未发现异常")
|
||||
Else
|
||||
Log("[Minecraft] Mod 检查异常结果:" & vbCrLf & Join(Result, vbCrLf))
|
||||
End If
|
||||
Return Result
|
||||
End Function
|
||||
#End If
|
||||
|
||||
End Module
|
||||
@@ -254,17 +254,21 @@ Retry:
|
||||
For Each ModJson In Task.Input
|
||||
'跳过重复的 Mod(疑似 CurseForge Bug)
|
||||
If FileList.ContainsKey(ModJson("id").ToObject(Of Integer)) Then Continue For
|
||||
'根据 modules 判断是资源包还是 Mod
|
||||
'建立 CompFile
|
||||
Dim File As New CompFile(ModJson, CompType.Mod)
|
||||
If Not File.Available Then Continue For
|
||||
'根据 modules 和文件名后缀判断是资源包还是 Mod
|
||||
Dim IsResourcePack As Boolean
|
||||
If ModJson("modules").Any Then 'modules 可能返回 null(#1006)
|
||||
Dim ModuleNames = CType(ModJson("modules"), JArray).Select(Function(l) l("name").ToString).ToList
|
||||
IsResourcePack = Not ModuleNames.Contains("META-INF") AndAlso ModuleNames.Contains("pack.mcmeta")
|
||||
IsResourcePack =
|
||||
(Not ModuleNames.Contains("META-INF")) AndAlso (Not ModuleNames.Contains("mcmod.info")) AndAlso '不包含 META-INF 或 mcmod.info
|
||||
ModuleNames.Contains("pack.mcmeta") AndAlso '包含 pack.mcmeta
|
||||
(Not File.FileName.EndsWith(".jar")) '文件后缀不是 .jar
|
||||
Else
|
||||
IsResourcePack = False
|
||||
End If
|
||||
'实际的添加
|
||||
Dim File As New CompFile(ModJson, CompType.Mod)
|
||||
If Not File.Available Then Continue For
|
||||
FileList.Add(ModJson("id"),
|
||||
File.ToNetFile($"{PathMcFolder}versions\{VersionName}\{If(IsResourcePack, "resourcepacks", "mods")}\"))
|
||||
Task.Progress += 1 / (1 + ModFileList.Count)
|
||||
@@ -278,6 +282,7 @@ Retry:
|
||||
'构造加载器
|
||||
Dim Request As New McInstallRequest With {
|
||||
.TargetVersionName = VersionName,
|
||||
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
|
||||
.MinecraftName = Json("minecraft")("version").ToString,
|
||||
.ForgeVersion = ForgeVersion,
|
||||
.FabricVersion = FabricVersion
|
||||
@@ -333,7 +338,7 @@ Retry:
|
||||
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
|
||||
Loader.Start(Request.TargetVersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
|
||||
@@ -431,6 +436,7 @@ Retry:
|
||||
'构造加载器
|
||||
Dim Request As New McInstallRequest With {
|
||||
.TargetVersionName = VersionName,
|
||||
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
|
||||
.MinecraftName = MinecraftVersion,
|
||||
.ForgeVersion = ForgeVersion,
|
||||
.FabricVersion = FabricVersion
|
||||
@@ -486,7 +492,7 @@ Retry:
|
||||
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
|
||||
Loader.Start(Request.TargetVersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
If ShowRibble Then FrmMain.BtnExtraDownload.Ribble()
|
||||
@@ -533,6 +539,7 @@ Retry:
|
||||
End If
|
||||
Dim Request As New McInstallRequest With {
|
||||
.TargetVersionName = VersionName,
|
||||
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
|
||||
.MinecraftName = Json("gameVersion").ToString
|
||||
}
|
||||
Dim InstallExpectTime As Double = 0
|
||||
@@ -584,7 +591,7 @@ Retry:
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
'If Archive IsNot Nothing Then Archive.Dispose() '解除占用,以免在加载器中触发 “正由另一进程使用,因此该进程无法访问此文件”
|
||||
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
|
||||
Loader.Start(Request.TargetVersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
FrmMain.BtnExtraDownload.Ribble()
|
||||
@@ -629,7 +636,7 @@ Retry:
|
||||
Hint("该整合包未提供游戏版本信息,无法安装!", HintType.Critical)
|
||||
Exit Sub
|
||||
End If
|
||||
Dim Request As New McInstallRequest With {.TargetVersionName = VersionName}
|
||||
Dim Request As New McInstallRequest With {.TargetVersionName = VersionName, .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\"}
|
||||
For Each Component In PackJson("components")
|
||||
Select Case If(Component("uid"), "").ToString
|
||||
Case "org.lwjgl"
|
||||
@@ -679,7 +686,7 @@ Retry:
|
||||
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
|
||||
Loader.Start(Request.TargetVersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
FrmMain.BtnExtraDownload.Ribble()
|
||||
@@ -738,6 +745,7 @@ Retry:
|
||||
End If
|
||||
Dim Request As New McInstallRequest With {
|
||||
.TargetVersionName = VersionName,
|
||||
.TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
|
||||
.MinecraftName = Addons("game"),
|
||||
.OptiFineVersion = If(Addons.ContainsKey("optifine"), Addons("optifine"), Nothing),
|
||||
.ForgeVersion = If(Addons.ContainsKey("forge"), Addons("forge"), Nothing),
|
||||
@@ -777,7 +785,7 @@ Retry:
|
||||
'启动
|
||||
Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
'If Archive IsNot Nothing Then Archive.Dispose() '解除占用,以免在加载器中触发 “正由另一进程使用,因此该进程无法访问此文件”
|
||||
Loader.Start(PathMcFolder & "versions\" & VersionName & "\")
|
||||
Loader.Start(Request.TargetVersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
FrmMain.BtnExtraDownload.Ribble()
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
Get
|
||||
Return _State
|
||||
End Get
|
||||
Set(ByVal value As MinecraftState)
|
||||
Set(value As MinecraftState)
|
||||
If _State = value Then Exit Property
|
||||
_State = value
|
||||
WatcherStateChanged()
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
|
||||
Case "打开网页"
|
||||
Data(0) = Data(0).Replace("\", "/")
|
||||
If Not (Data(0).StartsWith("http://") OrElse Data(0).StartsWith("https://")) Then
|
||||
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败")
|
||||
If Not Data(0).Contains("://") OrElse Data(0).ToLower.StartsWith("file") Then '为了支持更多协议(#2200)
|
||||
MyMsgBox("EventData 必须为一个网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败")
|
||||
Exit Sub
|
||||
End If
|
||||
Hint("正在打开网页,请稍候……")
|
||||
Hint("正在开启中,请稍候……")
|
||||
OpenWebsite(Data(0))
|
||||
|
||||
Case "打开文件", "打开帮助"
|
||||
@@ -65,15 +65,21 @@
|
||||
RunInThread(Sub() PageOtherTest.MemoryOptimize(True))
|
||||
|
||||
Case "清理垃圾"
|
||||
PageOtherTest.RubbishClear()
|
||||
RunInThread(Sub() PageOtherTest.RubbishClear())
|
||||
|
||||
Case "弹出窗口"
|
||||
MyMsgBox(Data(1).Replace("\n", vbCrLf), Data(0).Replace("\n", vbCrLf))
|
||||
|
||||
Case "切换页面"
|
||||
FrmMain.PageChange(Val(Data(0)), Val(Data(1)))
|
||||
|
||||
Case "导入整合包"
|
||||
RunInThread(Sub() ModpackInstall())
|
||||
|
||||
Case "下载文件"
|
||||
Data(0) = Data(0).Replace("\", "/")
|
||||
If Not (Data(0).StartsWith("http://") OrElse Data(0).StartsWith("https://")) Then
|
||||
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL 不支持其他乱七八糟的协议。", "事件执行失败")
|
||||
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL 不支持其他乱七八糟的下载协议。", "事件执行失败")
|
||||
Exit Sub
|
||||
End If
|
||||
PageOtherTest.StartCustomDownload(Data(0), GetFileNameFromPath(Data(0)))
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
For Each File In My.Computer.FileSystem.GetFiles(Path & "PCL\Musics\", FileIO.SearchOption.SearchAllSubDirectories, "*.*")
|
||||
'文件夹可能会被加入 .ini 文件夹配置文件、一些乱七八糟的 .jpg 文件啥的
|
||||
Dim Extend As String = File.Split(".").Last.ToLower
|
||||
If Not (Extend = "ini" OrElse Extend = "jpg" OrElse Extend = "txt" OrElse Extend = "cfg" OrElse Extend = "png") Then
|
||||
If Not (Extend = "ini" OrElse Extend = "jpg" OrElse Extend = "txt" OrElse Extend = "cfg" OrElse Extend = "lrc" OrElse Extend = "png") Then
|
||||
MusicAllList.Add(File)
|
||||
End If
|
||||
Next
|
||||
@@ -277,7 +277,7 @@
|
||||
Log(ex, "播放音乐失败(" & MusicCurrent & ")", LogLevel.Developer)
|
||||
If MusicAllList.Count > 1 Then
|
||||
Thread.Sleep(1000)
|
||||
MusicStartPlay(DequeueNextMusicAddress)
|
||||
MusicStartPlay(DequeueNextMusicAddress, IsFirstLoad)
|
||||
End If
|
||||
Finally
|
||||
If CurrentWave IsNot Nothing Then CurrentWave.Dispose()
|
||||
|
||||
@@ -25,7 +25,7 @@ Public Class CookieWebClient
|
||||
''' </summary>
|
||||
Public Timeout As Integer = 600000
|
||||
|
||||
Protected Overrides Function GetWebRequest(ByVal address As Uri) As WebRequest
|
||||
Protected Overrides Function GetWebRequest(address As Uri) As WebRequest
|
||||
Dim r As WebRequest = MyBase.GetWebRequest(address)
|
||||
Dim request = TryCast(r, HttpWebRequest)
|
||||
|
||||
@@ -37,19 +37,19 @@ Public Class CookieWebClient
|
||||
Return r
|
||||
End Function
|
||||
|
||||
Protected Overrides Function GetWebResponse(ByVal request As WebRequest, ByVal result As IAsyncResult) As WebResponse
|
||||
Protected Overrides Function GetWebResponse(request As WebRequest, result As IAsyncResult) As WebResponse
|
||||
Dim response As WebResponse = MyBase.GetWebResponse(request, result)
|
||||
ReadCookies(response)
|
||||
Return response
|
||||
End Function
|
||||
|
||||
Protected Overrides Function GetWebResponse(ByVal request As WebRequest) As WebResponse
|
||||
Protected Overrides Function GetWebResponse(request As WebRequest) As WebResponse
|
||||
Dim response As WebResponse = MyBase.GetWebResponse(request)
|
||||
ReadCookies(response)
|
||||
Return response
|
||||
End Function
|
||||
|
||||
Private Sub ReadCookies(ByVal r As WebResponse)
|
||||
Private Sub ReadCookies(r As WebResponse)
|
||||
Dim response = TryCast(r, HttpWebResponse)
|
||||
If response IsNot Nothing Then
|
||||
Dim cookies As CookieCollection = response.Cookies
|
||||
|
||||
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
|
||||
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
|
||||
' 方法是按如下所示使用“*”
|
||||
|
||||
<Assembly: AssemblyVersion("2.6.3.0")>
|
||||
<Assembly: AssemblyFileVersion("2.6.3.0")>
|
||||
<Assembly: AssemblyVersion("2.6.4.0")>
|
||||
<Assembly: AssemblyFileVersion("2.6.4.0")>
|
||||
<Assembly: NeutralResourcesLanguage("")>
|
||||
|
||||
@@ -386,7 +386,7 @@ Public Module ModDownloadLib
|
||||
'选择 Java
|
||||
Dim Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 0))
|
||||
If Java Is Nothing Then
|
||||
If Not JavaDownloadConfirm(17) Then Throw New Exception("由于未找到 Java,已取消安装。")
|
||||
If Not JavaDownloadConfirm("Java 8 或更高版本") Then Throw New Exception("由于未找到 Java,已取消安装。")
|
||||
'开始自动下载
|
||||
Dim JavaLoader = JavaFixLoaders(17)
|
||||
JavaLoader.Start(17, IsForceRestart:=True)
|
||||
@@ -489,7 +489,7 @@ Public Module ModDownloadLib
|
||||
''' <summary>
|
||||
''' 获取下载某个 OptiFine 版本的加载器列表。
|
||||
''' </summary>
|
||||
Private Function McDownloadOptiFineLoader(DownloadInfo As DlOptiFineListEntry, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
|
||||
Private Function McDownloadOptiFineLoader(DownloadInfo As DlOptiFineListEntry, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
|
||||
|
||||
'参数初始化
|
||||
McFolder = If(McFolder, PathMcFolder)
|
||||
@@ -553,14 +553,14 @@ Public Module ModDownloadLib
|
||||
'拷贝原版文件
|
||||
If Not IsCustomFolder Then Exit Sub
|
||||
SyncLock VanillaSyncLock
|
||||
Dim ClientName As String = New DirectoryInfo(ClientDownloadLoader.Input).Name '#2031 报告了此处 ClientDownloadLoader.Input 为 null 的问题,但无法复现
|
||||
Dim ClientName As String = GetFolderNameFromPath(ClientFolder)
|
||||
Directory.CreateDirectory(McFolder & "versions\" & DownloadInfo.Inherit)
|
||||
If Not File.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json") Then
|
||||
CopyFile(ClientDownloadLoader.Input & ClientName & ".json",
|
||||
CopyFile(ClientFolder & ClientName & ".json",
|
||||
McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json")
|
||||
End If
|
||||
If Not File.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar") Then
|
||||
CopyFile(ClientDownloadLoader.Input & ClientName & ".jar",
|
||||
CopyFile(ClientFolder & ClientName & ".jar",
|
||||
McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar")
|
||||
End If
|
||||
End SyncLock
|
||||
@@ -1114,7 +1114,7 @@ Public Module ModDownloadLib
|
||||
'选择 Java
|
||||
Dim Java = JavaSelect("已取消安装。", New Version(1, 8, 0, 0))
|
||||
If Java Is Nothing Then
|
||||
If Not JavaDownloadConfirm(17) Then Throw New Exception("由于未找到 Java,已取消安装。")
|
||||
If Not JavaDownloadConfirm("Java 8 或更高版本") Then Throw New Exception("由于未找到 Java,已取消安装。")
|
||||
'开始自动下载
|
||||
Dim JavaLoader = JavaFixLoaders(17)
|
||||
JavaLoader.Start(17, IsForceRestart:=True)
|
||||
@@ -1259,7 +1259,7 @@ Public Module ModDownloadLib
|
||||
''' <summary>
|
||||
''' 获取下载某个 Forge 版本的加载器列表。
|
||||
''' </summary>
|
||||
Private Function McDownloadForgeLoader(Version As String, Inherit As String, Optional DownloadInfo As DlForgeVersionEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
|
||||
Private Function McDownloadForgeLoader(Version As String, Inherit As String, Optional DownloadInfo As DlForgeVersionEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional ClientFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
|
||||
|
||||
'参数初始化
|
||||
McFolder = If(McFolder, PathMcFolder)
|
||||
@@ -1386,13 +1386,13 @@ Public Module ModDownloadLib
|
||||
'拷贝原版文件
|
||||
If Not IsCustomFolder Then Exit Sub
|
||||
SyncLock VanillaSyncLock
|
||||
Dim ClientName As String = New DirectoryInfo(ClientDownloadLoader.Input).Name
|
||||
Dim ClientName As String = GetFolderNameFromPath(ClientFolder)
|
||||
Directory.CreateDirectory(McFolder & "versions\" & Inherit)
|
||||
If Not File.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".json") Then
|
||||
CopyFile(ClientDownloadLoader.Input & ClientName & ".json", McFolder & "versions\" & Inherit & "\" & Inherit & ".json")
|
||||
CopyFile(ClientFolder & ClientName & ".json", McFolder & "versions\" & Inherit & "\" & Inherit & ".json")
|
||||
End If
|
||||
If Not File.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".jar") Then
|
||||
CopyFile(ClientDownloadLoader.Input & ClientName & ".jar", McFolder & "versions\" & Inherit & "\" & Inherit & ".jar")
|
||||
CopyFile(ClientFolder & ClientName & ".jar", McFolder & "versions\" & Inherit & "\" & Inherit & ".jar")
|
||||
End If
|
||||
End SyncLock
|
||||
#End Region
|
||||
@@ -1797,6 +1797,10 @@ Public Module ModDownloadLib
|
||||
''' 必填。安装目标版本名称。
|
||||
''' </summary>
|
||||
Public TargetVersionName As String
|
||||
''' <summary>
|
||||
''' 必填。安装目标文件夹。
|
||||
''' </summary>
|
||||
Public TargetVersionFolder As String
|
||||
|
||||
''' <summary>
|
||||
''' 必填。欲下载的 Minecraft 的版本名。
|
||||
@@ -1909,7 +1913,7 @@ Public Module ModDownloadLib
|
||||
Dim Loader As New LoaderCombo(Of String)(Request.TargetVersionName & " 安装", SubLoaders) With {.OnStateChanged = AddressOf McInstallState}
|
||||
|
||||
'启动
|
||||
Loader.Start(PathMcFolder & "versions\" & Request.TargetVersionName & "\")
|
||||
Loader.Start(Request.TargetVersionFolder)
|
||||
LoaderTaskbarAdd(Loader)
|
||||
FrmMain.BtnExtraDownload.ShowRefresh()
|
||||
FrmMain.BtnExtraDownload.Ribble()
|
||||
@@ -2009,28 +2013,29 @@ Public Module ModDownloadLib
|
||||
If OptiFineAsMod Then
|
||||
LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineSaveLoader(Request.OptiFineEntry, OptiFineFolder & Request.OptiFineEntry.NameFile)) With {.Show = False, .ProgressWeight = 16, .Block = Request.ForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
|
||||
Else
|
||||
LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineLoader(Request.OptiFineEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 24, .Block = Request.ForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
|
||||
LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineLoader(Request.OptiFineEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) With {.Show = False, .ProgressWeight = 24, .Block = Request.ForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
|
||||
End If
|
||||
End If
|
||||
'Forge
|
||||
If Request.ForgeVersion IsNot Nothing Then
|
||||
LoaderList.Add(New LoaderCombo(Of String)("下载 Forge " & Request.ForgeVersion, McDownloadForgeLoader(Request.ForgeVersion, Request.MinecraftName, Request.ForgeEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 25, .Block = Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
|
||||
LoaderList.Add(New LoaderCombo(Of String)("下载 Forge " & Request.ForgeVersion, McDownloadForgeLoader(Request.ForgeVersion, Request.MinecraftName, Request.ForgeEntry, TempMcFolder, ClientLoader, Request.TargetVersionFolder, False)) With {.Show = False, .ProgressWeight = 25, .Block = Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
|
||||
End If
|
||||
'LiteLoader
|
||||
If Request.LiteLoaderEntry IsNot Nothing Then
|
||||
LoaderList.Add(New LoaderCombo(Of String)("下载 LiteLoader " & Request.MinecraftName, McDownloadLiteLoaderLoader(Request.LiteLoaderEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 1, .Block = Request.FabricVersion Is Nothing})
|
||||
End If
|
||||
'Fabric Loader
|
||||
'Fabric
|
||||
If Request.FabricVersion IsNot Nothing Then
|
||||
LoaderList.Add(New LoaderCombo(Of String)("下载 Fabric " & Request.FabricVersion, McDownloadFabricLoader(Request.FabricVersion, Request.MinecraftName, TempMcFolder, False)) With {.Show = False, .ProgressWeight = 2, .Block = True})
|
||||
End If
|
||||
'合并安装
|
||||
LoaderList.Add(New LoaderTask(Of String, String)("安装游戏", Sub(Task As LoaderTask(Of String, String))
|
||||
InstallMerge(OutputFolder, OutputFolder, OptiFineFolder, OptiFineAsMod, ForgeFolder, Request.ForgeVersion, FabricFolder, LiteLoaderFolder)
|
||||
Task.Progress = 0.3
|
||||
If Directory.Exists(TempMcFolder & "libraries") Then CopyDirectory(TempMcFolder & "libraries", PathMcFolder & "libraries")
|
||||
If Directory.Exists(TempMcFolder & "mods") Then CopyDirectory(TempMcFolder & "mods", PathMcFolder & "mods")
|
||||
End Sub) With {.ProgressWeight = 2, .Block = True})
|
||||
LoaderList.Add(New LoaderTask(Of String, String)("安装游戏",
|
||||
Sub(Task As LoaderTask(Of String, String))
|
||||
InstallMerge(OutputFolder, OutputFolder, OptiFineFolder, OptiFineAsMod, ForgeFolder, Request.ForgeVersion, FabricFolder, LiteLoaderFolder)
|
||||
Task.Progress = 0.3
|
||||
If Directory.Exists(TempMcFolder & "libraries") Then CopyDirectory(TempMcFolder & "libraries", PathMcFolder & "libraries")
|
||||
If Directory.Exists(TempMcFolder & "mods") Then CopyDirectory(TempMcFolder & "mods", PathMcFolder & "mods")
|
||||
End Sub) With {.ProgressWeight = 2, .Block = True})
|
||||
'补全文件
|
||||
If Not DontFixLibraries AndAlso
|
||||
(Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.Split(".")(0) >= 20) OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing) Then
|
||||
|
||||
@@ -945,11 +945,16 @@
|
||||
''' 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadFabricApiGetError() As String
|
||||
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
|
||||
If LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
|
||||
If LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabricApi.State, Object).Error.Message
|
||||
If DlFabricApiLoader.Output Is Nothing Then
|
||||
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
|
||||
Return "正在获取版本列表……"
|
||||
End If
|
||||
For Each Version In DlFabricApiLoader.Output
|
||||
If IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Return Nothing
|
||||
If Not IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Continue For
|
||||
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
|
||||
Return Nothing
|
||||
Next
|
||||
Return "没有可用版本"
|
||||
End Function
|
||||
@@ -1032,14 +1037,21 @@
|
||||
''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
|
||||
''' </summary>
|
||||
Private Function LoadOptiFabricGetError() As String
|
||||
If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
|
||||
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
|
||||
If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
|
||||
If SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15") Then Return "不兼容老版本 Fabric,请手动下载 OptiFabric Origins"
|
||||
If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "正在获取版本列表……"
|
||||
If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFabric.State, Object).Error.Message
|
||||
If DlOptiFabricLoader.Output Is Nothing Then
|
||||
If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
|
||||
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
|
||||
If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
|
||||
Return "正在获取版本列表……"
|
||||
End If
|
||||
For Each Version In DlOptiFabricLoader.Output
|
||||
If IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Return Nothing
|
||||
If Not IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Continue For '2135#
|
||||
If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
|
||||
If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
|
||||
If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
|
||||
Return Nothing '通过检查
|
||||
Next
|
||||
Return "没有可用版本"
|
||||
End Function
|
||||
@@ -1114,6 +1126,7 @@
|
||||
'提交安装申请
|
||||
Dim Request As New McInstallRequest With {
|
||||
.TargetVersionName = TextSelectName.Text,
|
||||
.TargetVersionFolder = $"{PathMcFolder}versions\{TextSelectName.Text}\",
|
||||
.MinecraftJson = SelectedMinecraftJsonUrl,
|
||||
.MinecraftName = SelectedMinecraftId,
|
||||
.OptiFineEntry = SelectedOptiFine,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'皮肤储存
|
||||
Private _Address As String
|
||||
Public Property Address() As String
|
||||
Public Property Address As String
|
||||
Get
|
||||
Return _Address
|
||||
End Get
|
||||
@@ -76,12 +76,19 @@
|
||||
''' </summary>
|
||||
Public Sub Load()
|
||||
Try
|
||||
Address = Loader.Output
|
||||
'检查文件存在
|
||||
If Address = "" Then Throw New Exception("皮肤加载器 " & Loader.Name & " 没有输出")
|
||||
Address = Loader.Output
|
||||
If String.IsNullOrEmpty(Address) Then Throw New Exception("皮肤加载器 " & Loader.Name & " 没有输出")
|
||||
If Not Address.StartsWith(PathImage) AndAlso Not File.Exists(Address) Then Throw New FileNotFoundException("皮肤文件未找到", Address)
|
||||
'加载
|
||||
Dim Image As New MyBitmap(Address)
|
||||
Dim Image As MyBitmap
|
||||
Try
|
||||
Image = New MyBitmap(Address)
|
||||
Catch ex As Exception '#2272
|
||||
Log(ex, $"皮肤文件已损坏:{Address}", LogLevel.Hint)
|
||||
File.Delete(Address)
|
||||
Exit Sub
|
||||
End Try
|
||||
ImgBack.Tag = Address
|
||||
'大小检查
|
||||
Dim Scale As Integer = Image.Pic.Width / 64
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
Private IsLoad As Boolean = False
|
||||
Private Sub OnLoaded() Handles Me.Loaded
|
||||
FormMain.EndProgramForce(Result.Aborted)
|
||||
If IsLoad Then Exit Sub
|
||||
IsLoad = True
|
||||
'启动监视线程
|
||||
|
||||
@@ -11,6 +11,7 @@ Public Class PageLinkIoi
|
||||
'页面初始化
|
||||
Private IsLoad As Boolean = False
|
||||
Private Sub MeLoaded() Handles Me.Loaded
|
||||
FormMain.EndProgramForce(Result.Aborted)
|
||||
|
||||
'重复加载部分
|
||||
PanBack.ScrollToHome()
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
End Try
|
||||
FrmSpeedRight.PanMain.Children.Insert(0, Card)
|
||||
RightCards.Add(Loader.Name, Card)
|
||||
Log($"[Watcher] 新建下载管理卡片:{Loader.Name}")
|
||||
'添加取消按钮
|
||||
Dim Cancel As New MyIconButton With {.Name = "BtnCancel", .Logo = "F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z", .Height = 20, .Margin = New Thickness(0, 10, 10, 0), .LogoScale = 1.1, .HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Top}
|
||||
Card.Children.Add(Cancel)
|
||||
@@ -194,6 +195,8 @@
|
||||
AniDispose(sender, False)
|
||||
AniDispose(Card, True, Sub() If FrmSpeedRight.PanMain.Children.Count = 0 AndAlso FrmMain.PageCurrent = FormMain.PageType.DownloadManager Then FrmMain.PageBack())
|
||||
RightCards.Remove(Loader.Name)
|
||||
LoaderTaskbar.Remove(Loader)
|
||||
Log($"[Watcher] 关闭下载管理卡片:{Loader.Name}")
|
||||
RunInThread(Sub() Loader.Abort())
|
||||
End Sub
|
||||
'如果已经失败,再刷新一次,修改成失败的控件
|
||||
@@ -217,6 +220,7 @@
|
||||
Dim Card As Grid = RightCards(Loader.Name)
|
||||
FrmSpeedRight.PanMain.Children.Remove(Card)
|
||||
RightCards.Remove(Loader.Name)
|
||||
Log($"[Watcher] 移除下载管理卡片:{Loader.Name}")
|
||||
End Sub)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
@@ -7,22 +7,20 @@
|
||||
<Grid>
|
||||
<Grid x:Name="PanAllBack">
|
||||
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
|
||||
<StackPanel x:Name="PanMain" Margin="25,10" Grid.IsSharedSizeScope="True">
|
||||
<StackPanel x:Name="PanMain" Margin="25,10,25,10" Grid.IsSharedSizeScope="True"> <!-- 若显示多选模块则为 92 -->
|
||||
<local:MySearchBox Margin="0,15" HintText="搜索 Mod" x:Name="SearchBox" />
|
||||
<local:MyCard Grid.Row="0" Margin="0,0,0,15" Title="管理" x:Name="PanManage">
|
||||
<StackPanel Margin="25,40,15,20">
|
||||
<TextBlock Margin="0,0,0,11" Text="左键点击某个 Mod 可以单独启用或禁用它。将 Mod 文件拖入窗口可以快速安装 Mod。" TextWrapping="Wrap" />
|
||||
<TextBlock Margin="0,0,0,11" Text="点击红石灯图标可以快速启用或禁用单个 Mod。将 Mod 文件拖入窗口即可快速安装。" TextWrapping="Wrap" />
|
||||
<Grid Height="35">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Button" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<local:MyButton x:Name="BtnManageOpen" Grid.Column="0" MinWidth="140" Text="打开 Mod 文件夹" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
|
||||
<local:MyButton x:Name="BtnManageEnabled" Grid.Column="1" MinWidth="140" Text="全部启用" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
||||
<local:MyButton x:Name="BtnManageDisabled" Grid.Column="2" MinWidth="140" Text="全部禁用" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
||||
<local:MyButton x:Name="BtnManageCheck" Grid.Column="3" MinWidth="140" Text="检查 Mod" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ToolTip="快速检查 Mod 的版本要求、重复、前置缺失等问题。
结果仅供参考,由于部分 Mod 标注的信息有误,可能并不准确。" Visibility="Collapsed" />
|
||||
<local:MyButton x:Name="BtnManageSelectAll" Grid.Column="1" MinWidth="140" Text="全选" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" />
|
||||
<local:MyButton x:Name="BtnManageCheck" Grid.Column="2" MinWidth="140" Text="检查 Mod" Padding="13,0" Margin="0,0,20,0" HorizontalAlignment="Left" ToolTip="快速检查 Mod 的版本要求、重复、前置缺失等问题。
结果仅供参考,由于部分 Mod 标注的信息有误,可能并不准确。" Visibility="Collapsed" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
@@ -47,5 +45,22 @@
|
||||
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40,0" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
|
||||
<local:MyLoading Text="正在加载 Mod 列表" Margin="20,20,20,17" x:Name="Load" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</local:MyCard>
|
||||
<local:MyCard x:Name="CardSelect" Visibility="Collapsed" Opacity="0"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="25,25,25,0" UseAnimation="False" HasMouseAnimation="False">
|
||||
<local:MyCard.RenderTransform>
|
||||
<TranslateTransform x:Name="TransSelect" Y="-10" />
|
||||
</local:MyCard.RenderTransform>
|
||||
<TextBlock x:Name="LabSelect" Text="已选择 8 个文件" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="9" Foreground="{DynamicResource ColorBrush2}" />
|
||||
<StackPanel Orientation="Horizontal" Margin="5,28,5,5">
|
||||
<local:MyIconTextButton x:Name="BtnSelectEnable" Text="启用"
|
||||
LogoScale="1.05" Logo="M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m0 921.6a409.6 409.6 0 1 1 409.6-409.6 409.6 409.6 0 0 1-409.6 409.6z M716.8 339.968l-256 253.44L328.192 460.8A51.2 51.2 0 0 0 256 532.992l168.448 168.96a51.2 51.2 0 0 0 72.704 0l289.28-289.792A51.2 51.2 0 0 0 716.8 339.968z" />
|
||||
<local:MyIconTextButton x:Name="BtnSelectDisable" Text="禁用"
|
||||
LogoScale="0.98" Logo="M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m409.6 512a404.48 404.48 0 0 1-86.528 250.88L261.12 188.928A404.48 404.48 0 0 1 512 102.4a409.6 409.6 0 0 1 409.6 409.6zM102.4 512a404.48 404.48 0 0 1 86.528-250.88L762.88 835.072A404.48 404.48 0 0 1 512 921.6a409.6 409.6 0 0 1-409.6-409.6z" />
|
||||
<local:MyIconTextButton x:Name="BtnSelectDelete" Text="删除"
|
||||
LogoScale="0.96" Logo="M520.192 0C408.43 0 317.44 82.87 313.563 186.734H52.736c-29.038 0-52.663 21.943-52.663 49.079s23.625 49.152 52.663 49.152h58.075v550.473c0 103.35 75.118 187.757 167.717 187.757h472.43c92.599 0 167.716-83.894 167.716-187.757V285.477h52.59c29.038 0 52.59-21.943 52.663-49.08-0.073-27.135-23.625-49.151-52.663-49.151H726.235C723.237 83.017 631.955 0 520.192 0zM404.846 177.957c3.803-50.03 50.176-89.015 107.447-89.015 57.197 0 103.57 38.985 106.788 89.015H404.92zM284.379 933.669c-33.353 0-69.997-39.351-69.997-95.525v-549.01H833.39v549.522c0 56.247-36.645 95.525-69.998 95.525H284.379v-0.512z M357.23 800.695a48.274 48.274 0 0 0 47.616-49.006V471.7a48.274 48.274 0 0 0-47.543-49.08 48.274 48.274 0 0 0-47.69 49.006V751.69c0 27.282 20.846 49.006 47.617 49.006z m166.62 0a48.274 48.274 0 0 0 47.688-49.006V471.7a48.274 48.274 0 0 0-47.689-49.08 48.274 48.274 0 0 0-47.543 49.006V751.69c0 27.282 21.431 49.006 47.543 49.006z m142.92 0a48.274 48.274 0 0 0 47.543-49.006V471.7a48.274 48.274 0 0 0-47.543-49.08 48.274 48.274 0 0 0-47.616 49.006V751.69c0 27.282 20.773 49.006 47.543 49.006z" />
|
||||
<local:MyIconTextButton x:Name="BtnSelectCancel" Text="取消选择"
|
||||
LogoScale="0.8" Logo="M867.648 951.296 512 595.648l-355.648 355.648c-11.52 11.52-30.272 11.52-41.856 0L72.64 909.44c-11.52-11.52-11.52-30.272 0-41.856L428.352 512 72.64 156.352c-11.52-11.52-11.52-30.272 0-41.856l41.856-41.856c11.52-11.52 30.272-11.52 41.856 0L512 428.288l355.648-355.648c11.52-11.52 30.272-11.52 41.856 0l41.856 41.856c11.52 11.52 11.52 30.272 0 41.856L595.648 512l355.648 355.648c11.52 11.52 11.52 30.272 0 41.856l-41.856 41.856C897.984 962.88 879.168 962.88 867.648 951.296L867.648 951.296z" />
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
</Grid>
|
||||
</local:MyPageRight>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
Public Class PageVersionMod
|
||||
Imports System.Security.Principal
|
||||
Imports PCL.MyLoading
|
||||
|
||||
Public Class PageVersionMod
|
||||
|
||||
#Region "初始化"
|
||||
|
||||
@@ -6,7 +9,11 @@
|
||||
Public Sub PageOther_Loaded() Handles Me.Loaded
|
||||
|
||||
PanBack.ScrollToHome()
|
||||
AniControlEnabled += 1
|
||||
SelectedMods.Clear()
|
||||
RefreshList()
|
||||
ChangeAllSelected(False)
|
||||
AniControlEnabled -= 1
|
||||
|
||||
'非重复加载部分
|
||||
If IsLoad Then Exit Sub
|
||||
@@ -42,6 +49,7 @@
|
||||
|
||||
#Region "UI 化"
|
||||
|
||||
Private PanItems As StackPanel
|
||||
''' <summary>
|
||||
''' 将 Mod 列表加载为 UI。
|
||||
''' </summary>
|
||||
@@ -62,13 +70,13 @@
|
||||
|
||||
SearchBox.Text = ""
|
||||
'建立 StackPanel
|
||||
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, If(List.Count > 0, 20, 0)), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
|
||||
PanItems = New StackPanel With {.Margin = New Thickness(18, MyCard.SwapedHeight, 18, If(List.Count > 0, 20, 0)), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
|
||||
For Each ModEntity As McMod In List
|
||||
NewStack.Children.Add(McModListItem(ModEntity))
|
||||
PanItems.Children.Add(McModListItem(ModEntity))
|
||||
Next
|
||||
'建立 MyCard
|
||||
Dim NewCard As New MyCard With {.Title = McModGetTitle(List), .Margin = New Thickness(0, 0, 0, 15)}
|
||||
NewCard.Children.Add(NewStack)
|
||||
NewCard.Children.Add(PanItems)
|
||||
PanList.Children.Add(NewCard)
|
||||
'显示提示
|
||||
If List.Count > 0 AndAlso Not Setup.Get("HintModDisable") Then
|
||||
@@ -88,20 +96,12 @@
|
||||
For Each ModEntity As McMod In List
|
||||
Counter(ModEntity.State) += 1
|
||||
Next
|
||||
If List.Count = 0 Then
|
||||
'全空
|
||||
Return "未找到任何 Mod"
|
||||
ElseIf Counter(McMod.McModState.Disabled) = 0 AndAlso Counter(McMod.McModState.Unavaliable) = 0 Then
|
||||
'只有启用的 Mod
|
||||
Return "Mod 列表(" & Counter(McMod.McModState.Fine) & ")"
|
||||
Else
|
||||
'混合种类
|
||||
Dim TypeList As New List(Of String)
|
||||
If Counter(McMod.McModState.Fine) > 0 Then TypeList.Add("启用 " & Counter(McMod.McModState.Fine))
|
||||
If Counter(McMod.McModState.Disabled) > 0 Then TypeList.Add("禁用 " & Counter(McMod.McModState.Disabled))
|
||||
If Counter(McMod.McModState.Unavaliable) > 0 Then TypeList.Add("错误 " & Counter(McMod.McModState.Unavaliable))
|
||||
Return "Mod 列表(" & Join(TypeList, ",") & ")"
|
||||
End If
|
||||
If List.Count = 0 Then Return "未找到任何 Mod"
|
||||
Dim TypeList As New List(Of String)
|
||||
If Counter(McMod.McModState.Fine) > 0 Then TypeList.Add("启用 " & Counter(McMod.McModState.Fine))
|
||||
If Counter(McMod.McModState.Disabled) > 0 Then TypeList.Add("禁用 " & Counter(McMod.McModState.Disabled))
|
||||
If Counter(McMod.McModState.Unavaliable) > 0 Then TypeList.Add("错误 " & Counter(McMod.McModState.Unavaliable))
|
||||
Return "Mod 列表(" & Join(TypeList, ",") & ")"
|
||||
End Function
|
||||
Private Function McModListItem(Entry As McMod) As MyListItem
|
||||
'图标
|
||||
@@ -138,16 +138,21 @@
|
||||
' Desc += " : " & Join(DepList, ", ")
|
||||
'End If
|
||||
'实例化
|
||||
Dim NewItem As New MyListItem With {.Logo = Logo, .SnapsToDevicePixels = True, .Title = Title, .Info = Desc, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry}
|
||||
NewItem.PaddingRight = If(Entry.IsFileAvailable, 73, 55)
|
||||
'事件
|
||||
NewItem.ContentHandler = AddressOf McModContent
|
||||
AniControlEnabled += 1
|
||||
Dim NewItem As New MyListItem With {
|
||||
.LogoClickable = True, .Logo = Logo, .SnapsToDevicePixels = True, .Title = Title, .Info = Desc, .Height = 42, .Tag = Entry,
|
||||
.Type = MyListItem.CheckType.CheckBox, .IsScaleAnimationEnabled = False,
|
||||
.PaddingRight = 73,
|
||||
.ContentHandler = AddressOf McModContent, .Checked = SelectedMods.Contains(Entry.RawFileName)
|
||||
}
|
||||
AniControlEnabled -= 1
|
||||
Return NewItem
|
||||
End Function
|
||||
Private Sub McModContent(sender As MyListItem, e As EventArgs)
|
||||
Dim ModEntity As McMod = sender.Tag
|
||||
'注册点击事件
|
||||
AddHandler sender.Click, AddressOf Item_Click
|
||||
AddHandler sender.Changed, AddressOf CheckChanged
|
||||
AddHandler sender.LogoClick, AddressOf ItemLogo_Click
|
||||
'图标按钮
|
||||
Dim BtnDel As New MyIconButton With {.LogoScale = 1.1, .Logo = Logo.IconButtonDelete, .Tag = sender}
|
||||
BtnDel.ToolTip = "删除"
|
||||
@@ -161,18 +166,14 @@
|
||||
ToolTipService.SetVerticalOffset(BtnOpen, 30)
|
||||
ToolTipService.SetHorizontalOffset(BtnOpen, 2)
|
||||
AddHandler BtnOpen.Click, AddressOf Open_Click
|
||||
If ModEntity.IsFileAvailable Then
|
||||
Dim BtnCont As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .Tag = sender}
|
||||
BtnCont.ToolTip = "详情"
|
||||
ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center)
|
||||
ToolTipService.SetVerticalOffset(BtnCont, 30)
|
||||
ToolTipService.SetHorizontalOffset(BtnCont, 2)
|
||||
AddHandler BtnCont.Click, AddressOf Info_Click
|
||||
AddHandler sender.MouseRightButtonDown, AddressOf Info_Click
|
||||
sender.Buttons = {BtnCont, BtnOpen, BtnDel}
|
||||
Else
|
||||
sender.Buttons = {BtnOpen, BtnDel}
|
||||
End If
|
||||
Dim BtnCont As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .Tag = sender}
|
||||
BtnCont.ToolTip = "详情"
|
||||
ToolTipService.SetPlacement(BtnCont, Primitives.PlacementMode.Center)
|
||||
ToolTipService.SetVerticalOffset(BtnCont, 30)
|
||||
ToolTipService.SetHorizontalOffset(BtnCont, 2)
|
||||
AddHandler BtnCont.Click, AddressOf Info_Click
|
||||
AddHandler sender.MouseRightButtonDown, AddressOf Info_Click
|
||||
sender.Buttons = {BtnCont, BtnOpen, BtnDel}
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
@@ -210,13 +211,144 @@
|
||||
#End If
|
||||
|
||||
''' <summary>
|
||||
''' 一键启用 / 禁用。
|
||||
''' 全选。
|
||||
''' </summary>
|
||||
Private Sub BtnManageChange_Click(sender As MyButton, e As EventArgs) Handles BtnManageEnabled.Click, BtnManageDisabled.Click
|
||||
Private Sub BtnManageSelectAll_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageSelectAll.Click
|
||||
ChangeAllSelected(True)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "选择"
|
||||
|
||||
'选择的 Mod 的路径(不含 .disabled)
|
||||
Public SelectedMods As New List(Of String)
|
||||
|
||||
'单项切换选择状态
|
||||
Public Sub CheckChanged(sender As MyListItem, e As RouteEventArgs)
|
||||
If AniControlEnabled <> 0 Then Return
|
||||
'更新选择了的内容
|
||||
Dim SelectedKey As String = CType(sender.Tag, McMod).RawFileName
|
||||
If sender.Checked Then
|
||||
If Not SelectedMods.Contains(SelectedKey) Then SelectedMods.Add(SelectedKey)
|
||||
Else
|
||||
SelectedMods.Remove(SelectedKey)
|
||||
End If
|
||||
'更新下边栏 UI
|
||||
RefreshBottomBar()
|
||||
End Sub
|
||||
|
||||
'改变下边栏状态
|
||||
Private ShownCount As Integer = 0
|
||||
Private Sub RefreshBottomBar()
|
||||
'计数
|
||||
Dim NewCount As Integer = SelectedMods.Count
|
||||
Dim Selected = NewCount > 0
|
||||
If Selected Then LabSelect.Text = $"已选择 {NewCount} 个文件" '取消所有选择时不更新数字
|
||||
'按钮可用性
|
||||
If Selected Then
|
||||
Dim HasEnabled As Boolean = False
|
||||
Dim HasDisabled As Boolean = False
|
||||
For Each ModEntity In McModLoader.Output
|
||||
If SelectedMods.Contains(ModEntity.RawFileName) Then
|
||||
If ModEntity.State = McMod.McModState.Fine Then
|
||||
HasEnabled = True
|
||||
ElseIf ModEntity.State = McMod.McModState.Disabled Then
|
||||
HasDisabled = True
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
BtnSelectDisable.IsEnabled = HasEnabled
|
||||
BtnSelectEnable.IsEnabled = HasDisabled
|
||||
End If
|
||||
'更新显示状态
|
||||
CardSelect.IsHitTestVisible = Selected
|
||||
If AniControlEnabled = 0 Then
|
||||
If Selected Then
|
||||
'仅在数量增加时播放出现/跳跃动画
|
||||
If ShownCount >= NewCount Then
|
||||
ShownCount = NewCount
|
||||
Return
|
||||
Else
|
||||
ShownCount = NewCount
|
||||
End If
|
||||
'出现/跳跃动画
|
||||
CardSelect.Visibility = Visibility.Visible
|
||||
AniStart({
|
||||
AaOpacity(CardSelect, 1 - CardSelect.Opacity, 60),
|
||||
AaTranslateY(CardSelect, -27 - TransSelect.Y, 120, Ease:=New AniEaseOutFluent(AniEasePower.Weak)),
|
||||
AaTranslateY(CardSelect, 3, 150, 120, Ease:=New AniEaseInoutFluent(AniEasePower.Weak)),
|
||||
AaTranslateY(CardSelect, -1, 90, 270, Ease:=New AniEaseInoutFluent(AniEasePower.Weak))
|
||||
}, "Mod Sidebar")
|
||||
Else
|
||||
'不重复播放隐藏动画
|
||||
If ShownCount = 0 Then Return
|
||||
ShownCount = 0
|
||||
'隐藏动画
|
||||
AniStart({
|
||||
AaOpacity(CardSelect, -CardSelect.Opacity, 90),
|
||||
AaTranslateY(CardSelect, -10 - TransSelect.Y, 90, Ease:=New AniEaseInFluent(AniEasePower.Weak)),
|
||||
AaCode(Sub() CardSelect.Visibility = Visibility.Collapsed, After:=True)
|
||||
}, "Mod Sidebar")
|
||||
End If
|
||||
Else
|
||||
AniStop("Mod Sidebar")
|
||||
ShownCount = NewCount
|
||||
If Selected Then
|
||||
CardSelect.Visibility = Visibility.Visible
|
||||
CardSelect.Opacity = 1
|
||||
TransSelect.Y = -25
|
||||
Else
|
||||
CardSelect.Visibility = Visibility.Collapsed
|
||||
CardSelect.Opacity = 0
|
||||
TransSelect.Y = -10
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
'切换所有项的选择状态
|
||||
Private Sub ChangeAllSelected(Value As Boolean)
|
||||
AniControlEnabled += 1
|
||||
SelectedMods.Clear()
|
||||
If IsSearching Then
|
||||
'搜索中
|
||||
For Each Item As MyListItem In PanSearchList.Children
|
||||
Item.Checked = Value
|
||||
If Value Then SelectedMods.Add(CType(Item.Tag, McMod).RawFileName)
|
||||
Next
|
||||
If Not Value Then '只取消选择
|
||||
If PanItems IsNot Nothing Then
|
||||
For Each Item As MyListItem In PanItems.Children
|
||||
Item.Checked = Value
|
||||
Next
|
||||
End If
|
||||
End If
|
||||
Else
|
||||
'非搜索中
|
||||
If PanItems IsNot Nothing Then
|
||||
For Each Item As MyListItem In PanItems.Children
|
||||
Item.Checked = Value
|
||||
If Value Then SelectedMods.Add(CType(Item.Tag, McMod).RawFileName)
|
||||
Next
|
||||
End If
|
||||
End If
|
||||
AniControlEnabled -= 1
|
||||
'更新下边栏 UI
|
||||
RefreshBottomBar()
|
||||
End Sub
|
||||
Private Sub Load_State(sender As Object, newState As MyLoadingState, oldState As MyLoadingState) Handles Load.StateChanged
|
||||
ChangeAllSelected(False)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "下边栏"
|
||||
|
||||
'启用 / 禁用
|
||||
Private Sub BtnSelectEorD_Click(sender As MyIconTextButton, e As RouteEventArgs) Handles BtnSelectEnable.Click, BtnSelectDisable.Click
|
||||
Dim IsSuccessful As Boolean = True
|
||||
Dim SuccessfulCount As Integer = 0
|
||||
Dim IsDisable As Boolean = sender.Text.Contains("禁用")
|
||||
For Each ModEntity In McModLoader.Output
|
||||
Dim IsDisable As Boolean = sender.Equals(BtnSelectDisable)
|
||||
For Each ModEntity In McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.RawFileName)).ToList()
|
||||
Dim NewPath As String = Nothing
|
||||
If ModEntity.State = McMod.McModState.Fine And IsDisable Then
|
||||
'禁用
|
||||
@@ -225,7 +357,6 @@
|
||||
'启用
|
||||
NewPath = ModEntity.Path.Substring(0, ModEntity.Path.Count - ".disabled".Count)
|
||||
Else
|
||||
SuccessfulCount += 1
|
||||
Continue For
|
||||
End If
|
||||
'重命名
|
||||
@@ -233,27 +364,99 @@
|
||||
If File.Exists(NewPath) AndAlso Not File.Exists(ModEntity.Path) Then Continue For '因为未知原因 Mod 的状态已经切换完了
|
||||
File.Delete(NewPath)
|
||||
FileSystem.Rename(ModEntity.Path, NewPath)
|
||||
SuccessfulCount += 1
|
||||
Catch ex As FileNotFoundException
|
||||
Log(ex, "未找到需要重命名的 Mod(" & If(ex.FileName, "null") & ")", LogLevel.Feedback)
|
||||
RefreshList()
|
||||
Exit Sub
|
||||
Log(ex, $"未找到需要重命名的 Mod({If(ModEntity.Path, "null")})", LogLevel.Feedback)
|
||||
RefreshList(True)
|
||||
Return
|
||||
Catch ex As Exception
|
||||
Log(ex, "全局状态改变中重命名 Mod 失败")
|
||||
Log(ex, $"批量重命名 Mod 失败({If(ModEntity.Path, "null")})")
|
||||
IsSuccessful = False
|
||||
End Try
|
||||
'更改 Loader 和 UI 中的列表
|
||||
Dim NewModEntity As New McMod(NewPath)
|
||||
Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity)
|
||||
McModLoader.Output.RemoveAt(IndexOfLoader)
|
||||
McModLoader.Output.Insert(IndexOfLoader, NewModEntity)
|
||||
Dim Parent As StackPanel = If(IsSearching, PanSearchList, PanItems)
|
||||
Dim IndexOfUi As Integer = Parent.Children.IndexOf(Parent.Children.OfType(Of MyListItem).First(Function(i) CType(i.Tag, McMod) Is ModEntity))
|
||||
Parent.Children.RemoveAt(IndexOfUi)
|
||||
Parent.Children.Insert(IndexOfUi, McModListItem(NewModEntity))
|
||||
Next
|
||||
If Not IsSuccessful Then Hint("由于文件被占用,部分 Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
|
||||
Log("[System] 已确认 " & SuccessfulCount & "/" & McModLoader.Output.Count & " 个 Mod 的状态与要求一致")
|
||||
RefreshList()
|
||||
If Not IsSearching Then
|
||||
'改变禁用数量的显示
|
||||
CType(PanItems.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
|
||||
'更新加载器状态
|
||||
LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
|
||||
End If
|
||||
If Not IsSuccessful Then
|
||||
Hint("由于文件被占用,部分 Mod 的状态切换失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
|
||||
RefreshList(True)
|
||||
Else
|
||||
ChangeAllSelected(False)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
'删除
|
||||
Private Sub BtnSelectDelete_Click() Handles BtnSelectDelete.Click
|
||||
Dim IsSuccessful As Boolean = True
|
||||
Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
|
||||
Dim DeleteList As List(Of McMod) = McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.RawFileName)).ToList()
|
||||
For Each ModEntity In DeleteList
|
||||
'删除
|
||||
Try
|
||||
If IsShiftPressed Then
|
||||
File.Delete(ModEntity.Path)
|
||||
Else
|
||||
My.Computer.FileSystem.DeleteFile(ModEntity.Path, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin)
|
||||
End If
|
||||
Catch ex As OperationCanceledException
|
||||
Log(ex, "批量删除 Mod 被主动取消")
|
||||
RefreshList(True)
|
||||
Return
|
||||
Catch ex As Exception
|
||||
Log(ex, $"批量删除 Mod 失败({ModEntity.Path})", LogLevel.Msgbox)
|
||||
IsSuccessful = False
|
||||
End Try
|
||||
'更改 Loader 和 UI 中的列表
|
||||
McModLoader.Output.Remove(ModEntity)
|
||||
Dim Parent As StackPanel = If(IsSearching, PanSearchList, PanItems)
|
||||
Dim IndexOfUi As Integer = Parent.Children.IndexOf(Parent.Children.OfType(Of MyListItem).First(Function(i) CType(i.Tag, McMod) Is ModEntity))
|
||||
Parent.Children.RemoveAt(IndexOfUi)
|
||||
Next
|
||||
If Not IsSearching Then
|
||||
'改变禁用数量的显示
|
||||
CType(PanItems.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
|
||||
'更新加载器状态
|
||||
LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
|
||||
End If
|
||||
If Not IsSuccessful Then
|
||||
Hint("由于文件被占用,部分 Mod 删除失败,请尝试关闭正在运行的游戏后再试!", HintType.Critical)
|
||||
RefreshList(True)
|
||||
ElseIf If(IsSearching, PanSearchList, PanItems).Children.Count = 0 Then
|
||||
RefreshList(True)
|
||||
Else
|
||||
ChangeAllSelected(False)
|
||||
End If
|
||||
If IsSuccessful Then
|
||||
If IsShiftPressed Then
|
||||
Hint($"已彻底删除 {DeleteList.Count} 个文件!", HintType.Finish)
|
||||
Else
|
||||
Hint($"已将 {DeleteList.Count} 个文件删除到回收站!", HintType.Finish)
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
'取消选择
|
||||
Private Sub BtnSelectCancel_Click() Handles BtnSelectCancel.Click
|
||||
ChangeAllSelected(False)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "单个 Mod 项"
|
||||
|
||||
'点击:切换可用状态 / 显示错误原因
|
||||
Public Sub Item_Click(sender As MyListItem, e As EventArgs)
|
||||
'点击 Logo:切换可用状态 / 显示错误原因
|
||||
Public Sub ItemLogo_Click(sender As MyListItem, e As EventArgs)
|
||||
Try
|
||||
|
||||
Dim ModEntity As McMod = sender.Tag
|
||||
@@ -291,12 +494,13 @@
|
||||
Parent.Children.RemoveAt(IndexOfUi)
|
||||
Parent.Children.Insert(IndexOfUi, McModListItem(NewModEntity))
|
||||
'仅在非搜索页面才执行,以确保搜索页内外显示一致
|
||||
If String.IsNullOrWhiteSpace(SearchBox.Text) Then
|
||||
If Not IsSearching Then
|
||||
'改变禁用数量的显示
|
||||
CType(Parent.Parent, MyCard).Title = McModGetTitle(McModLoader.Output)
|
||||
'更新加载器状态
|
||||
LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.UpdateOnly)
|
||||
End If
|
||||
RefreshBottomBar()
|
||||
|
||||
Catch ex As Exception
|
||||
Log(ex, "单个状态改变中重命名 Mod 失败")
|
||||
@@ -358,27 +562,30 @@
|
||||
Dim ListItem As MyListItem
|
||||
ListItem = If(TypeOf sender Is MyIconButton, sender.Tag, sender)
|
||||
Dim ModEntity As McMod = ListItem.Tag
|
||||
'加载失败信息
|
||||
If ModEntity.State = McMod.McModState.Unavaliable Then
|
||||
MyMsgBox("无法读取此 Mod 的信息。" & vbCrLf & vbCrLf & "详细的错误信息:" & GetExceptionDetail(ModEntity.FileUnavailableReason), "Mod 读取失败")
|
||||
Return
|
||||
End If
|
||||
'获取信息
|
||||
Dim ContentLines As New List(Of String)
|
||||
If ModEntity.Description IsNot Nothing Then ContentLines.Add(ModEntity.Description & vbCrLf)
|
||||
If ModEntity.Authors IsNot Nothing Then ContentLines.Add("作者:" & ModEntity.Authors)
|
||||
ContentLines.Add("文件:" & ModEntity.FileName & "(" & GetString(New FileInfo(ModEntity.Path).Length) & ")")
|
||||
If ModEntity.Version IsNot Nothing Then ContentLines.Add("版本:" & ModEntity.Version)
|
||||
If ModeDebug Then
|
||||
Dim DebugInfo As New List(Of String)
|
||||
If ModEntity.ModId IsNot Nothing Then
|
||||
DebugInfo.Add("Mod ID:" & ModEntity.ModId)
|
||||
End If
|
||||
If ModEntity.Dependencies.Count > 0 Then
|
||||
DebugInfo.Add("依赖于:")
|
||||
For Each Dep In ModEntity.Dependencies
|
||||
DebugInfo.Add(" - " & Dep.Key & If(Dep.Value Is Nothing, "", ",版本:" & Dep.Value))
|
||||
Next
|
||||
End If
|
||||
If DebugInfo.Count > 0 Then
|
||||
ContentLines.Add(vbCrLf & "—————— 调试信息 ——————")
|
||||
ContentLines.AddRange(DebugInfo)
|
||||
End If
|
||||
Dim DebugInfo As New List(Of String)
|
||||
If ModEntity.ModId IsNot Nothing Then
|
||||
DebugInfo.Add("Mod ID:" & ModEntity.ModId)
|
||||
End If
|
||||
If ModEntity.Dependencies.Count > 0 Then
|
||||
DebugInfo.Add("依赖于:")
|
||||
For Each Dep In ModEntity.Dependencies
|
||||
DebugInfo.Add(" - " & Dep.Key & If(Dep.Value Is Nothing, "", ",版本:" & Dep.Value))
|
||||
Next
|
||||
End If
|
||||
If DebugInfo.Count > 0 Then
|
||||
ContentLines.Add("")
|
||||
ContentLines.AddRange(DebugInfo)
|
||||
End If
|
||||
'获取用于搜索的 Mod 名称
|
||||
Dim ModOriginalName As String = ModEntity.Name.Replace(" ", "+")
|
||||
@@ -426,22 +633,14 @@
|
||||
|
||||
#End Region
|
||||
|
||||
Public ReadOnly Property IsSearching As Boolean
|
||||
Get
|
||||
Return Not String.IsNullOrWhiteSpace(SearchBox.Text)
|
||||
End Get
|
||||
End Property
|
||||
Public Sub SearchRun() Handles SearchBox.TextChanged
|
||||
If String.IsNullOrWhiteSpace(SearchBox.Text) Then
|
||||
'隐藏
|
||||
LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.RunOnUpdated)
|
||||
AniStart({
|
||||
AaOpacity(PanSearch, -PanSearch.Opacity, 100),
|
||||
AaCode(Sub()
|
||||
PanSearch.Height = 0
|
||||
PanSearch.Visibility = Visibility.Collapsed
|
||||
PanList.Visibility = Visibility.Visible
|
||||
PanManage.Visibility = Visibility.Visible
|
||||
End Sub,, True),
|
||||
AaOpacity(PanList, 1 - PanList.Opacity, 150, 30),
|
||||
AaOpacity(PanManage, 1 - PanManage.Opacity, 150, 30)
|
||||
}, "FrmVersionMod Search Switch", True)
|
||||
Else
|
||||
ChangeAllSelected(False)
|
||||
If IsSearching Then
|
||||
'构造请求
|
||||
Dim QueryList As New List(Of SearchEntry(Of McMod))
|
||||
For Each Entry As McMod In McModLoader.Output
|
||||
@@ -472,15 +671,25 @@
|
||||
'显示
|
||||
AniStart({
|
||||
AaOpacity(PanList, -PanList.Opacity, 100),
|
||||
AaOpacity(PanManage, -PanManage.Opacity, 100),
|
||||
AaCode(Sub()
|
||||
PanList.Visibility = Visibility.Collapsed
|
||||
PanManage.Visibility = Visibility.Collapsed
|
||||
PanSearch.Visibility = Visibility.Visible
|
||||
PanSearch.TriggerForceResize()
|
||||
End Sub,, True),
|
||||
AaOpacity(PanSearch, 1 - PanSearch.Opacity, 200, 60)
|
||||
}, "FrmVersionMod Search Switch", True)
|
||||
Else
|
||||
'隐藏
|
||||
LoaderFolderRun(McModLoader, PageVersionLeft.Version.PathIndie & "mods\", LoaderFolderRunType.RunOnUpdated)
|
||||
AniStart({
|
||||
AaOpacity(PanSearch, -PanSearch.Opacity, 100),
|
||||
AaCode(Sub()
|
||||
PanSearch.Height = 0
|
||||
PanSearch.Visibility = Visibility.Collapsed
|
||||
PanList.Visibility = Visibility.Visible
|
||||
End Sub,, True),
|
||||
AaOpacity(PanList, 1 - PanList.Opacity, 150, 30)
|
||||
}, "FrmVersionMod Search Switch", True)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
d:DesignWidth="800" d:DesignHeight="800">
|
||||
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
|
||||
<StackPanel x:Name="PanMain" Margin="25,10">
|
||||
<local:MyHint Text="在这个页面修改的设置均只对当前版本生效,这对整合包制作应该会有所帮助。\n你也可以在设置页面中,修改对全部版本生效的全局设置。" IsWarn="False" Margin="0,0,0,10" />
|
||||
<local:MyCard x:Name="CardArgument" Margin="0,15" Title="启动选项">
|
||||
<local:MyHint Text="本页面的设置均只对当前版本生效,这对整合包制作应该会有所帮助。
你也可以在设置页面中修改对全部版本生效的全局设置。" IsWarn="False" Margin="0,15" />
|
||||
<local:MyCard x:Name="CardArgument" Margin="0,0,0,15" Title="启动选项">
|
||||
<StackPanel Margin="25,40,25,21">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -215,4 +215,4 @@
|
||||
</local:MyCard>
|
||||
</StackPanel>
|
||||
</local:MyScrollViewer>
|
||||
</local:MyPageRight>
|
||||
</local:MyPageRight>
|
||||
@@ -182,8 +182,12 @@
|
||||
<Compile Include="Controls\MyCard.vb" />
|
||||
<Compile Include="Controls\MyPageRight.vb" />
|
||||
<Compile Include="Controls\MyPageLeft.vb" />
|
||||
<Compile Include="Controls\MyIconTextButton.xaml.vb">
|
||||
<DependentUpon>MyIconTextButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Modules\Minecraft\ModComp.vb" />
|
||||
<Compile Include="Modules\Minecraft\ModJava.vb" />
|
||||
<Compile Include="Modules\Minecraft\ModMod.vb" />
|
||||
<Compile Include="Modules\Minecraft\ModModpack.vb" />
|
||||
<Compile Include="Modules\ModEvent.vb" />
|
||||
<Compile Include="Controls\MyExtraButton.xaml.vb">
|
||||
@@ -406,6 +410,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\MyIconTextButton.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Controls\MySearchBox.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -103,26 +103,34 @@
|
||||
</local:MyCard>
|
||||
|
||||
<local:MyCard Title="事件 4:其他事件类型" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
|
||||
<StackPanel Margin="25,40,23,15">
|
||||
<TextBlock TextWrapping="Wrap" Margin="0,4,0,6" FontWeight="Bold"
|
||||
<StackPanel Margin="25,40,23,15">
|
||||
<TextBlock Margin="0,4,0,6" FontWeight="Bold"
|
||||
Text="EventType 共有以下种类:" />
|
||||
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
|
||||
<TextBlock Margin="0,0,0,4"
|
||||
Text="· 打开网页、启动游戏、打开文件:已在上方的卡片中介绍" />
|
||||
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
|
||||
Text="· 今日人品、清理垃圾、内存优化:触发百宝箱中的对应功能" />
|
||||
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
|
||||
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
||||
Text="查看 PCL 源代码" EventType="打开网页" EventData="https://github.com/Hex-Dragon/PCL2/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 TextWrapping="Wrap" Margin="0,0,0,4"
|
||||
<TextBlock Margin="0,0,0,4"
|
||||
Text="· 刷新主页:点击重新加载主页。如果主页文件为联网更新,这会重新下载主页内容" />
|
||||
<TextBlock TextWrapping="Wrap" Margin="0,0,0,4"
|
||||
<TextBlock Margin="0,0,0,4"
|
||||
Text="· 下载文件:在点击时要求选择文件保存位置,并且下载 EventData 的链接中的文件" />
|
||||
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
||||
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
||||
Text="下载 MCBBS 的 Logo" EventType="下载文件" EventData="https://www.mcbbs.net/template/mcbbs/image/logo_sc.png" />
|
||||
<TextBlock TextWrapping="Wrap" Margin="0,4,0,0"
|
||||
<TextBlock Margin="0,4,0,4"
|
||||
Text="· 打开帮助:跳转到 EventData 对应的帮助文件(输入相对 Help 文件夹的路径)"/>
|
||||
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
||||
<local:MyButton Margin="0,5,0,6" Width="250" Height="35"
|
||||
Text="打开自定义帮助页面" EventType="打开帮助" EventData="帮助/自定义帮助.json"/>
|
||||
</StackPanel>
|
||||
<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"/>
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
|
||||
<local:MyCard Title="横向布局 1:StackPanel" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user