diff --git a/Plain Craft Launcher 2/Controls/MyHint.xaml.vb b/Plain Craft Launcher 2/Controls/MyHint.xaml.vb index b78df17..9724691 100644 --- a/Plain Craft Launcher 2/Controls/MyHint.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyHint.xaml.vb @@ -107,11 +107,14 @@ Public Class MyHint End Sub '触发点击事件 + Public Event Click(sender As Object, e As MouseButtonEventArgs) Private IsMouseDown As Boolean = False Private Sub MyHint_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp If Not IsMouseDown Then Return IsMouseDown = False Log("[Control] 按下提示条" & If(String.IsNullOrEmpty(Name), "", ":" & Name)) + RaiseEvent Click(sender, e) + If e.Handled Then Return e.Handled = True RaiseCustomEvent() '自定义事件 End Sub diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb index efd8885..46862eb 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.vb +++ b/Plain Craft Launcher 2/FormMain.xaml.vb @@ -11,6 +11,16 @@ Public Class FormMain Dim FeatureList As New List(Of KeyValuePair(Of Integer, String)) '统计更新日志条目 #If BETA Then + If LastVersion < 386 Then 'Release 2.12.5 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法下载 NeoForge 26.1")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:部分关键词搜不到资源,特别是中文 Mod 搜索经常没有结果")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:降低游戏的内存占用")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:老版本 Windows 无法启动游戏")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:连接 Mojang 的服务可能失败,提示错误码 421")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法访问爱发电")) + FeatureCount += 24 + BugCount += 19 + End If If LastVersion < 383 Then 'Release 2.12.3 FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:部分关键词搜不到资源,特别是中文 Mod 搜索经常没有结果")) FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:下载可能完全卡住,或是下载进度反复回退")) @@ -140,6 +150,16 @@ Public Class FormMain '3:BUG+ IMP* FEAT- '2:BUG* IMP- '1:BUG- + If LastVersion < 385 Then 'Snapshot 2.12.5 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法下载 NeoForge 26.1")) + If LastVersion = 384 Then + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:下载可能失败,提示下载管理刷新线程出错")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法保存选择的 Minecraft 文件夹")) + FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:使用中文搜索 Mod 时, 部分结果会忽略筛选条件")) + End If + FeatureCount += 3 + BugCount += 6 + End If If LastVersion < 384 Then 'Snapshot 2.12.4 FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:部分关键词搜不到资源,特别是中文 Mod 搜索经常没有结果")) FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:降低游戏的内存占用")) diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb index c83e8e5..6665adb 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModBase.vb @@ -14,13 +14,13 @@ Public Module ModBase #Region "声明" '下列版本信息由更新器自动修改 - Public Const VersionBaseName As String = "2.12.4" '不含分支前缀的显示用版本名 - Public Const VersionStandardCode As String = "2.12.4." & VersionBranchCode '标准格式的四段式版本号 + Public Const VersionBaseName As String = "2.12.5" '不含分支前缀的显示用版本名 + Public Const VersionStandardCode As String = "2.12.5." & VersionBranchCode '标准格式的四段式版本号 Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换 #If BETA Then Public Const VersionCode As Integer = 383 'Release #Else - Public Const VersionCode As Integer = 384 'Snapshot + Public Const VersionCode As Integer = 385 'Snapshot #End If '自动生成的版本信息 Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName @@ -1336,11 +1336,12 @@ Re: Dim Files As String() Try Files = Directory.GetFiles(Path) - Catch ex As DirectoryNotFoundException '#4549 - If Not Directory.Exists(Path) Then Return 0 '可能已被其他线程删除 - Log(ex, $"疑似为孤立符号链接,尝试直接删除({Path})", LogLevel.Developer) - Directory.Delete(Path) - Return 0 + Catch ex As DirectoryNotFoundException '#4549,也可能已被其他线程删除 + If Directory.Exists(Path) Then + Log(ex, $"疑似为孤立符号链接,尝试直接删除({Path})", LogLevel.Developer) + Directory.Delete(Path) + End If + Return DeletedCount End Try For Each FilePath As String In Files Dim RetriedFile As Boolean = False @@ -1348,6 +1349,8 @@ RetryFile: Try File.Delete(FilePath) DeletedCount += 1 + Catch ex As DirectoryNotFoundException + Return DeletedCount Catch ex As Exception If Not RetriedFile Then RetriedFile = True diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb index d6c89c4..a5e1131 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModNet.vb @@ -182,10 +182,19 @@ RequestFinished: Throw New Exception($"预处理下载文件路径失败({LocalPath})", ex) End Try '下载 + Dim RetryCount As Integer = 0 +Retry: Try File.WriteAllBytes(LocalPath, SendRequest(Url, HttpMethod.Get, SimulateBrowserHeaders:=SimulateBrowserHeaders)) + Catch ex As ThreadInterruptedException + File.Delete(LocalPath) + Throw Catch ex As Exception File.Delete(LocalPath) + If RetryCount < 2 Then + RetryCount += 1 + GoTo Retry + End If Throw New WebException($"通过网络请求直接下载小文件失败({LocalPath})", ex) End Try End Sub @@ -284,6 +293,9 @@ RequestFinished: Throw Catch ex As ResponsedWebException Throw + Catch ex As FileNotFoundException + '由于 CacheCow 读取缓存失败,然后系统调用不存在的 System.Net.Http.Formatting.resources 抛出(#8150) + Throw New Exception($"网络请求时读取缓存失败", ex) Catch ex As Exception RecordIPReliability(HostIp, -1) If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then 'CancellationToken 超时 @@ -416,7 +428,7 @@ RequestFinished: Public ReadOnly Property NetTaskSpeedLimitHigh As Long Get If _NetTaskSpeedLimitHigh Is Nothing Then - Dim Setting = PCL.Settings.Get("ToolDownloadSpeed") + Dim Setting As Integer = Settings.Get("ToolDownloadSpeed") If Setting <= 14 Then _NetTaskSpeedLimitHigh = (Setting + 1) * 0.1 * 1024 * 1024L ElseIf Setting <= 31 Then @@ -1959,13 +1971,9 @@ Retry: ''' 是否有正在进行中、需要在下载管理页面显示的下载任务? ''' Public Function HasDownloadingTask(Optional IgnoreCustomDownload As Boolean = False) As Boolean - For Each Task In LoaderTaskbar.ToList() - If (Task.Show AndAlso Task.State = LoadState.Loading) AndAlso - (Not IgnoreCustomDownload OrElse Not Task.Name.ToString.Contains("自定义下载")) Then - Return True - End If - Next - Return False + Return LoaderTaskbar.Any( + Function(Task) Task.Show AndAlso Task.State = LoadState.Loading AndAlso + (Not IgnoreCustomDownload OrElse Not Task.Name.ToString.Contains("自定义下载"))) End Function #End Region diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb index b7143a2..37aaa81 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb @@ -1,35 +1,38 @@ Public Module ModComp - Public Enum CompType - ''' - ''' 允许任意种类,或种类未知。 - ''' - Any = -1 + Public Enum CompType ''' ''' Mod。 ''' - [Mod] = 0 + [Mod] = 1 ''' ''' 整合包。 ''' - ModPack = 1 + ModPack = 2 ''' ''' 资源包。 ''' - ResourcePack = 2 + ResourcePack = 4 ''' ''' 光影包。 ''' - Shader = 3 + Shader = 8 ''' - ''' CurseForge:数据包。 - ''' Modrinth:数据包,或数据包与 Mod 的混合。 + ''' 数据包。 ''' - DataPack = 4 + DataPack = 16 ''' ''' 服务端插件。 ''' - Plugin = 5 + Plugin = 32 + ''' + ''' 同时包含数据包以及 Mod。 + ''' + ModOrDataPack = [Mod] Or DataPack + ''' + ''' 允许任意种类,或种类未知。 + ''' + Any = [Mod] Or ModPack Or ResourcePack Or Shader Or DataPack Or Plugin End Enum Public Enum CompModLoaderType 'https://docs.curseforge.com/?http#tocS_ModLoaderType @@ -132,10 +135,10 @@ ''' Public ReadOnly FromCurseForge As Boolean ''' - ''' 工程的种类。 - ''' 由于 Modrinth 混合使用 Mod 和数据包,结果不一定准确。 + ''' 工程中包含的文件种类。 + ''' 若为 Modrinth 工程,可能为 Mod 或 数据包。 ''' - Public ReadOnly Type As CompType + Public ReadOnly Types As CompType ''' ''' 工程的短名。例如 technical-enchant。 ''' @@ -191,6 +194,12 @@ ''' 例如:261(26.1.x)、180(1.18.x)。 ''' Public ReadOnly Drops As List(Of Integer) + ''' + ''' Modrinth API 返回的原始版本列表。 + ''' 仅用于 Modrinth 工程的二次筛选,不会被缓存,不会被预处理。 + ''' 若非从 Modrinth 获取则为 Nothing。 + ''' + Public ReadOnly UnsafeGameVersions As List(Of String) '数据库信息 @@ -203,7 +212,7 @@ Get If Not LoadedDatabase Then LoadedDatabase = True - If Type = CompType.Mod OrElse Type = CompType.DataPack Then + If Types.HasFlag(CompType.Mod) OrElse Types.HasFlag(CompType.DataPack) Then _DatabaseEntry = CompDatabase.FirstOrDefault(Function(c) If(FromCurseForge, c.CurseForgeSlug, c.ModrinthSlug) = Slug) End If End If @@ -240,7 +249,7 @@ If Data.ContainsKey("Tags") Then #Region "CompJson" FromCurseForge = Data("DataSource") = "CurseForge" - Type = Data("Type").ToObject(Of Integer) + Types = Data("Types").ToObject(Of Integer) Slug = Data("Slug") Id = Data("Id") If Data.ContainsKey("CurseForgeFileIds") Then CurseForgeFileIds = CType(Data("CurseForgeFileIds"), JArray).Select(Function(t) t.ToObject(Of Integer)).ToList @@ -284,23 +293,23 @@ If LogoUrl = "" Then LogoUrl = Nothing 'Type If Website.Contains("/mc-mods/") OrElse Website.Contains("/mod/") Then - Type = CompType.Mod + Types = CompType.Mod ElseIf Website.Contains("/modpacks/") Then - Type = CompType.ModPack + Types = CompType.ModPack ElseIf Website.Contains("/resourcepacks/") Then - Type = CompType.ResourcePack + Types = CompType.ResourcePack ElseIf Website.Contains("/texture-packs/") Then - Type = CompType.ResourcePack + Types = CompType.ResourcePack ElseIf Website.Contains("/shaders/") Then - Type = CompType.Shader + Types = CompType.Shader Else - Type = CompType.DataPack + Types = CompType.DataPack End If 'FileIndexes / VanillaMajorVersions / ModLoaders ModLoaders = New List(Of CompModLoaderType) Dim Files As New List(Of KeyValuePair(Of Integer, List(Of String))) 'FileId, GameVersions For Each File In If(Data("latestFiles"), New JArray) - Dim NewFile As New CompFile(File, Type) + Dim NewFile As New CompFile(File, Types) If Not NewFile.Available Then Continue For ModLoaders.AddRange(NewFile.ModLoaders) Dim GameVersions = File("gameVersions").ToObject(Of List(Of String)) @@ -408,14 +417,14 @@ Website = $"https://modrinth.com/{Data("project_type")}/{Slug}" 'GameVersions '搜索结果的键为 versions,获取特定工程的键为 game_versions - Drops = If(CType(If(Data("game_versions"), Data("versions")), JArray), New JArray). - Select(Function(v) McVersion.VersionToDrop(v)).Where(Function(v) v > 0).Distinct.OrderByDescending(Function(v) v).ToList + UnsafeGameVersions = If(CType(If(Data("game_versions"), Data("versions")), JArray), New JArray).Select(Function(v) v.ToString).Distinct.ToList + Drops = UnsafeGameVersions.Select(Function(v) McVersion.VersionToDrop(v)).Where(Function(v) v > 0).Distinct.OrderByDescending(Function(v) v).ToList 'Type Select Case Data("project_type").ToString - Case "modpack" : Type = CompType.ModPack - Case "resourcepack" : Type = CompType.ResourcePack - Case "shader" : Type = CompType.Shader - Case Else : Type = CompType.Mod 'Modrinth 将数据包标为 Mod + Case "modpack" : Types = CompType.ModPack + Case "resourcepack" : Types = CompType.ResourcePack + Case "shader" : Types = CompType.Shader + Case Else : Types = CompType.Mod 'Modrinth 将数据包标为 Mod,但 categories 字段里有 datapack End Select 'Tags & ModLoaders Tags = New List(Of String) @@ -437,7 +446,7 @@ Case "fabric" : ModLoaders.Add(CompModLoaderType.Fabric) Case "quilt" : ModLoaders.Add(CompModLoaderType.Quilt) Case "neoforge" : ModLoaders.Add(CompModLoaderType.NeoForge) - Case "datapack" : Type = CompType.DataPack '若包含数据包版本,则优先标为 DataPack + Case "datapack" : Types = CompType.DataPack '共用 Case "technology" : Tags.Add("科技") Case "magic" : Tags.Add("魔法") @@ -452,9 +461,9 @@ Case "game-mechanics" : Tags.Add("游戏机制") Case "transportation" : Tags.Add("运输") Case "storage" : Tags.Add("仓储") - Case "decoration" : If Type <> CompType.ResourcePack Then Tags.Add("装饰") - Case "mobs" : If Type <> CompType.ResourcePack Then Tags.Add("生物") - Case "equipment" : If Type <> CompType.ResourcePack Then Tags.Add("装备") + Case "decoration" : If Types <> CompType.ResourcePack Then Tags.Add("装饰") + Case "mobs" : If Types <> CompType.ResourcePack Then Tags.Add("生物") + Case "equipment" : If Types <> CompType.ResourcePack Then Tags.Add("装备") Case "social" : Tags.Add("服务器") Case "library" : Tags.Add("支持库") '整合包 @@ -504,6 +513,7 @@ Case "vanilla" : Tags.Add("原版可用") End Select Next + If Types = CompType.DataPack AndAlso ModLoaders.Any Then Types = CompType.DataPack Or CompType.Mod #End Region End If If Not Tags.Any() Then Tags.Add("其他") @@ -519,7 +529,7 @@ Public Function ToJson() As JObject Dim Json As New JObject Json("DataSource") = If(FromCurseForge, "CurseForge", "Modrinth") - Json("Type") = CInt(Type) + Json("Types") = CInt(Types) Json("Slug") = Slug Json("Id") = Id If CurseForgeFileIds IsNot Nothing Then Json("CurseForgeFileIds") = New JArray(CurseForgeFileIds) @@ -549,7 +559,7 @@ For i = 0 To Drops.Count - 1 '版本号一定为降序 '获取当前连续的版本号段 Dim StartDrop As Integer = Drops(i), EndDrop As Integer = Drops(i) - If StartDrop < 100 Then '如果支持新版本,则不显示 1.9- + If StartDrop < 120 Then '如果支持新版本,则不显示 1.11- If Segments.Any() AndAlso Not IsOld Then Exit For Else @@ -567,14 +577,14 @@ If StartDrop = EndDrop Then Segments.Add(StartName) ElseIf AllDrops IsNot Nothing AndAlso StartDrop >= AllDrops.First Then - If EndDrop < 100 Then + If EndDrop < 120 Then Segments.Clear() Segments.Add("全版本") Exit For Else Segments.Add(EndName & "+") End If - ElseIf EndDrop < 100 Then + ElseIf EndDrop < 120 Then Segments.Add(StartName & "-") Exit For ElseIf AllDrops Is Nothing OrElse AllDrops.IndexOf(EndDrop) - AllDrops.IndexOf(StartDrop) = 1 Then @@ -762,7 +772,7 @@ NoSubtitle: 'Mod 加载器一致 If ModLoaders.Count <> Project.ModLoaders.Count OrElse ModLoaders.Except(Project.ModLoaders).Any() Then Return False '若不为光影,则要求 MC 版本一致 - If Type <> CompType.Shader AndAlso (Drops.Count <> Project.Drops.Count OrElse Drops.Except(Project.Drops).Any()) Then Return False + If Types <> CompType.Shader AndAlso (Drops.Count <> Project.Drops.Count OrElse Drops.Except(Project.Drops).Any()) Then Return False '最近更新时间差距在一周以内 If Math.Abs((LastUpdate - Project.LastUpdate).TotalDays) > 7 Then Return False 'MCMOD 翻译名 / 原名 / 描述文本 / Slug 的英文部分相同 @@ -813,8 +823,8 @@ NoSubtitle: ''' Public ReadOnly Property CanContinue As Boolean Get - If Tag.StartsWithF("/") OrElse Not Source.HasFlag(CompSourceType.CurseForge) Then Storage.CurseForgeTotal = 0 - If Tag.EndsWithF("/") OrElse Not Source.HasFlag(CompSourceType.Modrinth) Then Storage.ModrinthTotal = 0 + If Tag.StartsWithF("/") OrElse Not Sources.HasFlag(CompSourceType.CurseForge) Then Storage.CurseForgeTotal = 0 + If Tag.EndsWithF("/") OrElse Not Sources.HasFlag(CompSourceType.Modrinth) Then Storage.ModrinthTotal = 0 If Storage.CurseForgeTotal = -1 OrElse Storage.ModrinthTotal = -1 Then Return True Return Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal End Get @@ -845,7 +855,7 @@ NoSubtitle: ''' ''' 允许的来源。 ''' - Public Source As CompSourceType = CompSourceType.Any + Public Sources As CompSourceType = CompSourceType.Any Public Sub New(Type As CompType, Storage As CompProjectStorage, TargetResultCount As Integer) Me.Type = Type Me.Storage = Storage @@ -904,7 +914,7 @@ NoSubtitle: Dim request = TryCast(obj, CompProjectRequest) Return request IsNot Nothing AndAlso Type = request.Type AndAlso TargetResultCount = request.TargetResultCount AndAlso - Tag = request.Tag AndAlso ModLoader = request.ModLoader AndAlso Source = request.Source AndAlso + Tag = request.Tag AndAlso ModLoader = request.ModLoader AndAlso Sources = request.Sources AndAlso GameVersion = request.GameVersion AndAlso SearchText = request.SearchText End Function Public Shared Operator =(left As CompProjectRequest, right As CompProjectRequest) As Boolean @@ -914,7 +924,7 @@ NoSubtitle: Return Not left = right End Operator Public Overrides Function GetHashCode() As Integer - Return (Type, Tag, ModLoader, GameVersion, SearchText, Source).GetHashCode() + Return (Type, Tag, ModLoader, GameVersion, SearchText, Sources).GetHashCode() End Function End Class @@ -1019,7 +1029,7 @@ NoSubtitle: Return Candidates End Function 'CurseForge - If Request.Source.HasFlag(CompSourceType.CurseForge) Then + If Request.Sources.HasFlag(CompSourceType.CurseForge) Then '数据库搜索 Static CurseForgeSearchEntries As List(Of SearchEntry(Of CompDatabaseEntry)) = CompDatabase.Where(Function(Entry) Entry.CurseForgeSlug IsNot Nothing).Select( @@ -1043,7 +1053,7 @@ NoSubtitle: End If End If 'Modrinth - If Request.Source.HasFlag(CompSourceType.Modrinth) Then + If Request.Sources.HasFlag(CompSourceType.Modrinth) Then '数据库搜索 Static ModrinthSearchEntries As List(Of SearchEntry(Of CompDatabaseEntry)) = CompDatabase.Where(Function(Entry) Entry.ModrinthSlug IsNot Nothing).Select( @@ -1094,7 +1104,7 @@ NextPage: Try 'CurseForge 搜索 - If Request.Source.HasFlag(CompSourceType.CurseForge) AndAlso + If Request.Sources.HasFlag(CompSourceType.CurseForge) AndAlso Not (Storage.CurseForgeTotal > -1 AndAlso Storage.CurseForgeTotal <= Storage.CurseForgeOffset) AndAlso '剩余的未显示的搜索结果不足 (Not IsChineseSearch OrElse (IsChineseSearch AndAlso Not String.IsNullOrEmpty(CurseForgeAltSearchText))) Then '如果是中文搜索,就只在有对应搜索关键词的时候才继续 WorkThreads.Add(RunInNewThread( @@ -1125,7 +1135,7 @@ NextPage: End If 'Modrinth 搜索 - If Request.Source.HasFlag(CompSourceType.Modrinth) AndAlso + If Request.Sources.HasFlag(CompSourceType.Modrinth) AndAlso Not (Storage.ModrinthTotal > -1 AndAlso Storage.ModrinthTotal <= Storage.ModrinthOffset) AndAlso '剩余的未显示的搜索结果不足 (Not IsChineseSearch OrElse (IsChineseSearch AndAlso Not String.IsNullOrEmpty(ModrinthAltSearchText))) Then '如果是中文搜索,就只在有对应搜索关键词的时候才继续 WorkThreads.Add(RunInNewThread( @@ -1153,7 +1163,7 @@ NextPage: End If 'Modrinth 直接获取工程 - If Request.Source.HasFlag(CompSourceType.Modrinth) AndAlso + If Request.Sources.HasFlag(CompSourceType.Modrinth) AndAlso Not (Storage.ModrinthTotal > -1 AndAlso Storage.ModrinthTotal <= Storage.ModrinthOffset) AndAlso '剩余的未显示的搜索结果不足 ModrinthSlugs.Any Then '有直接获取的 Slug WorkThreads.Add(RunInNewThread( @@ -1163,7 +1173,16 @@ NextPage: Log("[Comp] 开始 Modrinth 直接获取:" & ModrinthUrl) Dim ProjectList As New List(Of CompProject) For Each JsonEntry As JObject In DlModRequest(ModrinthUrl) - ProjectList.Add(New CompProject(JsonEntry)) + Dim Project As New CompProject(JsonEntry) + '应用筛选 + If Request.Type <> CompType.Any AndAlso Not Project.Types.HasFlag(Request.Type) Then Continue For + If Not String.IsNullOrEmpty(Request.Tag) AndAlso + Not JsonEntry("categories").Any(Function(c) c.ToString = Request.Tag.AfterLast("/")) Then Continue For 'Project.Tags 已经转换成中文了,只能从 json 判 + If Request.ModLoader <> CompModLoaderType.Any AndAlso Not IgnoreModLoaderFilter AndAlso + Not Project.ModLoaders.Any(Function(m) m = Request.ModLoader) Then Continue For + If Not String.IsNullOrEmpty(Request.GameVersion) AndAlso + Not Project.UnsafeGameVersions.Any(Function(d) d = Request.GameVersion) Then Continue For + ProjectList.Add(Project) Next '更新结果 ProjectList.ForEach(Sub(p) RawResults.Add(p)) @@ -1196,9 +1215,9 @@ NextPage: Else If IsChineseSearch AndAlso Not (Request.Type = CompType.Mod OrElse Request.Type = CompType.DataPack) Then Throw New Exception(MSG_NO_CHINESE_SEARCH_RESULT) - ElseIf Request.Source = CompSourceType.CurseForge AndAlso Request.Tag.StartsWithF("/") Then + ElseIf Request.Sources = CompSourceType.CurseForge AndAlso Request.Tag.StartsWithF("/") Then Throw New Exception("CurseForge 不兼容所选的类型") - ElseIf Request.Source = CompSourceType.Modrinth AndAlso Request.Tag.EndsWithF("/") Then + ElseIf Request.Sources = CompSourceType.Modrinth AndAlso Request.Tag.EndsWithF("/") Then Throw New Exception("Modrinth 不兼容所选的类型") Else Throw New Exception("没有搜索结果") @@ -1418,7 +1437,7 @@ NextPage: '实例化 ''' - ''' 从文件 Json 中初始化实例。若出错会抛出异常。 + ''' 从 json 中初始化实例。若出错会抛出异常。 ''' Public Sub New(Data As JObject, DefaultType As CompType) Type = DefaultType @@ -1505,25 +1524,16 @@ NextPage: Size = File("size") Hash = File("hashes")("sha1") End If - 'ModLoaders + 'Loaders '结果可能混杂着 Mod、数据包和服务端插件 Dim RawLoaders As List(Of String) = Data("loaders").Select(Function(v) v.ToString).ToList ModLoaders = New List(Of CompModLoaderType) - If Type = CompType.Mod Then '以尽量宽容的方式检测加载器,以免同时兼容两种的项被删除 - If RawLoaders.Intersect({"bukkit", "folia", "paper", "purpur", "spigot"}).Any() Then Type = CompType.Plugin 'Veinminer Enchantment 同时支持服务端与 Fabric - If RawLoaders.Contains("datapack") Then Type = CompType.DataPack - If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge) : Type = CompType.Mod - If RawLoaders.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge) : Type = CompType.Mod - If RawLoaders.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric) : Type = CompType.Mod - If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt) : Type = CompType.Mod - ElseIf Type = CompType.DataPack Then - If RawLoaders.Intersect({"bukkit", "folia", "paper", "purpur", "spigot"}).Any() Then Type = CompType.Plugin - If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge) : Type = CompType.Mod - If RawLoaders.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge) : Type = CompType.Mod - If RawLoaders.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric) : Type = CompType.Mod - If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt) : Type = CompType.Mod - If RawLoaders.Contains("datapack") Then Type = CompType.DataPack - End If + If RawLoaders.Intersect({"bukkit", "folia", "paper", "purpur", "spigot"}).Any() Then Type = CompType.Plugin 'Veinminer Enchantment 同时支持服务端与 Fabric + If RawLoaders.Contains("datapack") Then Type = CompType.DataPack + If RawLoaders.Contains("forge") Then ModLoaders.Add(CompModLoaderType.Forge) : Type = CompType.Mod + If RawLoaders.Contains("neoforge") Then ModLoaders.Add(CompModLoaderType.NeoForge) : Type = CompType.Mod + If RawLoaders.Contains("fabric") Then ModLoaders.Add(CompModLoaderType.Fabric) : Type = CompType.Mod + If RawLoaders.Contains("quilt") Then ModLoaders.Add(CompModLoaderType.Quilt) : Type = CompType.Mod 'Dependencies If Data.ContainsKey("dependencies") Then RawDependencies = Data("dependencies"). @@ -1694,7 +1704,7 @@ NextPage: 'Modrinth ResultJsonArray = DlModRequest($"https://api.modrinth.com/v2/project/{ProjectId}/version?include_changelog=false") End If - CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Type)). + CompFilesCache(ProjectId) = ResultJsonArray.Select(Function(a) New CompFile(a, TargetProject.Types)). Where(Function(a) a.Available).ToList. Distinct(Function(a, b) a.Id = b.Id) 'CurseForge 可能会重复返回相同项(#1330) End If diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb index f535386..b9d9458 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb @@ -858,10 +858,11 @@ VersionName = ApiName Version = New Version(ApiName.BeforeFirst("-")) If Version.Major >= 24 Then - Inherit = Version.Major & "." & Version.Minor + Inherit = $"{Version.Major}.{Version.Minor}.{Version.Build}" Else - Inherit = "1." & Version.Major & If(Version.Minor > 0, "." & Version.Minor, "") + Inherit = $"1.{Version.Major}.{Version.Minor}" End If + If Inherit.EndsWithF(".0") Then Inherit = Left(Inherit, Inherit.Length - 2) If VersionName.Contains("+") Then Inherit &= "-" & VersionName.AfterFirst("+") End If End Sub diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index 5672ca1..6722894 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -1446,9 +1446,10 @@ NextInstance: Args = Args.Where(Function(a) Not RegexCheck(a, "( )*-XX:[+-]?(Use\w+GC|ZGenerational|UseCompactObjectHeaders|G1\w+Percent|G1\w+Size|(Max|Min)(GCPauseMillis|HeapFreeRatio))")).ToList '添加 GC 参数 + Args.Add("-XX:+UnlockExperimentalVMOptions") + If McLaunchJavaSelected.MajorVersion >= 24 AndAlso McLaunchJavaSelected.Is64Bit Then Args.Add("-XX:+UseCompactObjectHeaders") If UseG1GC AndAlso SetupType = 4 Then '优化的 G1GC - Args.Add("-XX:+UnlockExperimentalVMOptions") Args.Add("-XX:+UseG1GC") Args.Add("-XX:G1NewSizePercent=20") Args.Add("-XX:G1ReservePercent=20") @@ -1459,10 +1460,8 @@ NextInstance: If McLaunchJavaSelected.MajorVersion = 8 Then Args.Add("-XX:+ParallelRefProcEnabled") If McLaunchJavaSelected.MajorVersion >= 12 Then Args.Add("-XX:MinHeapFreeRatio=25") '需要比 G1NewSizePercent 大一点 If McLaunchJavaSelected.MajorVersion >= 12 Then Args.Add("-XX:MaxHeapFreeRatio=40") '需要比 MinHeapFreeRatio 大一些 - If McLaunchJavaSelected.MajorVersion >= 24 AndAlso McLaunchJavaSelected.Is64Bit Then Args.Add("-XX:+UseCompactObjectHeaders") ElseIf UseG1GC Then 'Mojang G1GC - Args.Add("-XX:+UnlockExperimentalVMOptions") Args.Add("-XX:+UseG1GC") Args.Add("-XX:G1NewSizePercent=20") Args.Add("-XX:G1ReservePercent=20") diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb index 923652c..ad7ebd4 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb @@ -1119,7 +1119,7 @@ ExitDataLoad: Public Shared Function IsFormatFit(Version As String) As Boolean If Version Is Nothing Then Return False If RegexCheck(Version, "^1\.\d") Then Return True - If Val(RegexSeek(Version, "^[2-9]\d\.\d+")) > 25 Then Return True + If Val(RegexSeek(Version, "^[2-9]\d\.\d+")) >= 26 Then Return True Return False End Function ''' diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb index 2bbecff..4b53985 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMod.vb @@ -1,7 +1,7 @@ Imports System.IO.Compression Public Module ModMod - Private Const LocalModCacheVersion As Integer = 12 + Private Const LocalModCacheVersion As Integer = 13 Public Class McMod diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb index e0765ad..bf8a58b 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/Comp/MyCompItem.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.vb index 0a36182..6843a0b 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/MyCompItem.xaml.vb @@ -94,36 +94,36 @@ End If '打开详情页 Dim TargetType As CompType - Dim TargetVersion As String = Nothing + Dim TargetInstance As String = Nothing Dim TargetLoader As CompModLoaderType = CompModLoaderType.Any If FrmMain.PageCurrent.Page = FormMain.PageType.Download Then '从下载页进入 Select Case FrmMain.PageCurrentSub Case FormMain.PageSubType.DownloadMod TargetType = CompType.Mod - TargetVersion = FrmDownloadMod.Content.Loader.Input.GameVersion + TargetInstance = FrmDownloadMod.Content.Loader.Input.GameVersion TargetLoader = FrmDownloadMod.Content.Loader.Input.ModLoader Case FormMain.PageSubType.DownloadPack TargetType = CompType.ModPack - TargetVersion = FrmDownloadPack.Content.Loader.Input.GameVersion + TargetInstance = FrmDownloadPack.Content.Loader.Input.GameVersion Case FormMain.PageSubType.DownloadDataPack TargetType = CompType.DataPack - TargetVersion = FrmDownloadDataPack.Content.Loader.Input.GameVersion + TargetInstance = FrmDownloadDataPack.Content.Loader.Input.GameVersion Case FormMain.PageSubType.DownloadResourcePack TargetType = CompType.ResourcePack - TargetVersion = FrmDownloadResourcePack.Content.Loader.Input.GameVersion + TargetInstance = FrmDownloadResourcePack.Content.Loader.Input.GameVersion Case FormMain.PageSubType.DownloadShader TargetType = CompType.Shader - TargetVersion = FrmDownloadShader.Content.Loader.Input.GameVersion + TargetInstance = FrmDownloadShader.Content.Loader.Input.GameVersion End Select Else '从详情页进入(查看前置) TargetType = CompType.Any '允许任意类别 - TargetVersion = FrmMain.PageCurrent.Additional(2) + TargetInstance = FrmMain.PageCurrent.Additional(2) TargetLoader = FrmMain.PageCurrent.Additional(3) End If FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail, - .Additional = {sender.Tag, New List(Of String), TargetVersion, TargetLoader, TargetType}}) + .Additional = {sender.Tag, New List(Of String), TargetInstance, TargetLoader, TargetType}}) End Sub '鼠标点击判定 diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml index b451f64..d669f8d 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml @@ -34,15 +34,16 @@ + + + - - + - diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.vb index 746cdad..9df5bb3 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageComp.xaml.vb @@ -127,7 +127,7 @@ Public Class PageComp .GameVersion = GameVersion .Tag = ComboSearchTag.SelectedItem.Tag .ModLoader = If(PageType = CompType.Mod, Val(ComboSearchLoader.SelectedItem.Tag), CompModLoaderType.Any) - .Source = CType(Val(ComboSearchSource.SelectedItem.Tag), CompSourceType) + .Sources = CType(Val(ComboSearchSource.SelectedItem.Tag), CompSourceType) End With Return Request End Function diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml index eb4a37c..f95e25d 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml @@ -20,6 +20,7 @@ + diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb index 32bb750..6d6dc54 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/Comp/PageDownloadCompDetail.xaml.vb @@ -21,14 +21,15 @@ Project = FrmMain.PageCurrent.Additional(0) TargetInstance = FrmMain.PageCurrent.Additional(2) TargetLoader = FrmMain.PageCurrent.Additional(3) - PageType = FrmMain.PageCurrent.Additional(4) + TargetType = FrmMain.PageCurrent.Additional(4) End Sub Private Project As CompProject Private TargetInstance As String, TargetLoader As CompModLoaderType ''' - ''' 当前页面应展示的内容类别。可能为 Any。 + ''' 当前页面应展示的内容类别。 + ''' 若当前页面是在查看前置时进入,则也可能为 Any。 ''' - Private PageType As CompType + Private TargetType As CompType '自动重试 Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged Select Case CompFileLoader.State @@ -74,13 +75,13 @@ '筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表) Private Function GetResults() As List(Of CompFile) Dim Results As List(Of CompFile) = CompFileLoader.Output - Select Case PageType + Select Case TargetType Case CompType.Any Results = Results.Where(Function(r) r.Type <> CompType.Plugin).ToList Case CompType.Shader, CompType.ResourcePack '不筛选光影和资源包,否则原版光影会因为是资源包格式而被过滤(#6473) Case Else - Results = Results.Where(Function(r) r.Type = PageType).ToList + Results = Results.Where(Function(r) r.Type = TargetType).ToList End Select Return Results End Function @@ -204,7 +205,7 @@ GroupDone: If Not Pair.Value.Any() Then Continue For If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For '增加卡片 - Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(PageType = CompType.ModPack, 9, 8)} '9 是安装,8 是另存为 + Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(TargetType = CompType.ModPack, 9, 8)} '9 是安装,8 是另存为 Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value} NewCard.Children.Add(NewStack) NewCard.SwapControl = NewStack @@ -213,7 +214,7 @@ GroupDone: If Pair.Key = TargetCardName OrElse (FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761 CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then - MyCard.StackInstall(NewStack, If(PageType = CompType.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为 + MyCard.StackInstall(NewStack, If(TargetType = CompType.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为 Else NewCard.IsSwapped = True End If @@ -226,6 +227,14 @@ GroupDone: If PanResults.Children.Count = 1 Then CType(PanResults.Children(0), MyCard).IsSwapped = False End If + '替代提示 + If Project.Types = CompType.ModOrDataPack AndAlso (TargetType = CompType.Mod OrElse TargetType = CompType.DataPack) Then + HintAlternative.Visibility = Visibility.Visible + HintAlternative.Text = If(TargetType = CompType.Mod, + "以下是该项目的 Mod 版本。点击这里查看其数据包版本。", "以下是该项目的数据包版本。点击这里查看其 Mod 版本。") + Else + HintAlternative.Visibility = Visibility.Collapsed + End If Catch ex As Exception Log(ex, "可视化工程下载列表出错", LogLevel.Feedback) End Try @@ -494,4 +503,11 @@ GroupDone: ClipboardSet(CompItem.LabTitle.Text & CompItem.LabTitleRaw.Text) End Sub + 'Mod / 数据包 互相跳转 + Private Sub HintAlternative_Click() Handles HintAlternative.Click + TargetType = If(TargetType = CompType.Mod, CompType.DataPack, CompType.Mod) + FrmMain.PageCurrent.Additional(4) = TargetType '加载器会从这里重新拿数据 + PageLoaderRestart(IsForceRestart:=True) + End Sub + End Class diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb index 6eba85a..22b8ac7 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb @@ -47,7 +47,7 @@ Private Sub BtnEdit_Click(sender As Object, e As EventArgs) Handles BtnEdit.Click If McLoginLoader.State = LoadState.Loading Then Log("[Launch] 要求更换角色,但登录加载器繁忙", LogLevel.Debug) - If CType(McLoginLoader.Input, McLoginServer).ForceReselectProfile Then + If TypeOf McLoginLoader.Input Is McLoginServer AndAlso CType(McLoginLoader.Input, McLoginServer).ForceReselectProfile Then Hint("正在尝试更换,请稍候!") Else Hint("正在登录中,请稍后再更换角色!", HintType.Red) diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb index 65c39b0..269afb6 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb @@ -85,51 +85,56 @@ Hint("正在更改皮肤……") IsChanging = True '开始实际获取 - RunInNewThread( - Sub() - Try + RunInNewThread(Sub() EditSkin(SkinInfo), "Ms Skin Upload") + End Sub + Private Sub EditSkin(SkinInfo As McSkinInfo) Retry: - Do While McLoginMsLoader.State = LoadState.Loading '等待登录结束 - Thread.Sleep(10) - Loop - If McLoginMsLoader.State = LoadState.Failed Then Throw New Exception("登录失败", McLoginMsLoader.Error) - Dim AccessToken As String = Settings.Get("CacheMsV2Access") - Dim Uuid As String = Settings.Get("CacheMsV2Uuid") - Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/skins", HttpMethod.Post, - Content:=New Net.Http.MultipartFormDataContent From { - {New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"}, - {New Net.Http.ByteArrayContent(ReadFileBytes(SkinInfo.LocalFile)), "file", GetFileNameFromPath(SkinInfo.LocalFile)} - }, - Headers:={{"Authorization", "Bearer " & AccessToken}, {"Accept", "*/*"}, {"User-Agent", "MojangSharp/0.1"}}) - If Result.Contains("request requires user authentication") Then - Hint("正在登录,将在登录完成后继续更改皮肤……") - McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True) - GoTo Retry - ElseIf Result.Contains("""error""") Then - Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Red) + Try + Do While McLoginMsLoader.State = LoadState.Loading '等待登录结束 + Thread.Sleep(10) + Loop + If McLoginMsLoader.State = LoadState.Failed Then Throw New Exception("登录失败", McLoginMsLoader.Error) + Dim AccessToken As String = Settings.Get("CacheMsV2Access") + Dim Uuid As String = Settings.Get("CacheMsV2Uuid") + Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/skins", HttpMethod.Post, + Content:=New Net.Http.MultipartFormDataContent From { + {New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"}, + {New Net.Http.ByteArrayContent(ReadFileBytes(SkinInfo.LocalFile)), "file", GetFileNameFromPath(SkinInfo.LocalFile)} + }, + Headers:={{"Authorization", "Bearer " & AccessToken}, {"Accept", "*/*"}, {"User-Agent", "MojangSharp/0.1"}}) + If Result.Contains("request requires user authentication") Then + Hint("正在重新登录,将在登录后自动更改皮肤……") + McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True) + GoTo Retry + ElseIf Result.Contains("""error""") Then + Hint("更改皮肤失败:" & GetJson(Result)("error").ToString, HintType.Red) + Return + End If + '获取新皮肤地址 + Log("[Skin] 皮肤修改返回值:" & vbCrLf & Result) + Dim ResultJson As JObject = GetJson(Result) + If ResultJson.ContainsKey("errorMessage") Then Throw New Exception(ResultJson("errorMessage").ToString) '#5309 + For Each Skin As JObject In ResultJson("skins") + If Skin("state").ToString = "ACTIVE" Then + MySkin.ReloadCache(Skin("url")) Return End If - '获取新皮肤地址 - Log("[Skin] 皮肤修改返回值:" & vbCrLf & Result) - Dim ResultJson As JObject = GetJson(Result) - If ResultJson.ContainsKey("errorMessage") Then Throw New Exception(ResultJson("errorMessage").ToString) '#5309 - For Each Skin As JObject In ResultJson("skins") - If Skin("state").ToString = "ACTIVE" Then - MySkin.ReloadCache(Skin("url")) - Return - End If - Next - Throw New Exception("未知错误(" & Result & ")") - Catch ex As Exception - If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then - Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red) - Else - Log(ex, "更改皮肤失败", LogLevel.Hint) - End If - Finally - IsChanging = False - End Try - End Sub, "Ms Skin Upload") + Next + Throw New Exception("未知错误(" & Result & ")") + Catch ex As Exception + If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then + Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red) + ElseIf TypeOf ex Is ResponsedWebException AndAlso CType(ex, ResponsedWebException).StatusCode = HttpStatusCode.Unauthorized Then + Log(ex, "更改皮肤时遭遇 401 错误", LogLevel.Developer) + Hint("正在重新登录,将在登录后自动更改皮肤……") + McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True) + GoTo Retry + Else + Log(ex, "更改皮肤失败", LogLevel.Hint) + End If + Finally + IsChanging = False + End Try End Sub '保存皮肤 diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml index a19759d..56a215d 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml @@ -186,6 +186,8 @@ + + @@ -202,6 +204,7 @@ + @@ -315,6 +318,9 @@ + + + @@ -365,6 +371,7 @@ + @@ -381,6 +388,8 @@ + + @@ -394,6 +403,7 @@ + @@ -451,22 +461,29 @@ + + + + + + + @@ -500,6 +517,7 @@ + @@ -508,6 +526,7 @@ + @@ -536,6 +555,7 @@ + @@ -634,6 +654,7 @@ + @@ -707,9 +728,13 @@ + + + + @@ -732,6 +757,7 @@ + @@ -768,6 +794,7 @@ + @@ -786,6 +813,7 @@ + diff --git a/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb b/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb index 06839f5..1e477cd 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb @@ -211,7 +211,6 @@ ''' 该设置的值的实际类型。 ''' Public Type As Type - Public Sub New(Key As String, Value As Object, Optional Source As Sources = Sources.Normal, Optional Encrypted As Boolean = False, Optional OnChanged As Action(Of Object) = Nothing) Try Me.Key = Key @@ -224,6 +223,30 @@ Log(ex, "初始化设置项失败", LogLevel.Feedback) '#5095 的 fallback End Try End Sub + + ''' + ''' 立即将当前的 Value 写入对应的注册表或文件。 + ''' + Public Sub Save(Optional Instance As McInstance = Nothing) + Dim Value As String = Me.Value + If Encrypted Then + Try + If Value Is Nothing Then Value = "" + Value = SecretEncrypt(Value, "PCL" & Identify) + Catch ex As Exception + Log(ex, "加密设置失败:" & Key, LogLevel.Developer) + End Try + End If + Select Case Source + Case Sources.Normal + WriteIni("Setup", Key, Value) + Case Sources.Registry + WriteReg(Key, Value) + Case Sources.Instance + If Instance Is Nothing Then Throw New Exception($"保存版本独立设置 {Key} 时未提供目标版本") + WriteIni(Instance.PathVersion & "PCL\Setup.ini", Key, Value) + End Select + End Sub End Class ''' @@ -239,25 +262,9 @@ If Entry.Value = Value Then Return '设置新值 Entry.Value = Value - If Entry.Encrypted Then - Try - If Value Is Nothing Then Value = "" - Value = SecretEncrypt(Value, "PCL" & Identify) - Catch ex As Exception - Log(ex, "加密设置失败:" & Key, LogLevel.Developer) - End Try - End If - Select Case Entry.Source - Case Sources.Normal - WriteIni("Setup", Key, Value) - Case Sources.Registry - WriteReg(Key, Value) - Case Sources.Instance - If Instance Is Nothing Then Throw New Exception($"更改版本设置 {Key} 时未提供目标版本") - WriteIni(Instance.PathVersion & "PCL\Setup.ini", Key, Value) - End Select - '触发改变事件(必须在写入之后,以保证 VersionServerLogin 之类的在事件中读取到的是最新的值) - If Entry.OnChanged IsNot Nothing Then Entry.OnChanged.Invoke(Value) + Entry.Save(Instance) + '触发改变事件(必须在保存之后,以保证 VersionServerLogin 之类的在事件中读取到的是最新的值) + If Entry.OnChanged IsNot Nothing Then Entry.OnChanged.Invoke(Entry.Value) Catch ex As Exception Log(ex, "设置设置项时出错(" & Key & ", " & Value & ")", LogLevel.Feedback) End Try @@ -315,7 +322,8 @@ Catch ex As Exception Log(ex, "解密设置失败:" & Key, LogLevel.Developer) GotValue = Entry.DefaultValue - [Set](Key, Entry.DefaultValue) + Entry.Value = Entry.DefaultValue + Entry.Save(Instance) End Try End If End If