PageLaunchLeft.xaml.vb 41 KB

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