diff --git a/Plain Craft Launcher 2/Application.xaml.vb b/Plain Craft Launcher 2/Application.xaml.vb index cb4d0301..4791caf3 100644 --- a/Plain Craft Launcher 2/Application.xaml.vb +++ b/Plain Craft Launcher 2/Application.xaml.vb @@ -210,8 +210,8 @@ Public Class Application If AssemblyImazenWebp Is Nothing Then Log("[Start] 加载 DLL:Imazen.WebP") AssemblyImazenWebp = Assembly.Load(GetResources("Imazen_WebP")) - SetDllDirectory(PathTemp) - File.WriteAllBytes(PathTemp & "libwebp.dll", GetResources("libwebp64")) + SetDllDirectory(GetPureAsciiDir()) + File.WriteAllBytes(GetPureAsciiDir() & "\libwebp.dll", GetResources("libwebp64")) End If Return AssemblyImazenWebp End SyncLock diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb index a1f9b156..929d7621 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.vb +++ b/Plain Craft Launcher 2/FormMain.xaml.vb @@ -10,6 +10,19 @@ Public Class FormMain Dim FeatureList As New List(Of KeyValuePair(Of Integer, String)) '统计更新日志条目 #If BETA Then + If LastVersion < 340 Then 'Release 2.8.8 + If LastVersion = 338 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复数个与新正版登录相关的严重 Bug")) + FeatureCount += 3 + BugCount += 7 + End If + If LastVersion < 338 Then 'Release 2.8.7 + FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "使用新的正版登录方式,以提高安全性")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化安装整合包、检索 Mod 的稳定性")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复无法加载部分 Mod 的图标的 Bug")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复在 Mod 管理页面删除 Mod 导致报错的 Bug")) + FeatureCount += 11 + BugCount += 21 + End If If LastVersion < 336 Then 'Release 2.8.6 FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "下载 Mod 时会使用 MCIM 国内镜像源")) FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "Mod 管理页面允许筛选可更新/启用/禁用的 Mod")) @@ -134,6 +147,11 @@ Public Class FormMain '3:BUG+ IMP* FEAT- '2:BUG* IMP- '1:BUG- + If LastVersion < 339 Then 'Snapshot 2.8.8 + If LastVersion = 337 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复数个与新正版登录相关的严重 Bug")) + FeatureCount += 3 + BugCount += 7 + End If If LastVersion < 337 Then 'Snapshot 2.8.7 FeatureList.Add(New KeyValuePair(Of Integer, String)(4, "使用新的正版登录方式,以提高安全性")) FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化安装整合包、检索 Mod 的稳定性")) @@ -721,7 +739,7 @@ Public Class FormMain Exit Sub ElseIf e.Key = Key.Escape Then Dim Msg As Object = PanMsg.Children(0) - If TypeOf Msg Is MyMsgText AndAlso Msg.Btn3.Visibility = Visibility.Visible Then + If TypeOf Msg IsNot MyMsgInput AndAlso TypeOf Msg IsNot MyMsgSelect AndAlso Msg.Btn3.Visibility = Visibility.Visible Then Msg.Btn3_Click() ElseIf Msg.Btn2.Visibility = Visibility.Visible Then Msg.Btn2_Click() diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb index 9da1b3f9..96fe4b7d 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModBase.vb @@ -12,13 +12,13 @@ Public Module ModBase #Region "声明" '下列版本信息由更新器自动修改 - Public Const VersionBaseName As String = "2.8.7" '不含分支前缀的显示用版本名 - Public Const VersionStandardCode As String = "2.8.7." & VersionBranchCode '标准格式的四段式版本号 + Public Const VersionBaseName As String = "2.8.8" '不含分支前缀的显示用版本名 + Public Const VersionStandardCode As String = "2.8.8." & VersionBranchCode '标准格式的四段式版本号 Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换 #If BETA Then - Public Const VersionCode As Integer = 336 'Release + Public Const VersionCode As Integer = 340 'Release #Else - Public Const VersionCode As Integer = 337 'Snapshot + Public Const VersionCode As Integer = 339 'Snapshot #End If '自动生成的版本信息 Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName @@ -1840,6 +1840,13 @@ RetryDir: #Region "系统" + ''' + ''' 指示接取到这个异常的函数进行重试。 + ''' + Public Class RetryException + Inherits Exception + End Class + ''' ''' 当前程序是否拥有管理员权限。 ''' @@ -2430,6 +2437,14 @@ Retry: Return rect.Contains(bounds.TopLeft) OrElse rect.Contains(bounds.BottomRight) End Function + ''' + ''' 控件是否受到 TextTrimming 属性影响,导致内容被截取。 + ''' + Public Function IsTextTrimmed(Control As TextBlock) As Boolean + Control.Measure(New Size(Double.MaxValue, Double.MaxValue)) + Return Control.DesiredSize.Width > Control.ActualWidth + End Function + #End Region #Region "Debug" diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb index 0e71e588..e824443d 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb @@ -288,15 +288,13 @@ End SyncLock End Try '检验输入以确定情况 - If (Not IsForceRestart) AndAlso '不要求强行重启 - ((Input IsNot Nothing AndAlso Input.Equals(Me.Input)) OrElse (Input Is Nothing AndAlso Me.Input Is Nothing)) AndAlso '输入相同 - (State = LoadState.Loading OrElse State = LoadState.Finished) AndAlso '正在加载或已加载成功 + If IsForceRestart Then Return True '强制要求重启 + If ((Input Is Nothing) <> (Me.Input Is Nothing)) OrElse (Input IsNot Nothing AndAlso Not Input.Equals(Me.Input)) Then Return True '输入不同 + If (State = LoadState.Loading OrElse State = LoadState.Finished) AndAlso '正在加载或已结束 (IgnoreReloadTimeout OrElse ReloadTimeout = -1 OrElse LastFinishedTime = 0 OrElse GetTimeTick() - LastFinishedTime < ReloadTimeout) Then '没有超时 - '如果输入相同且未出错则不重试 - Return False + Return False '则不重试 Else - '需要开始 - Return True + Return True '需要开始 End If End Function Public Overrides Sub Start(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = False) @@ -317,7 +315,7 @@ Sub() Try IsForceRestarting = IsForceRestart - If ModeDebug Then Log("[Loader] 加载线程 " & Name & " (" & Thread.CurrentThread.ManagedThreadId & ") 已启动") + If ModeDebug Then Log("[Loader] 加载线程 " & Name & " (" & Thread.CurrentThread.ManagedThreadId & ") 已" & If(IsForceRestarting, "强制", "") & "启动") LoadDelegate(Me) If IsAborted Then Log("[Loader] 加载线程 " & Name & " (" & Thread.CurrentThread.ManagedThreadId & ") 已中断但线程正常运行至结束,输出被弃用(最新线程:" & If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId) & ")", LogLevel.Developer) @@ -441,12 +439,13 @@ Exit Sub End If End SyncLock - RunInThread(Sub() - '中断加载器 - For Each Loader In Loaders - Loader.Abort() - Next - End Sub) + RunInThread( + Sub() + '中断加载器 + For Each Loader In Loaders + Loader.Abort() + Next + End Sub) End Sub ''' @@ -485,7 +484,7 @@ Private Sub Update() If State = LoadState.Finished OrElse State = LoadState.Failed OrElse State = LoadState.Aborted Then Exit Sub Dim IsFinished As Boolean = True - Dim Ignore As Boolean = False + Dim Blocked As Boolean = False Dim Input As Object = Me.Input For Each Loader In Loaders Select Case Loader.State @@ -493,28 +492,30 @@ '检查是否需要重启 If Loader.GetType.Name.StartsWithF("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then - If ModeDebug Then Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name) + Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name) GoTo Restart End If '更新下一个加载器的输入 Input = CType(Loader, Object).Output End If + '如果不让继续启动,且已有加载器正在加载中,就不继续启动 + If Loader.Block AndAlso Not IsFinished Then Blocked = True Case LoadState.Loading '检查是否需要重启 If Loader.GetType.Name.StartsWithF("LoaderTask") Then If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then - If ModeDebug Then Log("[Loader] 由于输入条件变更,重启进行中的加载器 " & Loader.Name, LogLevel.Developer) + Log("[Loader] 由于输入条件变更,重启进行中的加载器 " & Loader.Name, LogLevel.Developer) GoTo Restart End If End If '已经有正在加载中的了,不需要再启动了 IsFinished = False - Ignore = True + Blocked = True Case Else Restart: '未启动,则启动加载器 IsFinished = False - If Ignore Then Continue For + If Blocked Then Continue For If Input IsNot Nothing Then '若输入类型与下一个加载器相同才继续 Dim LoaderType As String = Loader.GetType.Name @@ -528,8 +529,8 @@ Restart: Else Loader.Start(IsForceRestart:=IsForceRestarting) End If - '如果不让继续启动,那就不启动呗 - If Loader.Block Then Ignore = True + '阻止继续 + If Loader.Block Then Blocked = True End Select Next If IsFinished Then diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb index 9fa91361..ea13ad88 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModNet.vb @@ -140,7 +140,7 @@ Retry: ''' ''' 网页的 Url。 ''' 网页的编码,通常为 UTF-8。 - Public Function NetGetCodeByRequestMulty(Url As String, Optional Encode As Encoding = Nothing, Optional Accept As String = "", Optional IsJson As Boolean = False) + Public Function NetGetCodeByRequestMultiple(Url As String, Optional Encode As Encoding = Nothing, Optional Accept As String = "", Optional IsJson As Boolean = False) Dim Threads As New List(Of Thread) Dim RequestResult = Nothing Dim RequestEx As Exception = Nothing @@ -329,7 +329,7 @@ Retry: ''' ''' 同时发送多个网络请求并要求返回内容。 ''' - Public Function NetRequestMulty(Url As String, Method As String, Data As Object, ContentType As String, Optional RequestCount As Integer = 4, Optional Headers As Dictionary(Of String, String) = Nothing, Optional MakeLog As Boolean = True) + Public Function NetRequestMultiple(Url As String, Method As String, Data As Object, ContentType As String, Optional RequestCount As Integer = 4, Optional Headers As Dictionary(Of String, String) = Nothing, Optional MakeLog As Boolean = True) Dim Threads As New List(Of Thread) Dim RequestResult = Nothing Dim RequestEx As Exception = Nothing @@ -701,8 +701,7 @@ RequestFinished: ''' ''' 所属的文件列表任务。 ''' - Public Tasks As New Concurrent.ConcurrentBag(Of LoaderDownload) - + Public Tasks As New SynchronizedCollection(Of LoaderDownload) ''' ''' 所有下载源。 ''' @@ -1232,7 +1231,7 @@ SourceBreak: '根据情况判断,是否在多线程下禁用下载源(连续错误过多,或不支持断点续传) If ex.Message.Contains("该下载源不支持") OrElse ex.Message.Contains("未能解析") OrElse ex.Message.Contains("(404)") OrElse ex.Message.Contains("(502)") OrElse ex.Message.Contains("无返回数据") OrElse ex.Message.Contains("空间不足") OrElse ex.Message.Contains("获取到的分段大小不一致") OrElse - ((ex.Message.Contains("(403)") OrElse ex.Message.Contains("(429)")) AndAlso Not Info.Source.Url.ContainsF("bmclapi")) OrElse 'BMCLAPI 的部分源在高频率请求下会返回 403、429,所以不应因此禁用下载源 + (ex.Message.Contains("(403)") AndAlso Not Info.Source.Url.ContainsF("bmclapi")) OrElse 'BMCLAPI 的部分源在高频率请求下会返回 403,所以不应因此禁用下载源 (Info.Source.FailCount >= MathClamp(NetTaskThreadLimit, 5, 30) AndAlso DownloadDone < 1) OrElse Info.Source.FailCount > NetTaskThreadLimit + 2 Then Dim IsThisFail As Boolean = False @@ -1403,7 +1402,7 @@ Retry: ''' Public Sub Abort(CausedByTask As LoaderDownload) '从特定任务中移除,如果它还属于其他任务,则继续下载 - Tasks.TryTake(CausedByTask) + Tasks.Remove(CausedByTask) If Tasks.Any Then Exit Sub '确认中断 SyncLock LockState diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb index 50f77a3e..5cbf8e25 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb @@ -99,7 +99,7 @@ Task.Output = New List(Of NetFile) From {BackAssetsFile} '检查是否需要更新:每天只更新一次 If File.Exists(RealAddress) AndAlso Math.Abs((File.GetLastWriteTime(RealAddress).Date - Now.Date).TotalDays) < 1 Then - Log("[Download] 无需更新资源文件索引") + Log("[Download] 无需更新资源文件索引,取消") Task.Abort() End If End Sub)) @@ -1089,7 +1089,7 @@ Dim Urls As New List(Of KeyValuePair(Of String, Integer)) If McimUrl <> Url Then Select Case Setup.Get("ToolDownloadMod") - 'UNDONE: 受 #4811 影响 + 'UNDONE: 在 MCIM 源稳定后回调 Case 0 If ModeDebug Then Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10)) @@ -1138,7 +1138,7 @@ Dim Urls As New List(Of KeyValuePair(Of String, Integer)) If McimUrl <> Url Then Select Case Setup.Get("ToolDownloadMod") - 'UNDONE: 受 #4811 影响 + 'UNDONE: 在 MCIM 源稳定后回调 Case 0 If ModeDebug Then Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10)) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index 452816c8..123d56d8 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -106,7 +106,7 @@ Public Module ModLaunch '构造主加载器 Dim Loaders As New List(Of LoaderBase) From { New LoaderTask(Of Integer, Integer)("获取 Java", AddressOf McLaunchJava) With {.ProgressWeight = 4, .Block = False}, - McLoginLoader, + McLoginLoader, '.ProgressWeight = 15, .Block = False New LoaderCombo(Of String)("补全文件", DlClientFix(McVersionCurrent, False, AssetsIndexExistsBehaviour.DownloadInBackground)) With {.ProgressWeight = 15, .Show = False}, New LoaderTask(Of String, List(Of McLibToken))("获取启动参数", AddressOf McLaunchArgumentMain) With {.ProgressWeight = 2}, New LoaderTask(Of List(Of McLibToken), Integer)("解压文件", AddressOf McLaunchNatives) With {.ProgressWeight = 2}, @@ -529,8 +529,8 @@ Relogin: OAuthTokens = MsLoginStep1New(Data) Else '有 RefreshToken - OAuthTokens = MsLoginStep1Refresh(Input.OAuthRefreshToken) '要求重新打开登录网页认证 - If OAuthTokens(0) = "Relogin" Then GoTo Relogin + OAuthTokens = MsLoginStep1Refresh(Input.OAuthRefreshToken) + If OAuthTokens(0) = "Relogin" Then GoTo Relogin '要求重新打开登录网页认证 End If If Data.IsAborted Then Throw New ThreadInterruptedException Data.Progress = 0.25 @@ -838,9 +838,10 @@ LoginFinish: '参考:https://learn.microsoft.com/zh-cn/entra/identity-platform/v2-oauth2-device-code '初始请求 +Retry: McLaunchLog("开始微软登录步骤 1/6(原始登录)") - Dim PrepareJson As JObject = GetJson(NetRequestMulty("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", "POST", - $"client_id={OAuthClientId}&tenant=/consumers&scope=XboxLive.signin%20offline_access", "application/x-www-form-urlencoded", 2)) + Dim PrepareJson As JObject = GetJson(NetRequestRetry("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode", "POST", + $"client_id={OAuthClientId}&tenant=/consumers&scope=XboxLive.signin%20offline_access", "application/x-www-form-urlencoded")) McLaunchLog("网页登录地址:" & PrepareJson("verification_uri").ToString) '弹窗 @@ -849,24 +850,31 @@ LoginFinish: While Converter.Result Is Nothing Thread.Sleep(100) End While - If TypeOf Converter.Result Is Exception Then + If TypeOf Converter.Result Is RetryException Then + If MyMsgBox($"请在登录时选择 {vbLQ}其他登录方法{vbRQ},然后选择 {vbLQ}使用我的密码{vbRQ}。{vbCrLf}如果没有该选项,请选择 {vbLQ}设置密码{vbRQ},设置完毕后再登录。", + "需要使用密码登录", "重新登录", "设置密码", "取消", + Button2Action:=Sub() OpenWebsite("https://account.live.com/password/Change")) = 1 Then + GoTo Retry + Else + Throw New Exception("$$") + End If + ElseIf TypeOf Converter.Result Is Exception Then Throw CType(Converter.Result, Exception) Else Return Converter.Result End If End Function - '微软登录步骤 1,刷新登录:从 OAuth Code 或 OAuth RefreshToken 获取 {OAuth AccessToken, OAuth RefreshToken} Private Function MsLoginStep1Refresh(Code As String) As String() McLaunchLog("开始微软登录步骤 1/6(刷新登录)") Dim Result As String Try - Result = NetRequestMulty("https://login.live.com/oauth20_token.srf", "POST", + Result = NetRequestMultiple("https://login.live.com/oauth20_token.srf", "POST", $"client_id={OAuthClientId}&refresh_token={Uri.EscapeDataString(Code)}&grant_type=refresh_token&scope=XboxLive.signin%20offline_access", "application/x-www-form-urlencoded", 2) Catch ex As Exception - If ex.Message.Contains("must sign in again") OrElse ex.Message.Contains("invalid_grant") Then '#269 + If ex.Message.Contains("must sign in again") OrElse (ex.Message.Contains("refresh_token") AndAlso ex.Message.Contains("is not valid")) Then '#269 Return {"Relogin", ""} Else Throw @@ -878,7 +886,6 @@ LoginFinish: Dim RefreshToken As String = ResultJson("refresh_token").ToString Return {AccessToken, RefreshToken} End Function - '微软登录步骤 2:从 OAuth AccessToken 获取 XBLToken Private Function MsLoginStep2(AccessToken As String) As String McLaunchLog("开始微软登录步骤 2/6") @@ -891,8 +898,8 @@ LoginFinish: }, ""RelyingParty"": ""http://auth.xboxlive.com"", ""TokenType"": ""JWT"" - }" 'TODO: 新版登录改为 ""RpsTicket"": ""d=" & AccessToken & """ - Dim Result As String = NetRequestMulty("https://user.auth.xboxlive.com/user/authenticate", "POST", Request, "application/json", 3) + }" + Dim Result As String = NetRequestMultiple("https://user.auth.xboxlive.com/user/authenticate", "POST", Request, "application/json", 3) Dim ResultJson As JObject = GetJson(Result) Dim XBLToken As String = ResultJson("Token").ToString @@ -914,7 +921,7 @@ LoginFinish: }" Dim Result As String Try - Result = NetRequestMulty("https://xsts.auth.xboxlive.com/xsts/authorize", "POST", Request, "application/json", 3) + Result = NetRequestMultiple("https://xsts.auth.xboxlive.com/xsts/authorize", "POST", Request, "application/json", 3) Catch ex As Net.WebException '参考 https://github.com/PrismarineJS/prismarine-auth/blob/master/src/common/Constants.js If ex.Message.Contains("2148916227") Then @@ -957,7 +964,7 @@ LoginFinish: Dim Request As String = New JObject(New JProperty("identityToken", $"XBL3.0 x={Tokens(1)};{Tokens(0)}")).ToString(0) Dim Result As String Try - Result = NetRequestMulty("https://api.minecraftservices.com/authentication/login_with_xbox", "POST", Request, "application/json", 2) + Result = NetRequestRetry("https://api.minecraftservices.com/authentication/login_with_xbox", "POST", Request, "application/json") Catch ex As Net.WebException Dim Message As String = GetExceptionSummary(ex) If Message.Contains("(429)") Then @@ -979,7 +986,7 @@ LoginFinish: Private Sub MsLoginStep5(AccessToken As String) McLaunchLog("开始微软登录步骤 5/6") - Dim Result As String = NetRequestMulty("https://api.minecraftservices.com/entitlements/mcstore", "GET", "", "application/json", 2, New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}}) + Dim Result As String = NetRequestMultiple("https://api.minecraftservices.com/entitlements/mcstore", "GET", "", "application/json", 2, New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}}) Try Dim ResultJson As JObject = GetJson(Result) If Not (ResultJson.ContainsKey("items") AndAlso ResultJson("items").Any) Then @@ -1000,7 +1007,7 @@ LoginFinish: Dim Result As String Try - Result = NetRequestMulty("https://api.minecraftservices.com/minecraft/profile", "GET", "", "application/json", 2, New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}}) + Result = NetRequestMultiple("https://api.minecraftservices.com/minecraft/profile", "GET", "", "application/json", 2, New Dictionary(Of String, String) From {{"Authorization", "Bearer " & AccessToken}}) Catch ex As Net.WebException Dim Message As String = GetExceptionSummary(ex) If Message.Contains("(429)") Then @@ -1255,7 +1262,7 @@ LoginFinish: ''' 释放 Java Wrapper 并返回完整文件路径。 ''' Public Function ExtractJavaWrapper() As String - Dim BaseDir As String = GetJavaWrapperDir() + Dim BaseDir As String = GetPureASCIIDir() Dim WrapperPath As String = BaseDir & "\JavaWrapper.jar" Log("[Java] 选定的 Java Wrapper 路径:" & WrapperPath) SyncLock ExtractJavaWrapperLock '避免 OptiFine 和 Forge 安装时同时释放 Java Wrapper 导致冲突 @@ -1287,9 +1294,10 @@ LoginFinish: Private ExtractJavaWrapperLock As New Object ''' - ''' 获取 Java Wrapper 所在的文件夹,不以 \ 结尾。 + ''' 获取一个可用于临时存放文件的,不含任何特殊字符的文件夹路径。 + ''' 返回值不以 \ 结尾。 ''' - Public Function GetJavaWrapperDir() As String + Public Function GetPureASCIIDir() As String If (Path & "PCL").IsASCII() Then Return Path & "PCL" ElseIf PathAppdata.IsASCII() Then @@ -1410,7 +1418,7 @@ LoginFinish: '添加 Java Wrapper 作为主 Jar If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED") - DataList.Add("-Doolloo.jlw.tmpdir=""" & GetJavaWrapperDir() & """") + DataList.Add("-Doolloo.jlw.tmpdir=""" & GetPureASCIIDir() & """") DataList.Add("-jar """ & ExtractJavaWrapper() & """") '添加 MainClass @@ -1477,7 +1485,7 @@ NextVersion: '添加 Java Wrapper 作为主 Jar If McLaunchJavaSelected.VersionCode >= 9 Then DataList.Add("--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED") - DataList.Add("-Doolloo.jlw.tmpdir=""" & GetJavaWrapperDir() & """") + DataList.Add("-Doolloo.jlw.tmpdir=""" & GetPureASCIIDir() & """") DataList.Add("-jar """ & ExtractJavaWrapper() & """") '将 "-XXX" 与后面 "XXX" 合并到一起 diff --git a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb index 59720a6f..316d5e3f 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/MyLocalModItem.xaml.vb @@ -539,7 +539,7 @@ RetryStart: '压缩 Subtitle ColumnSubtitle.Width = New GridLength(1, GridUnitType.Star) ColumnExtend.Width = New GridLength(0, GridUnitType.Pixel) - ElseIf Not ColumnExtend.Width.IsStar AndAlso ColumnSubtitle.ActualWidth > LabSubtitle.ActualWidth + 10 Then + ElseIf Not ColumnExtend.Width.IsStar AndAlso Not LabSubtitle.IsTextTrimmed Then '向右展开 Subtitle ColumnSubtitle.Width = GridLength.Auto ColumnExtend.Width = New GridLength(1, GridUnitType.Star) diff --git a/Plain Craft Launcher 2/Modules/ModMusic.vb b/Plain Craft Launcher 2/Modules/ModMusic.vb index cc1ace63..52a87a85 100644 --- a/Plain Craft Launcher 2/Modules/ModMusic.vb +++ b/Plain Craft Launcher 2/Modules/ModMusic.vb @@ -280,7 +280,7 @@ '当前音乐已播放结束,继续下一曲 If CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped AndAlso MusicAllList.Any Then MusicStartPlay(DequeueNextMusicAddress) Catch ex As Exception - Log("[Music] 播放音乐失败的文件完整路径:" & MusicCurrent) + Log(ex, "播放音乐出现内部错误(" & MusicCurrent & ")", LogLevel.Developer) If TypeOf ex Is NAudio.MmException AndAlso (ex.Message.Contains("NoDriver") OrElse ex.Message.Contains("BadDeviceId")) Then Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Critical) Thread.Sleep(1000000000) diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb index 58f2f1b5..59171f6c 100644 --- a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb +++ b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb @@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 ' 方法是按如下所示使用“*” - - + + diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb index e048a69d..2f6019fa 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb @@ -359,7 +359,7 @@ Public Module ModDownloadLib '添加 Java Wrapper 作为主 Jar Dim Arguments As String If UseJavaWrapper Then - Arguments = $"-Doolloo.jlw.tmpdir=""{GetJavaWrapperDir()}"" -Duser.home=""{BaseMcFolderHome}"" -cp ""{Target}"" -jar ""{ExtractJavaWrapper()}"" optifine.Installer" + Arguments = $"-Doolloo.jlw.tmpdir=""{GetPureASCIIDir()}"" -Duser.home=""{BaseMcFolderHome}"" -cp ""{Target}"" -jar ""{ExtractJavaWrapper()}"" optifine.Installer" Else Arguments = $"-Duser.home=""{BaseMcFolderHome}"" -cp ""{Target}"" optifine.Installer" End If @@ -1026,7 +1026,7 @@ Retry: '添加 Java Wrapper 作为主 Jar Dim Arguments As String If UseJavaWrapper Then - Arguments = $"-Doolloo.jlw.tmpdir=""{GetJavaWrapperDir()}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{ExtractJavaWrapper()}"" com.bangbang93.ForgeInstaller ""{McFolder}" + Arguments = $"-Doolloo.jlw.tmpdir=""{GetPureASCIIDir()}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{ExtractJavaWrapper()}"" com.bangbang93.ForgeInstaller ""{McFolder}" Else Arguments = $"-cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" com.bangbang93.ForgeInstaller ""{McFolder}" End If diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/FormLoginOAuth.xaml b/Plain Craft Launcher 2/Pages/PageLaunch/FormLoginOAuth.xaml deleted file mode 100644 index 10e9c84e..00000000 --- a/Plain Craft Launcher 2/Pages/PageLaunch/FormLoginOAuth.xaml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/FormLoginOAuth.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/FormLoginOAuth.xaml.vb deleted file mode 100644 index 35cd8479..00000000 --- a/Plain Craft Launcher 2/Pages/PageLaunch/FormLoginOAuth.xaml.vb +++ /dev/null @@ -1,100 +0,0 @@ -Imports System.Windows.Navigation - -Public Class FormLoginOAuth - - Public Event OnLoginSuccess(code As String) - Public Event OnLoginCanceled(IsSwitch As Boolean) - - '跳转事件 - Private IsLoginSuccessed As Boolean = False - Private IsSwitch As Boolean = False - Private Sub Browser_Navigating(sender As WebBrowser, e As NavigatingCancelEventArgs) Handles Browser1.Navigating, Browser2.Navigating, Browser3.Navigating - Dim Url As String = e.Uri.AbsoluteUri - If ModeDebug Then Log("[Login] 登录浏览器 " & sender.Tag & " 导向:" & Url) - If Url.Contains("code=") Then - Dim Code As String = RegexSeek(Url, "(?<=code\=)[^&]+") - Log("[Login] 抓取到 OAuth 返回码:" & Code) - IsLoginSuccessed = True - RaiseEvent OnLoginSuccess(Code) - ElseIf Url.Contains("github.") Then - Hint("PCL 不支持使用 GitHub 登录微软账号!", HintType.Critical) - Close() - End If - End Sub - - '已导航事件 - Private IsFirstLoaded As Boolean = False - Private IsFirstLoadedLock As New Object - Private Sub Browser_Navigated(sender As WebBrowser, e As NavigationEventArgs) Handles Browser1.Navigated, Browser2.Navigated, Browser3.Navigated - SyncLock IsFirstLoadedLock - If IsFirstLoaded Then Exit Sub - IsFirstLoaded = True - End SyncLock - RunInThread(Sub() - Thread.Sleep(1000) - RunInUi(Sub() - sender.Visibility = Visibility.Visible - PanLoading.Visibility = Visibility.Collapsed - Log("[Login] 已将登录窗口切换至浏览器") - End Sub) - End Sub) - End Sub - - '窗体的进出事件 - Public Shared LoginUrl1 As String = "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?prompt=login&client_id=00000000402b5328&response_type=code&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_uri=https:%2F%2Flogin.live.com%2Foauth20_desktop.srf" - Public Shared LoginUrl2 As String = "https://login.live.com/oauth20_authorize.srf?prompt=login&client_id=00000000402b5328&response_type=code&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_uri=https:%2F%2Flogin.live.com%2Foauth20_desktop.srf" - Private Sub FrmLoginOAuth_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded - Browser1.Navigate(LoginUrl1) - RunInThread(Sub() - '估计是由于时间戳原因,同时导航会导致误报密码失败 - Thread.Sleep(2500) - RunInUi(Sub() - Try '防止在 Dispose 之后调用 - If Not IsFirstLoaded Then Browser2.Navigate(LoginUrl1) - Catch - End Try - End Sub) - Thread.Sleep(2500) - RunInUi(Sub() - Try - If Not IsFirstLoaded Then Browser3.Navigate(LoginUrl2) - Catch - End Try - End Sub) - End Sub) - End Sub - Private Sub FormLoginOAuth_Closed() Handles Me.Closed - RunInThread(Sub() - Thread.Sleep(1000) '释放会卡一下,所以稍等一下…… - RunInUiWait(Sub() - Try - Browser1.Dispose() - Catch ex As Exception - Log(ex, "释放微软登录浏览器 1 失败") - End Try - End Sub) - Thread.Sleep(200) - RunInUiWait(Sub() - Try - Browser2.Dispose() - Catch ex As Exception - Log(ex, "释放微软登录浏览器 2 失败") - End Try - End Sub) - Thread.Sleep(200) - RunInUiWait(Sub() - Try - Browser3.Dispose() - Catch ex As Exception - Log(ex, "释放微软登录浏览器 3 失败") - End Try - End Sub) - End Sub) - If Not IsLoginSuccessed Then RaiseEvent OnLoginCanceled(IsSwitch) - FrmMain.Focus() - End Sub - Private Sub HintSwitch_Click() Handles HintSwitch.Click - IsSwitch = True - Close() - End Sub -End Class diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb index b1f280a8..8fd9c7e6 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb @@ -56,6 +56,9 @@ }, "MyMsgBox " & Uuid) End Sub + '实现回车和 Esc 的接口(#4857) + Public Sub Btn1_Click() Handles Btn1.Click + End Sub Public Sub Btn3_Click() Handles Btn3.Click Finished(New ThreadInterruptedException) End Sub @@ -93,7 +96,7 @@ End Sub Private Sub WorkThread() - Thread.Sleep(4000) + Thread.Sleep(3000) If MyConverter.IsExited Then Exit Sub OpenWebsite(Website) ClipboardSet(UserCode) @@ -122,12 +125,15 @@ ElseIf ex.Message.Contains("expired_token") Then Finished(New Exception("$登录用时太长啦,重新试试吧!")) Return + ElseIf ex.Message.Contains("AADSTS70000") Then '可能不能判 “invalid_grant”,见 #269 + Finished(New RetryException) + Return ElseIf ex.Message.Contains("authorization_pending") Then - Thread.Sleep(1000) + Thread.Sleep(2000) ElseIf UnknownFailureCount <= 2 Then UnknownFailureCount += 1 Log(ex, $"登录轮询第 {UnknownFailureCount} 次失败") - Thread.Sleep(1000) + Thread.Sleep(2000) Else Finished(New Exception("登录轮询失败", ex)) Return diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb index 4e765b5e..5cad11cb 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb @@ -110,6 +110,10 @@ Download: Log("[Page] 主页预设:主页市场") Url = "https://homepage-market.pages.dev/Custom.xaml" GoTo Download + Case 8 + Log("[Page] 主页预设:更新日志") + Url = "https://updatehomepage.pages.dev/UpdateHomepage.xaml" + GoTo Download End Select End Select RunInUi(Sub() LoadContent(Content)) @@ -136,7 +140,7 @@ Download: Dim NeedDownload As Boolean = True Try Version = NetGetCodeByRequestOnce(VersionAddress, Timeout:=10000) - If Version.Length > 100 Then Throw New Exception($"获取的自定义主页版本过长({Version.Length} 字符)") + If Version.Length > 1000 Then Throw New Exception($"获取的自定义主页版本过长({Version.Length} 字符)") Dim CurrentVersion As String = Setup.Get("CacheSavedPageVersion") If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then Log($"[Page] 当前缓存的自定义主页已为最新,当前版本:{Version},检查源:{VersionAddress}") diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml index 389328d4..951a5dc3 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml @@ -104,82 +104,108 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -266,18 +292,18 @@ - - - - - - - + + - + + + + diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml index 9f289c3c..aeb3ae4e 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml @@ -244,6 +244,7 @@ + diff --git a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb index a722e08d..372b6a7a 100644 --- a/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageVersion/PageVersionMod.xaml.vb @@ -470,6 +470,11 @@ Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity) McModLoader.Output.RemoveAt(IndexOfLoader) McModLoader.Output.Insert(IndexOfLoader, NewModEntity) + If SearchResult IsNot Nothing Then + Dim IndexOfResult As Integer = SearchResult.IndexOf(ModEntity) + SearchResult.Remove(ModEntity) + SearchResult.Insert(IndexOfResult, NewModEntity) + End If '更改 UI 中的列表 Dim NewItem As MyLocalModItem = McModListItem(NewModEntity) ModItems(ModEntity.RawFileName) = NewItem @@ -574,7 +579,14 @@ '结果提示 Select Case Loader.State Case LoadState.Finished - Hint(If(FinishedFileNames.Count > 1, $"已成功更新 {FinishedFileNames.Count} 个 Mod!", $"已成功更新:{FinishedFileNames.Single}"), HintType.Finish) + Select Case FinishedFileNames.Count + Case 0 '一般是由于 Mod 文件被占用,然后玩家主动取消 + Log($"[Mod] 没有 Mod 被成功更新") + Case 1 + Hint($"已成功更新 {FinishedFileNames.Single}!", HintType.Finish) + Case Else + Hint($"已成功更新 {FinishedFileNames.Count} 个 Mod!", HintType.Finish) + End Select Case LoadState.Failed Hint("Mod 更新失败:" & GetExceptionSummary(Loader.Error), HintType.Critical) Case LoadState.Aborted diff --git a/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj b/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj index cd678c40..9c81af07 100644 --- a/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj +++ b/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj @@ -256,9 +256,6 @@ PageDownloadPack.xaml - - FormLoginOAuth.xaml - MyMsgLogin.xaml @@ -514,10 +511,6 @@ Designer MSBuild:Compile - - Designer - MSBuild:Compile - MSBuild:Compile Designer diff --git a/Plain Craft Launcher 2/Resources/Help.zip b/Plain Craft Launcher 2/Resources/Help.zip index a49d41f9..8db1d47a 100644 Binary files a/Plain Craft Launcher 2/Resources/Help.zip and b/Plain Craft Launcher 2/Resources/Help.zip differ diff --git "a/\346\234\200\346\226\260\346\255\243\345\274\217\347\211\210.zip" "b/\346\234\200\346\226\260\346\255\243\345\274\217\347\211\210.zip" index 144de9a9..0e58940f 100644 Binary files "a/\346\234\200\346\226\260\346\255\243\345\274\217\347\211\210.zip" and "b/\346\234\200\346\226\260\346\255\243\345\274\217\347\211\210.zip" differ