Files
PCL/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb
T
2026-10-17 03:39:13 +08:00

838 lines
43 KiB
VB.net
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Imports System.Windows.Threading
Public Class PageLaunchLeft
'加载当前版本
Private IsLoad As Boolean = False
Private IsLoadFinished As Boolean = False
Public Sub PageLaunchLeft_Loaded() Handles Me.Loaded
If IsLoad Then RefreshPage(True, False)
AprilPosTrans.X = 0
AprilPosTrans.Y = 0
If IsLoad Then Return
IsLoad = True
AniControlEnabled += 1
'开始按钮
AddHandler McInstanceListLoader.LoadingStateChanged, AddressOf RefreshButtonsUI
AddHandler McFolderListLoader.LoadingStateChanged, AddressOf RefreshButtonsUI
RefreshButtonsUI()
'加载版本
RunInNewThread(
Sub()
'自动整合包安装:准备
Dim PackInstallPath As String = Nothing
If FileUtils.Exists(Paths.Base & "modpack.zip") Then PackInstallPath = Paths.Base & "modpack.zip"
If FileUtils.Exists(Paths.Base & "modpack.mrpack") Then PackInstallPath = Paths.Base & "modpack.mrpack"
If PackInstallPath IsNot Nothing Then
Logger.Warn($"需自动安装整合包:{PackInstallPath}")
PageSelectLeft.CreateMcFolderInCurrentPath()
McFolderListLoader.WaitForExit()
End If
'确认 Minecraft 文件夹存在
If McFolderSelected = "" OrElse Not DirectoryUtils.Exists(McFolderSelected) Then
'无效的文件夹
If McFolderSelected = "" Then
Logger.Info("没有已储存的 Minecraft 文件夹")
Else
Logger.Warn($"Minecraft 文件夹无效,该文件夹已不存在:{McFolderSelected}")
End If
McFolderListLoader.WaitForExit(IsForceRestart:=True)
McFolderSelected = McFolderList.First.Location
End If
If Settings.Get(Of Boolean)("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
'自动整合包安装
If PackInstallPath IsNot Nothing Then
Try
Dim InstallLoader = ModpackInstall(PackInstallPath)
Logger.Info($"自动安装整合包已开始:{PackInstallPath}")
InstallLoader.WaitForExit()
If InstallLoader.State = LoadState.Finished Then
Logger.Info($"自动安装整合包成功,清理安装包:{PackInstallPath}")
FileUtils.Delete(PackInstallPath)
End If
Catch ex As Exception
If ex.IsCanceled Then
Logger.Info($"自动安装整合包已取消:{PackInstallPath}")
Else
Logger.Error(ex, $"自动安装整合包失败:{PackInstallPath}", LogBehavior.Alert)
End If
End Try
End If
'确认 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 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)
If Not McInstanceList.Any() OrElse McInstanceList.First.Value(0).Logo.Contains("RedstoneBlock") Then
Instance = Nothing
Logger.Info("无可用 Minecraft 版本")
Else
Instance = McInstanceList.First.Value(0)
Logger.Info($"自动选择 Minecraft 版本:{Instance.PathVersion}")
End If
End If
RunInUi(
Sub()
McInstanceSelected = Instance '绕这一圈是为了避免 McVersionCheck 触发第二次版本改变
IsLoadFinished = True
RefreshButtonsUI()
RefreshPage(False, False) '有可能选择的版本变化了,需要重新刷新
If McLoginAble() = "" Then McLoginLoader.Start() '自动登录
'用于自动化测试生成的程序是否可以正常运行
If Environment.CommandLine.Contains("--test") Then
RunInThread(
Sub()
Thread.Sleep(500)
RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.Download))
Thread.Sleep(500)
RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadMod))
Thread.Sleep(500)
RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.Setup))
Thread.Sleep(500)
RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.Other))
Thread.Sleep(500)
RunInUi(Sub() BtnVersion_Click())
Thread.Sleep(500)
RunInUi(Sub() BtnMore_Click())
Thread.Sleep(500)
FormMain.EndProgramForce(123)
End Sub)
End If
End Sub)
End Sub, "Version Check", ThreadPriority.AboveNormal)
'改变页面
Dim LoginType = Settings.Get(Of McLoginType)("LoginType")
If LoginType = McLoginType.Legacy OrElse LoginType = McLoginType.Ms Then CType(FindName("RadioLoginType" & LoginType), MyRadioButton).Checked = True
RefreshPage(False, False)
AniControlEnabled -= 1
End Sub
#Region "切换大页面"
''' <summary>
''' 切换至启动中页面。
''' </summary>
Public Sub PageChangeToLaunching()
'修改登陆方式
Select Case Settings.Get(Of McLoginType)("LoginType")
Case McLoginType.Legacy
LabLaunchingMethod.Text = "离线登录"
Case McLoginType.Ms
LabLaunchingMethod.Text = "正版登录"
Case McLoginType.Nide
LabLaunchingMethod.Text = "统一通行证"
Case McLoginType.Auth
LabLaunchingMethod.Text = "Authlib-Injector"
End Select
'初始化页面
LabLaunchingName.Text = McInstanceSelected.Name
LabLaunchingStage.Text = "初始化"
LabLaunchingTitle.Text = If(CurrentLaunchOptions?.SaveBatch Is Nothing, "正在启动游戏", "正在导出启动脚本")
LabLaunchingProgress.Text = "0.00 %"
LabLaunchingProgress.Opacity = 1
LabLaunchingDownload.Visibility = Visibility.Visible
LabLaunchingProgressLeft.Opacity = 0.6
LabLaunchingDownload.Visibility = Visibility.Visible
LabLaunchingDownload.Text = "0 B/s"
LabLaunchingDownload.Opacity = 0
LabLaunchingDownload.Visibility = Visibility.Collapsed
LabLaunchingDownloadLeft.Opacity = 0
LabLaunchingDownloadLeft.Visibility = Visibility.Collapsed
ProgressLaunchingFinished.Width = New GridLength(0, GridUnitType.Star)
ProgressLaunchingUnfinished.Width = New GridLength(1, GridUnitType.Star)
PanLaunchingHint.Opacity = 0
PanLaunchingHint.Visibility = Visibility.Collapsed
PanLaunchingInfo.Width = Double.NaN '重置宽度改变动画
McLaunchProcess = Nothing
McLaunchWatcher = Nothing
'获取 “你知道吗” 提示
LabLaunchingHint.Text = PageOtherTest.GetRandomHint()
'初始化其他页面
PanInput.IsHitTestVisible = False
PanLaunching.IsHitTestVisible = False
LoadLaunching.State.LoadingState = MyLoading.MyLoadingState.Run
PanLaunching.Visibility = Visibility.Visible
AniStart({
AaOpacity(PanInput, 0, 50), '略作延迟,这样如果预检测失败,不会出现奇怪的弹一下的动画
AaOpacity(PanInput, -PanInput.Opacity, 110, , New AniEaseInFluent, True),
AaScaleTransform(PanInput, 1.2 - CType(PanInput.RenderTransform, ScaleTransform).ScaleX, 160),
AaOpacity(PanLaunching, 1 - PanLaunching.Opacity, 150, 100),
AaScaleTransform(PanLaunching, 1 - CType(PanLaunching.RenderTransform, ScaleTransform).ScaleX, 500, 100, New AniEaseOutBack(AniEasePower.Weak)),
AaCode(Sub() PanLaunching.IsHitTestVisible = True, 150)
}, "Launch State Page")
End Sub
''' <summary>
''' 切换至登录页面。
''' </summary>
Public Sub PageChangeToLogin()
PageGet(PageCurrent).Reload(KeepInput:=False)
PanInput.IsHitTestVisible = False
PanLaunching.IsHitTestVisible = False
LoadLaunching.State.LoadingState = MyLoading.MyLoadingState.Stop
PanInput.Visibility = Visibility.Visible
AniStart({
AaOpacity(PanLaunching, -PanLaunching.Opacity, 150),
AaScaleTransform(PanLaunching, 0.8 - CType(PanLaunching.RenderTransform, ScaleTransform).ScaleX, 150,, New AniEaseOutFluent(AniEasePower.Weak)),
AaOpacity(PanInput, 1 - PanInput.Opacity, 250, 50),
AaScaleTransform(PanInput, 1 - CType(PanInput.RenderTransform, ScaleTransform).ScaleX, 300, 50, New AniEaseOutBack(AniEasePower.Weak)),
AaCode(Sub() PanInput.IsHitTestVisible = True, 200)
}, "Launch State Page", True)
End Sub
#End Region
#Region "切换登录页面"
Private Enum PageType
None
Legacy
Nide
NideSkin
Auth
AuthSkin
Ms
MsSkin
End Enum
''' <summary>
''' 当前页面的种类。
''' </summary>
Private PageCurrent As PageType = PageType.None
Private Function PageGet(Type As PageType)
Select Case Type
Case PageType.Legacy
If IsNothing(FrmLoginLegacy) Then FrmLoginLegacy = New PageLoginLegacy
Return FrmLoginLegacy
Case PageType.Nide
If IsNothing(FrmLoginNide) Then FrmLoginNide = New PageLoginNide
Return FrmLoginNide
Case PageType.NideSkin
If IsNothing(FrmLoginNideSkin) Then FrmLoginNideSkin = New PageLoginNideSkin
Return FrmLoginNideSkin
Case PageType.Auth
If IsNothing(FrmLoginAuth) Then FrmLoginAuth = New PageLoginAuth
Return FrmLoginAuth
Case PageType.AuthSkin
If IsNothing(FrmLoginAuthSkin) Then FrmLoginAuthSkin = New PageLoginAuthSkin
Return FrmLoginAuthSkin
Case PageType.Ms
If IsNothing(FrmLoginMs) Then FrmLoginMs = New PageLoginMs
Return FrmLoginMs
Case PageType.MsSkin
If IsNothing(FrmLoginMsSkin) Then FrmLoginMsSkin = New PageLoginMsSkin
Return FrmLoginMsSkin
Case Else
Throw New ArgumentOutOfRangeException("Type", "即将切换的登录分页编号越界")
End Select
End Function
''' <summary>
''' 切换现有登录页面种类,返回新页面的实例。
''' </summary>
''' <param name="Type">新页面的种类。</param>
''' <param name="Anim">是否显示动画。</param>
Private Function PageChange(Type As PageType, Anim As Boolean)
Dim PageNew As Object = FrmLoginMs '初始化一个东西,避免在执行时出现异常导致雪崩
Try
#Region "确定更改的页面实例并实例化"
If PageCurrent = Type Then Return PageNew
PageNew = PageGet(Type)
#End Region
#Region "切换页面"
AniStop("FrmLogin PageChange")
'清除页面关联性
If Not IsNothing(PageNew) AndAlso Not IsNothing(PageNew.Parent) Then PageNew.SetValue(ContentPresenter.ContentProperty, Nothing)
If Anim Then
'动画
Dispatcher.Invoke(
Sub()
'执行动画
AniStart({
AaOpacity(PanLogin, -PanLogin.Opacity, 100,, New AniEaseOutFluent),
AaCode(
Sub()
AniControlEnabled += 1
PanLogin.Children.Clear()
PanLogin.Children.Add(PageNew)
AniControlEnabled -= 1
End Sub, 100),
AaOpacity(PanLogin, 1, 100, 120, New AniEaseInFluent)
}, "FrmLogin PageChange")
End Sub, DispatcherPriority.Render)
Else
'无动画
AniControlEnabled += 1
PanLogin.Children.Clear()
PanLogin.Children.Add(PageNew)
AniControlEnabled -= 1
End If
#End Region
PageCurrent = Type
Return PageNew
Catch ex As Exception
Logger.Error(ex, $"切换登录分页失败({Type})")
Return PageNew
End Try
End Function
''' <summary>
''' 确认当前显示的子页面正确,并刷新该页面。
''' </summary>
Public Sub RefreshPage(KeepInput As Boolean, Anim As Boolean)
'获取页面的可用种类并回写缓存
Dim Type As PageType
Dim LoginPageType As Integer
If McInstanceSelected IsNot Nothing Then
LoginPageType = Settings.Get(Of Integer)("VersionServerLogin", Instance:=McInstanceSelected)
'缓存当前版本的页面种类,下一次打开 McInstanceSelected 为空时才能加载出正确的页面
Settings.Set("LoginPageType", LoginPageType)
Else
LoginPageType = Settings.Get(Of Integer)("LoginPageType")
End If
Select Case LoginPageType
Case 0 '正版或离线
UnknownType:
If RadioLoginType5.Checked Then
If Settings.Get(Of String)("CacheMsV2Access") = "" Then
Type = PageType.Ms
Else
Type = PageType.MsSkin
End If
Settings.Set("LoginType", McLoginType.Ms)
Else
Type = PageType.Legacy
Settings.Set("LoginType", McLoginType.Legacy)
End If
PanType.Visibility = Visibility.Visible
PanTypeOne.Visibility = Visibility.Collapsed
RadioLoginType5.Visibility = Visibility.Visible
RadioLoginType0.Visibility = Visibility.Visible
Case 1 '仅正版
If Settings.Get(Of String)("CacheMsV2Access") = "" Then
Type = PageType.Ms
Else
Type = PageType.MsSkin
End If
Settings.Set("LoginType", McLoginType.Ms)
PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonShield)
LabTypeOne.Text = "正版登录"
RadioLoginType5.Visibility = Visibility.Visible
RadioLoginType0.Visibility = Visibility.Collapsed
Case 2 '仅离线
Type = PageType.Legacy
Settings.Set("LoginType", McLoginType.Legacy)
PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonOffline)
LabTypeOne.Text = "离线登录"
Case 3 '统一通行证
If Settings.Get(Of String)("CacheNideAccess") = "" Then
Type = PageType.Nide
Else
Type = PageType.NideSkin
End If
Settings.Set("LoginType", McLoginType.Nide)
PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonCard)
LabTypeOne.Text = "统一通行证登录"
Case 4 'Authlib-Injector
If Settings.Get(Of String)("CacheAuthAccess") = "" Then
Type = PageType.Auth
Else
Type = PageType.AuthSkin
End If
Settings.Set("LoginType", McLoginType.Auth)
PanType.Visibility = Visibility.Collapsed
PanTypeOne.Visibility = Visibility.Visible
PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonCard)
LabTypeOne.Text = If(McInstanceSelected Is Nothing, Settings.Get(Of String)("CacheAuthServerName"), Settings.Get(Of String)("VersionServerAuthName", Instance:=McInstanceSelected))
If LabTypeOne.Text = "" Then LabTypeOne.Text = "第三方登录"
Case Else
Logger.Error($"未知的登录页面:{LoginPageType}", LogBehavior.Toast)
GoTo UnknownType
End Select
'刷新页面
If PageCurrent = Type Then Return
PageChange(Type, Anim).Reload(KeepInput)
Dim Control As MyRadioButton = FindName("RadioLoginType" & Settings.Get(Of McLoginType)("LoginType"))
If Control IsNot Nothing Then Control.Checked = True
End Sub
Private Sub RadioLoginType_Change(sender As Object, raiseByMouse As Boolean) Handles RadioLoginType0.Check, RadioLoginType5.Check
If raiseByMouse Then RefreshPage(True, True)
End Sub
#End Region
#Region "皮肤"
'微软正版皮肤
Public Shared SkinMs As New LoaderTask(Of (String, String), String)("Loader Skin Ms", AddressOf SkinMsLoad, AddressOf SkinMsInput, ThreadPriority.AboveNormal)
Private Shared Function SkinMsInput() As (String, String)
'获取名称
Return (Settings.Get(Of String)("CacheMsV2Name"), Settings.Get(Of String)("CacheMsV2Uuid"))
End Function
Private Shared Sub SkinMsLoad(Data As LoaderTask(Of (String, String), String))
'清空已有皮肤
'如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载
RunInUi(Sub() If FrmLoginMsSkin IsNot Nothing AndAlso FrmLoginMsSkin.Skin IsNot Nothing Then FrmLoginMsSkin.Skin.Clear())
'获取 Url
Dim UserName As String = Data.Input.Item1
Dim Uuid As String = Data.Input.Item2
If UserName = "" Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Logger.Info("获取微软正版皮肤失败,ID 为空")
GoTo Finish
End If
Try
Dim Result As String = McSkinGetAddress(Uuid, "Ms")
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & UserName)
Result = McSkinDownload(Result)
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & UserName)
Data.Output = Result
Catch ex As Exception
If ex.IsCanceled Then
Data.Output = ""
Return
ElseIf ex.GetDisplay(False).Contains("(429)") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Logger.Error($"获取正版皮肤失败({UserName}):获取皮肤太过频繁,请 5 分钟后再试!", LogBehavior.Toast)
ElseIf ex.GetDisplay(False).Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Logger.Info("用户未设置自定义皮肤,跳过皮肤加载")
Else
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Logger.Error(ex, $"获取微软正版皮肤失败({UserName})", LogBehavior.Toast)
End If
End Try
Finish:
'刷新显示
If FrmLoginMsSkin IsNot Nothing Then
RunInUi(AddressOf FrmLoginMsSkin.Skin.Load)
ElseIf Not Data.IsCanceled Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If
End Sub
'离线皮肤
Public Shared SkinLegacy As New LoaderTask(Of (String, String), String)("Loader Skin Legacy", AddressOf SkinLegacyLoad, AddressOf SkinLegacyInput, ThreadPriority.AboveNormal)
Private Shared Function SkinLegacyInput() As (String, String)
'根据类型判断输入
Dim Type As Integer = Settings.Get(Of Integer)("LaunchSkinType")
Select Case Type
Case 0
If FrmLoginLegacy?.IsReloaded Then
Return ("0", If(FrmLoginLegacy.ComboName.Text.Trim, ""))
ElseIf Settings.Get(Of String)("LoginLegacyName") = "" Then
Return ("0", "")
Else
Return ("0", If(Settings.Get(Of String)("LoginLegacyName").ToString.BeforeFirst("¨"), ""))
End If
Case 3
Return ("3", Settings.Get(Of String)("LaunchSkinID"))
Case Else
Return (Type.ToString, "")
End Select
End Function
Private Shared Sub SkinLegacyLoad(Data As LoaderTask(Of (String, String), String))
'清空已有皮肤
RunInUi(Sub() If FrmLoginLegacy IsNot Nothing AndAlso FrmLoginLegacy.Skin IsNot Nothing Then FrmLoginLegacy.Skin.Clear())
'获取 Url
Select Case CInt(Data.Input.Item1)
Case 0 '默认
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(Data.Input.Item2)) & ".png"
Case 1 'Steve
UseDefault:
Data.Output = PathImage & "Skins/Steve.png"
Case 2 'Alex
Data.Output = PathImage & "Skins/Alex.png"
Case 3 '正版
Dim ID As String = Data.Input.Item2
Try
If ID.Count < 2 Then
Data.Output = PathImage & "Skins/Steve.png"
Else
Dim Result As String = McLoginMojangUuid(ID, True)
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & ID)
Result = McSkinGetAddress(Result, "Mojang")
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & ID)
Result = McSkinDownload(Result)
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & ID)
Data.Output = Result
End If
Catch ex As Exception
If ex.IsCanceled Then
Data.Output = ""
Return
ElseIf ex.GetDisplay(False).Contains("(429)") Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(ID)) & ".png"
Logger.Info($"获取离线登录使用的正版皮肤失败({ID}):获取皮肤太过频繁,请 5 分钟后再试!")
Else
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(ID)) & ".png"
Logger.Warn(ex, $"获取离线登录使用的正版皮肤失败({ID})")
End If
End Try
Case 4 '自定义
If Not FileUtils.Exists(Paths.AppDataThenName & "CustomSkin.png") Then
Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL 将使用默认的 Steve 皮肤!")
Settings.Set("LaunchSkinType", 1)
GoTo UseDefault
End If
Data.Output = Paths.AppDataThenName & "CustomSkin.png"
End Select
'刷新显示
If FrmLoginLegacy IsNot Nothing Then
RunInUi(AddressOf FrmLoginLegacy.Skin.Load)
ElseIf Not Data.IsCanceled Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If
End Sub
'统一通行证皮肤
Public Shared SkinNide As New LoaderTask(Of (String, String), String)("Loader Skin Nide", AddressOf SkinNideLoad, AddressOf SkinNideInput, ThreadPriority.AboveNormal)
Private Shared Function SkinNideInput() As (String, String)
'获取名称
Return (Settings.Get(Of String)("CacheNideName"), Settings.Get(Of String)("CacheNideUuid"))
End Function
Private Shared Sub SkinNideLoad(Data As LoaderTask(Of (String, String), String))
'清空已有皮肤
'如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载
RunInUi(Sub() If FrmLoginNideSkin IsNot Nothing AndAlso FrmLoginNideSkin.Skin IsNot Nothing Then FrmLoginNideSkin.Skin.Clear())
'获取 Url
Dim UserName As String = Data.Input.Item1
Dim Uuid As String = Data.Input.Item2
If UserName = "" Then
Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png"
Logger.Info("获取统一通行证皮肤失败,ID 为空")
GoTo Finish
End If
Try
Dim Result As String = McSkinGetAddress(Uuid, "Nide")
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & UserName)
Result = McSkinDownload(Result)
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & UserName)
Data.Output = Result
Catch ex As Exception
If ex.IsCanceled Then
Data.Output = ""
Return
ElseIf ex.GetDisplay(False).Contains("(429)") Then
Data.Output = PathImage & "Skins/Steve.png"
Logger.Error($"获取统一通行证皮肤失败({UserName}):获取皮肤太过频繁,请 5 分钟后再试!", LogBehavior.Toast)
ElseIf ex.GetDisplay(False).Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/Steve.png"
Logger.Info("用户未设置自定义皮肤,跳过皮肤加载")
Else
Data.Output = PathImage & "Skins/Steve.png"
Logger.Error(ex, $"获取统一通行证皮肤失败({UserName})", LogBehavior.Toast)
End If
End Try
Finish:
'刷新显示
If FrmLoginNideSkin IsNot Nothing Then
RunInUi(AddressOf FrmLoginNideSkin.Skin.Load)
ElseIf Not Data.IsCanceled Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If
End Sub
'Authlib-Injector 皮肤
Public Shared SkinAuth As New LoaderTask(Of (String, String), String)("Loader Skin Auth", AddressOf SkinAuthLoad, AddressOf SkinAuthInput, ThreadPriority.AboveNormal)
Private Shared Function SkinAuthInput() As (String, String)
'获取名称
Return (Settings.Get(Of String)("CacheAuthName"), Settings.Get(Of String)("CacheAuthUuid"))
End Function
Private Shared Sub SkinAuthLoad(Data As LoaderTask(Of (String, String), String))
'清空已有皮肤
'如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载
RunInUi(Sub() If FrmLoginAuthSkin IsNot Nothing AndAlso FrmLoginAuthSkin.Skin IsNot Nothing Then FrmLoginAuthSkin.Skin.Clear())
'获取 Url
Dim UserName As String = Data.Input.Item1
Dim UUID As String = Data.Input.Item2
If UserName = "" Then
Data.Output = PathImage & "Skins/Steve.png"
Logger.Info("获取 Authlib-Injector 皮肤失败,ID 为空")
GoTo Finish
End If
Try
Dim Result As String = McSkinGetAddress(UUID, "Auth")
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & UserName)
Result = McSkinDownload(Result)
If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & UserName)
Data.Output = Result
Catch ex As Exception
If ex.IsCanceled Then
Data.Output = ""
Return
ElseIf ex.GetDisplay(False).Contains("(429)") Then
Data.Output = PathImage & "Skins/Steve.png"
Logger.Error($"获取 Authlib-Injector 皮肤失败({UserName}):获取皮肤太过频繁,请 5 分钟后再试!", LogBehavior.Toast)
ElseIf ex.GetDisplay(False).Contains("未设置自定义皮肤") Then
Data.Output = PathImage & "Skins/Steve.png"
Logger.Info("用户未设置自定义皮肤,跳过皮肤加载")
Else
Data.Output = PathImage & "Skins/Steve.png"
Logger.Error(ex, $"获取 Authlib-Injector 皮肤失败({UserName})", LogBehavior.Toast)
End If
End Try
Finish:
'刷新显示
If FrmLoginAuthSkin IsNot Nothing Then
RunInUi(AddressOf FrmLoginAuthSkin.Skin.Load)
ElseIf Not Data.IsCanceled Then '如果已经中断,Input 也被清空,就不会再次刷新
Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
End If
End Sub
'全部皮肤加载器
'需要放在其中元素的后面,否则会因为它提前被加载而莫名其妙变成 Nothing
Public Shared SkinLoaders As New List(Of LoaderTask(Of (String, String), String)) From {SkinMs, SkinLegacy, SkinNide, SkinAuth}
#End Region
'版本选择按钮
Private Sub BtnVersion_Click() Handles BtnVersion.Click
If McLaunchLoader.State = LoadState.Loading Then Return
FrmMain.PageChange(FormMain.PageType.InstanceSelect)
End Sub
'启动按钮
Public Sub LaunchButtonClick() Handles BtnLaunch.Click
If McLaunchLoader.State = LoadState.Loading OrElse Not BtnLaunch.IsEnabled OrElse
(FrmMain.PageRight IsNot Nothing AndAlso FrmMain.PageRight.PageState <> MyPageRight.PageStates.ContentStay AndAlso FrmMain.PageRight.PageState <> MyPageRight.PageStates.ContentEnter) Then Return
'愚人节处理
If IsAprilEnabled AndAlso Not IsAprilGiveup Then
ThemeUnlock(12, False, "隐藏主题 滑稽彩 已解锁!")
IsAprilGiveup = True
Settings.Set("AprilYear", Date.Now.Year)
FrmLaunchLeft.AprilScaleTrans.ScaleX = 1
FrmLaunchLeft.AprilScaleTrans.ScaleY = 1
FrmLaunchLeft.AprilPosTrans.X = 0
FrmLaunchLeft.AprilPosTrans.Y = 0
FrmMain.BtnExtraApril.ShowRefresh()
End If
'实际的启动
If BtnLaunch.Text = "启动游戏" Then
McLaunchStart()
ElseIf BtnLaunch.Text = "下载游戏" Then
FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
End If
End Sub
Private BtnLaunchState As Integer = 0
Private BtnLaunchInstance As McInstance = Nothing
Public Sub RefreshButtonsUI() Handles BtnLaunch.Loaded
If Not BtnLaunch.IsLoaded Then Return
'获取当前状态
Dim CurrentState As Integer
If (Not IsLoadFinished) OrElse McInstanceListLoader.State = LoadState.Loading OrElse McFolderListLoader.State = LoadState.Loading Then
CurrentState = 0
Else
If McInstanceSelected Is Nothing Then
If Settings.Get(Of Boolean)("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow Then
CurrentState = 1
Else
CurrentState = 2
End If
Else
CurrentState = 3
End If
End If
'更新状态
If CurrentState = BtnLaunchState AndAlso
If(McInstanceSelected Is Nothing, "", McInstanceSelected.PathVersion) = If(BtnLaunchInstance Is Nothing, "", BtnLaunchInstance.PathVersion) Then GoTo ExitRefresh
BtnLaunchInstance = McInstanceSelected
BtnLaunchState = CurrentState
Select Case CurrentState
Case 0
Logger.Info("启动按钮:正在加载 Minecraft 版本")
FrmLaunchLeft.BtnLaunch.Text = "正在加载"
FrmLaunchLeft.BtnLaunch.IsEnabled = False
FrmLaunchLeft.LabVersion.Text = "正在加载中,请稍候"
FrmLaunchLeft.BtnVersion.IsEnabled = False
FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed
Case 1
Logger.Info("启动按钮:无 Minecraft 版本,下载已禁用")
FrmLaunchLeft.BtnLaunch.Text = "启动游戏"
FrmLaunchLeft.BtnLaunch.IsEnabled = False
FrmLaunchLeft.LabVersion.Text = "未找到可用的游戏版本"
FrmLaunchLeft.BtnVersion.IsEnabled = True
FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed
Case 2
Logger.Info("启动按钮:无 Minecraft 版本,要求下载")
FrmLaunchLeft.BtnLaunch.Text = "下载游戏"
FrmLaunchLeft.BtnLaunch.IsEnabled = True
FrmLaunchLeft.LabVersion.Text = "未找到可用的游戏版本"
FrmLaunchLeft.BtnVersion.IsEnabled = True
FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed
Case 3
Logger.Info($"启动按钮:Minecraft 版本:{McInstanceSelected.PathVersion}")
FrmLaunchLeft.BtnLaunch.Text = "启动游戏"
FrmLaunchLeft.BtnVersion.IsEnabled = True
FrmLaunchLeft.BtnLaunch.IsEnabled = True
FrmLaunchLeft.LabVersion.Text = McInstanceSelected.Name
'FrmLaunchLeft.BtnMore.Visibility = Visibility.Visible '由功能隐藏设置修改
End Select
ExitRefresh:
'功能隐藏
FrmLaunchLeft.BtnVersion.Visibility = If(Not PageSetupUI.HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenFunctionSelect"), Visibility.Collapsed, Visibility.Visible)
If CurrentState = 3 Then
FrmLaunchLeft.BtnMore.Visibility = FrmLaunchLeft.BtnVersion.Visibility
End If
End Sub
'取消按钮
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)
End Sub
''' <summary>
''' 每 0.1s 执行一次,刷新启动的数据 UI 显示。
''' </summary>
Public Sub LaunchingRefresh()
Try
If McLaunchLoaderReal.State = LoadState.Canceled Then Return
'阶段状态获取
Dim IsLaunched As Boolean = False '是否已经启动游戏,只是在等待窗口
Try
For Each Loader In McLaunchLoaderReal.GetLoaderList(False)
If Loader.State = LoadState.Loading OrElse Loader.State = LoadState.Waiting Then
LabLaunchingStage.Text = Loader.Name
IsLaunched = Loader.Name = "等待游戏窗口出现" OrElse Loader.Name = "结束处理"
Exit Try
End If
Next
LabLaunchingStage.Text = "已完成"
Catch ex As Exception
Logger.Warn(ex, "获取是否启动完成失败,可能是由于启动状态改变导致集合已修改")
Return
End Try
LabLaunchingTitle.Text = If(IsLaunched OrElse McLaunchLoaderReal.State = LoadState.Finished,
"已启动游戏",
If(CurrentLaunchOptions.SaveBatch Is Nothing, "正在启动游戏", "正在导出启动脚本"))
If AniIsRun("Launch State Page") Then IsLaunched = False '等待页面切换动画完成
'更新进度
Dim ActualProgress = McLaunchLoaderReal.Progress
If ActualProgress >= ShowProgress Then ShowProgress += (ActualProgress - ShowProgress) * 0.1 + 0.0025 '向实际进度靠一点
If ActualProgress <= ShowProgress Then ShowProgress = ActualProgress '原来或处理后变得比实际进度高,直接回退
If IsLaunched Then ShowProgress = 1 '如果已经完成了,就不卖关子了
LabLaunchingProgress.Text = (ShowProgress * 100).ToString("0.00") & " %"
'更新下载速度
Dim HasLaunchDownloader As Boolean = False
Try
If NetManager.Speed = 0 AndAlso LabLaunchingDownload.Visibility = Visibility.Collapsed Then
'可能只是在检查文件,没有实际下载
HasLaunchDownloader = False
Else
For Each Loader In NetManager.Tasks
If Loader.RealParent IsNot Nothing AndAlso Loader.RealParent.Name = "Minecraft 启动" AndAlso Loader.State = LoadState.Loading Then HasLaunchDownloader = True
Next
End If
Catch ex As Exception
Logger.Warn(ex, "获取 Minecraft 启动下载器失败,可能是因为启动被取消")
HasLaunchDownloader = False
End Try
LabLaunchingDownload.Text = StringUtils.FormatByteSize(NetManager.Speed) & "/s"
'进度改变动画
Dim AnimList As New List(Of AniData) From {
AaGridLengthWidth(ProgressLaunchingFinished, ShowProgress - ProgressLaunchingFinished.Width.Value, 130,, New AniEaseOutFluent),
AaGridLengthWidth(ProgressLaunchingUnfinished, 1 - ShowProgress - ProgressLaunchingUnfinished.Width.Value, 130,, New AniEaseOutFluent)
}
If HasLaunchDownloader = (LabLaunchingDownload.Visibility = Visibility.Collapsed) Then 'IsDownloadStateChanged
LabLaunchingDownload.Visibility = Visibility.Visible
LabLaunchingDownloadLeft.Visibility = Visibility.Visible
AnimList.AddRange({
AaOpacity(LabLaunchingDownload, If(HasLaunchDownloader, 1, 0) - LabLaunchingDownload.Opacity, 90),
AaOpacity(LabLaunchingDownloadLeft, If(HasLaunchDownloader, 0.5, 0) - LabLaunchingDownloadLeft.Opacity, 90),
AaCode(
Sub()
If Not HasLaunchDownloader Then
LabLaunchingDownload.Visibility = Visibility.Collapsed
LabLaunchingDownloadLeft.Visibility = Visibility.Collapsed
End If
End Sub, 110)
})
End If
If (Not IsLaunched) = (LabLaunchingProgress.Visibility = Visibility.Collapsed) Then 'IsProgressStateChanged
LabLaunchingProgress.Visibility = Visibility.Visible
LabLaunchingProgressLeft.Visibility = Visibility.Visible
If IsLaunched Then PanLaunchingHint.Visibility = Visibility.Visible
AnimList.AddRange({
AaOpacity(LabLaunchingProgress, If(Not IsLaunched, 1, 0) - LabLaunchingProgress.Opacity, 90),
AaOpacity(LabLaunchingProgressLeft, If(Not IsLaunched, 0.5, 0) - LabLaunchingProgressLeft.Opacity, 90),
AaOpacity(PanLaunchingHint, If(IsLaunched, 1, 0) - PanLaunchingHint.Opacity, 90)
})
End If
AniStart(AnimList, "Launching Progress")
Catch ex As Exception
Logger.Error(ex, "刷新启动信息失败")
End Try
End Sub
Private ShowProgress As Double = 0
'尺寸改变动画
Private IsWidthAnimating As Boolean = False
Private ActualUsedWidth As Double
Private Sub PanLaunchingInfo_SizeChangedW(sender As Object, e As SizeChangedEventArgs) Handles PanLaunchingInfo.SizeChanged
Dim DeltaWidth As Double = e.NewSize.Width - e.PreviousSize.Width
If e.PreviousSize.Width = 0 OrElse IsWidthAnimating OrElse Math.Abs(DeltaWidth) < 1 OrElse PanLaunchingInfo.ActualWidth = 0 Then Return
AniStart({
AaWidth(PanLaunchingInfo, DeltaWidth, 180,, New AniEaseOutFluent),
AaCode(Sub()
IsWidthAnimating = False
PanLaunchingInfo.Width = ActualUsedWidth
End Sub,, True)
}, "Launching Info Width")
IsWidthAnimating = True
ActualUsedWidth = PanLaunchingInfo.Width
PanLaunchingInfo.Width = e.PreviousSize.Width
End Sub
Private IsHeightAnimating As Boolean = False
Private ActualUsedHeight As Double
Private Sub PanLaunchingInfo_SizeChangedH(sender As Object, e As SizeChangedEventArgs) Handles PanLaunchingInfo.SizeChanged
Dim DeltaHeight As Double = e.NewSize.Height - e.PreviousSize.Height
If e.PreviousSize.Height = 0 OrElse IsHeightAnimating OrElse Math.Abs(DeltaHeight) < 1 OrElse PanLaunchingInfo.ActualHeight = 0 Then Return
AniStart({
AaHeight(PanLaunchingInfo, DeltaHeight, 180,, New AniEaseOutFluent),
AaCode(Sub()
IsHeightAnimating = False
PanLaunchingInfo.Height = ActualUsedHeight
End Sub,, True)
}, "Launching Info Height")
IsHeightAnimating = True
ActualUsedHeight = PanLaunchingInfo.Height
PanLaunchingInfo.Height = e.PreviousSize.Height
End Sub
End Class