PageLaunchLeft.xaml.vb 42 KB

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