PageLaunchLeft.xaml.vb 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. Imports System.Windows.Threading
  2. Public Class PageLaunchLeft
  3. '加载当前版本
  4. Private IsLoad As Boolean = False
  5. Private IsLoadFinished As Boolean = False
  6. Public Sub PageLaunchLeft_Loaded() Handles Me.Loaded
  7. If IsLoad Then RefreshPage(True, False)
  8. AprilPosTrans.X = 0
  9. AprilPosTrans.Y = 0
  10. If IsLoad Then Return
  11. IsLoad = True
  12. AniControlEnabled += 1
  13. '开始按钮
  14. AddHandler McInstanceListLoader.LoadingStateChanged, AddressOf RefreshButtonsUI
  15. AddHandler McFolderListLoader.LoadingStateChanged, AddressOf RefreshButtonsUI
  16. RefreshButtonsUI()
  17. '加载版本
  18. RunInNewThread(
  19. Sub()
  20. '自动整合包安装:准备
  21. Dim PackInstallPath As String = Nothing
  22. If FileUtils.Exists(Paths.Base & "modpack.zip") Then PackInstallPath = Paths.Base & "modpack.zip"
  23. If FileUtils.Exists(Paths.Base & "modpack.mrpack") Then PackInstallPath = Paths.Base & "modpack.mrpack"
  24. If PackInstallPath IsNot Nothing Then
  25. Logger.Warn($"需自动安装整合包:{PackInstallPath}")
  26. PageSelectLeft.CreateMcFolderInCurrentPath()
  27. McFolderListLoader.WaitForExit()
  28. End If
  29. '确认 Minecraft 文件夹存在
  30. If McFolderSelected = "" OrElse Not DirectoryUtils.Exists(McFolderSelected) Then
  31. '无效的文件夹
  32. If McFolderSelected = "" Then
  33. Logger.Info("没有已储存的 Minecraft 文件夹")
  34. Else
  35. Logger.Warn($"Minecraft 文件夹无效,该文件夹已不存在:{McFolderSelected}")
  36. End If
  37. McFolderListLoader.WaitForExit(IsForceRestart:=True)
  38. McFolderSelected = McFolderList.First.Location
  39. End If
  40. If Settings.Get(Of Boolean)("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000))
  41. '自动整合包安装
  42. If PackInstallPath IsNot Nothing Then
  43. Try
  44. Dim InstallLoader = ModpackInstall(PackInstallPath)
  45. Logger.Info($"自动安装整合包已开始:{PackInstallPath}")
  46. InstallLoader.WaitForExit()
  47. If InstallLoader.State = LoadState.Finished Then
  48. Logger.Info($"自动安装整合包成功,清理安装包:{PackInstallPath}")
  49. FileUtils.Delete(PackInstallPath)
  50. End If
  51. Catch ex As Exception
  52. If ex.IsCanceled Then
  53. Logger.Info($"自动安装整合包已取消:{PackInstallPath}")
  54. Else
  55. Logger.Error(ex, $"自动安装整合包失败:{PackInstallPath}", LogBehavior.Alert)
  56. End If
  57. End Try
  58. End If
  59. '确认 Minecraft 版本存在
  60. Dim Selection As String = ReadIni(McFolderSelected & "PCL.ini", "Version")
  61. Dim Instance As McInstance = If(Selection = "", Nothing, New McInstance(Selection))
  62. If Instance Is Nothing OrElse Not PathUtils.IsParentOf(McFolderSelected, Instance.PathVersion) OrElse Not Instance.Check() Then
  63. '无效的版本
  64. Logger.Info($"当前选择的 Minecraft 版本无效:{If(Instance Is Nothing, "null", Instance.PathVersion)}", If(IsNothing(Instance), LogBehavior.None, LogBehavior.ToastIfDebug))
  65. If Not McInstanceListLoader.State = LoadState.Finished Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True)
  66. If Not McInstanceList.Any() OrElse McInstanceList.First.Value(0).Logo.Contains("RedstoneBlock") Then
  67. Instance = Nothing
  68. Logger.Info("无可用 Minecraft 版本")
  69. Else
  70. Instance = McInstanceList.First.Value(0)
  71. Logger.Info($"自动选择 Minecraft 版本:{Instance.PathVersion}")
  72. End If
  73. End If
  74. RunInUi(
  75. Sub()
  76. McInstanceSelected = Instance '绕这一圈是为了避免 McVersionCheck 触发第二次版本改变
  77. IsLoadFinished = True
  78. RefreshButtonsUI()
  79. RefreshPage(False, False) '有可能选择的版本变化了,需要重新刷新
  80. If McLoginAble() = "" Then McLoginLoader.Start() '自动登录
  81. '用于自动化测试生成的程序是否可以正常运行
  82. If Environment.CommandLine.Contains("--test") Then
  83. RunInThread(
  84. Sub()
  85. Thread.Sleep(500)
  86. RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.Download))
  87. Thread.Sleep(500)
  88. RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadMod))
  89. Thread.Sleep(500)
  90. RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.Setup))
  91. Thread.Sleep(500)
  92. RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.Other))
  93. Thread.Sleep(500)
  94. RunInUi(Sub() BtnVersion_Click())
  95. Thread.Sleep(500)
  96. RunInUi(Sub() BtnMore_Click())
  97. Thread.Sleep(500)
  98. FormMain.EndProgramForce(123)
  99. End Sub)
  100. End If
  101. End Sub)
  102. End Sub, "Version Check", ThreadPriority.AboveNormal)
  103. '改变页面
  104. Dim LoginType = Settings.Get(Of McLoginType)("LoginType")
  105. If LoginType = McLoginType.Legacy OrElse LoginType = McLoginType.Ms Then CType(FindName("RadioLoginType" & LoginType), MyRadioButton).Checked = True
  106. RefreshPage(False, False)
  107. AniControlEnabled -= 1
  108. End Sub
  109. #Region "切换大页面"
  110. ''' <summary>
  111. ''' 切换至启动中页面。
  112. ''' </summary>
  113. Public Sub PageChangeToLaunching()
  114. '修改登陆方式
  115. Select Case Settings.Get(Of McLoginType)("LoginType")
  116. Case McLoginType.Legacy
  117. LabLaunchingMethod.Text = "离线登录"
  118. Case McLoginType.Ms
  119. LabLaunchingMethod.Text = "正版登录"
  120. Case McLoginType.Nide
  121. LabLaunchingMethod.Text = "统一通行证"
  122. Case McLoginType.Auth
  123. LabLaunchingMethod.Text = "Authlib-Injector"
  124. End Select
  125. '初始化页面
  126. LabLaunchingName.Text = McInstanceSelected.Name
  127. LabLaunchingStage.Text = "初始化"
  128. LabLaunchingTitle.Text = If(CurrentLaunchOptions?.SaveBatch Is Nothing, "正在启动游戏", "正在导出启动脚本")
  129. LabLaunchingProgress.Text = "0.00 %"
  130. LabLaunchingProgress.Opacity = 1
  131. LabLaunchingDownload.Visibility = Visibility.Visible
  132. LabLaunchingProgressLeft.Opacity = 0.6
  133. LabLaunchingDownload.Visibility = Visibility.Visible
  134. LabLaunchingDownload.Text = "0 B/s"
  135. LabLaunchingDownload.Opacity = 0
  136. LabLaunchingDownload.Visibility = Visibility.Collapsed
  137. LabLaunchingDownloadLeft.Opacity = 0
  138. LabLaunchingDownloadLeft.Visibility = Visibility.Collapsed
  139. ProgressLaunchingFinished.Width = New GridLength(0, GridUnitType.Star)
  140. ProgressLaunchingUnfinished.Width = New GridLength(1, GridUnitType.Star)
  141. PanLaunchingHint.Opacity = 0
  142. PanLaunchingHint.Visibility = Visibility.Collapsed
  143. PanLaunchingInfo.Width = Double.NaN '重置宽度改变动画
  144. McLaunchProcess = Nothing
  145. McLaunchWatcher = Nothing
  146. '获取 “你知道吗” 提示
  147. LabLaunchingHint.Text = PageOtherTest.GetRandomHint()
  148. '初始化其他页面
  149. PanInput.IsHitTestVisible = False
  150. PanLaunching.IsHitTestVisible = False
  151. LoadLaunching.State.LoadingState = MyLoading.MyLoadingState.Run
  152. PanLaunching.Visibility = Visibility.Visible
  153. AniStart({
  154. AaOpacity(PanInput, 0, 50), '略作延迟,这样如果预检测失败,不会出现奇怪的弹一下的动画
  155. AaOpacity(PanInput, -PanInput.Opacity, 110, , New AniEaseInFluent, True),
  156. AaScaleTransform(PanInput, 1.2 - CType(PanInput.RenderTransform, ScaleTransform).ScaleX, 160),
  157. AaOpacity(PanLaunching, 1 - PanLaunching.Opacity, 150, 100),
  158. AaScaleTransform(PanLaunching, 1 - CType(PanLaunching.RenderTransform, ScaleTransform).ScaleX, 500, 100, New AniEaseOutBack(AniEasePower.Weak)),
  159. AaCode(Sub() PanLaunching.IsHitTestVisible = True, 150)
  160. }, "Launch State Page")
  161. End Sub
  162. ''' <summary>
  163. ''' 切换至登录页面。
  164. ''' </summary>
  165. Public Sub PageChangeToLogin()
  166. PageGet(PageCurrent).Reload(KeepInput:=False)
  167. PanInput.IsHitTestVisible = False
  168. PanLaunching.IsHitTestVisible = False
  169. LoadLaunching.State.LoadingState = MyLoading.MyLoadingState.Stop
  170. PanInput.Visibility = Visibility.Visible
  171. AniStart({
  172. AaOpacity(PanLaunching, -PanLaunching.Opacity, 150),
  173. AaScaleTransform(PanLaunching, 0.8 - CType(PanLaunching.RenderTransform, ScaleTransform).ScaleX, 150,, New AniEaseOutFluent(AniEasePower.Weak)),
  174. AaOpacity(PanInput, 1 - PanInput.Opacity, 250, 50),
  175. AaScaleTransform(PanInput, 1 - CType(PanInput.RenderTransform, ScaleTransform).ScaleX, 300, 50, New AniEaseOutBack(AniEasePower.Weak)),
  176. AaCode(Sub() PanInput.IsHitTestVisible = True, 200)
  177. }, "Launch State Page", True)
  178. End Sub
  179. #End Region
  180. #Region "切换登录页面"
  181. Private Enum PageType
  182. None
  183. Legacy
  184. Nide
  185. NideSkin
  186. Auth
  187. AuthSkin
  188. Ms
  189. MsSkin
  190. End Enum
  191. ''' <summary>
  192. ''' 当前页面的种类。
  193. ''' </summary>
  194. Private PageCurrent As PageType = PageType.None
  195. Private Function PageGet(Type As PageType)
  196. Select Case Type
  197. Case PageType.Legacy
  198. If IsNothing(FrmLoginLegacy) Then FrmLoginLegacy = New PageLoginLegacy
  199. Return FrmLoginLegacy
  200. Case PageType.Nide
  201. If IsNothing(FrmLoginNide) Then FrmLoginNide = New PageLoginNide
  202. Return FrmLoginNide
  203. Case PageType.NideSkin
  204. If IsNothing(FrmLoginNideSkin) Then FrmLoginNideSkin = New PageLoginNideSkin
  205. Return FrmLoginNideSkin
  206. Case PageType.Auth
  207. If IsNothing(FrmLoginAuth) Then FrmLoginAuth = New PageLoginAuth
  208. Return FrmLoginAuth
  209. Case PageType.AuthSkin
  210. If IsNothing(FrmLoginAuthSkin) Then FrmLoginAuthSkin = New PageLoginAuthSkin
  211. Return FrmLoginAuthSkin
  212. Case PageType.Ms
  213. If IsNothing(FrmLoginMs) Then FrmLoginMs = New PageLoginMs
  214. Return FrmLoginMs
  215. Case PageType.MsSkin
  216. If IsNothing(FrmLoginMsSkin) Then FrmLoginMsSkin = New PageLoginMsSkin
  217. Return FrmLoginMsSkin
  218. Case Else
  219. Throw New ArgumentOutOfRangeException("Type", "即将切换的登录分页编号越界")
  220. End Select
  221. End Function
  222. ''' <summary>
  223. ''' 切换现有登录页面种类,返回新页面的实例。
  224. ''' </summary>
  225. ''' <param name="Type">新页面的种类。</param>
  226. ''' <param name="Anim">是否显示动画。</param>
  227. Private Function PageChange(Type As PageType, Anim As Boolean)
  228. Dim PageNew As Object = FrmLoginMs '初始化一个东西,避免在执行时出现异常导致雪崩
  229. Try
  230. #Region "确定更改的页面实例并实例化"
  231. If PageCurrent = Type Then Return PageNew
  232. PageNew = PageGet(Type)
  233. #End Region
  234. #Region "切换页面"
  235. AniStop("FrmLogin PageChange")
  236. '清除页面关联性
  237. If Not IsNothing(PageNew) AndAlso Not IsNothing(PageNew.Parent) Then PageNew.SetValue(ContentPresenter.ContentProperty, Nothing)
  238. If Anim Then
  239. '动画
  240. Dispatcher.Invoke(
  241. Sub()
  242. '执行动画
  243. AniStart({
  244. AaOpacity(PanLogin, -PanLogin.Opacity, 100,, New AniEaseOutFluent),
  245. AaCode(
  246. Sub()
  247. AniControlEnabled += 1
  248. PanLogin.Children.Clear()
  249. PanLogin.Children.Add(PageNew)
  250. AniControlEnabled -= 1
  251. End Sub, 100),
  252. AaOpacity(PanLogin, 1, 100, 120, New AniEaseInFluent)
  253. }, "FrmLogin PageChange")
  254. End Sub, DispatcherPriority.Render)
  255. Else
  256. '无动画
  257. AniControlEnabled += 1
  258. PanLogin.Children.Clear()
  259. PanLogin.Children.Add(PageNew)
  260. AniControlEnabled -= 1
  261. End If
  262. #End Region
  263. PageCurrent = Type
  264. Return PageNew
  265. Catch ex As Exception
  266. Logger.Error(ex, $"切换登录分页失败({Type})")
  267. Return PageNew
  268. End Try
  269. End Function
  270. ''' <summary>
  271. ''' 确认当前显示的子页面正确,并刷新该页面。
  272. ''' </summary>
  273. Public Sub RefreshPage(KeepInput As Boolean, Anim As Boolean)
  274. '获取页面的可用种类并回写缓存
  275. Dim Type As PageType
  276. Dim LoginPageType As Integer
  277. If McInstanceSelected IsNot Nothing Then
  278. LoginPageType = Settings.Get(Of Integer)("VersionServerLogin", Instance:=McInstanceSelected)
  279. '缓存当前版本的页面种类,下一次打开 McInstanceSelected 为空时才能加载出正确的页面
  280. Settings.Set("LoginPageType", LoginPageType)
  281. Else
  282. LoginPageType = Settings.Get(Of Integer)("LoginPageType")
  283. End If
  284. '旧版本的第三方登录设置在此版本中回到微软/离线选择。
  285. If LoginPageType < 0 OrElse LoginPageType > 2 Then LoginPageType = 0
  286. Select Case LoginPageType
  287. Case 0 '正版或离线
  288. UnknownType:
  289. If RadioLoginType5.Checked Then
  290. If Settings.Get(Of String)("CacheMsV2Access") = "" Then
  291. Type = PageType.Ms
  292. Else
  293. Type = PageType.MsSkin
  294. End If
  295. Settings.Set("LoginType", McLoginType.Ms)
  296. Else
  297. Type = PageType.Legacy
  298. Settings.Set("LoginType", McLoginType.Legacy)
  299. End If
  300. PanType.Visibility = Visibility.Visible
  301. PanTypeOne.Visibility = Visibility.Collapsed
  302. RadioLoginType5.Visibility = Visibility.Visible
  303. RadioLoginType0.Visibility = Visibility.Visible
  304. Case 1 '仅正版
  305. If Settings.Get(Of String)("CacheMsV2Access") = "" Then
  306. Type = PageType.Ms
  307. Else
  308. Type = PageType.MsSkin
  309. End If
  310. Settings.Set("LoginType", McLoginType.Ms)
  311. PanType.Visibility = Visibility.Collapsed
  312. PanTypeOne.Visibility = Visibility.Visible
  313. PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonShield)
  314. LabTypeOne.Text = "正版登录"
  315. RadioLoginType5.Visibility = Visibility.Visible
  316. RadioLoginType0.Visibility = Visibility.Collapsed
  317. Case 2 '仅离线
  318. Type = PageType.Legacy
  319. Settings.Set("LoginType", McLoginType.Legacy)
  320. PanType.Visibility = Visibility.Collapsed
  321. PanTypeOne.Visibility = Visibility.Visible
  322. PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonOffline)
  323. LabTypeOne.Text = "离线登录"
  324. Case Else
  325. Logger.Error($"未知的登录页面:{LoginPageType}", LogBehavior.Toast)
  326. GoTo UnknownType
  327. End Select
  328. '刷新页面
  329. If PageCurrent = Type Then Return
  330. PageChange(Type, Anim).Reload(KeepInput)
  331. Dim Control As MyRadioButton = FindName("RadioLoginType" & Settings.Get(Of McLoginType)("LoginType"))
  332. If Control IsNot Nothing Then Control.Checked = True
  333. End Sub
  334. Private Sub RadioLoginType_Change(sender As Object, raiseByMouse As Boolean) Handles RadioLoginType0.Check, RadioLoginType5.Check
  335. If raiseByMouse Then RefreshPage(True, True)
  336. End Sub
  337. #End Region
  338. #Region "皮肤"
  339. '微软正版皮肤
  340. Public Shared SkinMs As New LoaderTask(Of (String, String), String)("Loader Skin Ms", AddressOf SkinMsLoad, AddressOf SkinMsInput, ThreadPriority.AboveNormal)
  341. Private Shared Function SkinMsInput() As (String, String)
  342. '获取名称
  343. Return (Settings.Get(Of String)("CacheMsV2Name"), Settings.Get(Of String)("CacheMsV2Uuid"))
  344. End Function
  345. Private Shared Sub SkinMsLoad(Data As LoaderTask(Of (String, String), String))
  346. Data.Output = PathImage & "Skins/" & McSkinSex(If(Data.Input.Item2, "")) & ".png"
  347. RunInUi(Sub() If FrmLoginMsSkin IsNot Nothing Then FrmLoginMsSkin.Skin.Load())
  348. End Sub
  349. '离线皮肤
  350. Public Shared SkinLegacy As New LoaderTask(Of (String, String), String)("Loader Skin Legacy", AddressOf SkinLegacyLoad, AddressOf SkinLegacyInput, ThreadPriority.AboveNormal)
  351. Private Shared Function SkinLegacyInput() As (String, String)
  352. '根据类型判断输入
  353. Dim Type As Integer = Settings.Get(Of Integer)("LaunchSkinType")
  354. Select Case Type
  355. Case 0
  356. If FrmLoginLegacy?.IsReloaded Then
  357. Return ("0", If(FrmLoginLegacy.ComboName.Text.Trim, ""))
  358. ElseIf Settings.Get(Of String)("LoginLegacyName") = "" Then
  359. Return ("0", "")
  360. Else
  361. Return ("0", If(Settings.Get(Of String)("LoginLegacyName").ToString.BeforeFirst("¨"), ""))
  362. End If
  363. Case 3
  364. Return ("3", Settings.Get(Of String)("LaunchSkinID"))
  365. Case Else
  366. Return (Type.ToString, "")
  367. End Select
  368. End Function
  369. Private Shared Sub SkinLegacyLoad(Data As LoaderTask(Of (String, String), String))
  370. '清空已有皮肤
  371. RunInUi(Sub() If FrmLoginLegacy IsNot Nothing AndAlso FrmLoginLegacy.Skin IsNot Nothing Then FrmLoginLegacy.Skin.Clear())
  372. '获取 Url
  373. Select Case CInt(Data.Input.Item1)
  374. Case 0 '默认
  375. Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(Data.Input.Item2)) & ".png"
  376. Case 1 'Steve
  377. UseDefault:
  378. Data.Output = PathImage & "Skins/Steve.png"
  379. Case 2 'Alex
  380. Data.Output = PathImage & "Skins/Alex.png"
  381. Case 3 '正版
  382. Dim ID As String = Data.Input.Item2
  383. Try
  384. If ID.Count < 2 Then
  385. Data.Output = PathImage & "Skins/Steve.png"
  386. Else
  387. Dim Result As String = McLoginMojangUuid(ID, True)
  388. If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & ID)
  389. Result = McSkinGetAddress(Result, "Mojang")
  390. If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & ID)
  391. Result = McSkinDownload(Result)
  392. If Data.IsCanceled Then Throw New OperationCanceledException("当前任务已取消:" & ID)
  393. Data.Output = Result
  394. End If
  395. Catch ex As Exception
  396. If ex.IsCanceled Then
  397. Data.Output = ""
  398. Return
  399. ElseIf ex.GetDisplay(False).Contains("(429)") Then
  400. Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(ID)) & ".png"
  401. Logger.Info($"获取离线登录使用的正版皮肤失败({ID}):获取皮肤太过频繁,请 5 分钟后再试!")
  402. Else
  403. Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(ID)) & ".png"
  404. Logger.Warn(ex, $"获取离线登录使用的正版皮肤失败({ID})")
  405. End If
  406. End Try
  407. Case 4 '自定义
  408. If Not FileUtils.Exists(Paths.AppDataThenName & "CustomSkin.png") Then
  409. Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL 将使用默认的 Steve 皮肤!")
  410. Settings.Set("LaunchSkinType", 1)
  411. GoTo UseDefault
  412. End If
  413. Data.Output = Paths.AppDataThenName & "CustomSkin.png"
  414. End Select
  415. '刷新显示
  416. If FrmLoginLegacy IsNot Nothing Then
  417. RunInUi(AddressOf FrmLoginLegacy.Skin.Load)
  418. ElseIf Not Data.IsCanceled Then '如果已经中断,Input 也被清空,就不会再次刷新
  419. Data.Input = Nothing '清空输入,因为皮肤实际上没有被渲染,如果不清空切换到页面的 Start 会由于输入相同而不渲染
  420. End If
  421. End Sub
  422. '统一通行证皮肤
  423. Public Shared SkinNide As New LoaderTask(Of (String, String), String)("Loader Skin Nide", AddressOf SkinNideLoad, AddressOf SkinNideInput, ThreadPriority.AboveNormal)
  424. Private Shared Function SkinNideInput() As (String, String)
  425. '获取名称
  426. Return (Settings.Get(Of String)("CacheNideName"), Settings.Get(Of String)("CacheNideUuid"))
  427. End Function
  428. Private Shared Sub SkinNideLoad(Data As LoaderTask(Of (String, String), String))
  429. Data.Output = PathImage & "Skins/" & McSkinSex(If(Data.Input.Item2, "")) & ".png"
  430. RunInUi(Sub() If FrmLoginNideSkin IsNot Nothing Then FrmLoginNideSkin.Skin.Load())
  431. End Sub
  432. 'Authlib-Injector 皮肤
  433. Public Shared SkinAuth As New LoaderTask(Of (String, String), String)("Loader Skin Auth", AddressOf SkinAuthLoad, AddressOf SkinAuthInput, ThreadPriority.AboveNormal)
  434. Private Shared Function SkinAuthInput() As (String, String)
  435. '获取名称
  436. Return (Settings.Get(Of String)("CacheAuthName"), Settings.Get(Of String)("CacheAuthUuid"))
  437. End Function
  438. Private Shared Sub SkinAuthLoad(Data As LoaderTask(Of (String, String), String))
  439. Data.Output = PathImage & "Skins/" & McSkinSex(If(Data.Input.Item2, "")) & ".png"
  440. RunInUi(Sub() If FrmLoginAuthSkin IsNot Nothing Then FrmLoginAuthSkin.Skin.Load())
  441. End Sub
  442. '全部皮肤加载器
  443. '需要放在其中元素的后面,否则会因为它提前被加载而莫名其妙变成 Nothing
  444. Public Shared SkinLoaders As New List(Of LoaderTask(Of (String, String), String)) From {SkinMs, SkinLegacy, SkinNide, SkinAuth}
  445. #End Region
  446. '版本选择按钮
  447. Private Sub BtnVersion_Click() Handles BtnVersion.Click
  448. If McLaunchLoader.State = LoadState.Loading Then Return
  449. FrmMain.PageChange(FormMain.PageType.InstanceSelect)
  450. End Sub
  451. '启动按钮
  452. Public Sub LaunchButtonClick() Handles BtnLaunch.Click
  453. If McLaunchLoader.State = LoadState.Loading OrElse Not BtnLaunch.IsEnabled OrElse
  454. (FrmMain.PageRight IsNot Nothing AndAlso FrmMain.PageRight.PageState <> MyPageRight.PageStates.ContentStay AndAlso FrmMain.PageRight.PageState <> MyPageRight.PageStates.ContentEnter) Then Return
  455. '愚人节处理
  456. If IsAprilEnabled AndAlso Not IsAprilGiveup Then
  457. ThemeUnlock(12, False, "隐藏主题 滑稽彩 已解锁!")
  458. IsAprilGiveup = True
  459. Settings.Set("AprilYear", Date.Now.Year)
  460. FrmLaunchLeft.AprilScaleTrans.ScaleX = 1
  461. FrmLaunchLeft.AprilScaleTrans.ScaleY = 1
  462. FrmLaunchLeft.AprilPosTrans.X = 0
  463. FrmLaunchLeft.AprilPosTrans.Y = 0
  464. FrmMain.BtnExtraApril.ShowRefresh()
  465. End If
  466. '实际的启动
  467. If BtnLaunch.Text = "启动游戏" Then
  468. McLaunchStart()
  469. ElseIf BtnLaunch.Text = "下载游戏" Then
  470. FrmMain.PageChange(FormMain.PageType.Download, FormMain.PageSubType.DownloadInstall)
  471. End If
  472. End Sub
  473. Private BtnLaunchState As Integer = 0
  474. Private BtnLaunchInstance As McInstance = Nothing
  475. Public Sub RefreshButtonsUI() Handles BtnLaunch.Loaded
  476. If Not BtnLaunch.IsLoaded Then Return
  477. '获取当前状态
  478. Dim CurrentState As Integer
  479. If (Not IsLoadFinished) OrElse McInstanceListLoader.State = LoadState.Loading OrElse McFolderListLoader.State = LoadState.Loading Then
  480. CurrentState = 0
  481. Else
  482. If McInstanceSelected Is Nothing Then
  483. If Settings.Get(Of Boolean)("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow Then
  484. CurrentState = 1
  485. Else
  486. CurrentState = 2
  487. End If
  488. Else
  489. CurrentState = 3
  490. End If
  491. End If
  492. '更新状态
  493. If CurrentState = BtnLaunchState AndAlso
  494. If(McInstanceSelected Is Nothing, "", McInstanceSelected.PathVersion) = If(BtnLaunchInstance Is Nothing, "", BtnLaunchInstance.PathVersion) Then GoTo ExitRefresh
  495. BtnLaunchInstance = McInstanceSelected
  496. BtnLaunchState = CurrentState
  497. Select Case CurrentState
  498. Case 0
  499. Logger.Info("启动按钮:正在加载 Minecraft 版本")
  500. FrmLaunchLeft.BtnLaunch.Text = "正在加载"
  501. FrmLaunchLeft.BtnLaunch.IsEnabled = False
  502. FrmLaunchLeft.LabVersion.Text = "正在加载中,请稍候"
  503. FrmLaunchLeft.BtnVersion.IsEnabled = False
  504. FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed
  505. Case 1
  506. Logger.Info("启动按钮:无 Minecraft 版本,下载已禁用")
  507. FrmLaunchLeft.BtnLaunch.Text = "启动游戏"
  508. FrmLaunchLeft.BtnLaunch.IsEnabled = False
  509. FrmLaunchLeft.LabVersion.Text = "未找到可用的游戏版本"
  510. FrmLaunchLeft.BtnVersion.IsEnabled = True
  511. FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed
  512. Case 2
  513. Logger.Info("启动按钮:无 Minecraft 版本,要求下载")
  514. FrmLaunchLeft.BtnLaunch.Text = "下载游戏"
  515. FrmLaunchLeft.BtnLaunch.IsEnabled = True
  516. FrmLaunchLeft.LabVersion.Text = "未找到可用的游戏版本"
  517. FrmLaunchLeft.BtnVersion.IsEnabled = True
  518. FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed
  519. Case 3
  520. Logger.Info($"启动按钮:Minecraft 版本:{McInstanceSelected.PathVersion}")
  521. FrmLaunchLeft.BtnLaunch.Text = "启动游戏"
  522. FrmLaunchLeft.BtnVersion.IsEnabled = True
  523. FrmLaunchLeft.BtnLaunch.IsEnabled = True
  524. FrmLaunchLeft.LabVersion.Text = McInstanceSelected.Name
  525. 'FrmLaunchLeft.BtnMore.Visibility = Visibility.Visible '由功能隐藏设置修改
  526. End Select
  527. ExitRefresh:
  528. '功能隐藏
  529. FrmLaunchLeft.BtnVersion.Visibility = If(Not PageSetupUI.HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenFunctionSelect"), Visibility.Collapsed, Visibility.Visible)
  530. If CurrentState = 3 Then
  531. FrmLaunchLeft.BtnMore.Visibility = FrmLaunchLeft.BtnVersion.Visibility
  532. End If
  533. End Sub
  534. '取消按钮
  535. Public Sub BtnCancel_Click() Handles BtnCancel.Click
  536. If McLaunchLoaderReal IsNot Nothing Then
  537. McLaunchLoaderReal.Cancel()
  538. McLaunchLog("已取消启动")
  539. Try
  540. If McLaunchWatcher IsNot Nothing Then
  541. McLaunchWatcher.Kill()
  542. ElseIf McLaunchProcess IsNot Nothing Then
  543. If Not McLaunchProcess.HasExited Then McLaunchProcess.Kill()
  544. End If
  545. Catch ex As Exception
  546. Logger.Error(ex, "取消启动结束进程失败", LogBehavior.Toast)
  547. End Try
  548. End If
  549. End Sub
  550. '版本设置按钮
  551. Private Sub BtnMore_Click() Handles BtnMore.Click
  552. If McLaunchLoader.State = LoadState.Loading Then Return
  553. If McInstanceLock.IsLocked(McInstanceSelected) Then
  554. Hint("该版本正在被修改,暂时无法进入版本设置!", HintType.Red)
  555. Return
  556. End If
  557. McInstanceSelected.Load()
  558. PageInstanceLeft.Instance = McInstanceSelected
  559. FrmMain.PageChange(FormMain.PageType.InstanceSetup, 0)
  560. End Sub
  561. ''' <summary>
  562. ''' 每 0.1s 执行一次,刷新启动的数据 UI 显示。
  563. ''' </summary>
  564. Public Sub LaunchingRefresh()
  565. Try
  566. If McLaunchLoaderReal.State = LoadState.Canceled Then Return
  567. '阶段状态获取
  568. Dim IsLaunched As Boolean = False '是否已经启动游戏,只是在等待窗口
  569. Try
  570. For Each Loader In McLaunchLoaderReal.GetLoaderList(False)
  571. If Loader.State = LoadState.Loading OrElse Loader.State = LoadState.Waiting Then
  572. LabLaunchingStage.Text = Loader.Name
  573. IsLaunched = Loader.Name = "等待游戏窗口出现" OrElse Loader.Name = "结束处理"
  574. Exit Try
  575. End If
  576. Next
  577. LabLaunchingStage.Text = "已完成"
  578. Catch ex As Exception
  579. Logger.Warn(ex, "获取是否启动完成失败,可能是由于启动状态改变导致集合已修改")
  580. Return
  581. End Try
  582. LabLaunchingTitle.Text = If(IsLaunched OrElse McLaunchLoaderReal.State = LoadState.Finished,
  583. "已启动游戏",
  584. If(CurrentLaunchOptions.SaveBatch Is Nothing, "正在启动游戏", "正在导出启动脚本"))
  585. If AniIsRun("Launch State Page") Then IsLaunched = False '等待页面切换动画完成
  586. '更新进度
  587. Dim ActualProgress = McLaunchLoaderReal.Progress
  588. If ActualProgress >= ShowProgress Then ShowProgress += (ActualProgress - ShowProgress) * 0.1 + 0.0025 '向实际进度靠一点
  589. If ActualProgress <= ShowProgress Then ShowProgress = ActualProgress '原来或处理后变得比实际进度高,直接回退
  590. If IsLaunched Then ShowProgress = 1 '如果已经完成了,就不卖关子了
  591. LabLaunchingProgress.Text = (ShowProgress * 100).ToString("0.00") & " %"
  592. '更新下载速度
  593. Dim HasLaunchDownloader As Boolean = False
  594. Try
  595. If NetManager.Speed = 0 AndAlso LabLaunchingDownload.Visibility = Visibility.Collapsed Then
  596. '可能只是在检查文件,没有实际下载
  597. HasLaunchDownloader = False
  598. Else
  599. For Each Loader In NetManager.Tasks
  600. If Loader.RealParent IsNot Nothing AndAlso Loader.RealParent.Name = "Minecraft 启动" AndAlso Loader.State = LoadState.Loading Then HasLaunchDownloader = True
  601. Next
  602. End If
  603. Catch ex As Exception
  604. Logger.Warn(ex, "获取 Minecraft 启动下载器失败,可能是因为启动被取消")
  605. HasLaunchDownloader = False
  606. End Try
  607. LabLaunchingDownload.Text = StringUtils.FormatByteSize(NetManager.Speed) & "/s"
  608. '进度改变动画
  609. Dim AnimList As New List(Of AniData) From {
  610. AaGridLengthWidth(ProgressLaunchingFinished, ShowProgress - ProgressLaunchingFinished.Width.Value, 130,, New AniEaseOutFluent),
  611. AaGridLengthWidth(ProgressLaunchingUnfinished, 1 - ShowProgress - ProgressLaunchingUnfinished.Width.Value, 130,, New AniEaseOutFluent)
  612. }
  613. If HasLaunchDownloader = (LabLaunchingDownload.Visibility = Visibility.Collapsed) Then 'IsDownloadStateChanged
  614. LabLaunchingDownload.Visibility = Visibility.Visible
  615. LabLaunchingDownloadLeft.Visibility = Visibility.Visible
  616. AnimList.AddRange({
  617. AaOpacity(LabLaunchingDownload, If(HasLaunchDownloader, 1, 0) - LabLaunchingDownload.Opacity, 90),
  618. AaOpacity(LabLaunchingDownloadLeft, If(HasLaunchDownloader, 0.5, 0) - LabLaunchingDownloadLeft.Opacity, 90),
  619. AaCode(
  620. Sub()
  621. If Not HasLaunchDownloader Then
  622. LabLaunchingDownload.Visibility = Visibility.Collapsed
  623. LabLaunchingDownloadLeft.Visibility = Visibility.Collapsed
  624. End If
  625. End Sub, 110)
  626. })
  627. End If
  628. If (Not IsLaunched) = (LabLaunchingProgress.Visibility = Visibility.Collapsed) Then 'IsProgressStateChanged
  629. LabLaunchingProgress.Visibility = Visibility.Visible
  630. LabLaunchingProgressLeft.Visibility = Visibility.Visible
  631. If IsLaunched Then PanLaunchingHint.Visibility = Visibility.Visible
  632. AnimList.AddRange({
  633. AaOpacity(LabLaunchingProgress, If(Not IsLaunched, 1, 0) - LabLaunchingProgress.Opacity, 90),
  634. AaOpacity(LabLaunchingProgressLeft, If(Not IsLaunched, 0.5, 0) - LabLaunchingProgressLeft.Opacity, 90),
  635. AaOpacity(PanLaunchingHint, If(IsLaunched, 1, 0) - PanLaunchingHint.Opacity, 90)
  636. })
  637. End If
  638. AniStart(AnimList, "Launching Progress")
  639. Catch ex As Exception
  640. Logger.Error(ex, "刷新启动信息失败")
  641. End Try
  642. End Sub
  643. Private ShowProgress As Double = 0
  644. '尺寸改变动画
  645. Private IsWidthAnimating As Boolean = False
  646. Private ActualUsedWidth As Double
  647. Private Sub PanLaunchingInfo_SizeChangedW(sender As Object, e As SizeChangedEventArgs) Handles PanLaunchingInfo.SizeChanged
  648. Dim DeltaWidth As Double = e.NewSize.Width - e.PreviousSize.Width
  649. If e.PreviousSize.Width = 0 OrElse IsWidthAnimating OrElse Math.Abs(DeltaWidth) < 1 OrElse PanLaunchingInfo.ActualWidth = 0 Then Return
  650. AniStart({
  651. AaWidth(PanLaunchingInfo, DeltaWidth, 180,, New AniEaseOutFluent),
  652. AaCode(Sub()
  653. IsWidthAnimating = False
  654. PanLaunchingInfo.Width = ActualUsedWidth
  655. End Sub,, True)
  656. }, "Launching Info Width")
  657. IsWidthAnimating = True
  658. ActualUsedWidth = PanLaunchingInfo.Width
  659. PanLaunchingInfo.Width = e.PreviousSize.Width
  660. End Sub
  661. Private IsHeightAnimating As Boolean = False
  662. Private ActualUsedHeight As Double
  663. Private Sub PanLaunchingInfo_SizeChangedH(sender As Object, e As SizeChangedEventArgs) Handles PanLaunchingInfo.SizeChanged
  664. Dim DeltaHeight As Double = e.NewSize.Height - e.PreviousSize.Height
  665. If e.PreviousSize.Height = 0 OrElse IsHeightAnimating OrElse Math.Abs(DeltaHeight) < 1 OrElse PanLaunchingInfo.ActualHeight = 0 Then Return
  666. AniStart({
  667. AaHeight(PanLaunchingInfo, DeltaHeight, 180,, New AniEaseOutFluent),
  668. AaCode(Sub()
  669. IsHeightAnimating = False
  670. PanLaunchingInfo.Height = ActualUsedHeight
  671. End Sub,, True)
  672. }, "Launching Info Height")
  673. IsHeightAnimating = True
  674. ActualUsedHeight = PanLaunchingInfo.Height
  675. PanLaunchingInfo.Height = e.PreviousSize.Height
  676. End Sub
  677. End Class