From dbffe737e9895927fc444d52699411c44da32e4c Mon Sep 17 00:00:00 2001 From: YIJANGs <153354935+YIJANGs@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:51:13 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E5=BB=B6=E9=95=BFToken=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index 5b7b43f..1775842 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -544,7 +544,7 @@ NextInner: '检查是否已经登录完成 If Not Data.IsForceRestarting AndAlso '不要求强行重启 Input.AccessToken <> "" AndAlso '已经登录过了 - (McLoginMsRefreshTime > 0 AndAlso GetTimeMs() - McLoginMsRefreshTime < 1000 * 60 * 10) Then '完成时间在 10 分钟内 + (McLoginMsRefreshTime > 0 AndAlso GetTimeMs() - McLoginMsRefreshTime < 1000 * 60 * 60 * 5) Then '完成时间在 5小时内 Data.Output = New McLoginResult With {.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid, .ProfileJson = Input.ProfileJson} GoTo SkipLogin From 3db574fcdccaccb3549b1b4e1f2698be060e748a Mon Sep 17 00:00:00 2001 From: YIJANGs <153354935+YIJANGs@users.noreply.github.com> Date: Tue, 3 Mar 2026 17:39:39 +0800 Subject: [PATCH 2/7] Update ModLaunch.vb --- .../Modules/Minecraft/ModLaunch.vb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index 1775842..1983ecd 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -535,7 +535,7 @@ NextInner: Public McLoginAuthLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Auth", AddressOf McLoginServerStart) With {.ReloadTimeout = 1000 * 60 * 10} '主加载函数,返回所有需要的登录信息 - Private McLoginMsRefreshTime As Long = 0 '上次刷新登录的时间 + Private McLoginMsRefreshTime As Long = 0 'Minecraft Access Token到期时间 Private Sub McLoginMsStart(Data As LoaderTask(Of McLoginMs, McLoginResult)) Dim Input As McLoginMs = Data.Input Dim LogUsername As String = Input.UserName @@ -544,7 +544,7 @@ NextInner: '检查是否已经登录完成 If Not Data.IsForceRestarting AndAlso '不要求强行重启 Input.AccessToken <> "" AndAlso '已经登录过了 - (McLoginMsRefreshTime > 0 AndAlso GetTimeMs() - McLoginMsRefreshTime < 1000 * 60 * 60 * 5) Then '完成时间在 5小时内 + (McLoginMsRefreshTime > 0 AndAlso GetTimeMs() < McLoginMsRefreshTime) Then '在有效期过期前 Data.Output = New McLoginResult With {.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid, .ProfileJson = Input.ProfileJson} GoTo SkipLogin @@ -571,7 +571,9 @@ Relogin: Dim Tokens = MsLoginStep3(XBLToken) Data.Progress = 0.55 If Data.IsAborted Then Throw New ThreadInterruptedException - Dim AccessToken As String = MsLoginStep4(Tokens) + Dim MinecraftAPI As String() = MsLoginStep4(Tokens) '更改了第4步验证的返回格式,第一项为Minecraft Access Token,第二项为Token有效期 + Dim AccessToken As String = MinecraftAPI(0) 'Access Token + McLoginMsRefreshTime = GetTimeMs() + MinecraftAPI(1) 'Token 到期时间 Data.Progress = 0.7 If Data.IsAborted Then Throw New ThreadInterruptedException MsLoginStep5(AccessToken) @@ -1002,7 +1004,7 @@ Retry: } End Function '微软登录步骤 4:从 {XSTSToken, UHS} 获取 Minecraft AccessToken - Private Function MsLoginStep4(Tokens As String()) As String + Private Function MsLoginStep4(Tokens As String()) As String() McLaunchLog("开始微软登录步骤 4/6") Dim Request As String = New JObject(New JProperty("identityToken", $"XBL3.0 x={Tokens(1)};{Tokens(0)}")).ToString(0) @@ -1023,7 +1025,10 @@ Retry: End If End Try - Return GetJson(Result)("access_token").ToString + Return { + GetJson(Result)("access_token").ToString, + GetJson(Result)("expires_in").ToString + } End Function '微软登录步骤 5:验证微软账号是否持有 MC,这也会刷新 XGP Private Sub MsLoginStep5(AccessToken As String) From be9798669dc9694a0582a2ebc7b5970f1c75a8bc Mon Sep 17 00:00:00 2001 From: YIJANGs <153354935+YIJANGs@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:02:17 +0800 Subject: [PATCH 3/7] Update ModLaunch.vb --- Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index 1983ecd..ee574ab 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -573,7 +573,7 @@ Relogin: If Data.IsAborted Then Throw New ThreadInterruptedException Dim MinecraftAPI As String() = MsLoginStep4(Tokens) '更改了第4步验证的返回格式,第一项为Minecraft Access Token,第二项为Token有效期 Dim AccessToken As String = MinecraftAPI(0) 'Access Token - McLoginMsRefreshTime = GetTimeMs() + MinecraftAPI(1) 'Token 到期时间 + McLoginMsRefreshTime = GetTimeMs() + (MinecraftAPI(1) * 1000) 'Token 到期时间,并转换为毫秒 Data.Progress = 0.7 If Data.IsAborted Then Throw New ThreadInterruptedException MsLoginStep5(AccessToken) @@ -1027,7 +1027,7 @@ Retry: Return { GetJson(Result)("access_token").ToString, - GetJson(Result)("expires_in").ToString + GetJson(Result)("expires_in").ToString '以秒为单位 } End Function '微软登录步骤 5:验证微软账号是否持有 MC,这也会刷新 XGP From 3951a12d008797c554ebe78a11eacb18fd1e0aa4 Mon Sep 17 00:00:00 2001 From: YIJANGs <153354935+YIJANGs@users.noreply.github.com> Date: Fri, 6 Mar 2026 20:53:47 +0800 Subject: [PATCH 4/7] 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 理论上有效 --- .../Modules/Minecraft/ModLaunch.vb | 12 ++++++------ Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index ee574ab..5b6bd49 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -535,16 +535,15 @@ NextInner: Public McLoginAuthLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Auth", AddressOf McLoginServerStart) With {.ReloadTimeout = 1000 * 60 * 10} '主加载函数,返回所有需要的登录信息 - Private McLoginMsRefreshTime As Long = 0 'Minecraft Access Token到期时间 + Private McLoginMsRefreshTime As Long = Val(Setup.Get("CacheMsV2OAuthExpires")) 'Minecraft Access Token到期时间 Private Sub McLoginMsStart(Data As LoaderTask(Of McLoginMs, McLoginResult)) Dim Input As McLoginMs = Data.Input Dim LogUsername As String = Input.UserName McLaunchLog("登录方式:正版(" & If(LogUsername = "", "尚未登录", LogUsername) & ")") Data.Progress = 0.05 '检查是否已经登录完成 - If Not Data.IsForceRestarting AndAlso '不要求强行重启 - Input.AccessToken <> "" AndAlso '已经登录过了 - (McLoginMsRefreshTime > 0 AndAlso GetTimeMs() < McLoginMsRefreshTime) Then '在有效期过期前 + If Not Data.IsForceRestarting AndAlso '不要求强行重启 | 'Input.AccessToken <> "" AndAlso '已经登录过了,但因为其影响了Token刷新时间的判定 在Token有效时重启PCL仍然会重新登录,所以注释掉了 + (McLoginMsRefreshTime > 0 AndAlso GetUnixTimestamp() < McLoginMsRefreshTime) Then '在有效期过期前 Data.Output = New McLoginResult With {.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid, .ProfileJson = Input.ProfileJson} GoTo SkipLogin @@ -573,7 +572,7 @@ Relogin: If Data.IsAborted Then Throw New ThreadInterruptedException Dim MinecraftAPI As String() = MsLoginStep4(Tokens) '更改了第4步验证的返回格式,第一项为Minecraft Access Token,第二项为Token有效期 Dim AccessToken As String = MinecraftAPI(0) 'Access Token - McLoginMsRefreshTime = GetTimeMs() + (MinecraftAPI(1) * 1000) 'Token 到期时间,并转换为毫秒 + McLoginMsRefreshTime = GetUnixTimestamp() + MinecraftAPI(1) 'Token 到期时间,以秒为单位 Data.Progress = 0.7 If Data.IsAborted Then Throw New ThreadInterruptedException MsLoginStep5(AccessToken) @@ -587,13 +586,14 @@ Relogin: Setup.Set("CacheMsV2Uuid", Result(0)) Setup.Set("CacheMsV2Name", Result(1)) Setup.Set("CacheMsV2ProfileJson", Result(2)) + Setup.Set("CacheMsV2OAuthExpires", McLoginMsRefreshTime) Dim MsJson As JObject = GetJson(Setup.Get("LoginMsJson")) MsJson.Remove(Input.UserName) '如果更改了玩家名…… MsJson(Result(1)) = OAuthRefreshToken Setup.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None)) Data.Output = New McLoginResult With {.AccessToken = AccessToken, .Name = Result(1), .Uuid = Result(0), .Type = "Microsoft", .ClientToken = Result(0), .ProfileJson = Result(2)} '结束 - McLoginMsRefreshTime = GetTimeMs() + 'McLoginMsRefreshTime = GetTimeMs() '不知道为什么会有一个这个东西 McLaunchLog("微软登录完成") SkipLogin: Setup.Set("HintBuy", True) '关闭正版购买提示 diff --git a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb index 0377692..20dd1d9 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb @@ -52,6 +52,7 @@ {"CacheMsName", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsV2Migrated", New SetupEntry(False, Source:=SetupSource.Registry)}, {"CacheMsV2OAuthRefresh", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, + {"CacheMsV2OAuthExpires", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsV2Access", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsV2ProfileJson", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsV2Uuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, From 802ca803149f99c930ba79552958b1de344c08f2 Mon Sep 17 00:00:00 2001 From: YIJANG <153354935+0x1A5@users.noreply.github.com> Date: Fri, 6 Mar 2026 21:59:26 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20ModSetup.vb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 薄奚梦灵 --- Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb index 20dd1d9..dd693b8 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/ModSetup.vb @@ -52,7 +52,7 @@ {"CacheMsName", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsV2Migrated", New SetupEntry(False, Source:=SetupSource.Registry)}, {"CacheMsV2OAuthRefresh", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, - {"CacheMsV2OAuthExpires", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, + {"CacheMsV2OAuthExpires", New SetupEntry(0, Source:=SetupSource.Registry)}, {"CacheMsV2Access", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsV2ProfileJson", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, {"CacheMsV2Uuid", New SetupEntry("", Source:=SetupSource.Registry, Encoded:=True)}, From fa02f5e0159caecaaf519ec31f5ff6b4f3884e30 Mon Sep 17 00:00:00 2001 From: YIJANGs <153354935+YIJANGs@users.noreply.github.com> Date: Wed, 8 Apr 2026 22:50:27 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E9=87=8D=E5=86=99=E7=9A=84=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Modules/Minecraft/ModLaunch.vb | 19 ++++++++++++------- .../Pages/PageSetup/Settings.vb | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index c684380..b146918 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -534,16 +534,15 @@ NextInner: Public McLoginAuthLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Auth", AddressOf McLoginServerStart) With {.ReloadTimeout = 1000 * 60 * 10} '主加载函数,返回所有需要的登录信息 - Private McLoginMsRefreshTime As Long = 0 '上次刷新登录的时间 + Private McLoginMsRefreshTime As Long = Val(Settings.Get("CacheMsV2OAuthExpires")) 'Minecraft Access Token到期时间 Private Sub McLoginMsStart(Data As LoaderTask(Of McLoginMs, McLoginResult)) Dim Input As McLoginMs = Data.Input Dim LogUsername As String = Input.UserName McLaunchLog("登录方式:正版(" & If(LogUsername = "", "尚未登录", LogUsername) & ")") Data.Progress = 0.05 '检查是否已经登录完成 - If Not Data.IsForceRestarting AndAlso '不要求强行重启 - Input.AccessToken <> "" AndAlso '已经登录过了 - (McLoginMsRefreshTime > 0 AndAlso GetTimeMs() - McLoginMsRefreshTime < 1000 * 60 * 10) Then '完成时间在 10 分钟内 + If Not Data.IsForceRestarting AndAlso '不要求强行重启 'Input.AccessToken <> "" AndAlso '已经登录过了 + (McLoginMsRefreshTime > 0 AndAlso GetUnixTimestamp() < McLoginMsRefreshTime) Then '完成时间在有效期内 Data.Output = New McLoginResult With {.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid, .ProfileJson = Input.ProfileJson} GoTo SkipLogin @@ -570,7 +569,9 @@ Relogin: Dim Tokens = MsLoginStep3(XBLToken) Data.Progress = 0.55 If Data.IsInterrupted Then Throw New ThreadInterruptedException - Dim AccessToken As String = MsLoginStep4(Tokens) + Dim Step4Tokens As String() = MsLoginStep4(Tokens) + Dim AccessToken As String = Step4Tokens(0) + McLoginMsRefreshTime = GetUnixTimestamp() + Step4Tokens(1) 'Token 到期时间,以秒为单位 Data.Progress = 0.7 If Data.IsInterrupted Then Throw New ThreadInterruptedException MsLoginStep5(AccessToken) @@ -584,6 +585,7 @@ Relogin: Settings.Set("CacheMsV2Uuid", Result(0)) Settings.Set("CacheMsV2Name", Result(1)) Settings.Set("CacheMsV2ProfileJson", Result(2)) + Settings.Set("CacheMsV2OAuthExpires", McLoginMsRefreshTime) Dim MsJson As JObject = GetJson(Settings.Get("LoginMsJson")) MsJson.Remove(Input.UserName) '如果更改了玩家名…… MsJson(Result(1)) = OAuthRefreshToken @@ -1001,7 +1003,7 @@ Retry: } End Function '微软登录步骤 4:从 {XSTSToken, UHS} 获取 Minecraft AccessToken - Private Function MsLoginStep4(Tokens As String()) As String + Private Function MsLoginStep4(Tokens As String()) As String() McLaunchLog("开始微软登录步骤 4/6") Dim Request As String = New JObject(New JProperty("identityToken", $"XBL3.0 x={Tokens(1)};{Tokens(0)}")).ToString(0) @@ -1022,7 +1024,10 @@ Retry: End If End Try - Return GetJson(Result)("access_token").ToString + Return { + GetJson(Result)("access_token").ToString, + GetJson(Result)("expires_in").ToString '以秒为单位 + } End Function '微软登录步骤 5:验证微软账号是否持有 MC,这也会刷新 XGP Private Sub MsLoginStep5(AccessToken As String) diff --git a/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb b/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb index f90473b..4590d44 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb @@ -45,6 +45,7 @@ New Setting("CacheMsName", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheMsV2Migrated", False, Source:=Sources.Registry), New Setting("CacheMsV2OAuthRefresh", "", Source:=Sources.Registry, Encrypted:=True), + New Setting("CacheMsV2OAuthExpires", 0, Source:=Sources.Registry), New Setting("CacheMsV2Access", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheMsV2ProfileJson", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheMsV2Uuid", "", Source:=Sources.Registry, Encrypted:=True), From 15fda76fd35a513002ce82e7a59acfda2557ccbd Mon Sep 17 00:00:00 2001 From: YIJANGs <153354935+YIJANGs@users.noreply.github.com> Date: Thu, 9 Apr 2026 21:56:51 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E9=99=90?= =?UTF-8?q?=E9=87=8D=E5=90=AF=E5=8A=A0=E8=BD=BD=E5=99=A8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在原595行的代码使得内存中的到期时间改变。使得输入值变化(理论上是这样) --- Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index b146918..b72c4fd 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -541,7 +541,7 @@ NextInner: McLaunchLog("登录方式:正版(" & If(LogUsername = "", "尚未登录", LogUsername) & ")") Data.Progress = 0.05 '检查是否已经登录完成 - If Not Data.IsForceRestarting AndAlso '不要求强行重启 'Input.AccessToken <> "" AndAlso '已经登录过了 + If Not Data.IsForceRestarting AndAlso '不要求强行重启 'Input.AccessToken <> "" AndAlso '因为会影响有效期判断(每次启动就刷新,不论是否过期),所以注释掉了 (McLoginMsRefreshTime > 0 AndAlso GetUnixTimestamp() < McLoginMsRefreshTime) Then '完成时间在有效期内 Data.Output = New McLoginResult With {.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid, .ProfileJson = Input.ProfileJson} @@ -592,7 +592,6 @@ Relogin: Settings.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None)) Data.Output = New McLoginResult With {.AccessToken = AccessToken, .Name = Result(1), .Uuid = Result(0), .Type = "Microsoft", .ClientToken = Result(0), .ProfileJson = Result(2)} '结束 - McLoginMsRefreshTime = GetTimeMs() McLaunchLog("微软登录完成") SkipLogin: Settings.Set("HintBuy", True) '关闭正版购买提示