728 lines
48 KiB
VB.net
728 lines
48 KiB
VB.net
''' <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
|