PageLaunchLeft.xaml.vb 42 KB

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