This commit is contained in:
LTCat
2026-10-17 03:39:13 +08:00
parent 9dcb799fb0
commit ade6e04c6e
65 changed files with 6989 additions and 2643 deletions
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
<local:MyPageRight
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PCL" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PageDownloadInstall"
PanScroll="PanBack">
<Grid>
@@ -14,19 +14,96 @@
</StackPanel.RenderTransform>
</StackPanel>
<StackPanel Grid.Row="1" x:Name="PanSelect" Visibility="Collapsed" Opacity="0" IsHitTestVisible="False" Margin="0,0,0,45">
<StackPanel.Resources>
<Style x:Key="ModifyCompareIcon" TargetType="{x:Type local:MyImage}">
<Setter Property="Width" Value="18" />
<Setter Property="Height" Value="18" />
<Setter Property="RenderOptions.BitmapScalingMode" Value="Linear" />
</Style>
<Style x:Key="ModifyCompareText" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BasedOnTextBlock}">
<Setter Property="Margin" Value="7,0,0,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="ModifyCompareArrow" TargetType="{x:Type Path}">
<Setter Property="Data" Value="M3,3 L7,7 3,11 M9,3 L13,7 9,11" />
<Setter Property="Margin" Value="10,0,18,0" />
<Setter Property="Height" Value="14" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Stroke" Value="{DynamicResource ColorBrushGray2}" />
<Setter Property="StrokeThickness" Value="1.4" />
<Setter Property="StrokeStartLineCap" Value="Round" />
<Setter Property="StrokeEndLineCap" Value="Round" />
<Setter Property="StrokeLineJoin" Value="Round" />
</Style>
<sys:String x:Key="ModifyRestoreLogo">M9.83,3.17 A1.18,1.18 0 0 1 9.83,4.83 L6.85,7.82 H14.5 A6.68,6.68 0 0 1 14.5,21.18 H11 A1.18,1.18 0 0 1 11,18.82 H14.5 A4.32,4.32 0 0 0 14.5,10.18 H6.85 L9.83,13.17 A1.18,1.18 0 0 1 8.17,14.83 L3.17,9.83 A1.18,1.18 0 0 1 3.17,8.17 L8.17,3.17 A1.18,1.18 0 0 1 9.83,3.17 Z</sys:String>
<sys:String x:Key="ModifyClearLogo">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</sys:String>
<Style x:Key="ModifyRestoreButton" TargetType="{x:Type local:MyIconButton}">
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Height" Value="30" />
<Setter Property="Width" Value="30" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Margin" Value="0,5,32,0" />
<Setter Property="ToolTip" Value="撤销更改" />
<Setter Property="Cursor" Value="Hand" />
</Style>
<Style x:Key="ModifyClearButton" TargetType="{x:Type local:MyIconButton}">
<Setter Property="Height" Value="30" />
<Setter Property="Width" Value="30" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Margin" Value="0,5,32,0" />
<Setter Property="ToolTip" Value="取消安装" />
</Style>
</StackPanel.Resources>
<StackPanel.RenderTransform>
<TranslateTransform X="40" />
</StackPanel.RenderTransform>
<local:MyCard Margin="0,15,0,15" UseAnimation="False" Height="62">
<local:MyCard x:Name="CardSelectName" Margin="0,15,0,15" MinHeight="62">
<local:MyIconButton HorizontalAlignment="Left" Theme="Black" Opacity="0.6" x:Name="BtnBack" Margin="13,0,0,0" Height="26" Width="26"
LogoScale="0.87" Logo="M1097 584 250 584 562 896C591 925 591 972 562 1001 533 1030 487 1030 458 1001L21 565C6 550-0 531 0 511L0 511 0 511C-0 492 6 472 21 457L458 21C487-7 533-7 562 21 591 50 591 97 562 126L250 438 1097 438C1137 438 1170 471 1170 511 1170 551 1137 584 1097 584L1097 584Z" />
<local:MyImage x:Name="ImgLogo" Margin="52,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Left" Height="32" RenderOptions.BitmapScalingMode="HighQuality" />
<local:MyTextBox Margin="93,0,16,0" Padding="-1,0" MinHeight="30" FontSize="15" VerticalAlignment="Center" x:Name="TextSelectName" MaxLength="70" HasBackground="False" />
<local:MyImage x:Name="ImgLogo" Margin="52,15,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Height="32" RenderOptions.BitmapScalingMode="HighQuality" />
<local:MyTextBox Margin="93,16,16,0" Padding="-1,0" MinHeight="30" FontSize="15" VerticalAlignment="Top" x:Name="TextSelectName" MaxLength="70" HasBackground="False" ShowValidateResult="False" />
<TextBlock x:Name="LabSelectName" Visibility="Collapsed" Height="21" Margin="56,47,42,11" Padding="0,4,0,0" VerticalAlignment="Top" FontSize="12.5" Foreground="{DynamicResource ColorBrushGray3}" TextTrimming="CharacterEllipsis" />
<local:MyIconButton x:Name="BtnOriginalNameRestore" Style="{StaticResource ModifyRestoreButton}" Margin="0,16,6,0"
Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
<local:MyHint x:Name="HintSelectName" Theme="Red" Visibility="Collapsed" />
<local:MyHint Text="如果不安装 Fabric API,大多数 Mod 都会无法使用!" Margin="0,10,0,0" x:Name="HintFabricAPI" Theme="Red" />
<local:MyHint Text="必须安装 OptiFabric 才能正常使用 OptiFine!" Margin="0,10,0,0" x:Name="HintOptiFabric" Theme="Red" />
<local:MyHint Text="安装结束后,请在 Mod 下载中搜索 OptiFabric Origins 并下载,否则 OptiFine 会无法使用!" Margin="0,10,0,0" x:Name="HintOptiFabricOld" Theme="Yellow" />
<local:MyHint Text="OptiFine 与一部分 Mod 的兼容性不佳,请谨慎安装。" Margin="0,10,0,0" x:Name="HintModOptiFine" Theme="Yellow" />
<local:MyCard Title="Minecraft" Height="40" Margin="0,12,0,0" x:Name="CardMinecraft" Visibility="Collapsed">
<Grid x:Name="PanMinecraftInfo" Height="18" Margin="132,11,35,0" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /><ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<local:MyImage x:Name="ImgMinecraft" Height="18" Width="18" Margin="0,0,7,0" RenderOptions.BitmapScalingMode="Linear" />
<TextBlock x:Name="LabMinecraftVersion" Grid.Column="1" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" />
</Grid>
<Grid x:Name="PanMinecraftCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel>
<local:MyImage x:Name="ImgMinecraftOld" Style="{StaticResource ModifyCompareIcon}" DockPanel.Dock="Left" />
<TextBlock x:Name="LabMinecraftOld" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
<DockPanel Grid.Column="2">
<local:MyImage x:Name="ImgMinecraftNew" Style="{StaticResource ModifyCompareIcon}" DockPanel.Dock="Left" />
<TextBlock x:Name="LabMinecraftNew" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
</Grid>
<Grid Height="40" VerticalAlignment="Top" Background="Transparent" Cursor="Hand">
<Path HorizontalAlignment="Right" Margin="0,0,16,0" Stretch="Uniform" Height="6" Width="10" Fill="{StaticResource ColorBrush1}" RenderTransformOrigin="0.5,0.5">
<Path.Data>M2,4 l-2,2 10,10 10,-10 -2,-2 -8,8 -8,-8 z</Path.Data>
<Path.RenderTransform><RotateTransform Angle="270" /></Path.RenderTransform>
</Path>
</Grid>
<local:MyIconButton x:Name="BtnMinecraftRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
<local:MyCard Title="Forge" Height="40" Margin="0,12,0,0" x:Name="CardForge" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanForge" />
<Grid x:Name="PanForgeInfo" Height="18" Margin="132,11,15,0" VerticalAlignment="Top" Tag="True">
@@ -37,13 +114,25 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Image x:Name="ImgForge" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Anvil.png" />
<local:MyImage x:Name="ImgForge" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Anvil.png" />
<TextBlock x:Name="LabForge" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
</Grid>
<Grid x:Name="BtnForgeClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
<Path x:Name="BtnForgeClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="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" />
<Grid x:Name="PanForgeCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel>
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Anvil.png" DockPanel.Dock="Left" />
<TextBlock x:Name="LabForgeOld" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
<DockPanel Grid.Column="2">
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Anvil.png" DockPanel.Dock="Left" />
<TextBlock Style="{StaticResource ModifyCompareText}" />
</DockPanel>
</Grid>
<local:MyIconButton x:Name="BtnForgeClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
<local:MyIconButton x:Name="BtnForgeRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
<local:MyCard Title="NeoForge" Height="40" Margin="0,12,0,0" x:Name="CardNeoForge" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanNeoForge" />
@@ -55,13 +144,25 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Image x:Name="ImgNeoForge" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/NeoForge.png" />
<local:MyImage x:Name="ImgNeoForge" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/NeoForge.png" />
<TextBlock x:Name="LabNeoForge" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
</Grid>
<Grid x:Name="BtnNeoForgeClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
<Path x:Name="BtnNeoForgeClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="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" />
<Grid x:Name="PanNeoForgeCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel>
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/NeoForge.png" DockPanel.Dock="Left" />
<TextBlock x:Name="LabNeoForgeOld" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
<DockPanel Grid.Column="2">
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/NeoForge.png" DockPanel.Dock="Left" />
<TextBlock Style="{StaticResource ModifyCompareText}" />
</DockPanel>
</Grid>
<local:MyIconButton x:Name="BtnNeoForgeClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
<local:MyIconButton x:Name="BtnNeoForgeRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
<local:MyCard Title="Fabric" Height="40" Margin="0,12,0,0" x:Name="CardFabric" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanFabric" />
@@ -73,13 +174,25 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Image x:Name="ImgFabric" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Fabric.png" />
<local:MyImage x:Name="ImgFabric" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Fabric.png" />
<TextBlock x:Name="LabFabric" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
</Grid>
<Grid x:Name="BtnFabricClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
<Path x:Name="BtnFabricClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="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" />
<Grid x:Name="PanFabricCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel>
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Fabric.png" DockPanel.Dock="Left" />
<TextBlock x:Name="LabFabricOld" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
<DockPanel Grid.Column="2">
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Fabric.png" DockPanel.Dock="Left" />
<TextBlock Style="{StaticResource ModifyCompareText}" />
</DockPanel>
</Grid>
<local:MyIconButton x:Name="BtnFabricClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
<local:MyIconButton x:Name="BtnFabricRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
<local:MyCard Title="Fabric API" Height="40" Margin="0,12,0,0" x:Name="CardFabricApi" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanFabricApi" />
@@ -91,13 +204,25 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Image x:Name="ImgFabricApi" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Fabric.png" />
<local:MyImage x:Name="ImgFabricApi" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Fabric.png" />
<TextBlock x:Name="LabFabricApi" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
</Grid>
<Grid x:Name="BtnFabricApiClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
<Path x:Name="BtnFabricApiClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="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" />
<Grid x:Name="PanFabricApiCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel>
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Fabric.png" DockPanel.Dock="Left" />
<TextBlock x:Name="LabFabricApiOld" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
<DockPanel Grid.Column="2">
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Fabric.png" DockPanel.Dock="Left" />
<TextBlock Style="{StaticResource ModifyCompareText}" />
</DockPanel>
</Grid>
<local:MyIconButton x:Name="BtnFabricApiClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
<local:MyIconButton x:Name="BtnFabricApiRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
<local:MyCard Title="OptiFine" Height="40" Margin="0,12,0,0" x:Name="CardOptiFine" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top">
@@ -111,13 +236,25 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Image x:Name="ImgOptiFine" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/GrassPath.png" />
<local:MyImage x:Name="ImgOptiFine" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/GrassPath.png" />
<TextBlock x:Name="LabOptiFine" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
</Grid>
<Grid x:Name="BtnOptiFineClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
<Path x:Name="BtnOptiFineClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="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" />
<Grid x:Name="PanOptiFineCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel>
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/GrassPath.png" DockPanel.Dock="Left" />
<TextBlock x:Name="LabOptiFineOld" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
<DockPanel Grid.Column="2">
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/GrassPath.png" DockPanel.Dock="Left" />
<TextBlock Style="{StaticResource ModifyCompareText}" />
</DockPanel>
</Grid>
<local:MyIconButton x:Name="BtnOptiFineClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
<local:MyIconButton x:Name="BtnOptiFineRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
<local:MyCard Title="OptiFabric" Height="40" Margin="0,12,0,0" x:Name="CardOptiFabric" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanOptiFabric" />
@@ -129,13 +266,25 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Image x:Name="ImgOptiFabric" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="HighQuality" Source="pack://application:,,,/images/Blocks/OptiFabric.png" />
<local:MyImage x:Name="ImgOptiFabric" Margin="0,0,7,0" SnapsToDevicePixels="True" Height="18" RenderOptions.BitmapScalingMode="HighQuality" Source="pack://application:,,,/images/Blocks/OptiFabric.png" />
<TextBlock x:Name="LabOptiFabric" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
</Grid>
<Grid x:Name="BtnOptiFabricClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
<Path x:Name="BtnOptiFabricClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="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" />
<Grid x:Name="PanOptiFabricCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel>
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/OptiFabric.png" DockPanel.Dock="Left" />
<TextBlock x:Name="LabOptiFabricOld" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
<DockPanel Grid.Column="2">
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/OptiFabric.png" DockPanel.Dock="Left" />
<TextBlock Style="{StaticResource ModifyCompareText}" />
</DockPanel>
</Grid>
<local:MyIconButton x:Name="BtnOptiFabricClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
<local:MyIconButton x:Name="BtnOptiFabricRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
<local:MyCard Title="LiteLoader" Height="40" Margin="0,12,0,0" x:Name="CardLiteLoader" IsSwapped="True" CanSwap="True" SwapLogoRight="True">
<StackPanel Margin="20,40,18,15" VerticalAlignment="Top" Name="PanLiteLoader" />
@@ -147,13 +296,25 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Image x:Name="ImgLiteLoader" Margin="-1,0,6,0" SnapsToDevicePixels="True" Height="20" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Egg.png" />
<local:MyImage x:Name="ImgLiteLoader" Margin="-1,0,6,0" SnapsToDevicePixels="True" Height="20" RenderOptions.BitmapScalingMode="Linear" Source="pack://application:,,,/images/Blocks/Egg.png" />
<TextBlock x:Name="LabLiteLoader" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Grid.Column="1" />
</Grid>
<Grid x:Name="BtnLiteLoaderClear" Height="30" Width="30" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,32,0" Background="{StaticResource ColorBrushSemiTransparent}">
<Path x:Name="BtnLiteLoaderClearInner" Height="10" Width="10" Stretch="Uniform" Fill="{StaticResource ColorBrushGray1}" HorizontalAlignment="Center" VerticalAlignment="Center"
Data="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" />
<Grid x:Name="PanLiteLoaderCompare" Height="18" Margin="132,11,80,0" VerticalAlignment="Top" Visibility="Collapsed" IsHitTestVisible="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<DockPanel>
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Egg.png" DockPanel.Dock="Left" />
<TextBlock x:Name="LabLiteLoaderOld" Style="{StaticResource ModifyCompareText}" />
</DockPanel>
<Path Grid.Column="1" Style="{StaticResource ModifyCompareArrow}" />
<DockPanel Grid.Column="2">
<local:MyImage Style="{StaticResource ModifyCompareIcon}" Source="pack://application:,,,/images/Blocks/Egg.png" DockPanel.Dock="Left" />
<TextBlock Style="{StaticResource ModifyCompareText}" />
</DockPanel>
</Grid>
<local:MyIconButton x:Name="BtnLiteLoaderClear" Style="{StaticResource ModifyClearButton}" Theme="Black" LogoScale="0.5" Logo="{StaticResource ModifyClearLogo}" />
<local:MyIconButton x:Name="BtnLiteLoaderRestore" Style="{StaticResource ModifyRestoreButton}" Theme="Black" LogoScale="0.55" Logo="{StaticResource ModifyRestoreLogo}" />
</local:MyCard>
</StackPanel>
</Grid>
@@ -163,7 +324,7 @@
LogoScale="0.95" Logo="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
</Grid>
<local:MyCard HorizontalAlignment="Center" VerticalAlignment="Center" Margin="40,0" SnapsToDevicePixels="True" x:Name="PanLoad" UseAnimation="False">
<local:MyLoading Text="正在获取版本列表" Margin="20,20,20,17" x:Name="LoadMinecraft" HorizontalAlignment="Center" VerticalAlignment="Center" />
<local:MyLoading Text="正在加载" Margin="20,20,20,17" x:Name="LoadMinecraft" HorizontalAlignment="Center" VerticalAlignment="Center" ShowProgress="True" />
<local:MyLoading Visibility="Collapsed" x:Name="LoadOptiFine" HasAnimation="False" />
<local:MyLoading Visibility="Collapsed" x:Name="LoadForge" HasAnimation="False" />
<local:MyLoading Visibility="Collapsed" x:Name="LoadNeoForge" HasAnimation="False" />
@@ -196,4 +357,4 @@
</StackPanel>
</Border>
</Grid>
-->
-->
@@ -1,12 +1,30 @@
Public Class PageDownloadInstall
Private Sub LoaderInit() Handles Me.Initialized
Public Sub ControlInit()
DisabledPageAnimControls.Add(BtnStart)
LoadOptiFine.State = DlOptiFineListLoader
LoadLiteLoader.State = DlLiteLoaderListLoader
LoadFabric.State = DlFabricListLoader
LoadFabricApi.State = DlFabricApiLoader
LoadNeoForge.State = DlNeoForgeListLoader
LoadOptiFabric.State = DlOptiFabricLoader
McDownloadForgeRecommendedRefresh()
End Sub
Public Overridable Sub LoaderInit() Handles Me.Initialized
ControlInit()
PageLoaderInit(LoadMinecraft, PanLoad, PanAllBack, Nothing, DlClientListLoader, AddressOf LoadMinecraft_OnFinish)
End Sub
Private IsLoad As Boolean = False
Private Sub Init() Handles Me.Loaded
Public Overridable Sub Init() Handles Me.Loaded
If IsLoad Then
IsSelectNameEdited = False
ExitSelectPage()
If DlClientListLoader.State = LoadState.Finished Then TrySelectWaitingVersion()
End If
IsLoad = True
PanBack.ScrollToHome()
DlOptiFineListLoader.Start()
DlLiteLoaderListLoader.Start()
@@ -17,35 +35,19 @@ Public Class PageDownloadInstall
TextSelectName.ValidateRules = New ObjectModel.Collection(Of Validate) From {New ValidateFolderName(McFolderSelected & "versions")}
TextSelectName.Validate()
ReloadSelected()
'非重复加载部分
If IsLoad Then Return
IsLoad = True
McDownloadForgeRecommendedRefresh()
LoadOptiFine.State = DlOptiFineListLoader
LoadLiteLoader.State = DlLiteLoaderListLoader
LoadFabric.State = DlFabricListLoader
LoadFabricApi.State = DlFabricApiLoader
LoadNeoForge.State = DlNeoForgeListLoader
LoadOptiFabric.State = DlOptiFabricLoader
End Sub
#Region "页面切换"
'页面切换动画
Public IsInSelectPage As Boolean = False
Private IsFirstLoaded As Boolean = False
Private Sub EnterSelectPage()
If IsInSelectPage Then Return
''' <summary>
''' 选择页面 UI 初始化。
''' </summary>
Public Sub PrepareSelectPage()
IsInSelectPage = True
PanInner.Margin = New Thickness(25, 10, 25, 40)
AutoSelectedFabricApi = False
AutoSelectedOptiFabric = False
IsSelectNameEdited = False
PanSelect.Visibility = Visibility.Visible
PanSelect.IsHitTestVisible = True
PanMinecraft.IsHitTestVisible = False
@@ -54,13 +56,9 @@ Public Class PageDownloadInstall
DisabledPageAnimControls.Remove(BtnStart)
BtnStart.Show = True
CardOptiFine.IsSwapped = True
CardLiteLoader.IsSwapped = True
CardForge.IsSwapped = True
CardNeoForge.IsSwapped = True
CardFabric.IsSwapped = True
CardFabricApi.IsSwapped = True
CardOptiFabric.IsSwapped = True
For Each Card In {CardOptiFine, CardLiteLoader, CardForge, CardNeoForge, CardFabric, CardFabricApi, CardOptiFabric}
Card.IsSwapped = True
Next
'如果在选择页面按了刷新键,选择页的东西可能会由于动画被隐藏,但不会由于加载结束而再次显示,因此这里需要手动恢复
For Each Control In GetAllAnimControls(PanSelect)
@@ -69,9 +67,16 @@ Public Class PageDownloadInstall
Control.RenderTransform = New TranslateTransform
End If
Next
End Sub
Private Sub EnterSelectPage()
If IsInSelectPage Then Return
AutoSelectedFabricApi = False
AutoSelectedOptiFabric = False
PrepareSelectPage()
'启动 Forge 加载
If McVersion.IsFormatFit(VanillaName) Then
If McVersion.IsStandardFormat(VanillaName) Then
Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion " & VanillaName, AddressOf DlForgeVersionMain)
LoadForge.State = ForgeLoader
ForgeLoader.Start(VanillaName)
@@ -87,35 +92,27 @@ Public Class PageDownloadInstall
AaCode(
Sub()
PanBack.ScrollToHome()
TextSelectName.Validate()
OptiFine_Loaded()
LiteLoader_Loaded()
Forge_Loaded()
NeoForge_Loaded()
Fabric_Loaded()
FabricApi_Loaded()
OptiFabric_Loaded()
ReloadSelected()
ReloadComponentLists()
PanMinecraft.Visibility = Visibility.Collapsed
End Sub, After:=True),
AaOpacity(PanSelect, 1 - PanSelect.Opacity, 70, 100),
AaTranslateX(PanSelect, -CType(PanSelect.RenderTransform, TranslateTransform).X, 160, 100, Ease:=New AniEaseOutFluent(AniEasePower.ExtraStrong)),
AaCode(
Sub()
PanBack.IsHitTestVisible = True
'初始化 Binding
If IsFirstLoaded Then Return
IsFirstLoaded = True
BtnOptiFineClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFine.MainTextBlock, .Mode = BindingMode.OneWay})
BtnLiteLoaderClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardLiteLoader.MainTextBlock, .Mode = BindingMode.OneWay})
BtnForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardForge.MainTextBlock, .Mode = BindingMode.OneWay})
BtnNeoForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardNeoForge.MainTextBlock, .Mode = BindingMode.OneWay})
BtnFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabric.MainTextBlock, .Mode = BindingMode.OneWay})
BtnFabricApiClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabricApi.MainTextBlock, .Mode = BindingMode.OneWay})
BtnOptiFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFabric.MainTextBlock, .Mode = BindingMode.OneWay})
End Sub,, True)
AaCode(Sub() PanBack.IsHitTestVisible = True,, True)
}, "FrmDownloadInstall SelectPageSwitch", True)
End Sub
Public Sub ReloadComponentLists()
TextSelectName.Validate()
OptiFine_Loaded()
LiteLoader_Loaded()
Forge_Loaded()
NeoForge_Loaded()
Fabric_Loaded()
FabricApi_Loaded()
OptiFabric_Loaded()
ReloadSelected()
End Sub
Public Sub ExitSelectPage() Handles BtnBack.Click
If Not IsInSelectPage Then Return
IsInSelectPage = False
@@ -144,10 +141,11 @@ Public Class PageDownloadInstall
End Sub,, True)
}, "FrmDownloadInstall SelectPageSwitch")
End Sub
Public Sub MinecraftSelected(sender As MyListItem, e As MouseButtonEventArgs)
Public Overridable Sub MinecraftSelected(sender As MyListItem, e As MouseButtonEventArgs)
VanillaName = sender.Title
VanillaData = sender.Tag
VanillaIcon = sender.Logo
LabMinecraftVersion.Text = VanillaName
EnterSelectPage()
End Sub
@@ -156,9 +154,9 @@ Public Class PageDownloadInstall
#Region "选择"
'Minecraft
Private VanillaName As String
Private VanillaData As JObject
Private VanillaIcon As String
Public VanillaName As String
Public VanillaData As JObject
Public VanillaIcon As String
Private ReadOnly Property VanillaDrop As Integer
Get
Return McVersion.VersionToDrop(VanillaName)
@@ -166,24 +164,25 @@ Public Class PageDownloadInstall
End Property
'附加组件
Private SelectedOptiFine As DlOptiFineListEntry = Nothing
Private SelectedLiteLoader As DlLiteLoaderListEntry = Nothing
Private SelectedForge As DlForgeVersionEntry = Nothing
Private SelectedNeoForge As DlNeoForgeListEntry = Nothing
Private SelectedFabric As String = Nothing
Private SelectedFabricApi As ResourceVersion = Nothing
Private SelectedOptiFabric As ResourceVersion = Nothing
Public SelectedOptiFine As DlOptiFineListEntry = Nothing
Public SelectedLiteLoader As DlLiteLoaderListEntry = Nothing
Public SelectedForge As DlForgeVersionEntry = Nothing
Public SelectedNeoForge As DlNeoForgeListEntry = Nothing
Public SelectedFabric As String = Nothing
Public SelectedFabricApi As ResourceVersion = Nothing
Public SelectedOptiFabric As ResourceVersion = Nothing
''' <summary>
''' 重载已选择的项目的显示。
''' </summary>
Private Sub ReloadSelected() Handles CardOptiFine.Swap, LoadOptiFine.StateChanged, CardForge.Swap, LoadForge.StateChanged, CardNeoForge.Swap, LoadNeoForge.StateChanged, CardFabric.Swap, LoadFabric.StateChanged, CardFabricApi.Swap, LoadFabricApi.StateChanged, CardOptiFabric.Swap, LoadOptiFabric.StateChanged, CardLiteLoader.Swap, LoadLiteLoader.StateChanged
Public Overridable Sub ReloadSelected() Handles CardOptiFine.Swap, LoadOptiFine.StateChanged, CardForge.Swap, LoadForge.StateChanged, CardNeoForge.Swap, LoadNeoForge.StateChanged, CardFabric.Swap, LoadFabric.StateChanged, CardFabricApi.Swap, LoadFabricApi.StateChanged, CardOptiFabric.Swap, LoadOptiFabric.StateChanged, CardLiteLoader.Swap, LoadLiteLoader.StateChanged
Static Ongoing As Boolean = False '#3742 中,LoadOptiFineGetError 会初始化 LoadOptiFine,触发事件 LoadOptiFine.StateChanged,导致再次调用 SelectReload
If VanillaName Is Nothing OrElse Ongoing Then Return
Ongoing = True
'主预览
SelectNameUpdate()
ImgLogo.Source = GetSelectLogo()
ImgMinecraft.Source = VanillaIcon
'OptiFine
Dim OptiFineError As String = LoadOptiFineGetError()
CardOptiFine.MainSwap.Visibility = If(OptiFineError Is Nothing, Visibility.Visible, Visibility.Collapsed)
@@ -222,7 +221,7 @@ Public Class PageDownloadInstall
End If
End If
'Forge
If Not McVersion.IsFormatFit(VanillaName) Then
If Not McVersion.IsStandardFormat(VanillaName) Then
CardForge.Visibility = Visibility.Collapsed
Else
CardForge.Visibility = Visibility.Visible
@@ -356,7 +355,7 @@ Public Class PageDownloadInstall
''' <summary>
''' 清空已选择的项目。
''' </summary>
Private Sub ClearSelected()
Public Sub ClearSelected()
VanillaName = Nothing
VanillaData = Nothing
VanillaIcon = Nothing
@@ -367,7 +366,10 @@ Public Class PageDownloadInstall
SelectedFabric = Nothing
SelectedFabricApi = Nothing
SelectedOptiFabric = Nothing
IsSelectNameEdited = False
For Each ClearButton In {BtnOptiFineClear, BtnLiteLoaderClear, BtnForgeClear, BtnNeoForgeClear,
BtnFabricClear, BtnFabricApiClear, BtnOptiFabricClear}
ClearButton.Visibility = Visibility.Collapsed
Next
End Sub
'信息栏动画
Private Sub SetPanelVisibility(Panel As Grid, IsVisible As Boolean)
@@ -389,7 +391,7 @@ Public Class PageDownloadInstall
''' <summary>
''' 获取版本图标。
''' </summary>
Private Function GetSelectLogo() As String
Public Overridable Function GetSelectLogo() As String
If SelectedFabric IsNot Nothing Then
Return "pack://application:,,,/images/Blocks/Fabric.png"
ElseIf SelectedForge IsNot Nothing Then
@@ -409,7 +411,7 @@ Public Class PageDownloadInstall
''' <summary>
''' 获取默认版本名。
''' </summary>
Private Function GetSelectName() As String
Public Function GetSelectName() As String
Dim Name As String = VanillaName
If SelectedFabric IsNot Nothing Then Name += "-Fabric " & SelectedFabric.BeforeFirst("+")
If SelectedForge IsNot Nothing Then Name += "-Forge_" & SelectedForge.VersionName
@@ -418,36 +420,39 @@ Public Class PageDownloadInstall
If SelectedOptiFine IsNot Nothing Then Name += "-OptiFine_" & SelectedOptiFine.DisplayName.Replace(VanillaName & " ", "").Replace(" ", "_")
Return Name
End Function
Private IsSelectNameEdited As Boolean = False
Private IsSelectNameChanging As Boolean = False
Public IsSelectNameEdited As Boolean = False
Private Sub SelectNameUpdate()
If IsSelectNameEdited OrElse IsSelectNameChanging Then Return
IsSelectNameChanging = True
If IsSelectNameEdited Then Return
TextSelectName.Text = GetSelectName()
IsSelectNameChanging = False
IsSelectNameEdited = False
End Sub
Private Sub TextSelectName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TextSelectName.TextChanged
If IsSelectNameChanging Then Return
IsSelectNameEdited = True
ReloadSelected()
End Sub
Private Sub TextSelectName_ValidateChanged(sender As Object, e As EventArgs) Handles TextSelectName.ValidateChanged
BtnStart.IsEnabled = TextSelectName.IsValidated
HintSelectName.Text = TextSelectName.ValidateResult
HintSelectName.Visibility = If(TextSelectName.IsValidated, Visibility.Collapsed, Visibility.Visible)
End Sub
#End Region
#Region "加载器"
Public MinecraftVersions As JArray
Private Sub LoadMinecraft_OnFinish()
MinecraftVersions = CType(DlClientListLoader.Output.Value("versions").DeepClone(), JArray)
ShowMinecraftVersionList()
TrySelectWaitingVersion() '自动选择版本
End Sub
'结果数据化
Private Sub LoadMinecraft_OnFinish()
Public Overridable Sub ShowMinecraftVersionList()
ExitSelectPage() '返回
Try
Dim Dict As New Dictionary(Of String, List(Of JObject)) From {
{"正式版", New List(Of JObject)}, {"预览版", New List(Of JObject)}, {"远古版", New List(Of JObject)}, {"愚人节版", New List(Of JObject)}
}
Dim Versions As JArray = DlClientListLoader.Output.Value("versions")
For Each Version As JObject In Versions
For Each Version As JObject In MinecraftVersions
'确定分类
Dim Type As String = Version("type")
Select Case Type
@@ -498,7 +503,7 @@ Public Class PageDownloadInstall
'清空当前
PanMinecraft.Children.Clear()
'添加最新版本
Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15), .SwapType = 2}
Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15)}
Dim PinnedVersions As New List(Of JObject)
Dim Release As JObject = Dict("正式版")(0).DeepClone()
Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
@@ -508,36 +513,41 @@ Public Class PageDownloadInstall
Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
PinnedVersions.Add(Snapshot)
End If
Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = PinnedVersions}
MyCard.StackInstall(PanInfo, 7)
Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
CardInfo.Children.Add(PanInfo)
CardInfo.SwapControl = PanInfo
CardInfo.SetContentBuilder(PinnedVersions, '使用 Lambda 转发点击事件,避免 #535
Function(Version) McDownloadListItem(Version, Sub(sender, e) MinecraftSelected(sender, e), False))
CardInfo.BuildContent()
PanMinecraft.Children.Insert(0, CardInfo)
'添加其他版本
For Each Pair As KeyValuePair(Of String, List(Of JObject)) In Dict
If Not Pair.Value.Any() Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = 7}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15)}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
NewCard.Children.Add(NewStack)
NewCard.SwapControl = NewStack
NewCard.SetContentBuilder(Pair.Value,
Function(Version) McDownloadListItem(Version, Sub(sender, e) MinecraftSelected(sender, e), False))
NewCard.IsSwapped = True
PanMinecraft.Children.Add(NewCard)
Next
'自动选择版本
If VersionWaitingSelect Is Nothing Then Exit Try
Logger.Info($"自动选择 MC 版本:{VersionWaitingSelect}")
For Each Version As JObject In Versions
If Version("id").ToString <> VersionWaitingSelect Then Continue For
Dim Item = McDownloadListItem(Version, Sub()
End Sub, False).Init()
MinecraftSelected(Item, Nothing)
VersionWaitingSelect = Nothing
Return
Next
Catch ex As Exception
Logger.Error(ex, "可视化安装版本列表出错")
End Try
End Sub
Private Sub TrySelectWaitingVersion()
If VersionWaitingSelect Is Nothing Then Return
For Each Version As JObject In MinecraftVersions
If Version("id").ToString <> VersionWaitingSelect Then Continue For
Logger.Info($"自动选择 MC 版本:{VersionWaitingSelect}")
MinecraftSelected(McDownloadListItem(Version, Nothing, False).Init(), Nothing)
VersionWaitingSelect = Nothing
Return
Next
End Sub
''' <summary>
''' 当 MC 版本列表加载完时,立即自动选择的版本。用于外部调用。
''' </summary>
@@ -550,16 +560,16 @@ Public Class PageDownloadInstall
''' <summary>
''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadOptiFineGetError() As String
Public Function LoadOptiFineGetError() As String
If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
'检查 Forge 1.13 - 1.14.3:全部不兼容
If SelectedForge IsNot Nothing AndAlso
CompareVersion(VanillaName, "1.13") >= 0 AndAlso CompareVersion("1.14.3", VanillaName) >= 0 Then
McUtils.CompareVersionGE(VanillaName, "1.13") AndAlso McUtils.CompareVersionGE("1.14.3", VanillaName) Then
Return "与 Forge 不兼容"
End If
'检查 Fabric 1.20.5+:全部不兼容
If SelectedFabric IsNot Nothing AndAlso
CompareVersion(VanillaName, "1.20.4") > 0 Then
McUtils.CompareVersion(VanillaName, "1.20.4") > 0 Then
Return "与 Fabric 不兼容"
End If
'检查 Loader
@@ -584,12 +594,12 @@ Public Class PageDownloadInstall
End Function
'检查某个 OptiFine 是否与某个 Forge 兼容
Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
Public Shared Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry) As Boolean
If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
If OptiFine.RequiredForgeVersion Is Nothing Then Return False '不兼容 Forge
If String.IsNullOrWhiteSpace(OptiFine.RequiredForgeVersion) Then Return True '#4183
If OptiFine.RequiredForgeVersion.Contains(".") Then 'XX.X.XXX
Return CompareVersion(Forge.Version.ToString, OptiFine.RequiredForgeVersion) = 0
Return McUtils.CompareVersion(Forge.Version.ToString, OptiFine.RequiredForgeVersion) = 0
Else 'XXXX
Return Forge.Version.Revision = OptiFine.RequiredForgeVersion
End If
@@ -619,7 +629,7 @@ Public Class PageDownloadInstall
Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
If Not Left.IsPreview AndAlso Right.IsPreview Then Return True
If Left.IsPreview AndAlso Not Right.IsPreview Then Return False
Return CompareVersionGE(Left.DisplayName, Right.DisplayName)
Return McUtils.CompareVersionGE(Left.DisplayName, Right.DisplayName)
End Function)
'可视化
PanOptiFine.Children.Clear()
@@ -641,12 +651,12 @@ Public Class PageDownloadInstall
CardOptiFine.IsSwapped = True
ReloadSelected()
End Sub
Private Sub OptiFine_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFineClear.MouseLeftButtonUp
Private Sub OptiFine_Clear(sender As Object, e As EventArgs) Handles BtnOptiFineClear.Click
SelectedOptiFine = Nothing
SelectedOptiFabric = Nothing
BtnOptiFabricClear.Visibility = Visibility.Collapsed
AutoSelectedOptiFabric = False
CardOptiFine.IsSwapped = True
e.Handled = True
Forge_Loaded()
NeoForge_Loaded()
ReloadSelected()
@@ -659,7 +669,7 @@ Public Class PageDownloadInstall
''' <summary>
''' 获取 LiteLoader 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadLiteLoaderGetError() As String
Public Function LoadLiteLoaderGetError() As String
'检查 Loader
If GetLoaderError(LoadLiteLoader) IsNot Nothing Then Return GetLoaderError(LoadLiteLoader)
'检查版本
@@ -699,10 +709,9 @@ Public Class PageDownloadInstall
CardLiteLoader.IsSwapped = True
ReloadSelected()
End Sub
Private Sub LiteLoader_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnLiteLoaderClear.MouseLeftButtonUp
Private Sub LiteLoader_Clear(sender As Object, e As EventArgs) Handles BtnLiteLoaderClear.Click
SelectedLiteLoader = Nothing
CardLiteLoader.IsSwapped = True
e.Handled = True
ReloadSelected()
End Sub
@@ -713,8 +722,8 @@ Public Class PageDownloadInstall
''' <summary>
''' 获取 Forge 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadForgeGetError() As String
If CompareVersionGE("1.5.1", VanillaName) AndAlso CompareVersionGE(VanillaName, "1.1") Then Return "无"
Public Function LoadForgeGetError() As String
If McUtils.CompareVersionGE("1.5.1", VanillaName) AndAlso McUtils.CompareVersionGE(VanillaName, "1.1") Then Return "无"
'检查 Loader
If GetLoaderError(LoadForge) IsNot Nothing Then Return GetLoaderError(LoadForge)
Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
@@ -725,7 +734,7 @@ Public Class PageDownloadInstall
If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
If SelectedOptiFine IsNot Nothing AndAlso
CompareVersionGE(VanillaName, "1.13") AndAlso CompareVersionGE("1.14.3", VanillaName) Then
McUtils.CompareVersionGE(VanillaName, "1.13") AndAlso McUtils.CompareVersionGE("1.14.3", VanillaName) Then
Return "与 OptiFine 不兼容" '1.13 ~ 1.14.3 OptiFine 检查
End If
If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, Version) Then Continue For
@@ -775,10 +784,9 @@ Public Class PageDownloadInstall
OptiFine_Loaded()
ReloadSelected()
End Sub
Private Sub Forge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnForgeClear.MouseLeftButtonUp
Private Sub Forge_Clear(sender As Object, e As EventArgs) Handles BtnForgeClear.Click
SelectedForge = Nothing
CardForge.IsSwapped = True
e.Handled = True
OptiFine_Loaded()
ReloadSelected()
End Sub
@@ -790,7 +798,7 @@ Public Class PageDownloadInstall
''' <summary>
''' 获取 NeoForge 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadNeoForgeGetError() As String
Public Function LoadNeoForgeGetError() As String
If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
@@ -832,10 +840,9 @@ Public Class PageDownloadInstall
OptiFine_Loaded()
ReloadSelected()
End Sub
Private Sub NeoForge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnNeoForgeClear.MouseLeftButtonUp
Private Sub NeoForge_Clear(sender As Object, e As EventArgs) Handles BtnNeoForgeClear.Click
SelectedNeoForge = Nothing
CardNeoForge.IsSwapped = True
e.Handled = True
OptiFine_Loaded()
ReloadSelected()
End Sub
@@ -847,9 +854,9 @@ Public Class PageDownloadInstall
''' <summary>
''' 获取 Fabric 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadFabricGetError() As String
Public Function LoadFabricGetError() As String
'检查 OptiFine 1.20.5+:没有 OptiFabric 故全部不兼容
If SelectedOptiFine IsNot Nothing AndAlso CompareVersionGE(VanillaName, "1.20.5") Then Return "与 OptiFine 不兼容"
If SelectedOptiFine IsNot Nothing AndAlso McUtils.CompareVersionGE(VanillaName, "1.20.5") Then Return "与 OptiFine 不兼容"
'检查 Loader
If GetLoaderError(LoadFabric) IsNot Nothing Then Return GetLoaderError(LoadFabric)
'检查版本
@@ -879,9 +886,10 @@ Public Class PageDownloadInstall
If Not Versions.Any() Then Return
'可视化
PanFabric.Children.Clear()
PanFabric.Tag = Versions
CardFabric.SwapControl = PanFabric
CardFabric.SwapType = 12
CardFabric.SetContentBuilder(Versions.OfType(Of JObject),
Function(Version) FabricDownloadListItem(Version, AddressOf Fabric_Selected))
If Not CardFabric.IsSwapped Then CardFabric.BuildContent()
Catch ex As Exception
Logger.Error(ex, "可视化 Fabric 安装版本列表出错")
End Try
@@ -895,14 +903,15 @@ Public Class PageDownloadInstall
CardFabric.IsSwapped = True
ReloadSelected()
End Sub
Private Sub Fabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricClear.MouseLeftButtonUp
Private Sub Fabric_Clear(sender As Object, e As EventArgs) Handles BtnFabricClear.Click
SelectedFabric = Nothing
SelectedFabricApi = Nothing
BtnFabricApiClear.Visibility = Visibility.Collapsed
AutoSelectedFabricApi = False
SelectedOptiFabric = Nothing
BtnOptiFabricClear.Visibility = Visibility.Collapsed
AutoSelectedOptiFabric = False
CardFabric.IsSwapped = True
e.Handled = True
ReloadSelected()
End Sub
@@ -911,14 +920,14 @@ Public Class PageDownloadInstall
#Region "Fabric API 列表"
''' <summary>
''' 判断某 Fabric API 是否适配当前选择的原版版本。
''' 判断某 Fabric API 是否适配指定的原版版本。
''' </summary>
Public Function IsFabricApiCompatible(FabricApi As ResourceVersion) As Boolean
Public Shared Function IsFabricApiCompatible(FabricApi As ResourceVersion, MinecraftVersion As String) As Boolean
Dim FabricApiName = FabricApi.Display
Try
If FabricApiName Is Nothing OrElse VanillaName Is Nothing Then Return False
If FabricApiName Is Nothing OrElse MinecraftVersion Is Nothing Then Return False
FabricApiName = FabricApiName.Lower
Dim TargetName = VanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").Lower
Dim TargetName = MinecraftVersion.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").Lower
If FabricApiName.StartsWithF("[" & TargetName & "]") Then Return True
If Not FabricApiName.Contains("/") OrElse Not FabricApiName.Contains("]") Then Return False
'直接的判断(例如 1.18.1/22w03a)
@@ -946,7 +955,7 @@ Public Class PageDownloadInstall
End While
Return True
Catch ex As Exception
Logger.Warn(ex, $"判断 Fabric API 版本适配性出错({FabricApiName}, {VanillaName})")
Logger.Warn(ex, $"判断 Fabric API 版本适配性出错({FabricApiName}, {MinecraftVersion})")
Return False
End Try
End Function
@@ -954,12 +963,12 @@ Public Class PageDownloadInstall
''' <summary>
''' 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadFabricApiGetError() As String
Public Function LoadFabricApiGetError() As String
'检查 Loader
If GetLoaderError(LoadFabricApi) IsNot Nothing Then Return GetLoaderError(LoadFabricApi)
If DlFabricApiLoader.Output Is Nothing Then Return If(SelectedFabric Is Nothing, "需要安装 Fabric", "获取中……")
'检查版本
If DlFabricApiLoader.Output.Any(Function(f) IsFabricApiCompatible(f)) Then
If DlFabricApiLoader.Output.Any(Function(f) IsFabricApiCompatible(f, VanillaName)) Then
Return If(SelectedFabric Is Nothing, "需要安装 Fabric", Nothing)
Else
Return "无"
@@ -971,7 +980,7 @@ Public Class PageDownloadInstall
If LoadFabricApiGetError() IsNot Nothing Then e.Handled = True
End Sub
Private AutoSelectedFabricApi As Boolean = False
Public AutoSelectedFabricApi As Boolean = False
''' <summary>
''' 尝试重新可视化 FabricApi 版本列表。
''' </summary>
@@ -982,7 +991,7 @@ Public Class PageDownloadInstall
'获取版本列表
Dim Versions As New List(Of ResourceVersion)
For Each Version In DlFabricApiLoader.Output
If IsFabricApiCompatible(Version) Then
If IsFabricApiCompatible(Version, VanillaName) Then
If Not Version.Display.StartsWithF("[") Then
Logger.Warn($"已特判修改 Fabric API 显示名:{Version.Display}")
Version.Display = "[" & VanillaName & "] " & Version.Display
@@ -995,7 +1004,6 @@ Public Class PageDownloadInstall
'可视化
PanFabricApi.Children.Clear()
For Each Version In Versions
If Not IsFabricApiCompatible(Version) Then Continue For
PanFabricApi.Children.Add(FabricApiDownloadListItem(Version, AddressOf FabricApi_Selected))
Next
'自动选择 Fabric API
@@ -1016,10 +1024,9 @@ Public Class PageDownloadInstall
CardFabricApi.IsSwapped = True
ReloadSelected()
End Sub
Private Sub FabricApi_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricApiClear.MouseLeftButtonUp
Private Sub FabricApi_Clear(sender As Object, e As EventArgs) Handles BtnFabricApiClear.Click
SelectedFabricApi = Nothing
CardFabricApi.IsSwapped = True
e.Handled = True
ReloadSelected()
End Sub
@@ -1028,23 +1035,23 @@ Public Class PageDownloadInstall
#Region "OptiFabric 列表"
''' <summary>
''' 判断某 OptiFabric 是否适配当前选择的原版版本。
''' 判断某 OptiFabric 是否适配指定的原版版本。
''' </summary>
Private Function IsOptiFabricCompatible(ModFile As ResourceVersion) As Boolean
Public Shared Function IsOptiFabricCompatible(ModFile As ResourceVersion, MinecraftVersion As String) As Boolean
Try
If VanillaName Is Nothing Then Return False
Return ModFile.GameVersions.Contains(VanillaName)
If MinecraftVersion Is Nothing Then Return False
Return ModFile.GameVersions.Contains(MinecraftVersion)
Catch ex As Exception
Logger.Warn(ex, $"判断 OptiFabric 版本适配性出错({VanillaName})")
Logger.Warn(ex, $"判断 OptiFabric 版本适配性出错({MinecraftVersion})")
Return False
End Try
End Function
Private AutoSelectedOptiFabric As Boolean = False
Public AutoSelectedOptiFabric As Boolean = False
''' <summary>
''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
''' </summary>
Private Function LoadOptiFabricGetError() As String
Public Function LoadOptiFabricGetError() As String
If VanillaDrop >= 140 AndAlso VanillaDrop <= 150 Then Return "不兼容老版本 Fabric,请手动下载 OptiFabric Origins"
'检查 Loader
If GetLoaderError(LoadOptiFabric) IsNot Nothing Then Return GetLoaderError(LoadOptiFabric)
@@ -1056,7 +1063,7 @@ Public Class PageDownloadInstall
Return "获取中……"
End If
For Each Version In DlOptiFabricLoader.Output
If Not IsOptiFabricCompatible(Version) Then Continue For '2135#
If Not IsOptiFabricCompatible(Version, VanillaName) 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"
@@ -1080,7 +1087,7 @@ Public Class PageDownloadInstall
'获取版本列表
Dim Versions As New List(Of ResourceVersion)
For Each Version In DlOptiFabricLoader.Output
If IsOptiFabricCompatible(Version) Then Versions.Add(Version)
If IsOptiFabricCompatible(Version, VanillaName) Then Versions.Add(Version)
Next
If Not Versions.Any() Then Return
'排序
@@ -1088,7 +1095,6 @@ Public Class PageDownloadInstall
'可视化
PanOptiFabric.Children.Clear()
For Each Version In Versions
If Not IsOptiFabricCompatible(Version) Then Continue For
PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
Next
'自动选择 OptiFabric
@@ -1108,10 +1114,9 @@ Public Class PageDownloadInstall
CardOptiFabric.IsSwapped = True
ReloadSelected()
End Sub
Private Sub OptiFabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFabricClear.MouseLeftButtonUp
Private Sub OptiFabric_Clear(sender As Object, e As EventArgs) Handles BtnOptiFabricClear.Click
SelectedOptiFabric = Nothing
CardOptiFabric.IsSwapped = True
e.Handled = True
ReloadSelected()
End Sub
@@ -1119,10 +1124,42 @@ Public Class PageDownloadInstall
#Region "安装"
''' <summary>
''' 获取当前选择的组件信息。
''' </summary>
Public Function GetSelectedComponents() As McComponents
Return New McComponents(
minecraftVersion:=VanillaName,
optiFineEntry:=If(SelectedOptiFine Is Nothing, Nothing, JObject.FromObject(SelectedOptiFine)),
forgeVersion:=SelectedForge?.VersionName,
neoForgeVersion:=SelectedNeoForge?.VersionName,
fabricVersion:=SelectedFabric,
fabricApiVersion:=If(SelectedFabricApi?.Version, If(SelectedFabricApi?.Id, SelectedFabricApi?.Display)),
optiFabricVersion:=If(SelectedOptiFabric?.Version, If(SelectedOptiFabric?.Id, SelectedOptiFabric?.Display)),
liteLoaderVersion:=SelectedLiteLoader?.JsonToken?("version").ToString())
End Function
Private Sub TextSelectName_KeyDown(sender As Object, e As KeyEventArgs) Handles TextSelectName.KeyDown
If e.Key = Key.Enter AndAlso IsInSelectPage AndAlso BtnStart.IsEnabled Then BtnStart_Click()
End Sub
Private Sub BtnStart_Click() Handles BtnStart.Click
'提交安装申请
Dim InstanceName As String = TextSelectName.Text
Dim Request As New McInstallRequest With {
.NewInstanceName = InstanceName,
.InstanceFolder = $"{McFolderSelected}versions\{InstanceName}\",
.Components = GetSelectedComponents(),
.MinecraftJson = VanillaData("url").ToString,
.ForgeEntry = SelectedForge,
.NeoForgeEntry = SelectedNeoForge,
.FabricApi = SelectedFabricApi,
.OptiFabric = SelectedOptiFabric,
.LiteLoaderEntry = SelectedLiteLoader
}
StartInstall(Request)
End Sub
Public Overridable Sub StartInstall(Request As McInstallRequest)
'确认版本隔离
If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
(Settings.Get(Of Integer)("LaunchArgumentIndieV2") = 0 OrElse Settings.Get(Of Integer)("LaunchArgumentIndieV2") = 2) Then
@@ -1132,22 +1169,7 @@ Public Class PageDownloadInstall
Return
End If
End If
'提交安装申请
Dim InstanceName As String = TextSelectName.Text
Dim Request As New McInstallRequest With {
.NewInstanceName = InstanceName,
.VersionFolder = $"{McFolderSelected}versions\{InstanceName}\",
.MinecraftJson = VanillaData("url").ToString,
.MinecraftName = VanillaName,
.OptiFineEntry = SelectedOptiFine,
.ForgeEntry = SelectedForge,
.NeoForgeEntry = SelectedNeoForge,
.FabricVersion = SelectedFabric,
.FabricApi = SelectedFabricApi,
.OptiFabric = SelectedOptiFabric,
.LiteLoaderEntry = SelectedLiteLoader
}
If Not McInstall(Request) Then Return
If Not McInstallStart(Request) Then Return
'返回,这样在再次进入安装页面时这个版本就会显示文件夹已重复
ExitSelectPage()
End Sub
@@ -0,0 +1,727 @@
''' <summary>
''' 版本修改页:完整还原已安装组件后,复用安装页的选择交互。
''' </summary>
Public Class PageDownloadModify
Inherits PageDownloadInstall
Private InitLoader As LoaderTask(Of McInstance, Object)
Private ForgeVersionLoader As LoaderTask(Of String, List(Of DlForgeVersionEntry))
Private InitialTarget As McComponents '进入时的组件快照
''' <summary>
''' 原版的版本号是否可靠(不是通过 json 模糊分析)。
''' </summary>
Private IsVanillaVersionReliable As Boolean
Private OriginalName As String
Private CustomLogo As String
''' <summary>
''' 开始修改 MC 版本时,记录当前选择的组件,以在修改 MC 版本后尝试自动选中相同组件。
''' </summary>
Private ReadOnly PendingComponents As New Dictionary(Of MyLoading, String)
Private IsRestoringComponents As Boolean
Public Overrides Sub LoaderInit() '父级 Handles Me.Initialized
ControlInit()
InitLoader = New LoaderTask(Of McInstance, Object)("初始化版本修改", AddressOf LoadInstance)
PageLoaderInit(LoadMinecraft, PanLoad, PanAllBack, Nothing, InitLoader, AddressOf LoadInstanceFinished, Function() PageInstanceLeft.Instance)
End Sub
Public Overrides Sub Init() '父级 Handles Me.Loaded
PanBack.ScrollToHome()
Static IsLoad As Boolean = False
If IsLoad Then PageLoaderRestart()
IsLoad = True
End Sub
Private Sub PageUnloaded() Handles Me.Unloaded
InitLoader.Cancel()
End Sub
''' <summary>
''' 读取或初始化版本的安装清单。
''' </summary>
Private Sub LoadInstance(Task As LoaderTask(Of McInstance, Object))
'旧状态清理
RunInUiWait(
Sub()
AniStop("FrmDownloadInstall SelectPageSwitch")
IsSelectNameEdited = False
ClearSelected()
PendingComponents.Clear()
InitialTarget = Nothing
IsInSelectPage = False
PanAllBack.IsHitTestVisible = False
End Sub)
Task.Input.Config.DiscardCache()
'获取 Components
Dim Manifest = Configs.McInstallManifest.Get(Task.Input.Config)
If Manifest IsNot Nothing AndAlso Manifest.SchemaVersion > Versions.McInstallManifestVersion Then
Logger.Warn($"安装清单由更新版本的 PCL 创建(清单版本:{Manifest.SchemaVersion},当前版本:{Versions.McInstallManifestVersion})")
Throw New Exception($"更新 PCL 后才能修改它!点击【设置 → 其他 → 检查更新】以更新。")
End If
If Manifest IsNot Nothing Then
Dim LatestManifest = Manifest.RefreshModComponents(Task.Input.PathIndie)
If LatestManifest IsNot Manifest Then
Manifest = LatestManifest
Configs.McInstallManifest.Set(Manifest, Task.Input.Config)
Task.Input.Config.Save()
End If
End If
Dim Components As McComponents
Dim OptiFineVersion As String = Nothing
If Manifest IsNot Nothing Then
'有清单:从清单读取
Components = Manifest.Components
If Components Is Nothing Then Throw New Exception("安装清单缺少组件信息,无法还原已安装组件。")
IsVanillaVersionReliable = True
Else
'无清单:通过版本 JSON 获取
Dim VersionInfo = New McInstance(Task.Input.PathVersion).Version
If VersionInfo.VanillaName = "Unknown" Then Throw New Exception("无法确定 Minecraft 版本,无法修改")
Dim UnknownLoaders = VersionInfo.ModLoaderVersions.
Where(Function(Loader) String.IsNullOrWhiteSpace(Loader.Value) OrElse Loader.Value = "未知版本").
Select(Function(Loader) Loader.Key.ToString()).ToList()
If UnknownLoaders.Any() Then Throw New Exception($"无法确定 {UnknownLoaders.Join("、")} 的版本,无法修改")
Components = New McComponents(VersionInfo.VanillaName, VersionInfo.ModLoaderVersions)
OptiFineVersion = VersionInfo.OptiFine
IsVanillaVersionReliable = VersionInfo.Reliable
End If
Dim MinecraftVersion = Components.MinecraftVersion
If String.IsNullOrWhiteSpace(MinecraftVersion) Then Throw New Exception("无法确定当前 Minecraft 版本,请检查版本文件")
'等待子列表加载器完成获取
Dim LoaderList As New Dictionary(Of String, LoaderBase) From {
{"Minecraft", DlClientListLoader}, {"OptiFine", DlOptiFineListLoader}, {"LiteLoader", DlLiteLoaderListLoader},
{"NeoForge", DlNeoForgeListLoader}, {"Fabric", DlFabricListLoader}, {"Fabric API", DlFabricApiLoader}, {"OptiFabric", DlOptiFabricLoader}}
Dim ForgeLoader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = Nothing
If McVersion.IsStandardFormat(MinecraftVersion) Then
ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion " & MinecraftVersion, AddressOf DlForgeVersionMain)
LoaderList.Add("Forge", ForgeLoader)
End If
For Each Loader In LoaderList.Values
Loader.Start(If(Loader Is ForgeLoader, MinecraftVersion, Nothing), Task.IsForceRestarting)
Next
Do
If Task.IsCanceled Then Return
For Each Pair In LoaderList
Dim Loader = Pair.Value
If Loader.State = LoadState.Failed Then
If Loader Is ForgeLoader AndAlso Loader.Error.Message = "无" Then Continue For 'Forge 无版本时不报错
Throw New Exception($"获取 {Pair.Key} 版本列表失败,请稍后再试,或使用 VPN 改善网络环境", Loader.Error)
ElseIf Loader.State = LoadState.Canceled Then
Throw New Exception($"获取 {Pair.Key} 版本列表被中断,请稍后再试,或使用 VPN 改善网络环境")
End If
Next
If LoaderList.Values.All(Function(Loader) Loader.State = LoadState.Finished OrElse Loader.State = LoadState.Failed) Then Exit Do
Task.Progress = 0.7 * LoaderList.Values.Average(Function(Loader) Loader.Progress)
Thread.Sleep(10)
Loop
If Task.IsCanceled Then Return
Task.Progress = 0.7
'Minecraft
MinecraftVersions = CType(DlClientListLoader.Output.Value("versions").DeepClone(), JArray)
VanillaData = MinecraftVersions.OfType(Of JObject).FirstOrDefault(
Function(v) v("id").ToString.Replace("∞", "infinite") = MinecraftVersion.Replace("∞", "infinite"))
If VanillaData Is Nothing Then Throw New Exception($"Minecraft 列表中没有已安装的 {MinecraftVersion}")
VanillaData("id") = MinecraftVersion
'OptiFine
If Manifest IsNot Nothing Then
SelectedOptiFine = Components.OptiFineEntry?.ToObject(Of DlOptiFineListEntry)()
If SelectedOptiFine IsNot Nothing AndAlso Not DlOptiFineListLoader.Output.Value.Any(Function(v) v.FileName = SelectedOptiFine.FileName) Then
'如果 OptiFine 是 pre 版,可能只在 BMCLAPI 下有,官方源删了。如果是这种缺失数据的情况,换用 BMCLAPI 源作为输出
If DlOptiFineListBmclapiLoader.State <> LoadState.Finished Then DlOptiFineListBmclapiLoader.WaitForExit()
DlOptiFineListLoader.Output = DlOptiFineListBmclapiLoader.Output
End If
ElseIf OptiFineVersion IsNot Nothing AndAlso OptiFineVersion <> "未知版本" Then
SelectedOptiFine = DlOptiFineListLoader.Output.Value.FirstOrDefault(
Function(v) v.Inherit = MinecraftVersion AndAlso
v.InstanceName.AfterLast("-OptiFine_").Replace("HD_U_", "") = OptiFineVersion.Replace("HD_U_", ""))
If SelectedOptiFine Is Nothing Then Throw New Exception($"OptiFine 列表中没有已安装的 {OptiFineVersion}")
End If
'Forge
If Components.ModLoaderVersions.ContainsKey(ModLoaders.Forge) Then
SelectedForge = ForgeLoader?.Output?.FirstOrDefault(
Function(v) v.Inherit = MinecraftVersion AndAlso v.VersionName = Components.ModLoaderVersions(ModLoaders.Forge) AndAlso
v.Category <> "universal" AndAlso v.Category <> "client" AndAlso (SelectedOptiFine Is Nothing OrElse IsOptiFineSuitForForge(SelectedOptiFine, v)))
If SelectedForge Is Nothing Then Throw New Exception($"Forge 列表中没有已安装的 {Components.ModLoaderVersions(ModLoaders.Forge)}")
End If
'NeoForge
If Components.ModLoaderVersions.ContainsKey(ModLoaders.NeoForge) Then
SelectedNeoForge = DlNeoForgeListLoader.Output.Value.FirstOrDefault(
Function(v) v.Inherit = MinecraftVersion AndAlso v.VersionName = Components.ModLoaderVersions(ModLoaders.NeoForge))
If SelectedNeoForge Is Nothing Then Throw New Exception($"NeoForge 列表中没有已安装的 {Components.ModLoaderVersions(ModLoaders.NeoForge)}")
End If
'Fabric
If Components.ModLoaderVersions.ContainsKey(ModLoaders.Fabric) Then
Dim FabricEntry = DlFabricListLoader.Output.Value("loader").OfType(Of JObject).FirstOrDefault(
Function(v) v("version").ToString = Components.ModLoaderVersions(ModLoaders.Fabric),
Function(v) v("version").ToString.Replace("+build", "") = Components.ModLoaderVersions(ModLoaders.Fabric))
If FabricEntry Is Nothing OrElse Not DlFabricListLoader.Output.Value("game").OfType(Of JObject).
Any(Function(v) v("version").ToString = MinecraftVersion.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3")) Then
Throw New Exception($"Fabric 列表中没有已安装的 {Components.ModLoaderVersions(ModLoaders.Fabric)}")
End If
SelectedFabric = FabricEntry("version").ToString
End If
'LiteLoader
If Components.ModLoaderVersions.ContainsKey(ModLoaders.LiteLoader) Then
SelectedLiteLoader = DlLiteLoaderListLoader.Output.Value.FirstOrDefault(
Function(v) v.Inherit = MinecraftVersion AndAlso v.JsonToken("version").ToString = Components.ModLoaderVersions(ModLoaders.LiteLoader))
If SelectedLiteLoader Is Nothing Then Throw New Exception($"LiteLoader 列表中没有已安装的 {Components.ModLoaderVersions(ModLoaders.LiteLoader)}")
End If
'Fabric API
If Components.FabricApiVersion IsNot Nothing Then
SelectedFabricApi = DlFabricApiLoader.Output.FirstOrDefault(
Function(v) (v.Version = Components.FabricApiVersion OrElse v.Id = Components.FabricApiVersion OrElse
v.Display = Components.FabricApiVersion) AndAlso IsFabricApiCompatible(v, MinecraftVersion))
If SelectedFabricApi Is Nothing Then Throw New Exception($"Fabric API 列表中没有已安装的 {Components.FabricApiVersion}")
End If
'OptiFabric
If Components.OptiFabricVersion IsNot Nothing Then
SelectedOptiFabric = DlOptiFabricLoader.Output.FirstOrDefault(
Function(v) (v.Version = Components.OptiFabricVersion OrElse v.Id = Components.OptiFabricVersion OrElse
v.Display = Components.OptiFabricVersion) AndAlso IsOptiFabricCompatible(v, MinecraftVersion))
If SelectedOptiFabric Is Nothing Then Throw New Exception($"OptiFabric 列表中没有已安装的 {Components.OptiFabricVersion}")
End If
'扫描尚未识别的 Mod 组件
Dim ManagedFiles As New List(Of McInstallManifest.ManagedFile)
If Manifest IsNot Nothing Then ManagedFiles.AddRange(Manifest.ManagedFiles)
#Region "从 mods 文件夹中获取以 Mod 形式安装的组件信息"
'获取 mods 文件夹下的 jar 文件与 SHA1
Dim Mods As New Lazy(Of List(Of (File As FileInfo, Sha1 As String)))(
Function()
Dim ModsFolder = Task.Input.PathIndie & "mods\"
Dim Files = DirectoryUtils.EnumerateFiles(ModsFolder, searchPattern:="*.jar").ToList()
If SelectedLiteLoader IsNot Nothing Then 'LiteLoader 的 OptiFine 安装目录
Files.AddRange(DirectoryUtils.EnumerateFiles(Path.Combine(ModsFolder, MinecraftVersion), searchPattern:="*.jar"))
End If
Dim Entries As New List(Of (File As FileInfo, Sha1 As String))
For Each FilePath In Files
If Task.IsCanceled Then Return Entries
Dim File = FileUtils.GetInfo(FilePath)
Entries.Add((File, New LocalResourceFile(File).ModrinthHash))
Task.Progress = 0.7 + 0.28 * Entries.Count / Files.Count
Next
Return Entries
End Function)
'Fabric API
If SelectedFabric IsNot Nothing AndAlso SelectedFabricApi Is Nothing Then
Dim FabricApiList = DlFabricApiLoader.Output.Where(Function(v) IsFabricApiCompatible(v, MinecraftVersion)).ToList()
Dim Matches As New List(Of (File As FileInfo, Sha1 As String, Version As ResourceVersion))
For Each Entry In Mods.Value
Dim Match = FabricApiList.FirstOrDefault(Function(v) v.Hash = Entry.Sha1)
If Match Is Nothing Then Continue For
Matches.Add((Entry.File, Entry.Sha1, Match))
Next
Dim SelectedFile = SelectMod("Fabric API", Matches)
If SelectedFile IsNot Nothing Then
SelectedFabricApi = SelectedFile.Value.Version
ManagedFiles.Add(New McInstallManifest.ManagedFile("mods/" & SelectedFile.Value.File.Name.Lower(), SelectedFile.Value.Sha1, SelectedFile.Value.File.LastWriteTimeUtc, "FabricApi"))
End If
End If
If Task.IsCanceled Then Return
'OptiFabric
If SelectedFabric IsNot Nothing AndAlso SelectedOptiFabric Is Nothing Then
Dim OptiFabricList = DlOptiFabricLoader.Output.Where(Function(v) IsOptiFabricCompatible(v, MinecraftVersion)).ToList()
Dim HasMd5 = OptiFabricList.Any(Function(v) If(v.Hash, "").Length = 32) 'CurseForge 的 OptiFabric 信息可能提供 SHA1 或 MD5
Dim Matches As New List(Of (File As FileInfo, Sha1 As String, Version As ResourceVersion))
For Each Entry In Mods.Value
Dim Match = OptiFabricList.FirstOrDefault(Function(v) v.Hash = Entry.Sha1)
If Match Is Nothing AndAlso HasMd5 Then
Dim Md5 = CryptographyUtils.ComputeFileHash(Entry.File.FullName, CryptographyUtils.HashMethod.Md5)
Match = OptiFabricList.FirstOrDefault(Function(v) v.Hash = Md5)
End If
If Match Is Nothing Then Continue For
Matches.Add((Entry.File, Entry.Sha1, Match))
Next
Dim SelectedFile = SelectMod("OptiFabric", Matches)
If SelectedFile IsNot Nothing Then
SelectedOptiFabric = SelectedFile.Value.Version
ManagedFiles.Add(New McInstallManifest.ManagedFile("mods/" & SelectedFile.Value.File.Name.Lower(), SelectedFile.Value.Sha1, SelectedFile.Value.File.LastWriteTimeUtc, "OptiFabric"))
End If
End If
If Task.IsCanceled Then Return
'OptiFine
Dim OptiFineFiles As New List(Of (File As FileInfo, Sha1 As String, OriginalName As String))
If SelectedOptiFine Is Nothing AndAlso (SelectedForge IsNot Nothing OrElse SelectedLiteLoader IsNot Nothing OrElse SelectedFabric IsNot Nothing) Then 'OptiFine 只在有 Mod 加载器时才看在不在 mods 文件夹中
Static OptiFineHashes As JObject = FileUtils.ReadAsJson("Minecraft\OptiFineHashes.json", type:=GetType(Resource)) 'JSON 内容:{"SHA1": "原始文件名", ...}
OptiFineFiles = Mods.Value.
Select(Function(Entry) (Entry.File, Entry.Sha1, OriginalName:=OptiFineHashes(Entry.Sha1)?.ToString())). '用本地文件的 SHA1 匹配下载时的原始文件名,再根据原始文件名取得下载源信息
Where(Function(Entry) Entry.OriginalName IsNot Nothing).ToList()
Dim Matches As New List(Of (File As FileInfo, Sha1 As String, Version As DlOptiFineListEntry))
For Each Entry In OptiFineFiles '遍历 hash 匹配到了的本地文件
Dim Match = DlOptiFineListLoader.Output.Value.FirstOrDefault(
Function(v) v.Inherit = MinecraftVersion AndAlso v.FileName = Entry.OriginalName AndAlso (SelectedForge Is Nothing OrElse IsOptiFineSuitForForge(v, SelectedForge)))
If Match Is Nothing Then
Hint($"无法从 OptiFine 列表还原 {Entry.File.Name} 对应的 {Entry.OriginalName},将跳过该文件。")
Continue For
End If
Matches.Add((Entry.File, Entry.Sha1, Match))
Next
Dim SelectedFile = SelectMod("OptiFine", Matches)
If SelectedFile IsNot Nothing Then
SelectedOptiFine = SelectedFile.Value.Version
Dim RelativePath = PathUtils.RemoveExtendedPrefix(SelectedFile.Value.File.FullName).Substring(Task.Input.PathIndie.Length).Replace("\", "/").Lower()
ManagedFiles.Add(New McInstallManifest.ManagedFile(RelativePath, SelectedFile.Value.Sha1, SelectedFile.Value.File.LastWriteTimeUtc, "OptiFine"))
End If
End If
If Task.IsCanceled Then Return
#End Region
'保存 Manifest
If IsVanillaVersionReliable Then
Components = New McComponents(MinecraftVersion, Components.ModLoaderVersions,
If(SelectedOptiFine Is Nothing, Nothing, JObject.FromObject(SelectedOptiFine)),
If(SelectedFabricApi?.Version, If(SelectedFabricApi?.Id, SelectedFabricApi?.Display)),
If(SelectedOptiFabric?.Version, If(SelectedOptiFabric?.Id, SelectedOptiFabric?.Display)))
If Manifest Is Nothing OrElse Not Components.IsEquivalentTo(Manifest.Components) OrElse Not ManagedFiles.SequenceEqual(Manifest.ManagedFiles) Then
Configs.McInstallManifest.Set(New McInstallManifest(Versions.McInstallManifestVersion, Components, Date.UtcNow, ManagedFiles), Task.Input.Config)
Task.Input.Config.Save()
Logger.Info($"已为 {Task.Input.Name} 更新安装清单")
End If
End If
If Task.IsCanceled Then Return
ForgeVersionLoader = ForgeLoader
End Sub
Private Function SelectMod(Of T)(ComponentName As String, Matches As List(Of (File As FileInfo, Sha1 As String, Version As T))) As (File As FileInfo, Sha1 As String, Version As T)?
If Matches.Count = 0 Then Return Nothing
If Matches.Count = 1 Then Return Matches(0)
Dim Choice As Integer? = Nothing
RunInUiWait(Sub() Choice = MyMsgBoxSelect(Matches.Select(Function(Entry) CType(New MyRadioBox With {.Text = Entry.File.Name}, IMyRadio)), $"选择当前使用的 {ComponentName}"))
If Not Choice.HasValue Then Throw New Exception($"发现了多个 {ComponentName}")
Return Matches(Choice.Value)
End Function
''' <summary>
''' 初始化修改页
''' </summary>
Private Sub LoadInstanceFinished(Task As LoaderTask(Of McInstance, Object))
'还原原版信息
OriginalName = Task.Input.Name
CustomLogo = Nothing
If ReadIni(Task.Input.PathVersion & "PCL\Setup.ini", "LogoCustom", False) Then
CustomLogo = If(Task.Input.Logo.EndsWithF("PCL\Logo.png"), Task.Input.PathVersion & "PCL\Logo.png", Task.Input.Logo)
End If
Dim Item = McDownloadListItem(VanillaData, Nothing, False).Init()
VanillaName = Item.Title
VanillaIcon = Item.Logo
LabMinecraftVersion.Text = VanillaName
TextSelectName.Text = OriginalName
IsSelectNameEdited = Not String.Equals(OriginalName, GetSelectName(), StringComparison.Ordinal)
TextSelectName.ValidateRules = New ObjectModel.Collection(Of Validate) From {
New ValidateFolderName(McFolderSelected & "versions", IgnoreList:=New List(Of String) From {OriginalName})}
'修改页 UI
CardMinecraft.Visibility = Visibility.Visible
BtnBack.Visibility = Visibility.Collapsed
ImgLogo.Margin = New Thickness(15, 15, 0, 0)
TextSelectName.Margin = New Thickness(56, 16, 16, 0)
LabSelectName.Text = $"原名 :   {OriginalName}"
UpdateOriginalNameVisibility()
BtnStart.Text = "开始修改"
BtnStart.Logo = FrmInstanceLeft.ItemModify.Logo
AutoSelectedFabricApi = SelectedFabric IsNot Nothing
AutoSelectedOptiFabric = SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing
If ForgeVersionLoader IsNot Nothing Then LoadForge.State = ForgeVersionLoader
PrepareSelectPage()
ReloadComponentLists()
'进入动画
PanMinecraft.Visibility = Visibility.Collapsed
PanMinecraft.Opacity = 0
PanMinecraft.RenderTransform = New TranslateTransform(-50, 0)
PanSelect.Opacity = 1
PanSelect.RenderTransform = New TranslateTransform
PanBack.IsHitTestVisible = True
PanAllBack.IsHitTestVisible = True
InitialTarget = GetSelectedComponents()
'设置原始数据
BtnMinecraftRestore.Tag = VanillaData
BtnOptiFineRestore.Tag = SelectedOptiFine
BtnForgeRestore.Tag = SelectedForge
BtnNeoForgeRestore.Tag = SelectedNeoForge
BtnFabricRestore.Tag = SelectedFabric
BtnFabricApiRestore.Tag = SelectedFabricApi
BtnOptiFabricRestore.Tag = SelectedOptiFabric
BtnLiteLoaderRestore.Tag = SelectedLiteLoader
ImgMinecraftOld.Source = VanillaIcon
LabMinecraftOld.Text = LabMinecraftVersion.Text
LabOptiFineOld.Text = If(SelectedOptiFine Is Nothing, "无", LabOptiFine.Text)
LabForgeOld.Text = If(SelectedForge Is Nothing, "无", LabForge.Text)
LabNeoForgeOld.Text = If(SelectedNeoForge Is Nothing, "无", LabNeoForge.Text)
LabFabricOld.Text = If(SelectedFabric Is Nothing, "无", LabFabric.Text)
LabLiteLoaderOld.Text = If(SelectedLiteLoader Is Nothing, "无", LabLiteLoader.Text)
LabFabricApiOld.Text = If(SelectedFabricApi Is Nothing, "无", LabFabricApi.Text)
LabOptiFabricOld.Text = If(SelectedOptiFabric Is Nothing, "无", LabOptiFabric.Text)
RefreshComparisons()
End Sub
Public Overrides Function GetSelectLogo() As String
Return If(CustomLogo, MyBase.GetSelectLogo())
End Function
Public Overrides Sub ShowMinecraftVersionList()
If IsInSelectPage Then
'把当前已选择的组件记录到 PendingComponents
Dim Components = GetSelectedComponents()
For Each Component In {
(Loader:=LoadOptiFine, Version:=Components.OptiFineVersion),
(Loader:=LoadFabricApi, Version:=Components.FabricApiVersion),
(Loader:=LoadOptiFabric, Version:=Components.OptiFabricVersion),
(Loader:=LoadForge, Version:=SelectedForge?.VersionName),
(Loader:=LoadNeoForge, Version:=SelectedNeoForge?.VersionName),
(Loader:=LoadFabric, Version:=SelectedFabric),
(Loader:=LoadLiteLoader, Version:=SelectedLiteLoader?.JsonToken?("version").ToString())}
'保留尚未加载完成的组件选择
If Component.Version IsNot Nothing Then PendingComponents(Component.Loader) = Component.Version
Next
End If
MyBase.ShowMinecraftVersionList()
End Sub
Public Overrides Sub ReloadSelected()
If IsRestoringComponents Then Return
If IsInSelectPage AndAlso VanillaName IsNot Nothing AndAlso PendingComponents.Any() Then
IsRestoringComponents = True
Try
Dim HasProcessed As Boolean = False
'优先恢复 Mod 加载器,再匹配兼容的附加组件
For Each LoadingComponent In {LoadFabric, LoadForge, LoadNeoForge, LoadLiteLoader, LoadOptiFine, LoadFabricApi, LoadOptiFabric}
Dim Version As String = Nothing
If Not PendingComponents.TryGetValue(LoadingComponent, Version) Then Continue For
If Not LoadingComponent.State.IsLoader Then Continue For
Dim Loader = DirectCast(LoadingComponent.State, LoaderBase)
'检查前置组件
If LoadingComponent Is LoadOptiFine Then
If {LoadFabric, LoadForge, LoadNeoForge, LoadLiteLoader}.Any(Function(Component) PendingComponents.ContainsKey(Component)) Then Continue For
ElseIf LoadingComponent Is LoadFabricApi Then
If PendingComponents.ContainsKey(LoadFabric) Then Continue For
ElseIf LoadingComponent Is LoadForge Then
If Not McVersion.IsStandardFormat(VanillaName) Then
PendingComponents.Remove(LoadingComponent)
Continue For
End If
If DirectCast(Loader, LoaderTask(Of String, List(Of DlForgeVersionEntry))).Input <> VanillaName Then Continue For
If Loader.State = LoadState.Failed AndAlso Loader.Error.Message = "无" Then
PendingComponents.Remove(LoadingComponent)
Continue For
End If
ElseIf LoadingComponent Is LoadOptiFabric Then
If PendingComponents.ContainsKey(LoadFabric) OrElse PendingComponents.ContainsKey(LoadOptiFine) Then Continue For
End If
If Loader.State <> LoadState.Finished Then Continue For
'移除已处理的组件
PendingComponents.Remove(LoadingComponent)
HasProcessed = True
'匹配目标 MC 版本下兼容的组件
If LoadingComponent Is LoadFabric Then
If SelectedFabric Is Nothing AndAlso LoadFabricGetError() Is Nothing Then
Dim Versions = DlFabricListLoader.Output.Value("loader").OfType(Of JObject)
SelectedFabric = If(Versions.FirstOrDefault(Function(v) v("version").ToString = Version), Versions.FirstOrDefault())?("version").ToString()
End If
ElseIf LoadingComponent Is LoadOptiFine Then
If SelectedOptiFine Is Nothing AndAlso LoadOptiFineGetError() Is Nothing Then
Dim Versions = DlOptiFineListLoader.Output.Value.Where(Function(v) v.Inherit = VanillaName AndAlso
(SelectedForge Is Nothing OrElse IsOptiFineSuitForForge(v, SelectedForge)))
SelectedOptiFine = If(Versions.FirstOrDefault(Function(v) v.InstanceName.AfterLast("-OptiFine_") = Version),
Versions.OrderBy(Function(v) v.IsPreview).
ThenByDescending(Function(v) v.DisplayName, Comparer(Of String).Create(AddressOf McUtils.CompareVersion)).FirstOrDefault())
End If
ElseIf LoadingComponent Is LoadForge Then
If SelectedForge Is Nothing AndAlso LoadForgeGetError() Is Nothing Then
Dim Versions = DirectCast(Loader, LoaderTask(Of String, List(Of DlForgeVersionEntry))).Output.Where(
Function(v) v.Inherit = VanillaName AndAlso
v.Category <> "universal" AndAlso v.Category <> "client" AndAlso
(SelectedOptiFine Is Nothing OrElse IsOptiFineSuitForForge(SelectedOptiFine, v)))
SelectedForge = If(Versions.FirstOrDefault(Function(v) v.VersionName = Version), Versions.OrderByDescending(Function(v) v).FirstOrDefault())
End If
ElseIf LoadingComponent Is LoadNeoForge Then
If SelectedNeoForge Is Nothing AndAlso LoadNeoForgeGetError() Is Nothing Then
Dim Versions = DlNeoForgeListLoader.Output.Value.Where(Function(v) v.Inherit = VanillaName)
SelectedNeoForge = If(Versions.FirstOrDefault(Function(v) v.VersionName = Version), Versions.FirstOrDefault())
End If
ElseIf LoadingComponent Is LoadLiteLoader Then
If SelectedLiteLoader Is Nothing AndAlso LoadLiteLoaderGetError() Is Nothing Then
Dim Versions = DlLiteLoaderListLoader.Output.Value.Where(Function(v) v.Inherit = VanillaName)
SelectedLiteLoader = If(Versions.FirstOrDefault(Function(v) v.JsonToken("version").ToString = Version), Versions.FirstOrDefault())
End If
ElseIf LoadingComponent Is LoadFabricApi Then
If SelectedFabricApi Is Nothing AndAlso LoadFabricApiGetError() Is Nothing Then
Dim Versions = DlFabricApiLoader.Output.Where(Function(v) IsFabricApiCompatible(v, VanillaName))
SelectedFabricApi = If(Versions.FirstOrDefault(Function(v) v.Version = Version OrElse v.Id = Version OrElse v.Display = Version),
Versions.OrderByDescending(Function(v) v.ReleaseDate).FirstOrDefault())
End If
If SelectedFabricApi IsNot Nothing Then AutoSelectedFabricApi = True
ElseIf LoadingComponent Is LoadOptiFabric Then
If SelectedOptiFabric Is Nothing AndAlso LoadOptiFabricGetError() Is Nothing Then
Dim Versions = DlOptiFabricLoader.Output.Where(Function(v) IsOptiFabricCompatible(v, VanillaName))
SelectedOptiFabric = If(Versions.FirstOrDefault(Function(v) v.Version = Version OrElse v.Id = Version OrElse v.Display = Version),
Versions.OrderByDescending(Function(v) v.ReleaseDate).FirstOrDefault())
End If
If SelectedOptiFabric IsNot Nothing Then AutoSelectedOptiFabric = True
End If
Next
'更新组件列表
If HasProcessed Then ReloadComponentLists()
Finally
IsRestoringComponents = False
End Try
End If
'刷新当前选择与原始版本的对比
MyBase.ReloadSelected()
If InitialTarget IsNot Nothing Then RefreshComparisons()
End Sub
Private Sub RefreshComparisons()
Dim Current = GetSelectedComponents()
ImgMinecraftNew.Source = VanillaIcon
'Minecraft
Dim IsMinecraftUnchanged = InitialTarget.MinecraftVersion = Current.MinecraftVersion
ShowComparison(PanMinecraftCompare, PanMinecraftInfo, InitialTarget.MinecraftVersion, Current.MinecraftVersion,
LabMinecraftVersion.Text, BtnMinecraftRestore, True)
'OptiFine
Dim OriginalOptiFine = TryCast(BtnOptiFineRestore.Tag, DlOptiFineListEntry)
ShowComparison(PanOptiFineCompare, PanOptiFineInfo, InitialTarget.OptiFineVersion, Current.OptiFineVersion,
LabOptiFine.Text, BtnOptiFineRestore, InitialTarget.OptiFineEntry Is Nothing OrElse
IsMinecraftUnchanged AndAlso CardOptiFine.MainSwap.Visibility = Visibility.Visible AndAlso OriginalOptiFine IsNot Nothing AndAlso
(SelectedForge Is Nothing OrElse IsOptiFineSuitForForge(OriginalOptiFine, SelectedForge)), BtnOptiFineClear)
'Fabric API
ShowComparison(PanFabricApiCompare, PanFabricApiInfo, InitialTarget.FabricApiVersion, Current.FabricApiVersion,
LabFabricApi.Text, BtnFabricApiRestore, InitialTarget.FabricApiVersion Is Nothing OrElse
IsMinecraftUnchanged AndAlso SelectedFabric IsNot Nothing AndAlso CardFabricApi.MainSwap.Visibility = Visibility.Visible, BtnFabricApiClear)
'OptiFabric
ShowComparison(PanOptiFabricCompare, PanOptiFabricInfo, InitialTarget.OptiFabricVersion, Current.OptiFabricVersion,
LabOptiFabric.Text, BtnOptiFabricRestore, InitialTarget.OptiFabricVersion Is Nothing OrElse
IsMinecraftUnchanged AndAlso SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso CardOptiFabric.MainSwap.Visibility = Visibility.Visible, BtnOptiFabricClear)
'Mod Loader
For Each Loader In {
(Kind:=ModLoaders.Forge, Card:=CardForge, ComparePanel:=PanForgeCompare, CurrentPanel:=PanForgeInfo, Label:=LabForge, RestoreButton:=BtnForgeRestore, ClearButton:=BtnForgeClear),
(Kind:=ModLoaders.NeoForge, Card:=CardNeoForge, ComparePanel:=PanNeoForgeCompare, CurrentPanel:=PanNeoForgeInfo, Label:=LabNeoForge, RestoreButton:=BtnNeoForgeRestore, ClearButton:=BtnNeoForgeClear),
(Kind:=ModLoaders.Fabric, Card:=CardFabric, ComparePanel:=PanFabricCompare, CurrentPanel:=PanFabricInfo, Label:=LabFabric, RestoreButton:=BtnFabricRestore, ClearButton:=BtnFabricClear),
(Kind:=ModLoaders.LiteLoader, Card:=CardLiteLoader, ComparePanel:=PanLiteLoaderCompare, CurrentPanel:=PanLiteLoaderInfo, Label:=LabLiteLoader, RestoreButton:=BtnLiteLoaderRestore, ClearButton:=BtnLiteLoaderClear)}
Dim OldVersion As String = Nothing, NewVersion As String = Nothing
InitialTarget.ModLoaderVersions.TryGetValue(Loader.Kind, OldVersion)
Current.ModLoaderVersions.TryGetValue(Loader.Kind, NewVersion)
Dim CanRestore = OldVersion Is Nothing OrElse IsMinecraftUnchanged AndAlso
Loader.Card.MainSwap.Visibility = Visibility.Visible AndAlso Loader.RestoreButton.Tag IsNot Nothing
If Loader.Kind = ModLoaders.Forge AndAlso OldVersion IsNot Nothing AndAlso CanRestore Then
CanRestore = SelectedOptiFine Is Nothing OrElse IsOptiFineSuitForForge(SelectedOptiFine, DirectCast(Loader.RestoreButton.Tag, DlForgeVersionEntry))
End If
If Loader.Kind = ModLoaders.Fabric AndAlso OldVersion IsNot Nothing Then
Dim TargetVersion = VanillaName.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3")
CanRestore = CardFabric.Visibility = Visibility.Visible AndAlso CardFabric.MainSwap.Visibility = Visibility.Visible AndAlso
DlFabricListLoader.Output.Value("loader").OfType(Of JObject).Any(Function(v) v("version").ToString = OldVersion) AndAlso
DlFabricListLoader.Output.Value("game").OfType(Of JObject).Any(Function(v) v("version").ToString = TargetVersion)
End If
ShowComparison(Loader.ComparePanel, Loader.CurrentPanel, OldVersion, NewVersion, Loader.Label.Text,
Loader.RestoreButton, CanRestore, Loader.ClearButton)
Next
UpdateStartButton()
End Sub
Private Sub ShowComparison(ComparePanel As Grid, CurrentPanel As FrameworkElement, OldVersion As String, NewVersion As String, NewText As String,
RestoreButton As MyIconButton, CanRestore As Boolean, Optional ClearButton As FrameworkElement = Nothing)
'获取不可安装的原因
Dim UnavailableReason As String = Nothing
If NewVersion Is Nothing Then
If RestoreButton Is BtnOptiFineRestore Then
UnavailableReason = LoadOptiFineGetError()
ElseIf RestoreButton Is BtnForgeRestore Then
UnavailableReason = If(McVersion.IsStandardFormat(VanillaName), LoadForgeGetError(), "无")
ElseIf RestoreButton Is BtnNeoForgeRestore Then
UnavailableReason = If(CardNeoForge.Visibility = Visibility.Collapsed, "无", LoadNeoForgeGetError())
ElseIf RestoreButton Is BtnFabricRestore Then
UnavailableReason = If(CardFabric.Visibility = Visibility.Collapsed, "无", LoadFabricGetError())
ElseIf RestoreButton Is BtnLiteLoaderRestore Then
UnavailableReason = If(CardLiteLoader.Visibility = Visibility.Collapsed, "无", LoadLiteLoaderGetError())
ElseIf RestoreButton Is BtnFabricApiRestore Then
UnavailableReason = LoadFabricApiGetError()
ElseIf RestoreButton Is BtnOptiFabricRestore Then
UnavailableReason = LoadOptiFabricGetError()
End If
NewText = If(UnavailableReason, "可以添加")
End If
'修改对比
Dim IsPending = NewVersion Is Nothing AndAlso (NewText = "获取中……" OrElse NewText.StartsWithF("获取失败:"))
Dim IsChanged = OldVersion <> NewVersion AndAlso Not IsPending
CanRestore = IsChanged AndAlso OldVersion IsNot Nothing AndAlso CanRestore
ComparePanel.Visibility = If(IsChanged, Visibility.Visible, Visibility.Collapsed)
CurrentPanel.Visibility = If(IsChanged, Visibility.Collapsed, Visibility.Visible)
'还原与取消安装按钮
RestoreButton.Visibility = If(CanRestore, Visibility.Visible, Visibility.Collapsed)
If ClearButton IsNot Nothing Then ClearButton.ToolTip = If(OldVersion Is Nothing, "取消安装", "移除")
Dim HasClearButton = ClearButton IsNot Nothing AndAlso ClearButton.Visibility = Visibility.Visible
RestoreButton.Margin = New Thickness(0, 5, If(CanRestore AndAlso HasClearButton, 60, 32), 0)
ComparePanel.Margin = New Thickness(ComparePanel.Margin.Left, ComparePanel.Margin.Top,
If(CanRestore AndAlso HasClearButton, 110, 80), ComparePanel.Margin.Bottom)
If Not IsChanged Then Return
'显示修改前已安装组件的对比卡片
If OldVersion IsNot Nothing Then
Dim Card = CType(ComparePanel.Parent, MyCard)
If Card.Visibility = Visibility.Collapsed Then
Card.IsSwapped = True
If Card.MainSwap IsNot Nothing Then Card.MainSwap.Visibility = Visibility.Collapsed
Card.Visibility = Visibility.Visible
End If
End If
Dim OldSide = CType(ComparePanel.Children(0), DockPanel)
Dim NewSide = CType(ComparePanel.Children(2), DockPanel)
OldSide.Children(0).Visibility = If(OldVersion Is Nothing, Visibility.Collapsed, Visibility.Visible)
CType(OldSide.Children(1), TextBlock).Margin = If(OldVersion Is Nothing, New Thickness(0), New Thickness(7, 0, 0, 0))
NewSide.Children(0).Visibility = If(NewVersion Is Nothing, Visibility.Collapsed, Visibility.Visible)
Dim NewLabel = CType(NewSide.Children(1), TextBlock)
NewLabel.Margin = If(NewVersion Is Nothing, New Thickness(0), New Thickness(7, 0, 0, 0))
NewLabel.Text = If(NewVersion Is Nothing, "移除", NewText)
If NewVersion Is Nothing AndAlso UnavailableReason IsNot Nothing Then
NewLabel.Inlines.Add(New Run($"({If(UnavailableReason = "无", "无可用版本", UnavailableReason)})") With {.Foreground = ColorGray4})
End If
End Sub
Private Sub RestoreComponent(sender As Object, e As EventArgs) Handles BtnMinecraftRestore.Click, BtnOptiFineRestore.Click, BtnForgeRestore.Click,
BtnNeoForgeRestore.Click, BtnFabricRestore.Click, BtnFabricApiRestore.Click, BtnOptiFabricRestore.Click, BtnLiteLoaderRestore.Click
Dim Button = DirectCast(sender, MyIconButton)
'恢复初始选择
If Button Is BtnMinecraftRestore Then
IsRestoringComponents = True
Try
PendingComponents.Clear()
MinecraftSelected(McDownloadListItem(DirectCast(Button.Tag, JObject), Nothing, False).Init(), Nothing)
If ForgeVersionLoader IsNot Nothing Then LoadForge.State = ForgeVersionLoader
'恢复初始的组件
SelectedOptiFine = TryCast(BtnOptiFineRestore.Tag, DlOptiFineListEntry)
SelectedForge = TryCast(BtnForgeRestore.Tag, DlForgeVersionEntry)
SelectedNeoForge = TryCast(BtnNeoForgeRestore.Tag, DlNeoForgeListEntry)
SelectedFabric = TryCast(BtnFabricRestore.Tag, String)
SelectedLiteLoader = TryCast(BtnLiteLoaderRestore.Tag, DlLiteLoaderListEntry)
SelectedFabricApi = TryCast(BtnFabricApiRestore.Tag, ResourceVersion)
SelectedOptiFabric = TryCast(BtnOptiFabricRestore.Tag, ResourceVersion)
AutoSelectedFabricApi = SelectedFabric IsNot Nothing
AutoSelectedOptiFabric = SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing
Finally
IsRestoringComponents = False
End Try
ReloadComponentLists()
Return
ElseIf Button Is BtnOptiFineRestore Then
SelectedOptiFine = TryCast(Button.Tag, DlOptiFineListEntry)
AutoSelectedOptiFabric = SelectedOptiFine IsNot Nothing AndAlso SelectedFabric IsNot Nothing
If SelectedOptiFine Is Nothing Then SelectedOptiFabric = Nothing
ElseIf Button Is BtnForgeRestore Then
SelectedForge = TryCast(Button.Tag, DlForgeVersionEntry)
ElseIf Button Is BtnNeoForgeRestore Then
SelectedNeoForge = TryCast(Button.Tag, DlNeoForgeListEntry)
ElseIf Button Is BtnFabricRestore Then
SelectedFabric = TryCast(Button.Tag, String)
AutoSelectedFabricApi = SelectedFabric IsNot Nothing
AutoSelectedOptiFabric = SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing
If SelectedFabric Is Nothing Then
SelectedFabricApi = Nothing
SelectedOptiFabric = Nothing
End If
ElseIf Button Is BtnFabricApiRestore Then
SelectedFabricApi = TryCast(Button.Tag, ResourceVersion)
AutoSelectedFabricApi = True
ElseIf Button Is BtnOptiFabricRestore Then
SelectedOptiFabric = TryCast(Button.Tag, ResourceVersion)
AutoSelectedOptiFabric = True
ElseIf Button Is BtnLiteLoaderRestore Then
SelectedLiteLoader = TryCast(Button.Tag, DlLiteLoaderListEntry)
End If
DirectCast(Button.Parent, MyCard).IsSwapped = True
'刷新组件
ReloadComponentLists()
End Sub
Private Sub CardMinecraft_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles CardMinecraft.MouseLeftButtonUp
ShowMinecraftVersionList()
e.Handled = True
End Sub
Private Sub UpdateStartButton() Handles TextSelectName.TextChanged, TextSelectName.ValidateChanged
BtnStart.IsEnabled = TextSelectName.IsValidated AndAlso InitialTarget IsNot Nothing AndAlso
Not PendingComponents.Any() AndAlso
(Not IsVanillaVersionReliable OrElse Not InitialTarget.IsEquivalentTo(GetSelectedComponents()) OrElse
Not String.Equals(TextSelectName.Text, OriginalName, StringComparison.Ordinal))
End Sub
Private Sub UpdateOriginalNameVisibility() Handles TextSelectName.TextChanged
Dim IsNameChanged = Not String.Equals(TextSelectName.Text, OriginalName, StringComparison.Ordinal)
Dim NewVisibility = If(IsNameChanged, Visibility.Visible, Visibility.Collapsed)
If LabSelectName.Visibility = NewVisibility Then Return
LabSelectName.Visibility = NewVisibility
BtnOriginalNameRestore.Visibility = NewVisibility
Dim RightMargin = If(IsNameChanged, 40, 16)
If IsInSelectPage AndAlso AniControlEnabled = 0 Then
AniStart(AaDouble(Sub(Delta) TextSelectName.Margin = New Thickness(56, 16, TextSelectName.Margin.Right + Delta, 0),
RightMargin - TextSelectName.Margin.Right, 150,, New AniEaseOutFluent), "DownloadModify Name Margin")
Else
AniStop("DownloadModify Name Margin")
TextSelectName.Margin = New Thickness(56, 16, RightMargin, 0)
End If
End Sub
Private Sub BtnOriginalNameRestore_Click(sender As Object, e As EventArgs) Handles BtnOriginalNameRestore.Click
TextSelectName.Text = OriginalName
IsSelectNameEdited = Not String.Equals(OriginalName, GetSelectName(), StringComparison.Ordinal)
End Sub
Public Overrides Sub StartInstall(Request As McInstallRequest)
UpdateStartButton()
If Not BtnStart.IsEnabled Then Return
Dim TargetInstance = InitLoader.Input
Dim Target = Request.Components
Dim InstanceName = Request.NewInstanceName
Dim IsNameChanged = Not String.Equals(InstanceName, TargetInstance.Name, StringComparison.Ordinal)
Request.NewInstanceName = If(IsNameChanged, InstanceName, Nothing)
Request.InstanceFolder = TargetInstance.PathVersion
'警告
Dim Warnings As New List(Of String)
If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
Not PathUtils.IsSame(TargetInstance.PathIndie, TargetInstance.PathVersion) Then
Warnings.Add("该版本尚未开启版本隔离,可能与别的 MC 版本共用同一个 Mod 和存档文件夹。" & vbCrLf &
"修改版本后,已有的 Mod、存档等需要手动迁移到新的游戏目录。")
End If
Dim IsMinecraftVersionChanged = InitialTarget.MinecraftVersion <> Target.MinecraftVersion
If Not IsVanillaVersionReliable AndAlso Not IsMinecraftVersionChanged Then
Warnings.Add($"PCL 未能精准识别该版本,请确认它是不是 Minecraft {InitialTarget.MinecraftVersion},如果不正确,请取消并选择正确的版本!")
End If
If Not Configs.HintModifyInstanceWarning.Get() Then
Warnings.Add("如果该版本安装了 PCL 不兼容的加载器,或经过第三方修改,这些改动将会丢失!")
End If
Dim IsModLoaderChanged As Boolean = False
For Each Loader In InitialTarget.ModLoaderVersions.Keys.Union(Target.ModLoaderVersions.Keys)
Dim CurrentVersion As String = Nothing, TargetVersion As String = Nothing
Dim HasCurrent = InitialTarget.ModLoaderVersions.TryGetValue(Loader, CurrentVersion)
Dim HasTarget = Target.ModLoaderVersions.TryGetValue(Loader, TargetVersion)
If HasCurrent <> HasTarget OrElse CurrentVersion <> TargetVersion Then
IsModLoaderChanged = True
Exit For
End If
Next
If (IsModLoaderChanged OrElse IsMinecraftVersionChanged) AndAlso InitialTarget.ModLoaderVersions.Any Then
Warnings.Add("现有的 Mod、资源包等在修改后可能会不兼容!")
End If
If Warnings.Any() Then
If MyMsgBox("请注意:" & vbCrLf & "• " & Warnings.Join(vbCrLf & "• "), "修改确认", "开始修改", "取消", IsWarn:=True) <> 1 Then Return
End If
If Not Configs.HintModifyInstanceWarning.Get() Then Configs.HintModifyInstanceWarning.Set(True)
'开始修改
If IsVanillaVersionReliable AndAlso InitialTarget.IsEquivalentTo(Target) Then
'仅重命名
Try
Dim OldPath = TargetInstance.PathVersion
Dim RenamedInstance = TargetInstance.Rename(InstanceName)
If PageInstanceLeft.Instance IsNot Nothing AndAlso PathUtils.IsSame(PageInstanceLeft.Instance.PathVersion, OldPath) Then PageInstanceLeft.Instance = RenamedInstance
If McInstanceSelected IsNot Nothing AndAlso PathUtils.IsSame(McInstanceSelected.PathVersion, OldPath) Then McInstanceSelected = RenamedInstance
PageInstanceLeft.ReloadCurrentJava()
Hint("重命名成功!", HintType.Green)
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
FrmMain.PageBack()
Catch ex As Exception
Logger.Error(ex, "重命名版本失败", LogBehavior.Alert)
End Try
Else
'实际修改
If McModificationStart(Request, TargetInstance) Then FrmMain.PageBack()
End If
End Sub
End Class
@@ -64,10 +64,10 @@ Public Class PageDownloadResourceDetail
If IsXSpecial Then Return 1
If IsYSpecial Then Return -1
'比较版本号
Dim VersionCodeSort = -CompareVersion(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", ""))
Dim VersionCodeSort = -McUtils.CompareVersion(x.Replace(x.BeforeFirst(" ") & " ", ""), y.Replace(y.BeforeFirst(" ") & " ", ""))
If VersionCodeSort <> 0 Then Return VersionCodeSort
'比较全部
Return -CompareVersion(x, y)
Return -McUtils.CompareVersion(x, y)
End Function
Public Sub New(Optional Topmost As String = "")
Me.Topmost = If(Topmost, "")
@@ -98,7 +98,7 @@ Public Class PageDownloadResourceDetail
Dim UpdateFilters =
Sub()
Filters = Results.SelectMany(Function(v) v.GameVersions).Select(Function(v) GetGroupedVersionName(v, GroupedDrop, GroupedOld)).
Distinct.OrderByDescending(Function(s) s, New VersionComparer).ToList
Distinct.OrderByDescending(Function(s) s, Comparer(Of String).Create(Function(x, y) McUtils.CompareVersion(x, y))).ToList
End Sub
'确定分组方式
@@ -174,7 +174,7 @@ GroupDone:
Dim Loaders As New List(Of String)
If Project.ModLoaders.Flags.Count > 1 AndAlso '工程至少有两个加载器
Version.ResourceType = ResourceTypes.Mod AndAlso '是 Mod
McVersion.IsFormatFit(VerName) Then '不是 “快照版本” 之类的
McVersion.IsStandardFormat(VerName) Then '不是 “快照版本” 之类的
Loaders.AddRange(Version.ModLoaders.Flags.Select(Function(f) f.ToString & " "))
End If
If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里
@@ -206,16 +206,17 @@ GroupDone:
If Not Pair.Value.Any() Then Continue For
If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For
'增加卡片
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(TargetResourceType = ResourceTypes.ModPack, 9, 8)} '9 是安装,8 是另存为
Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15)}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
NewCard.Children.Add(NewStack)
NewCard.SwapControl = NewStack
NewCard.SetContentBuilder(AddressOf InitializeStackResourceVersions)
PanResults.Children.Add(NewCard)
'确定卡片是否默认展开
If Pair.Key = TargetCardName OrElse
(FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761
CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then
MyCard.StackInstall(NewStack, If(TargetResourceType = ResourceTypes.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为
NewCard.BuildContent()
Else
NewCard.IsSwapped = True
End If
@@ -240,13 +241,53 @@ GroupDone:
Logger.Error(ex, "可视化工程下载列表出错")
End Try
End Sub
''' <summary>
''' 根据卡片中的 StackPanel.Tag 将资源版本列表数据实例化为 UI。
''' </summary>
Private Sub InitializeStackResourceVersions(Stack As StackPanel)
Dim Versions = CType(Stack.Tag, List(Of ResourceVersion)).SortByComparison(Function(a, b) a.ReleaseDate > b.ReleaseDate)
Dim HasDuplicates = Versions.DistinctBy(Function(a) a.Display).Count <> Versions.Count
Dim Dependences As List(Of String)
'获取并添加前置信息
If TargetResourceType = ResourceTypes.ModPack Then
Dependences = New List(Of String) '整合包的前置信息会显示其中包含的一大堆 Mod,不是真正意义的前置
Else
Dependences = Versions.SelectMany(Function(f) f.Dependencies).Distinct.Ordered.ToList()
End If
If Dependences.Any() Then
Dependences = Dependences.Where(
Function(d)
If Not ResourceProject.Cache.ContainsKey(d) Then Logger.Warn($"未找到 ID {d} 的前置信息")
Return ResourceProject.Cache.ContainsKey(d)
End Function).ToList
'添加开头间隔
Stack.Children.Add(New TextBlock With {.Text = "前置资源", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 2, 0, 5)})
'添加前置列表
For Each Dep In Dependences
Dim Item = ResourceProject.Cache(Dep).ToResourceItem(False, False)
Stack.Children.Add(Item)
Next
'添加结尾间隔
Stack.Children.Add(New TextBlock With {.Text = "版本列表", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 12, 0, 5)})
End If
'实例化每个元素
For Each Version In Versions
If TargetResourceType = ResourceTypes.ModPack Then
Stack.Children.Add(Version.ToListItem(AddressOf Install_Click, AddressOf Save_Click, IsBadDisplay:=HasDuplicates))
Else
Stack.Children.Add(Version.ToListItem(AddressOf Save_Click, IsBadDisplay:=HasDuplicates))
End If
Next
Stack.Children.Add(New FrameworkElement With {.Height = 18})
Stack.Tag = Nothing
End Sub
Private Function GetGroupedVersionName(Name As String, GroupedByDrop As Boolean, FoldOld As Boolean) As String
Dim Drop = McVersion.VersionToDrop(Name)
If Name Is Nothing Then
Return "其他"
ElseIf Name.Contains("w") OrElse Drop = 209 Then
Return "快照版"
ElseIf Not McVersion.IsFormatFit(Name) OrElse (FoldOld AndAlso Drop < 120) Then
ElseIf Not McVersion.IsStandardFormat(Name) OrElse (FoldOld AndAlso Drop < 120) Then
Return "远古版"
ElseIf GroupedByDrop Then
Return McVersion.DropToVersion(Drop)
@@ -469,19 +510,23 @@ GroupDone:
'弹窗要求选择保存位置
Dim Target As String
Dim Ext As String = If(File.ResourceType = ResourceTypes.Mod,
If(File.FileName.EndsWithF(".litemod"), "litemod", "jar"),
If(File.FileName.EndsWithF(".mrpack"), "mrpack", "zip"))
If(PathUtils.GetExtension(File.FileName) = "litemod", "litemod", "jar"),
If(PathUtils.GetExtension(File.FileName) = "mrpack", "mrpack", "zip"))
Target = Dialogs.SaveFile("选择保存位置", FileName, DefaultFolder, {(Ext, Desc & "文件")})
If Target Is Nothing Then Return
'构造步骤加载器
Dim LoaderName As String = Desc & "下载:" & PathUtils.GetFileNameWithoutExtension(Target) & " "
If Target <> DefaultFolder Then CachedFolder(File.ResourceType) = PathUtils.RemoveLastPart(Target)
If Not PathUtils.IsSame(PathUtils.RemoveLastPart(Target), DefaultFolder) Then CachedFolder(File.ResourceType) = PathUtils.RemoveLastPart(Target)
Dim Loaders As New List(Of LoaderBase)
Loaders.Add(New LoaderDownload("下载文件", {
File.ToNetFile(Target, If(TargetResourceType = ResourceTypes.Any, ResourceVersion.DownloadReason.Dependency, ResourceVersion.DownloadReason.Standalone))
}) With {.ProgressWeight = 6, .Block = True})
'启动
Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged = AddressOf LoaderStateChangedHintOnly}
Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged =
Sub(MyLoader)
LoaderStateChangedHintOnly(MyLoader)
If MyLoader.State = LoadState.Finished AndAlso File.ResourceType = ResourceTypes.ModPack Then OpenExplorer(Target)
End Sub}
Loader.Start(1)
LoaderTaskbarAdd(Loader)
FrmMain.BtnExtraDownload.ShowRefresh()
@@ -510,29 +555,4 @@ GroupDone:
PageLoaderRestart(IsForceRestart:=True)
End Sub
''' <summary>
''' 预载包含大量 ProjectVersion 的卡片,添加必要的元素和前置列表。
''' </summary>
Public Shared Sub ResourceFilesCardPreload(Stack As StackPanel, Files As List(Of ResourceVersion))
'获取卡片对应的前置 ID
'如果为整合包就不会有 Dependencies 信息,所以不用管
Dim Deps As List(Of String) = Files.SelectMany(Function(f) f.Dependencies).Distinct.ToList()
Deps.Sort()
If Not Deps.Any() Then Return
Deps = Deps.Where(
Function(dep)
If Not ResourceProject.Cache.ContainsKey(dep) Then Logger.Warn($"未找到 ID {dep} 的前置信息")
Return ResourceProject.Cache.ContainsKey(dep)
End Function).ToList
'添加开头间隔
Stack.Children.Add(New TextBlock With {.Text = "前置资源", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 2, 0, 5)})
'添加前置列表
For Each Dep In Deps
Dim Item = ResourceProject.Cache(Dep).ToResourceItem(False, False)
Stack.Children.Add(Item)
Next
'添加结尾间隔
Stack.Children.Add(New TextBlock With {.Text = "版本列表", .FontSize = 14, .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 12, 0, 5)})
End Sub
End Class
@@ -90,11 +90,11 @@ Public Class PageResource
Next
Return ComboSearchLoader.Items(0)
End Function
If TargetInstance.Version.HasForge Then
If TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.Forge) Then
ComboSearchLoader.SelectedItem = GetTargetItemByName("Forge")
ElseIf TargetInstance.Version.HasFabric Then
ElseIf TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.Fabric) Then
ComboSearchLoader.SelectedItem = GetTargetItemByName("Fabric")
ElseIf TargetInstance.Version.HasNeoForge Then
ElseIf TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.NeoForge) Then
ComboSearchLoader.SelectedItem = GetTargetItemByName("NeoForge")
End If
TargetInstance = Nothing
@@ -335,7 +335,7 @@ Public Class MyLocalModItem
BtnUpdate.Visibility = Visibility.Collapsed
End If
'标题与描述
Dim DescFileName As String = Entry.File.Name.BeforeLast(".")
Dim DescFileName As String = PathUtils.GetFileNameWithoutExtension(Entry.EnabledName)
Dim NewDescription As String
If Settings.Get(Of Integer)("ToolModLocalNameStyle") = 1 Then
'标题显示文件名,详情显示译名
@@ -65,10 +65,10 @@
<local:MyCheckBox Margin="30,0,0,0">
<local:MyCheckBox.Tag>
<local:ExportOption
Title="OptiFine 设置"
Rules="optionsof.txt|optionsshaders.txt"
DefaultChecked="True"
RequireOptiFine="True" />
Title="OptiFine 设置"
Rules="optionsof.txt|optionsshaders.txt"
DefaultChecked="True"
RequireOptiFine="True" />
</local:MyCheckBox.Tag>
</local:MyCheckBox>
<local:MyCheckBox x:Name="CheckOptionsMod">
@@ -22,14 +22,14 @@ Public Class PageInstanceExport
End Sub
Private Sub PageInstanceExport_Loaded() Handles Me.Loaded
AniControlEnabled += 1
If CurrentInstance <> PageInstanceLeft.Instance.PathVersion Then RefreshAll() '切换到了另一个版本,重置页面
If Not PathUtils.IsSame(CurrentInstance, PageInstanceLeft.Instance.PathVersion) Then RefreshAll() '切换到了另一个版本,重置页面
CustomEventService.SetEventData(BtnAdvancedHelp,
If(BuildType = BuildTypes.Release, "指南/整合包制作 - Public.json", "指南/整合包制作 - Snapshot.json"))
AniControlEnabled -= 1
End Sub
Public Sub RefreshAll() Implements IRefreshable.Refresh
Logger.Info("刷新导出页面")
HintOptiFine.Visibility = If(PageInstanceLeft.Instance.Version.HasOptiFine, Visibility.Visible, Visibility.Collapsed)
HintOptiFine.Visibility = If(PageInstanceLeft.Instance.Version.HasOptiFine AndAlso Not PageInstanceLeft.Instance.Version.OptiFineAsMod, Visibility.Visible, Visibility.Collapsed)
CurrentInstance = PageInstanceLeft.Instance.PathVersion
TextExportName.Text = ""
TextExportName.HintText = PageInstanceLeft.Instance.Name
@@ -114,7 +114,7 @@ Public Class PageInstanceExport
'确认选项是否应该被显示
Dim IsVisible =
Function(TargetOption As ExportOption) As Boolean
'检查需要 OptiFine 或 Mod 加载器
'检查需要 OptiFine(例如光影)或 Mod 加载器(例如 mods/)
If TargetOption.RequireOptiFine AndAlso Not PageInstanceLeft.Instance.Version.HasOptiFine Then Return False
If TargetOption.RequireModLoader AndAlso Not PageInstanceLeft.Instance.Modable Then Return False
If TargetOption.RequireModLoaderOrOptiFine AndAlso Not PageInstanceLeft.Instance.Version.HasOptiFine AndAlso Not PageInstanceLeft.Instance.Modable Then Return False
@@ -257,9 +257,9 @@ Public Class PageInstanceExport
For Each ShaderPackCheckBox In PanOptionsShaderPacks.Children.OfType(Of MyCheckBox)()
If Not ShaderPackCheckBox.Checked Then Continue For
Dim ShaderPackOption = GetExportOption(ShaderPackCheckBox)
Dim SettingFileName = ShaderPackOption.Rules.TrimEnd("/") & ".txt"
If Not FileUtils.Exists(Path.Combine(PageInstanceLeft.Instance.PathIndie, SettingFileName)) Then Continue For
Rules.Add(StringUtils.LikePatternEscape($"shaderpacks/{SettingFileName}"))
Dim SettingsFile = $"shaderpacks/{ShaderPackOption.Title}.txt"
If Not FileUtils.Exists(Path.Combine(PageInstanceLeft.Instance.PathIndie, SettingsFile)) Then Continue For
Rules.Add(StringUtils.LikePatternEscape(SettingsFile))
Next
End If
@@ -457,11 +457,11 @@ Public Class PageInstanceExport
'缓存所需参数
Dim CacheFolder = RequestTaskTempFolder()
Dim OverridesFolder = CacheFolder & "modpack\overrides\"
Dim McVersion = PageInstanceLeft.Instance
Dim TargetInstance = PageInstanceLeft.Instance
Dim IncludeJava As Boolean =
(RulesOverrides Is Nothing AndAlso CheckOptionsJava.Visibility = Visibility.Visible AndAlso CheckOptionsJava.Checked) OrElse
(RulesOverrides IsNot Nothing AndAlso CheckOptionsJava.Checked AndAlso Settings.Get(Of Integer)("VersionArgumentJavaV2", McVersion) = 2)
Dim PathIndie As String = McVersion.PathIndie
(RulesOverrides IsNot Nothing AndAlso CheckOptionsJava.Checked AndAlso Settings.Get(Of Integer)("VersionArgumentJavaV2", TargetInstance) = 2)
Dim PathIndie As String = TargetInstance.PathIndie
Dim CheckHostedAssets As Boolean = Not CheckAdvancedInclude.Checked
Dim ModrinthUploadMode As Boolean = CheckAdvancedModrinth.Checked
Dim IncludePCL As Boolean = CheckOptionsPcl.Checked
@@ -498,7 +498,7 @@ Public Class PageInstanceExport
'文件夹:进一步搜索
For Each SubFolder In Folder.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
'跳过部分又没用文件又多的文件夹,加快搜索
If {"assets", "versions", "libraries"}.Contains(SubFolder.Name) AndAlso PathIndie = PathUtils.RemoveExtendedPrefix(Folder.FullName) Then Continue For
If {"assets", "versions", "libraries"}.Contains(SubFolder.Name) AndAlso PathUtils.IsSame(PathIndie, Folder.FullName) Then Continue For
If {"structureCacheV1", ".fabric", ".git", "avatar-cache", "cosmetic-cache"}.Contains(SubFolder.Name) Then Continue For
SearchFolder(SubFolder)
Next
@@ -536,10 +536,10 @@ Public Class PageInstanceExport
Loader.Progress = 0.85
'复制 Java
If IncludeJava Then
Dim JavaToExport = SelectOrDownloadJava(McVersion, False, Loader.CreateCancellationToken, Loader.CreateSyncProgressProvider(0.85, 0.93))
Dim JavaToExport = SelectOrDownloadJava(TargetInstance, False, Loader.CreateCancellationToken, Loader.CreateSyncProgressProvider(0.85, 0.93))
If JavaToExport Is Nothing Then Throw New FileNotFoundException("版本文件夹中没有找到可导出的 Java。")
Dim JavaFolder = PathUtils.RemoveLastPart(JavaToExport.Folder)
Dim DestFolder As String = Path.Combine(OverridesFolder, JavaFolder.AfterFirst(McVersion.PathVersion, True))
Dim DestFolder As String = Path.Combine(OverridesFolder, JavaFolder.AfterFirst(TargetInstance.PathVersion, True))
DirectoryUtils.Copy(JavaFolder, DestFolder)
Logger.Info($"已复制版本文件夹中的 Java:{JavaFolder} → {DestFolder}")
End If
@@ -563,7 +563,7 @@ Public Class PageInstanceExport
Next
Loader.Progress = 0.97
'复制 PCL 版本设置
If DirectoryUtils.Exists(McVersion.PathVersion & "PCL\") Then DirectoryUtils.Copy(McVersion.PathVersion & "PCL\", OverridesFolder & "PCL\")
If DirectoryUtils.Exists(TargetInstance.PathVersion & "PCL\") Then DirectoryUtils.Copy(TargetInstance.PathVersion & "PCL\", OverridesFolder & "PCL\")
WriteIni(OverridesFolder & "PCL\Setup.ini", "IsStar", False)
'复制 PCL 本体(正式版)
If BuildType = BuildTypes.Release AndAlso IncludePCL Then FileUtils.Copy(PathExe, CacheFolder & "Plain Craft Launcher.exe")
@@ -686,16 +686,16 @@ Public Class PageInstanceExport
Next
Loader.Progress = 0.2
'导出最终 JSON 文件
Dim Dependencies As New JObject From {{"minecraft", McVersion.Version.VanillaName}}
If McVersion.Version.HasForge Then Dependencies.Add("forge", McVersion.Version.Forge)
If McVersion.Version.HasFabric Then Dependencies.Add("fabric-loader", McVersion.Version.Fabric)
If McVersion.Version.HasNeoForge Then Dependencies.Add("neoforge", McVersion.Version.NeoForge)
Dim Dependencies As New JObject From {{"minecraft", TargetInstance.Version.VanillaName}}
If TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.Forge) Then Dependencies.Add("forge", TargetInstance.Version.ModLoaderVersions(ModLoaders.Forge))
If TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.Fabric) Then Dependencies.Add("fabric-loader", TargetInstance.Version.ModLoaderVersions(ModLoaders.Fabric))
If TargetInstance.Version.ModLoaders.HasFlagF(ModLoaders.NeoForge) Then Dependencies.Add("neoforge", TargetInstance.Version.ModLoaderVersions(ModLoaders.NeoForge))
Dim ResultJson As New JObject From {
{"game", "minecraft"},
{"formatVersion", 1},
{"versionId", PackVersion},
{"name", PackName},
{"summary", McVersion.Info},
{"summary", TargetInstance.Info},
{"files", Files},
{"dependencies", Dependencies}
}
@@ -13,21 +13,29 @@
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemMod" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="2" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z" >
<local:MyListItem x:Name="ItemModify" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="2" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="修改" LogoScale="0.95"
Logo="F1 M652.624 145.904c62.256-62.272 163.2-62.272 225.472 0 62.272 62.256 62.272 163.2 0 225.472L477.808 771.664a28.8 28.8 0 0 1-10.816 6.8L242.4 857.376c-47.04 16.544-92.32-28.736-75.776-75.776l78.896-224.592c1.44-4.08 3.76-7.776 6.816-10.816L652.624 145.904z M828.604 195.396a89.44 89.44 0 0 0-126.488 0L308.48 589.032 241.68 781.12 433.768 714.32 828.604 321.884a89.44 89.44 0 0 0 0-126.488z M606.256 194.816a35 35 0 0 1 49.504 0l173.728 173.728a35 35 0 0 1-49.504 49.504L606.256 244.32a35 35 0 0 1 0-49.504z M261.984 539.104a35 35 0 0 1 49.504 0l173.728 173.728a35 35 0 0 1-49.504 49.504L261.984 588.608a35 35 0 0 1 0-49.504z" >
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="2" ToolTip="刷新" Click="Refresh_Click" LogoScale="0.85" Logo="M512.0 838.3c-80.2 0-153.4-29.3-210.2-77.4l75.5-75.5c11.5-11.5 25.8-22.0 25.8-37.0a27.2 27.2 0 0 0-27.1-27.1H104.0c-27.1 0-27.1 23.9-27.1 27.1v271.9a27.1 27.1 0 0 0 27.1 27.1c15.0 0 27.8-16.6 42.5-31.2l77.9-77.9c76.6 67.7 177.1 108.9 287.4 108.9 221.7 0 404.5-166.0 431.2-380.6h-109.8c-25.9 154.2-159.7 271.9-321.3 271.9zM919.9 76.6c-15.0 0-27.8 16.6-42.5 31.3L799.5 185.8c-76.5-67.7-177.1-108.9-287.4-108.9-221.8 0-404.5 166.1-431.3 380.6H190.6c25.9-154.2 159.7-271.9 321.4-271.9 80.2 0 153.4 29.3 210.1 77.4l-75.5 75.5c-11.6 11.5-25.8 22.0-25.8 37.1a27.2 27.2 0 0 0 27.1 27.1h271.9c27.1 0 27.1-23.9 27.1-27.1V103.8a27.1 27.1 0 0 0-27.1-27.1z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemModDisabled" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="3" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
<local:MyListItem x:Name="ItemMod" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="3" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z" >
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="3" ToolTip="刷新" Click="Refresh_Click" LogoScale="0.85" Logo="M512.0 838.3c-80.2 0-153.4-29.3-210.2-77.4l75.5-75.5c11.5-11.5 25.8-22.0 25.8-37.0a27.2 27.2 0 0 0-27.1-27.1H104.0c-27.1 0-27.1 23.9-27.1 27.1v271.9a27.1 27.1 0 0 0 27.1 27.1c15.0 0 27.8-16.6 42.5-31.2l77.9-77.9c76.6 67.7 177.1 108.9 287.4 108.9 221.7 0 404.5-166.0 431.2-380.6h-109.8c-25.9 154.2-159.7 271.9-321.3 271.9zM919.9 76.6c-15.0 0-27.8 16.6-42.5 31.3L799.5 185.8c-76.5-67.7-177.1-108.9-287.4-108.9-221.8 0-404.5 166.1-431.3 380.6H190.6c25.9-154.2 159.7-271.9 321.4-271.9 80.2 0 153.4 29.3 210.1 77.4l-75.5 75.5c-11.6 11.5-25.8 22.0-25.8 37.1a27.2 27.2 0 0 0 27.1 27.1h271.9c27.1 0 27.1-23.9 27.1-27.1V103.8a27.1 27.1 0 0 0-27.1-27.1z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
<local:MyListItem x:Name="ItemModDisabled" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z" />
<local:MyListItem x:Name="ItemExport" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="导出"
<local:MyListItem x:Name="ItemExport" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="5" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="导出"
Logo="M511 995a128 128 0 0 1-57-13L70 791a126 126 0 0 1-70-113V311a126 126 0 0 1 15-60V248c1-2 3-5 5-8a127 127 0 0 1 49-42L454 13a128 128 0 0 1 112 0l383 190a126 126 0 0 1 72 113v360a126 126 0 0 1-70 115L568 984c-17 7-37 11-57 11z m42-470v370l360-178c14-7 23-21 23-38v-335L554 524zM85 330v347a42 42 0 0 0 23 38l360 178V523L85 330zM135 260l375 189 137-65L286 188 135 260z m245-118l363 197 150-71-365-180a42 42 0 0 0-37 0l-111 53z">
<local:MyListItem.Buttons>
<x:Array Type="{x:Type local:MyIconButton}">
<local:MyIconButton Tag="4" ToolTip="刷新" Click="Refresh_Click" LogoScale="0.85" Logo="M512.0 838.3c-80.2 0-153.4-29.3-210.2-77.4l75.5-75.5c11.5-11.5 25.8-22.0 25.8-37.0a27.2 27.2 0 0 0-27.1-27.1H104.0c-27.1 0-27.1 23.9-27.1 27.1v271.9a27.1 27.1 0 0 0 27.1 27.1c15.0 0 27.8-16.6 42.5-31.2l77.9-77.9c76.6 67.7 177.1 108.9 287.4 108.9 221.7 0 404.5-166.0 431.2-380.6h-109.8c-25.9 154.2-159.7 271.9-321.3 271.9zM919.9 76.6c-15.0 0-27.8 16.6-42.5 31.3L799.5 185.8c-76.5-67.7-177.1-108.9-287.4-108.9-221.8 0-404.5 166.1-431.3 380.6H190.6c25.9-154.2 159.7-271.9 321.4-271.9 80.2 0 153.4 29.3 210.1 77.4l-75.5 75.5c-11.6 11.5-25.8 22.0-25.8 37.1a27.2 27.2 0 0 0 27.1 27.1h271.9c27.1 0 27.1-23.9 27.1-27.1V103.8a27.1 27.1 0 0 0-27.1-27.1z" />
<local:MyIconButton Tag="5" ToolTip="刷新" Click="Refresh_Click" LogoScale="0.85" Logo="M512.0 838.3c-80.2 0-153.4-29.3-210.2-77.4l75.5-75.5c11.5-11.5 25.8-22.0 25.8-37.0a27.2 27.2 0 0 0-27.1-27.1H104.0c-27.1 0-27.1 23.9-27.1 27.1v271.9a27.1 27.1 0 0 0 27.1 27.1c15.0 0 27.8-16.6 42.5-31.2l77.9-77.9c76.6 67.7 177.1 108.9 287.4 108.9 221.7 0 404.5-166.0 431.2-380.6h-109.8c-25.9 154.2-159.7 271.9-321.3 271.9zM919.9 76.6c-15.0 0-27.8 16.6-42.5 31.3L799.5 185.8c-76.5-67.7-177.1-108.9-287.4-108.9-221.8 0-404.5 166.1-431.3 380.6H190.6c25.9-154.2 159.7-271.9 321.4-271.9 80.2 0 153.4 29.3 210.1 77.4l-75.5 75.5c-11.6 11.5-25.8 22.0-25.8 37.1a27.2 27.2 0 0 0 27.1 27.1h271.9c27.1 0 27.1-23.9 27.1-27.1V103.8a27.1 27.1 0 0 0-27.1-27.1z" />
</x:Array>
</local:MyListItem.Buttons>
</local:MyListItem>
@@ -6,6 +6,10 @@ Public Class PageInstanceLeft
''' </summary>
Public Shared Instance As McInstance = Nothing
Private Sub PageInstanceLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
PageSetupUI.HiddenRefresh()
End Sub
Public Sub RefreshModDisabled() Handles Me.Loaded
If Instance IsNot Nothing AndAlso Instance.Modable Then
ItemMod.Visibility = Visibility.Visible
@@ -26,7 +30,7 @@ Public Class PageInstanceLeft
''' <summary>
''' 勾选事件改变页面。
''' </summary>
Private Sub PageCheck(sender As FrameworkElement, e As RouteEventArgs) Handles ItemOverall.Check, ItemMod.Check, ItemModDisabled.Check, ItemSetup.Check, ItemExport.Check
Private Sub PageCheck(sender As FrameworkElement, e As RouteEventArgs) Handles ItemOverall.Check, ItemMod.Check, ItemModDisabled.Check, ItemSetup.Check, ItemModify.Check, ItemExport.Check
'尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0
'若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False)
If sender.Tag IsNot Nothing Then PageChange(Val(sender.Tag))
@@ -45,11 +49,14 @@ Public Class PageInstanceLeft
If FrmInstanceModDisabled Is Nothing Then FrmInstanceModDisabled = New PageInstanceModDisabled
Return FrmInstanceModDisabled
Case FormMain.PageSubType.InstanceSetup
If IsNothing(FrmInstanceSetup) Then FrmInstanceSetup = New PageInstanceSetup
If FrmInstanceSetup Is Nothing Then FrmInstanceSetup = New PageInstanceSetup
Return FrmInstanceSetup
Case FormMain.PageSubType.InstanceExport
If FrmInstanceExport Is Nothing Then FrmInstanceExport = New PageInstanceExport
Return FrmInstanceExport
Case FormMain.PageSubType.InstanceModify
If FrmDownloadModify Is Nothing Then FrmDownloadModify = New PageDownloadModify
Return FrmDownloadModify
Case Else
Throw New Exception("未知的版本设置子页面种类:" & ID)
End Select
@@ -60,6 +67,10 @@ Public Class PageInstanceLeft
''' </summary>
Public Sub PageChange(ID As FormMain.PageSubType)
If PageID = ID Then Return
If Instance IsNot Nothing AndAlso McInstanceLock.IsLocked(Instance) Then
Hint("该版本正在被修改,请稍后再切换页面!", HintType.Red)
Return
End If
AniControlEnabled += 1
Try
PageChangeRun(PageGet(ID))
@@ -98,13 +109,20 @@ Public Class PageInstanceLeft
Refresh(FrmMain.PageCurrentSub)
End Sub
Public Sub Refresh(SubType As FormMain.PageSubType)
If Instance IsNot Nothing AndAlso McInstanceLock.IsLocked(Instance) Then
Hint("该版本正在被修改,请稍后再刷新!", HintType.Red)
Return
End If
Select Case SubType
Case FormMain.PageSubType.InstanceMod
PageInstanceMod.Refresh()
ItemMod.Checked = True
Case FormMain.PageSubType.InstanceExport
If FrmInstanceExport IsNot Nothing Then FrmInstanceExport.RefreshAll()
FrmInstanceExport?.RefreshAll()
ItemExport.Checked = True
Case FormMain.PageSubType.InstanceModify
FrmDownloadModify?.PageLoaderRestart()
ItemModify.Checked = True
End Select
End Sub
@@ -284,7 +284,7 @@ Public Class PageInstanceMod
''' 返回输入的文件是否为一个 Mod 文件,仅用于判断拖拽行为。
''' </summary>
Public Shared Function InstallMods(FilePathList As IEnumerable(Of String)) As Boolean
Dim Extension As String = FilePathList.First.AfterLast(".").Lower
Dim Extension As String = PathUtils.GetExtension(FilePathList.First)
'检查文件扩展名
If Not {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then Return False
Logger.Info("文件为 jar/litemod 格式,尝试作为 Mod 安装")
@@ -307,15 +307,15 @@ Public Class PageInstanceMod
Install:
Try
For Each ModFile In FilePathList
Dim NewFileName = PathUtils.GetLastPart(ModFile).Replace(".disabled", "").Replace(".old", "")
Dim NewFileName = (New LocalResourceFile(ModFile)).EnabledName
If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227
NewFileName = Instance.PathIndie & "mods\" & NewFileName
If ModFile = NewFileName Then Continue For '防止安装相同文件导致文件被删除
If PathUtils.IsSame(ModFile, NewFileName) Then Continue For '防止安装相同文件导致文件被删除
FileUtils.Delete(NewFileName, True)
FileUtils.Copy(ModFile, NewFileName)
Next
If FilePathList.IsSingle Then
Hint($"已安装 {PathUtils.GetLastPart(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Green)
Hint($"已安装 {(New LocalResourceFile(FilePathList.First)).EnabledName}!", HintType.Green)
Else
Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Green)
End If
@@ -553,8 +553,8 @@ Install:
Dim File As ResourceVersion = Entry.UpdateFile
If Not File.DownloadAvailable Then Continue For
'确认更新后的文件名
Dim CurrentReplaceName = Entry.ProjectVersion.FileName.Replace(".jar", "").Replace(".old", "").Replace(".disabled", "")
Dim NewestReplaceName = Entry.UpdateFile.FileName.Replace(".jar", "").Replace(".old", "").Replace(".disabled", "")
Dim CurrentReplaceName = PathUtils.GetFileNameWithoutExtension(Entry.ProjectVersion.FileName)
Dim NewestReplaceName = PathUtils.GetFileNameWithoutExtension(Entry.UpdateFile.FileName)
Dim CurrentSegs = CurrentReplaceName.Split("-"c).ToList()
Dim NewestSegs = NewestReplaceName.Split("-"c).ToList()
Dim Shortened As Boolean = False
@@ -104,51 +104,21 @@ Public Class PageInstanceOverall
'重命名版本
Private Sub BtnDisplayRename_Click(sender As Object, e As EventArgs) Handles BtnDisplayRename.Click
Try
If McInstanceLock.IsLocked(PageInstanceLeft.Instance) Then
Hint("该版本正在被修改,请稍后再重命名!", HintType.Red)
Return
End If
'确认输入的新名称
Dim OldName As String = PageInstanceLeft.Instance.Name
Dim OldPath As String = PageInstanceLeft.Instance.PathVersion
'修改此部分的同时修改快速安装的版本名检测*
Dim NewName As String = MyMsgBoxInput("重命名版本", "", OldName, New ObjectModel.Collection(Of Validate) From {
New ValidateFolderName(McFolderSelected & "versions", IgnoreList:=New List(Of String) From {OldName})
})
If String.IsNullOrWhiteSpace(NewName) Then Return
Dim NewPath As String = McFolderSelected & "versions\" & NewName & "\"
'重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储
Dim JsonObject As JObject
Dim OldJsonPath As String = PageInstanceLeft.Instance.GetJsonPath()
Try
JsonObject = FileUtils.ReadAsJson(OldJsonPath)
Catch ex As Exception
Logger.Warn(ex, "在重命名读取 JSON 时失败")
JsonObject = PageInstanceLeft.Instance.JsonObject
End Try
'重命名主文件夹
DirectoryUtils.Move(OldPath, NewPath)
'清理 ini 缓存
PageInstanceLeft.Instance.ResetSettingsCache()
'重命名 jar 文件与 natives 文件夹
'不能进行遍历重命名,否则在版本名很短的时候容易误伤其他文件(#6443)
If DirectoryUtils.Exists($"{NewPath}{OldName}-natives") Then DirectoryUtils.Move($"{NewPath}{OldName}-natives", $"{NewPath}{NewName}-natives")
If FileUtils.Exists($"{NewPath}{OldName}.jar") Then FileUtils.Move($"{NewPath}{OldName}.jar", $"{NewPath}{NewName}.jar")
'替换版本设置文件中的路径
If FileUtils.Exists(NewPath & "PCL\Setup.ini") Then
FileUtils.Write(NewPath & "PCL\Setup.ini", FileUtils.ReadAsString(NewPath & "PCL\Setup.ini").Replace(OldPath, NewPath))
End If
'更改已选中的版本
If ReadIni(McFolderSelected & "PCL.ini", "Version") = OldName Then
WriteIni(McFolderSelected & "PCL.ini", "Version", NewName)
End If
'更新版本 Json
Try
JsonObject("id") = NewName
FileUtils.Delete(NewPath & PathUtils.GetLastPart(OldJsonPath))
FileUtils.Write(NewPath & NewName & ".json", JsonObject.ToString)
Catch ex As Exception
Logger.Warn(ex, "重命名版本 json 失败")
End Try
Dim NewInstance = PageInstanceLeft.Instance.Rename(NewName)
'刷新与提示
Hint("重命名成功!", HintType.Green)
PageInstanceLeft.Instance = New McInstance(NewName).Load()
PageInstanceLeft.Instance = NewInstance
If Not IsNothing(McInstanceSelected) AndAlso McInstanceSelected.Equals(PageInstanceLeft.Instance) Then WriteIni(McFolderSelected & "PCL.ini", "Version", NewName)
Reload()
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
@@ -267,6 +237,10 @@ Public Class PageInstanceOverall
'补全文件
Private Sub BtnManageCheck_Click(sender As Object, e As EventArgs) Handles BtnManageCheck.Click
Try
If McInstanceLock.IsLocked(PageInstanceLeft.Instance) Then
Hint("该版本正在被修改,请稍后再补全文件!", HintType.Red)
Return
End If
'忽略文件检查提示
If ShouldIgnoreFileCheck(PageInstanceLeft.Instance) Then
Hint("请先关闭 [版本设置 → 设置 → 高级启动选项 → 关闭文件校验],然后再尝试补全文件!", HintType.Blue)
@@ -304,8 +278,12 @@ Public Class PageInstanceOverall
'修改此代码时,同时修改 PageSelectRight 中的代码
Private Sub BtnManageDelete_Click(sender As Object, e As EventArgs) Handles BtnManageDelete.Click
Try
If McInstanceLock.IsLocked(PageInstanceLeft.Instance) Then
Hint("该版本正在被修改,请稍后再删除!", HintType.Red)
Return
End If
Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
Dim IsHintIndie As Boolean = PageInstanceLeft.Instance.State <> McInstanceState.Error AndAlso PageInstanceLeft.Instance.PathIndie <> McFolderSelected
Dim IsHintIndie As Boolean = PageInstanceLeft.Instance.State <> McInstance.McInstanceState.Error AndAlso PageInstanceLeft.Instance.PathIndie <> McFolderSelected
Dim SavesFolder = DirectoryUtils.GetInfo(PageInstanceLeft.Instance.PathIndie & "saves\")
Dim SaveEntries = If(IsHintIndie AndAlso SavesFolder.Exists, SavesFolder.EnumerateDirectories.OrderByDescending(Function(Save) Save.LastWriteTime).Select(Function(Save) $"{Save.Name}(上次修改:{StringUtils.FormatTimeSpan(Save.LastWriteTime - Date.Now, False)})").ToList, New List(Of String))
Select Case MyMsgBox($"你确定要{If(IsShiftPressed, "永久", "")}删除版本 {PageInstanceLeft.Instance.Name} 吗?" &
@@ -499,7 +499,7 @@ PreFin:
ComboArgumentJavaSelect.Items.Add(JavaItem)
Dim Buttons As New List(Of MyIconButton)
'从列表中移除按钮
Dim IsOfficial As Boolean = JavaEntry.Folder.StartsWithF($"{Paths.AppData}.minecraft\runtime\")
Dim IsOfficial As Boolean = PathUtils.IsParentOf($"{Paths.AppData}.minecraft\runtime\", JavaEntry.Folder)
Dim DeleteButton As New MyIconButton With {.Logo = Logo.IconButtonStop, .Height = 24, .Width = 24}
DeleteButton.IsEnabled = Not IsOfficial
DeleteButton.ToolTip = If(DeleteButton.IsEnabled, "从列表中移除", "无法移除官方 Java")
@@ -65,7 +65,7 @@ Public Class PageLaunchLeft
'确认 Minecraft 版本存在
Dim Selection As String = ReadIni(McFolderSelected & "PCL.ini", "Version")
Dim Instance As McInstance = If(Selection = "", Nothing, New McInstance(Selection))
If Instance Is Nothing OrElse Not Instance.PathVersion.StartsWithF(McFolderSelected) OrElse Not Instance.Check() Then
If Instance Is Nothing OrElse Not PathUtils.IsParentOf(McFolderSelected, Instance.PathVersion) OrElse Not Instance.Check() Then
'无效的版本
Logger.Info($"当前选择的 Minecraft 版本无效:{If(Instance Is Nothing, "null", Instance.PathVersion)}", If(IsNothing(Instance), LogBehavior.None, LogBehavior.ToastIfDebug))
If Not McInstanceListLoader.State = LoadState.Finished Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
@@ -691,12 +691,28 @@ ExitRefresh:
End If
End Sub
'取消按钮
Private Sub BtnCancel_Click() Handles BtnCancel.Click
McLaunchCancel()
Public Sub BtnCancel_Click() Handles BtnCancel.Click
If McLaunchLoaderReal IsNot Nothing Then
McLaunchLoaderReal.Cancel()
McLaunchLog("已取消启动")
Try
If McLaunchWatcher IsNot Nothing Then
McLaunchWatcher.Kill()
ElseIf McLaunchProcess IsNot Nothing Then
If Not McLaunchProcess.HasExited Then McLaunchProcess.Kill()
End If
Catch ex As Exception
Logger.Error(ex, "取消启动结束进程失败", LogBehavior.Toast)
End Try
End If
End Sub
'版本设置按钮
Private Sub BtnMore_Click() Handles BtnMore.Click
If McLaunchLoader.State = LoadState.Loading Then Return
If McInstanceLock.IsLocked(McInstanceSelected) Then
Hint("该版本正在被修改,暂时无法进入版本设置!", HintType.Red)
Return
End If
McInstanceSelected.Load()
PageInstanceLeft.Instance = McInstanceSelected
FrmMain.PageChange(FormMain.PageType.InstanceSetup, 0)
@@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:behaviors="clr-namespace:PCL.Controls.Behaviors"
xmlns:local="clr-namespace:PCL" PanScroll="PanBack">
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" x:Name="PanBack">
<StackPanel Name="PanMain" Margin="25,25,25,10" Grid.IsSharedSizeScope="True">
@@ -11,8 +12,10 @@
<StackPanel x:Name="PanCustom">
</StackPanel>
<local:MyCard Margin="0,0,0,15" Title="启动日志" x:Name="PanLog">
<TextBlock x:Name="LabLog" Margin="20,38,20,18" TextTrimming="None" TextWrapping="Wrap" />
<local:MyTextBox x:Name="LabLog" Margin="15,34,15,13" Padding="0,4" IsReadOnly="True" IsUndoEnabled="False"
AcceptsReturn="True" TextWrapping="Wrap" BorderThickness="0" HasBackground="False"
VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled" />
</local:MyCard>
</StackPanel>
</local:MyScrollViewer>
</local:MyPageRight>
</local:MyPageRight>
@@ -101,19 +101,34 @@ Public Class PageLaunchRight
Url = "https://pcl.wyc-w.top/index.xaml"
Case 15
Logger.Info("主页预设:Minecraft 芝士站")
Url = "https://www.xxag.top/mkss"
Url = "https://mkss-services.awaeric.xyz"
Case 16
Logger.Info("主页预设:整合包推荐引擎")
Url = "https://qawsedrftgyhujiko.fun/pcl2/Custom.xaml"
Case 17
Logger.Info("Bangumi 番剧主页")
Url = "https://bangumi.p.kaphia.qzz.io"
Logger.Info("主页预设:Bangumi 番剧主页")
Url = "https://bangumi.p.kaphia.top"
Case 18
Logger.Info("Bilibili 热门")
Url = "https://bilibili.p.kaphia.qzz.io"
Logger.Info("主页预设:Bilibili 热门")
Url = "https://bilibili.p.kaphia.top"
Case 19
Logger.Info("Music 云音乐热门")
Url = "https://cloudmusic.p.kaphia.qzz.io"
Logger.Info("主页预设:Music 云音乐热门")
Url = "https://cloudmusic.p.kaphia.top"
Case 20
Logger.Info("主页预设:模组推荐")
Url = "https://g-fish.dpdns.org/download/ModPage.xaml"
Case 21
Logger.Info("主页预设:每日游戏推荐")
Url = "https://pcl.xn--9iq209asnop94b.top/download/GamePage.xaml"
Case 22
Logger.Info("主页预设:Wallpaper 每日壁纸")
Url = "https://wallpaper.p.kaphia.top"
Case 23
Logger.Info("主页预设:Weather 天气预报")
Url = "https://weather-p.kaphia.top/{variable:PCLDailyWeatherPage:choose}.xaml"
Case 24
Logger.Info("主页预设:新一代狗屁王大杂烩主页")
Url = "https://end.g-fish.dpdns.org/Custom.xaml"
End Select
End Select
'联网下载
@@ -45,7 +45,7 @@ Public Class PageLoginLegacy
If LoginData.UserName.Trim = "" Then Return "玩家名不能为空!"
If LoginData.UserName.Contains("""") Then Return "玩家名不能包含英文引号!"
If McInstanceSelected IsNot Nothing AndAlso
McInstanceSelected.Version.Vaild AndAlso McInstanceSelected.Version.Vanilla >= New Version(20, 0, 3) AndAlso
McInstanceSelected.Version.Valid AndAlso McInstanceSelected.Version.Vanilla >= New Version(20, 0, 3) AndAlso
LoginData.UserName.Trim.Length > 16 Then
Return "自 1.20.3 起,玩家名至多只能包含 16 个字符!"
End If
@@ -358,8 +358,9 @@ Public Class PageLinkMain
'复制邀请码
Private Sub Copy() Handles BtnFinishCopy.Click
Dim CodeText As String = $"在 PCL 启动器中输入邀请码【{GetInviteCode()}】,即可加入联机房间!"
ClipboardSet(CodeText, SuccessHint:="已复制邀请码!")
ClipboardSet(CodeText, False)
Settings.Set("LinkLastAutoJoinInviteCode", CodeText)
Hint("已复制邀请码!", HintType.Green)
End Sub
Private Function GetInviteCode() As String
Return $"{NetworkName}-{NetworkSecret}-{INVITE_CODE_VERSION.ToString.PadLeft(2, "0"c)}{ _
@@ -368,7 +369,8 @@ Public Class PageLinkMain
'复制 IP
Private Sub BtnFinishIp_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles BtnFinishIp.MouseLeftButtonUp
ClipboardSet(ClientAddress, SuccessHint:="已复制服务器地址!")
ClipboardSet(ClientAddress, False)
Hint("已复制服务器地址!", HintType.Green)
End Sub
#End Region
File diff suppressed because it is too large Load Diff
@@ -48,12 +48,13 @@ Public Class PageOtherHelp
If Item.Types.Contains(Type) Then TypeItems.Add(Item)
Next
'增加卡片
Dim NewCard As New MyCard With {.Title = Type, .Margin = New Thickness(0, 0, 0, 15), .SwapType = 11}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TypeItems}
Dim NewCard As New MyCard With {.Title = Type, .Margin = New Thickness(0, 0, 0, 15)}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
NewCard.Children.Add(NewStack)
NewCard.SwapControl = NewStack
NewCard.SetContentBuilder(TypeItems, Function(Entry) Entry.ToListItem)
If Type = "指南" Then
MyCard.StackInstall(NewStack, 11, "指南")
NewCard.BuildContent()
Else
NewCard.IsSwapped = True
End If
@@ -64,7 +64,7 @@ Public Class PageSelectLeft
</ContextMenu>
)
End Select
If (Folder.Type = McFolder.Types.Vanilla OrElse Folder.Type = McFolder.Types.RenamedVanilla) AndAlso Folder.Location = Paths.Base & ".minecraft\" AndAlso McFolderList.IsSingle Then CType(ContMenu.FindName("Delete"), MyMenuItem).Header = "清空"
If (Folder.Type = McFolder.Types.Vanilla OrElse Folder.Type = McFolder.Types.RenamedVanilla) AndAlso PathUtils.IsSame(Folder.Location, Paths.Base & ".minecraft\") AndAlso McFolderList.IsSingle Then CType(ContMenu.FindName("Delete"), MyMenuItem).Header = "清空"
'注册事件
If Not Folder.Type = McFolder.Types.Vanilla Then CType(ContMenu.FindName("Remove"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Remove_Click))
CType(ContMenu.FindName("Open"), MyMenuItem).AddHandler(MyMenuItem.ClickEvent, New RoutedEventHandler(AddressOf FrmSelectLeft.Open_Click))
@@ -116,7 +116,7 @@ Public Class PageSelectLeft
'确认勾选状态
For i = 0 To McFolderList.Count - 1
If McFolderList(i).Location = McFolderSelected Then
If PathUtils.IsSame(McFolderList(i).Location, McFolderSelected) Then
CType(FrmSelectLeft.PanList.Children(i + 1), MyListItem).Checked = True '去掉第一个标题
Return
End If
@@ -139,9 +139,9 @@ Public Class PageSelectLeft
'添加文件夹
Public Sub Add_Click()
Dim NewFolder As String = ""
'检查是否有下载任务
If HasDownloadingTask() Then
Hint("在下载任务进行时,无法添加游戏文件夹!", HintType.Red)
'下载或版本修改期间禁止更改游戏文件夹
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask() Then
Hint("请在其他任务完成后,再添加游戏文件夹!", HintType.Red)
Return
End If
Try
@@ -150,8 +150,11 @@ Public Class PageSelectLeft
If NewFolder Is Nothing Then Return
If NewFolder.Contains("!") OrElse NewFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Red) : Return
'要求输入显示名称
Dim SplitedNames As String() = NewFolder.TrimEnd("\").Split("\")
Dim DefaultName As String = If(SplitedNames.Last = ".minecraft", If(SplitedNames.Count >= 3, SplitedNames(SplitedNames.Count - 2), ""), SplitedNames.Last)
Dim DefaultName = PathUtils.GetLastPart(NewFolder)
If DefaultName = ".minecraft" Then
Dim ParentFolder = PathUtils.RemoveLastPart(NewFolder)
DefaultName = If(ParentFolder.EndsWithF(":"), "", PathUtils.GetLastPart(ParentFolder))
End If
If DefaultName.Length > 40 Then DefaultName = DefaultName.Substring(0, 39)
Dim NewName As String = MyMsgBoxInput("输入显示名称", "输入该文件夹在左边栏列表中显示的名称。", DefaultName,
New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})})
@@ -169,7 +172,7 @@ Public Class PageSelectLeft
RunInThread(
Sub()
Try
If Not FolderPath.EndsWithF("\") Then FolderPath &= "\"
FolderPath = PathUtils.AddSlashSuffix(FolderPath)
'检查文件夹权限
If Not CheckPermission(FolderPath) Then
If ShowHint Then
@@ -195,7 +198,7 @@ Public Class PageSelectLeft
For i = 0 To Folders.Count - 1
Dim Folder As String = Folders(i)
If Folder = "" Then Continue For
If Folder.Split(">")(1) = FolderPath Then
If PathUtils.IsSame(Folder.Split(">")(1), FolderPath) Then
IsAdded = True
If Folder.Split(">")(0) = DisplayName Then
If ShowHint Then Hint("此文件夹已在列表中!", HintType.Blue)
@@ -246,9 +249,9 @@ Public Class PageSelectLeft
'创建文件夹
Public Sub Create_Click()
'检查是否有下载任务
If HasDownloadingTask() Then
Hint("在下载任务进行时,无法创建游戏文件夹!", HintType.Red)
'下载或版本修改期间禁止更改游戏文件夹
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask() Then
Hint("请在其他任务完成后,再创建游戏文件夹!", HintType.Red)
Return
End If
CreateMcFolderInCurrentPath()
@@ -270,6 +273,10 @@ Public Class PageSelectLeft
Dim Target As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
'若为 “移除”,则提醒是否删除 PCL 的配置文件
If Target.Type = McFolder.Types.Custom Then
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask() Then
Hint("请在其他任务完成后,再移除游戏文件夹!", HintType.Red)
Return
End If
Select Case MyMsgBox("是否需要清理 PCL 在该文件夹中的配置文件?" & vbCrLf & "这包括各个版本的独立设置(如自定义图标、第三方登录配置)等,对游戏本身没有影响。", "配置文件清理", "删除", "保留", "取消")
Case 1
'删除配置文件
@@ -292,6 +299,10 @@ Public Class PageSelectLeft
End Try
End Sub
Public Sub Delete_Click(sender As Object, e As RoutedEventArgs)
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask() Then
Hint("请在其他任务完成后,再删除游戏文件夹!", HintType.Red)
Return
End If
Dim Target As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
Dim DeleteText As String = If((Target.Type = McFolder.Types.Vanilla OrElse Target.Type = McFolder.Types.RenamedVanilla) AndAlso Target.Location = Paths.Base & ".minecraft\" AndAlso McFolderList.IsSingle, "清空", "删除")
If MyMsgBox("你确定要" & DeleteText & "这个文件夹吗?" & vbCrLf &
@@ -328,7 +339,7 @@ Public Class PageSelectLeft
Dim DeletedName As String = Nothing
Dim Folders = Settings.Get(Of String)("LaunchFolders").Split("|"c, True).ToList
For Each Folder In Folders.ToList
If Not Folder.EndsWithF(Target.Location) Then Continue For
If Not Folder.Contains(">") OrElse Not PathUtils.IsSame(Folder.AfterFirst(">"), Target.Location) Then Continue For
DeletedName = Folder.BeforeFirst(">")
Folders.Remove(Folder)
Exit For
@@ -349,7 +360,7 @@ Public Class PageSelectLeft
End Sub
Public Shared Sub RefreshCurrent(Folder As String)
WriteIni(Folder & "PCL.ini", "InstanceCache", "") '删除缓存以强制要求下一次加载时更新列表
If Folder = McFolderSelected Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
If PathUtils.IsSame(Folder, McFolderSelected) Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
End Sub
Public Sub Rename_Click(sender As Object, e As RoutedEventArgs)
Dim Folder As McFolder = CType(CType(CType(sender.Parent, ContextMenu).Parent, Primitives.Popup).PlacementTarget, MyListItem).Tag
@@ -365,7 +376,7 @@ Public Class PageSelectLeft
For i = 0 To Folders.Count - 1
Dim FolderCurrent As String = Folders(i)
If FolderCurrent = "" Then Continue For
If FolderCurrent.Split(">")(1) = Folder.Location Then
If PathUtils.IsSame(FolderCurrent.Split(">")(1), Folder.Location) Then
IsAdded = True
If FolderCurrent.Split(">")(0) = NewName Then
'名称未修改
@@ -390,9 +401,9 @@ Public Class PageSelectLeft
'点击选项
Public Sub Folder_Change(sender As MyListItem, e As RouteEventArgs)
If Not e.RaiseByMouse OrElse Not sender.Checked Then Return
'检查是否有下载任务
If HasDownloadingTask(True) Then
Hint("在下载任务进行时,无法切换游戏文件夹!", HintType.Red)
'下载或版本修改期间禁止更改游戏文件夹
If McInstanceLock.IsAnyLocked OrElse HasDownloadingTask(True) Then
Hint("请在其他任务完成后,再切换游戏文件夹!", HintType.Red)
e.Handled = True
Return
End If
@@ -30,6 +30,8 @@ Public Class PageSelectRight
For Each Card As KeyValuePair(Of McInstanceCardType, List(Of McInstance)) In McInstanceList.ToArray
'确认是否为隐藏版本显示状态
If Card.Key = McInstanceCardType.Hidden Xor ShowHidden Then Continue For
Dim Instances = Card.Value.Where(Function(Instance) Not McInstanceLock.IsLocked(Instance)).ToList
If Not Instances.Any Then Continue For
#Region "确认卡片名称"
Dim CardName As String = ""
Select Case Card.Key
@@ -40,11 +42,11 @@ Public Class PageSelectRight
Dim IsNeoForgeExists As Boolean = False
Dim IsFabricExists As Boolean = False
Dim IsLiteExists As Boolean = False
For Each Instance As McInstance In Card.Value
If Instance.Version.HasFabric Then IsFabricExists = True
If Instance.Version.HasLiteLoader Then IsLiteExists = True
If Instance.Version.HasForge Then IsForgeExists = True
If Instance.Version.HasNeoForge Then IsNeoForgeExists = True
For Each Instance As McInstance In Instances
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.Fabric) Then IsFabricExists = True
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.LiteLoader) Then IsLiteExists = True
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.Forge) Then IsForgeExists = True
If Instance.Version.ModLoaders.HasFlagF(ModLoaders.NeoForge) Then IsNeoForgeExists = True
Next
If If(IsLiteExists, 1, 0) + If(IsForgeExists, 1, 0) + If(IsFabricExists, 1, 0) + If(IsNeoForgeExists, 1, 0) > 1 Then
CardName = "可安装 Mod"
@@ -72,17 +74,18 @@ Public Class PageSelectRight
End Select
#End Region
'建立控件
Dim CardTitle As String = CardName & If(CardName = "收藏夹", "", " (" & Card.Value.Count & ")")
Dim NewCard As New MyCard With {.Title = CardTitle, .Margin = New Thickness(0, 0, 0, 15), .SwapType = 0}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Card.Value}
Dim CardTitle As String = CardName & If(CardName = "收藏夹", "", " (" & Instances.Count & ")")
Dim NewCard As New MyCard With {.Title = CardTitle, .Margin = New Thickness(0, 0, 0, 15)}
Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0)}
NewCard.Children.Add(NewStack)
NewCard.SwapControl = NewStack
NewCard.SetContentBuilder(Instances, Function(Instance) Instance.ToListItem(AddressOf McInstanceListContent))
PanMain.Children.Add(NewCard)
'确定卡片是否展开
If Card.Key = McInstanceCardType.Rubbish OrElse Card.Key = McInstanceCardType.Error OrElse Card.Key = McInstanceCardType.Fool Then
NewCard.IsSwapped = True
Else
MyCard.StackInstall(NewStack, 0, CardTitle)
NewCard.BuildContent()
End If
Next
@@ -128,15 +131,16 @@ Public Class PageSelectRight
BtnStar.LogoScale = 1.1
BtnStar.Logo = Logo.IconButtonLikeLine
End If
AddHandler BtnStar.Click, Sub()
WriteIni(Instance.PathVersion & "PCL\Setup.ini", "IsStar", Not Instance.IsStar)
McInstanceListForceRefresh = True
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
End Sub
AddHandler BtnStar.Click,
Sub()
WriteIni(Instance.PathVersion & "PCL\Setup.ini", "IsStar", Not Instance.IsStar)
McInstanceListForceRefresh = True
LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
End Sub
Dim BtnDel As New MyIconButton With {.LogoScale = 1.1, .Logo = Logo.IconButtonDelete}
BtnDel.ToolTip = "删除"
AddHandler BtnDel.Click, Sub() DeleteInstance(sender, Instance)
If Instance.State <> McInstanceState.Error Then
If Instance.State <> McInstance.McInstanceState.Error Then
Dim BtnCont As New MyIconButton With {.LogoScale = 1.1, .Logo = Logo.IconButtonSetup}
BtnCont.ToolTip = "设置"
AddHandler BtnCont.Click,
@@ -166,6 +170,10 @@ Public Class PageSelectRight
'点击选项
Public Shared Sub Item_Click(sender As MyListItem, e As EventArgs)
Dim Instance As McInstance = sender.Tag
If McInstanceLock.IsLocked(Instance) Then
Hint("该版本正在被修改,请稍后再选择!", HintType.Red)
Return
End If
If New McInstance(Instance.PathVersion).Check Then
'正常版本
McInstanceSelected = Instance
@@ -183,8 +191,12 @@ Public Class PageSelectRight
'修改此代码时,同时修改 PageInstanceOverall 中的代码
Public Shared Sub DeleteInstance(Item As MyListItem, Instance As McInstance)
Try
If McInstanceLock.IsLocked(Instance) Then
Hint("该版本正在被修改,请稍后再删除!", HintType.Red)
Return
End If
Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown
Dim IsHintIndie As Boolean = Instance.State <> McInstanceState.Error AndAlso Instance.PathIndie <> McFolderSelected
Dim IsHintIndie As Boolean = Instance.State <> McInstance.McInstanceState.Error AndAlso Instance.PathIndie <> McFolderSelected
Dim SavesFolder = DirectoryUtils.GetInfo(Instance.PathIndie & "saves\")
Dim SaveEntries = If(IsHintIndie AndAlso SavesFolder.Exists, SavesFolder.EnumerateDirectories.OrderByDescending(Function(Save) Save.LastWriteTime).Select(Function(Save) $"{Save.Name}(上次修改:{StringUtils.FormatTimeSpan(Save.LastWriteTime - Date.Now, False)})").ToList, New List(Of String))
Select Case MyMsgBox($"你确定要{If(IsShiftPressed, "永久", "")}删除版本 {Instance.Name} 吗?" &
@@ -207,7 +219,7 @@ Public Class PageSelectRight
Dim Card As MyCard = Parent.Parent
Card.Title = Card.Title.Replace(Parent.Children.Count - 1, Parent.Children.Count - 2) '有一个占位符
Parent.Children.Remove(Item)
If McInstanceSelected IsNot Nothing AndAlso Instance.PathVersion = McInstanceSelected.PathVersion Then
If McInstanceSelected IsNot Nothing AndAlso PathUtils.IsSame(Instance.PathVersion, McInstanceSelected.PathVersion) Then
'删除当前版本就更改选择
McInstanceSelected = MyVirtualizingElement.TryInit(Parent.Children(0)).Tag
End If
@@ -27,8 +27,6 @@
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="28" />
<RowDefinition Height="9" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="默认版本隔离" Margin="0,0,25,0" />
<local:MyComboBox local:SettingService.Key="LaunchArgumentIndieV2" x:Name="ComboArgumentIndieV2"
@@ -106,9 +104,6 @@
</local:MyTextBox.ValidateRules>
</local:MyTextBox>
</Grid>
<local:MyCheckBox Margin="0,8,0,4" Text="在正版登录时验证 SSL 证书" Grid.Row="12" Height="22" Grid.ColumnSpan="2"
x:Name="CheckDownloadCert" local:SettingService.Key="ToolDownloadCert"
ToolTip="开启验证可以提高安全性,但可能会导致正版登录失败(见 #3018)。&#xa;若登录因为 “未能为 SSL/TLS 安全通道建立信任关系” 失败,请考虑关闭此选项。" />
</Grid>
</StackPanel>
</local:MyCard>
@@ -291,6 +286,7 @@
<local:MyCheckBox Height="28" Text="禁用 Java Launch Wrapper" local:SettingService.Key="LaunchAdvanceDisableJLW" ToolTip="是否使用 Java Launch Wrapper 修复 Java 18- 在中文路径下可能无法正常启动的问题。&#xa;详见:https://github.com/00ll00/java_launch_wrapper" />
<local:MyCheckBox Height="28" Text="禁用 LWJGL Unsafe Agent" local:SettingService.Key="LaunchAdvanceDisableLUA" ToolTip="是否使用 LWJGL Unsafe Agent 修复 LWJGL 3.4.1 的一个性能问题。&#xa;详见:https://github.com/HMCL-dev/lwjgl-unsafe-agent" />
<local:MyCheckBox Height="28" Text="使用高性能显卡" local:SettingService.Key="LaunchAdvanceGraphicCard" ToolTip="自动在 Windows 设置 → 系统 → 屏幕 → 显示卡 中将 PCL 和 Java 改为使用高性能显卡。&#xa;如果同时有集成显卡和独立显卡,这能确保 MC 使用独立显卡进行渲染,以大幅提高帧率。" />
<local:MyCheckBox Height="28" Text="在正版登录时验证 SSL 证书" local:SettingService.Key="ToolDownloadCert" ToolTip="开启验证可以提高安全性,但可能会导致正版登录失败(见 #3018)。&#xa;若登录因为 “未能为 SSL/TLS 安全通道建立信任关系” 失败,请考虑关闭此选项。" />
</StackPanel>
<local:MyHint Text="版本独立设置中还有更多高级选项可供调整。" Margin="0,5,0,10" Theme="Blue" Grid.Row="11" Grid.ColumnSpan="2"
CanClose="True" RelativeSetup="HintMoreAdvancedSetup" />
@@ -396,7 +396,7 @@ PreFin:
AddHandler DownButton.Click, Sub() MoveJavaInList(JavaEntry, 1)
Buttons.Add(DownButton)
'从列表中移除按钮
Dim IsOfficial As Boolean = JavaEntry.Folder.StartsWithF($"{Paths.AppData}.minecraft\runtime\")
Dim IsOfficial As Boolean = PathUtils.IsParentOf($"{Paths.AppData}.minecraft\runtime\", JavaEntry.Folder)
Dim DeleteButton As New MyIconButton With {.Logo = Logo.IconButtonStop, .Height = 24, .Width = 24}
DeleteButton.IsEnabled = Not IsOfficial
DeleteButton.ToolTip = If(DeleteButton.IsEnabled, "从列表中移除", "无法移除官方 Java")
@@ -235,18 +235,16 @@
<local:MyHint Margin="0,15,0,-4" Text="内容见 ModSetup" Theme="Blue" x:Name="HintCustom" />
<local:MyHint Margin="0,15,0,6" Text="请谨慎使用陌生人提供的主页,恶意代码可能会造成损害!" Theme="Yellow" x:Name="HintCustomWarn"
CanClose="True" RelativeSetup="HintCustomWarn" />
<Grid Height="35" x:Name="PanCustomLocal" Visibility="Collapsed" Margin="0,10,0,5">
<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="BtnCustomRefresh" Grid.Column="0" Height="32" MinWidth="140" Text="刷新主页" Padding="13,0" Margin="0,0,20,0" ColorType="Highlight" />
<local:MyButton x:Name="BtnCustomFile" Grid.Column="1" Height="32" MinWidth="140" Text="生成教学文件" Padding="13,0" Margin="0,0,20,0" />
<local:MyButton x:Name="BtnCustomTutorial" Grid.Column="2" Height="32" MinWidth="140" Text="查看教程" Padding="13,0" Margin="0,0,20,0" />
<local:MyButton x:Name="BtnCustomOpen" Grid.Column="3" Height="32" MinWidth="140" Text="打开主页文件夹" Padding="13,0" Margin="0,0,20,0" />
</Grid>
<WrapPanel x:Name="PanCustomLocal" Visibility="Collapsed" Margin="0,0,0,5">
<local:MyButton x:Name="BtnCustomRefresh" Text="刷新主页"
MinWidth="140" Height="35" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" ColorType="Highlight" />
<local:MyButton x:Name="BtnCustomFile" Text="生成教学文件"
MinWidth="140" Height="35" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" />
<local:MyButton x:Name="BtnCustomTutorial" Text="查看教程"
MinWidth="140" Height="35" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" />
<local:MyButton x:Name="BtnCustomFolder" Text="打开主页文件夹"
MinWidth="140" Height="35" Padding="13,0" Margin="0,10,20,0" HorizontalAlignment="Left" />
</WrapPanel>
<Grid x:Name="PanCustomNet" Visibility="Collapsed" Margin="0,10,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
@@ -288,6 +286,11 @@
<local:MyComboBoxItem local:SettingService.Value="17" Content="Bangumi 番剧主页(作者:wzyaeu)" />
<local:MyComboBoxItem local:SettingService.Value="18" Content="Bilibili 热门(作者:wzyaeu)" />
<local:MyComboBoxItem local:SettingService.Value="19" Content="Music 云音乐热门(作者:wzyaeu)" />
<local:MyComboBoxItem local:SettingService.Value="20" Content="模组推荐(作者:llsgllsg)" />
<local:MyComboBoxItem local:SettingService.Value="21" Content="每日游戏推荐(作者:llsgllsg)" />
<local:MyComboBoxItem local:SettingService.Value="22" Content="Wallpaper 每日壁纸(作者:wzyaeu)" />
<local:MyComboBoxItem local:SettingService.Value="23" Content="Weather 天气预报(作者:wzyaeu)" />
<local:MyComboBoxItem local:SettingService.Value="24" Content="新一代狗屁王大杂烩主页(作者:llsgllsg)" />
</local:MyComboBox>
</Grid>
</StackPanel>
@@ -334,6 +337,7 @@
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="3" Text="版本管理" x:Name="CheckHiddenFunctionSelect" local:SettingService.Key="UiHiddenFunctionSelect" ToolTip="隐藏启动按钮下方的版本选择与版本设置入口。" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="4" Text="Mod 更新" x:Name="CheckHiddenFunctionModUpdate" local:SettingService.Key="UiHiddenFunctionModUpdate" ToolTip="禁止在 Mod 管理页面更新 Mod。" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="5" Text="功能隐藏" x:Name="CheckHiddenFunctionHidden" local:SettingService.Key="UiHiddenFunctionHidden" ToolTip="仅隐藏本选项卡,设置的禁用内容依然有效。&#xa;可以在保留个性化设置页面的情况下避免隐藏设置被修改。" />
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="4" Grid.Column="6" Text="版本修改" x:Name="CheckHiddenFunctionModify" local:SettingService.Key="UiHiddenFunctionInstanceModify" ToolTip="隐藏版本设置中的版本修改功能。" />
</Grid>
</StackPanel>
</local:MyCard>
@@ -306,19 +306,6 @@ Refresh:
"你可以在生成教学文件后直接刷新主页,对照着进行修改,更有助于理解。" & vbCrLf &
"直接将主页文件拖进 PCL 窗口也可以快捷加载。", "主页自定义教程")
End Sub
Private Sub BtnCustomOpen_Click(sender As Object, e As EventArgs) Handles BtnCustomOpen.Click
Try
Dim CustomPath As String = Paths.Base & "PCL\Custom.xaml"
If FileUtils.Exists(CustomPath) Then
OpenExplorer(CustomPath)
Else
OpenExplorer(Paths.Base & "PCL\")
Hint("未找到 Custom.xaml,已打开 PCL 文件夹。", HintType.Blue)
End If
Catch ex As Exception
Logger.Error(ex, "打开主页文件失败")
End Try
End Sub
Public Shared Sub OnMainPageTypeChanged()
If FrmSetupUI Is Nothing Then Return
Select Case CInt(Settings.Get(Of Integer)("UiCustomType"))
@@ -354,6 +341,14 @@ Refresh:
End Select
FrmSetupUI.CardCustom.TriggerForceResize()
End Sub
Private Sub BtnCustomFolder_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnCustomFolder.Click
Dim CustomPath As String = Paths.Base & "PCL\Custom.xaml"
If FileUtils.Exists(CustomPath) Then
OpenExplorer(CustomPath)
Else
OpenExplorer(Paths.Base & "PCL\")
End If
End Sub
'主题
Private Sub LabLauncherTheme5Unlock_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles LabLauncherTheme5Unlock.MouseLeftButtonUp
@@ -458,6 +453,10 @@ Refresh:
If FrmSetupUI IsNot Nothing Then
FrmSetupUI.CardSwitch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenFunctionHidden"), Visibility.Collapsed, Visibility.Visible)
End If
'版本设置子页面
If FrmInstanceLeft IsNot Nothing Then
FrmInstanceLeft.ItemModify.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenFunctionInstanceModify"), Visibility.Collapsed, Visibility.Visible)
End If
'设置子页面
If FrmSetupLeft IsNot Nothing Then
FrmSetupLeft.ItemLaunch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenSetupLaunch"), Visibility.Collapsed, Visibility.Visible)
@@ -158,6 +158,7 @@ Public Class Settings
New Setting("UiHiddenPageOther", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenFunctionSelect", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenFunctionModUpdate", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenFunctionInstanceModify", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenFunctionHidden", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenSetupLaunch", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
New Setting("UiHiddenSetupUi", False, OnChanged:=AddressOf PageSetupUI.HiddenRefresh),
@@ -93,7 +93,8 @@ Public Class PageSpeedLeft
Tb.Text = Loader.Error.GetDisplay(True)
AddHandler Tb.MouseLeftButtonDown,
Sub(sender As TextBlock, e As EventArgs)
ClipboardSet(sender.Text, SuccessHint:="已复制错误详情!")
ClipboardSet(sender.Text, False)
Hint("已复制错误详情!", HintType.Green)
End Sub
Card.Children.Add(Tb)
#End Region