diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index 527d412..0ee2dcf 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -1,4 +1,4 @@ -Imports System.IO.Compression +Imports System.IO.Compression Public Module ModLaunch @@ -236,15 +236,18 @@ NextInner: '正版购买提示 If Not Setup.Get("HintBuy") AndAlso Setup.Get("LoginType") <> McLoginType.Ms Then If IsSystemLanguageChinese() Then - Select Case Setup.Get("SystemLaunchCount") - Case 3, 8, 15, 30, 50, 70, 90, 110, 130, 180, 220, 280, 330, 380, 450, 550, 660, 750, 880, 950, 1100, 1300, 1500, 1700, 1900 - If MyMsgBox("你已经启动了 " & Setup.Get("SystemLaunchCount") & " 次 Minecraft 啦!" & vbCrLf & - "如果觉得 Minecraft 还不错,可以购买正版支持一下,毕竟开发游戏也真的很不容易……不要一直白嫖啦。" & vbCrLf & vbCrLf & - "在登录一次正版账号后,就不会再出现这个提示了!", - "考虑一下正版?", "支持正版游戏!", "下次一定") = 1 Then - OpenWebsite("https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj") - End If - End Select + RunInNewThread( + Sub() + Select Case Setup.Get("SystemLaunchCount") + Case 3, 8, 15, 30, 50, 70, 90, 110, 130, 180, 220, 280, 330, 380, 450, 550, 660, 750, 880, 950, 1100, 1300, 1500, 1700, 1900 + If MyMsgBox("你已经启动了 " & Setup.Get("SystemLaunchCount") & " 次 Minecraft 啦!" & vbCrLf & + "如果觉得 Minecraft 还不错,可以购买正版支持一下,毕竟开发游戏也真的很不容易……不要一直白嫖啦。" & vbCrLf & vbCrLf & + "在登录一次正版账号后,就不会再出现这个提示了!", + "考虑一下正版?", "支持正版游戏!", "下次一定") = 1 Then + OpenWebsite("https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj") + End If + End Select + End Sub, "Buy Minecraft") ElseIf Setup.Get("LoginType") = McLoginType.Legacy Then Select Case MyMsgBox("你必须先登录正版账号,才能进行离线登录!", "正版验证", "购买正版", "试玩", "返回", Button1Action:=Sub() OpenWebsite("https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj")) @@ -501,7 +504,7 @@ NextInner: #Region "分方式登录模块" '各个登录方式的主对象与输入构造 - Public McLoginMsLoader As New LoaderTask(Of McLoginMs, McLoginResult)("Loader Login Ms", AddressOf McLoginMsStart) + Public McLoginMsLoader As New LoaderTask(Of McLoginMs, McLoginResult)("Loader Login Ms", AddressOf McLoginMsStart) With {.ReloadTimeout = 1} Public McLoginLegacyLoader As New LoaderTask(Of McLoginLegacy, McLoginResult)("Loader Login Legacy", AddressOf McLoginLegacyStart) Public McLoginNideLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Nide", AddressOf McLoginServerStart) With {.ReloadTimeout = 1000 * 60 * 10} Public McLoginAuthLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Auth", AddressOf McLoginServerStart) With {.ReloadTimeout = 1000 * 60 * 10} @@ -629,7 +632,6 @@ LoginFinish: Dim Dict As New Dictionary(Of String, String) Dim Emails As New List(Of String) Dim Passwords As New List(Of String) - Try If Not Setup.Get("Login" & Input.Token & "Email") = "" Then Emails.AddRange(Setup.Get("Login" & Input.Token & "Email").ToString.Split("¨")) If Not Setup.Get("Login" & Input.Token & "Pass") = "" Then Passwords.AddRange(Setup.Get("Login" & Input.Token & "Pass").ToString.Split("¨")) @@ -697,205 +699,54 @@ LoginFinish: End Sub Private Sub McLoginRequestRefresh(ByRef Data As LoaderTask(Of McLoginServer, McLoginResult), RequestUser As Boolean) McLaunchLog("刷新登录开始(Refresh, " & Data.Input.Token & ")") - Dim LittleSkinAccess = Setup.Get("Cache" & Data.Input.Token & "APIToken") - Dim LittleSkinRefresh = Setup.Get("Cache" & Data.Input.Token & "Refresh") - Dim RefreshData As New JObject() - Dim UserName As String - Dim UUID As String - Dim AccessToken As String - Dim RefreshToken As String - Dim IDToken As String - Dim LoginJson As JObject - 'AccessToken 和 RefreshToken 都要有,不然没法刷新 - Dim Noth As Boolean = LittleSkinRefresh = "" - Dim Nls As Boolean = LittleSkinAccess = "" - Log(Noth.ToString, LogLevel.Debug) - Log(Nls.ToString, LogLevel.Debug) - If Not LittleSkinAccess = "" AndAlso Not LittleSkinRefresh = "" Then - RefreshData.Add(New JProperty("grant_type", "refresh_token")) - RefreshData.Add(New JProperty("refresh_token", LittleSkinRefresh)) - RefreshData.Add(New JProperty("access_token", LittleSkinAccess)) - RefreshData.Add(New JProperty("client_id", LittleSkinClientId)) - LoginJson = GetJson(NetRequestOnce( - Url:="https://open.littleskin.cn/oauth/token", - Method:="POST", - Data:=RefreshData, - Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh_CN"}}, - ContentType:="application/json; charset=utf-8")) - AccessToken = LoginJson("access_token").ToString(0) - RefreshToken = LoginJson("refresh_token").ToString(0) - IDToken = LoginJson("id_token").ToString(0) - Dim SelectPrpfile As String = Base64Decode(IDToken.Split(".")(1)) - UserName = GetJson(GetJson(SelectPrpfile)("selectedProfile").ToString)("name").ToString - UUID = GetJson(GetJson(SelectPrpfile)("selectedProfile").ToString)("id").ToString - Data.Output.Uuid = UUID - Data.Output.Name = UserName - Setup.Set("Cache" & Data.Input.Token & "Refresh", RefreshToken) - Setup.Set("Cache" & Data.Input.Token & "APIToken", AccessToken) - Else - Throw New Exception("登录信息无效") - End If - + Dim RefreshInfo As JObject = New JObject() RefreshInfo.Add(New JProperty("accessToken", Setup.Get("Cache" & Data.Input.Token & "Access"))) RefreshInfo.Add(New JProperty("requestUser", True)) - LoginJson = GetJson(NetRequestRetry( + Dim LoginJson As JObject = GetJson(NetRequestRetry( Url:=Data.Input.BaseUrl & "/refresh", Method:="POST", Data:=RefreshInfo.ToString(0), Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh-CN"}}, ContentType:="application/json; charset=utf-8")) '将登录结果输出 - If LoginJson("selectedProfile") Is Nothing Then Throw New Exception("选择的角色 " & Setup.Get("Cache" & Data.Input.Token & "Name") & " 无效!") Data.Output.AccessToken = LoginJson("accessToken").ToString Data.Output.ClientToken = LoginJson("clientToken").ToString + Data.Output.Uuid = LoginJson("selectedProfile")("id").ToString + Data.Output.Name = LoginJson("selectedProfile")("name").ToString Data.Output.Type = Data.Input.Token - If Data.Output.Uuid = LoginJson("selectedProfile")("id").ToString AndAlso Data.Output.Name = LoginJson("selectedProfile")("name").ToString Then - - Else - Data.Output.Uuid = LoginJson("selectedProfile")("id").ToString - Data.Output.Name = LoginJson("selectedProfile")("name").ToString - End If - '保存缓存 - Setup.Set("Cache" & Data.Input.Token & "Access", Data.Output.AccessToken) Setup.Set("Cache" & Data.Input.Token & "Client", Data.Output.ClientToken) Setup.Set("Cache" & Data.Input.Token & "Uuid", Data.Output.Uuid) Setup.Set("Cache" & Data.Input.Token & "Name", Data.Output.Name) - If Data.Input.UserName Is Nothing Then - ' 用一个通用字符模板填充内容 - Setup.Set("Cache" & Data.Input.Token & "Username", "LittleSkinOAuth 登录") - Setup.Set("Cache" & Data.Input.Token & "Pass", "LittleSkinOAuth 登录") - End If + Setup.Set("Cache" & Data.Input.Token & "Username", Data.Input.UserName) + Setup.Set("Cache" & Data.Input.Token & "Pass", Data.Input.Password) McLaunchLog("刷新登录成功(Refresh, " & Data.Input.Token & ")") - End Sub - - Private Function McLoginRequestLogin(ByRef Data As LoaderTask(Of McLoginServer, McLoginResult)) As Boolean Try Dim NeedRefresh As Boolean = False - Dim RequestData As New JObject() - Dim LittleSkinOAuth As Boolean = False - Dim LoginJson - Dim AccessToken As String - Dim RefreshToken As String - 'LittleSkin OAuth 登录检查 - - If Data.Input.BaseUrl.ToLower.Contains("littleskin.cn") And Not LittleSkinClientId = "" Then - 'ClientId - RequestData.Add(New JProperty("client_id", LittleSkinClientId)) - '一堆权限 - RequestData.Add(New JProperty("scope", "offline_access openid Yggdrasil.PlayerProfiles.Select Yggdrasil.MinecraftToken.Create")) - LittleSkinOAuth = True - Else - RequestData.Add(New JProperty("agent", New JObject(New JProperty("name", "Minecraft"), New JProperty("version", 1)))) - RequestData.Add(New JProperty("username", Data.Input.UserName)) - RequestData.Add(New JProperty("password", Data.Input.Password)) - RequestData.Add(New JProperty("requestUser", True)) - LittleSkinOAuth = False - End If - - ' LittleSkin OAuth 登录步骤 1: 获取授权代码 - If LittleSkinOAuth Then - McLaunchLog("开始 LittleSkin OAuth 登录步骤 1/3(原始登录)") - LoginJson = GetJson(NetRequestOnce( - Url:="https://open.littleskin.cn/oauth/device_code", - Method:="POST", - Data:=RequestData.ToString(0), - Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh_CN"}}, - ContentType:="application/json; charset=utf-8")) - Else - LoginJson = GetJson(NetRequestRetry( + McLaunchLog("登录开始(Login, " & Data.Input.Token & ")") + Dim RequestData As New JObject( + New JProperty("agent", New JObject(New JProperty("name", "Minecraft"), New JProperty("version", 1))), + New JProperty("username", Data.Input.UserName), + New JProperty("password", Data.Input.Password), + New JProperty("requestUser", True)) + Dim LoginJson As JObject = GetJson(NetRequestRetry( Url:=Data.Input.BaseUrl & "/authenticate", Method:="POST", Data:=RequestData.ToString(0), Headers:=New Dictionary(Of String, String) From {{"Accept-Language", "zh-CN"}}, ContentType:="application/json; charset=utf-8")) - - - End If '检查登录结果 - ' LittleSkin - If LittleSkinOAuth Then - ' 轮询验证 - '花了点时间改了逻辑。现在按照 OAuth 标准编写的服务端应该都能用这个处理轮询登录 - Dim Converter As New MyMsgBoxConverter With {.Content = LoginJson, .ForceWait = True, .Type = MyMsgBoxType.Login, .AuthUrl = "https://open.littleskin.cn/oauth/token"} - WaitingMyMsgBox.Add(Converter) - While Converter.Result Is Nothing - Thread.Sleep(100) - End While - Log(Converter.Result.ToString, LogLevel.Hint) - Log(Converter.Result.ToString, LogLevel.Debug) - 'LittleSkin OAuth 登录步骤 2: 获取用户选定档案 - McLaunchLog("LittleSkin OAuth 登录步骤 2/3") - '因为还有个 ID Token,硬编码只解析 AccessToken 和 RefreshToken - Dim Result = Converter.Result - Dim IDToken As String - AccessToken = Result("access_token") - RefreshToken = Result("refresh_token") - Dim ProfileData As New JObject() - Dim UserName As String - Dim UUID As String - ' IDToken 编码的档案 - ' 这一行不能用 Try Catch,否则后面解析会抛出 NullReferenceException - IDToken = Result("id_token") - Dim SelectProfile = GetJson(Base64Decode(IDToken.ToString.Split(".")(1)))("selectedProfile").ToString - UserName = GetJson(SelectProfile)("name") - UUID = GetJson(SelectProfile)("id") - - 'LittleSkin OAuth 登录步骤 3::获取 Minecraft AccessToken 启动令牌 - McLaunchLog("LittleSkin OAuth 登录步骤 3/3") - Dim RequestInfo = New JObject() - RequestInfo.Add(New JProperty("uuid", UUID)) - '需要 Yggdrasil.MinecraftToken.Create - Result = GetJson(NetRequestOnce(Url:=Data.Input.BaseUrl & "/oauth", - Method:="POST", - Data:=RequestInfo.ToString(0), - Headers:=New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}}, - ContentType:="application/json; charset=utf-8")) - - - - Dim ClientToken = Result("clientToken").ToString - Dim MCAccessToken = Result("accessToken").ToString - - McLaunchLog("LittleSkin OAuth 登录完成") - - Data.Output.AccessToken = MCAccessToken - Data.Output.ClientToken = ClientToken - Data.Output.Name = UserName - Data.Output.Uuid = UUID - Data.Output.Type = Data.Input.Token - - Setup.Set("Cache" & Data.Input.Token & "Access", Data.Output.AccessToken) - Setup.Set("Cache" & Data.Input.Token & "Refresh", RefreshToken) - Setup.Set("Cache" & Data.Input.Token & "Uuid", Data.Output.Uuid) - Setup.Set("Cache" & Data.Input.Token & "Name", Data.Output.Name) - '刷新需要 AccessToken 和 RefreshToken 配合使用 - 'Setup.Set("Cache" & Data.Input.Token & "Client", Data.Output.ClientToken) - Setup.Set("Cache" & Data.Input.Token & "APIToken", AccessToken) - If Data.Input.UserName Is Nothing AndAlso Data.Input.Password Is Nothing Then - Setup.Set("Cache" & Data.Input.Token & "Username", "LittleSkinOAuth 登录") - Setup.Set("Cache" & Data.Input.Token & "Pass", "LittleSkinOAuth 登录") - Else - Setup.Set("Cache" & Data.Input.Token & "Username", Data.Input.UserName) - Setup.Set("Cache" & Data.Input.Token & "Pass", Data.Input.Password) - End If - Return True - '原始登录 - Else - If LoginJson("availableProfiles").Count = 0 Then - If Data.Input.ForceReselectProfile Then Hint("你还没有创建角色, 无法更换!", HintType.Critical) - Throw New Exception("$你还没有创建角色, 请在创建角色后再试!") - ElseIf Data.Input.ForceReselectProfile AndAlso LoginJson("availableProfiles").Count = 1 Then - Hint("你的账户中只有一个角色, 无法更换!", HintType.Critical) - - End If - + If LoginJson("availableProfiles").Count = 0 Then + If Data.Input.ForceReselectProfile Then Hint("你还没有创建角色,无法更换!", HintType.Critical) + Throw New Exception("$你还没有创建角色,请在创建角色后再试!") + ElseIf Data.Input.ForceReselectProfile AndAlso LoginJson("availableProfiles").Count = 1 Then + Hint("你的账户中只有一个角色,无法更换!", HintType.Critical) End If Dim SelectedName As String = Nothing Dim SelectedId As String = Nothing @@ -907,7 +758,7 @@ LoginFinish: If Profile("id").ToString = CacheId Then SelectedName = Profile("name").ToString SelectedId = Profile("id").ToString - McLaunchLog("根据缓存选择的角色: " & SelectedName) + McLaunchLog("根据缓存选择的角色:" & SelectedName) End If Next '缓存无效,要求玩家选择 @@ -1023,8 +874,7 @@ Retry: ElseIf TypeOf Converter.Result Is Exception Then Throw CType(Converter.Result, Exception) Else - Dim LoginData = Converter.Result - Return {LoginData("access_token"), LoginData("refresh_token")} + Return Converter.Result End If End Function '微软登录步骤 1,刷新登录:从 OAuth Code 或 OAuth RefreshToken 获取 {OAuth AccessToken, OAuth RefreshToken} @@ -1044,10 +894,7 @@ Retry: End If End Try - - Dim ResultJson As JObject = GetJson(Result) - Dim AccessToken As String = ResultJson("access_token").ToString Dim RefreshToken As String = ResultJson("refresh_token").ToString Return {AccessToken, RefreshToken} @@ -1055,6 +902,7 @@ Retry: '微软登录步骤 2:从 OAuth AccessToken 获取 XBLToken Private Function MsLoginStep2(AccessToken As String) As String McLaunchLog("开始微软登录步骤 2/6") + Dim Request As String = "{ ""Properties"": { ""AuthMethod"": ""RPS"", @@ -2198,8 +2046,8 @@ IgnoreCustomSkin: "@echo off" & vbCrLf & "title 启动 - " & McVersionCurrent.Name & vbCrLf & "echo 游戏正在启动,请稍候。" & vbCrLf & - "set APPDATA=""" & PathMcFolder & """" & vbCrLf & - "cd /D """ & PathMcFolder & """" & vbCrLf & + "set APPDATA=""" & McVersionCurrent.PathIndie & """" & vbCrLf & + "cd /D """ & McVersionCurrent.PathIndie & """" & vbCrLf & CustomCommandGlobal & vbCrLf & CustomCommandVersion & vbCrLf & """" & McLaunchJavaSelected.PathJava & """ " & McLaunchArgument & vbCrLf &