From 13e69ed84bd6eeb429f73d2aa2f2cac54231c843 Mon Sep 17 00:00:00 2001 From: Yifan Liu Date: Fri, 3 Mar 2023 22:19:37 -0600 Subject: [PATCH] feat: support ota update of acitivity info (and any other resources) --- src/MaaWpfGui/Helper/StageManager.cs | 66 ++++++++++++++++++---------- src/MaaWpfGui/Helper/WebService.cs | 7 +-- src/MaaWpfGui/Main/AsstProxy.cs | 10 +++++ 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/MaaWpfGui/Helper/StageManager.cs b/src/MaaWpfGui/Helper/StageManager.cs index ea742d71e6..da5c1452fd 100644 --- a/src/MaaWpfGui/Helper/StageManager.cs +++ b/src/MaaWpfGui/Helper/StageManager.cs @@ -19,7 +19,6 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; -using System.Windows.Documents; using MaaWpfGui.Helper; using Newtonsoft.Json.Linq; using Semver; @@ -75,8 +74,38 @@ namespace MaaWpfGui { string.Empty, new StageInfo { Display = Localization.GetString("DefaultStage"), Value = string.Empty } }, }; - var stageApi = "StageActivity.json"; - var activity = fromWeb ? WebService.RequestMaaApiWithCache(stageApi) : WebService.LoadApiCache(stageApi); + var clientType = ViewStatusStorage.Get("Start.ClientType", string.Empty); + + // 官服和B服使用同样的资源 + if (clientType == "Bilibili" || clientType == string.Empty) + { + clientType = "Official"; + } + + // Download the activities + var stageApi = "gui/StageActivity.json"; + JObject activity = fromWeb ? WebService.RequestMaaApiWithCache(stageApi) : WebService.LoadApiCache(stageApi); + + // Download the tasks resources into cache so MaaCore can load them later + var tasksPath = "resource/tasks.json"; + JObject tasksJson = fromWeb ? WebService.RequestMaaApiWithCache(tasksPath) : WebService.LoadApiCache(tasksPath); + + // Download the client specific resources only when the Official ones are successfully downloaded so that the client specific resource version is the actual version + // TODO: There may be an issue when the CN resource is loaded from cache (e.g. network down) while global resource is downloaded (e.g. network up again) + JObject tasksJsonClient = null; + if (clientType != "Official" && tasksJson != null) + { + tasksPath = clientType + '/' + tasksPath; + tasksJsonClient = fromWeb ? WebService.RequestMaaApiWithCache(tasksPath) : WebService.RequestMaaApiWithCache(tasksPath); + } + + bool isDebugVersion = Marshal.PtrToStringAnsi(AsstGetVersion()) == "DEBUG VERSION"; + bool curVerParsed = !isDebugVersion ? + SemVersion.TryParse(Marshal.PtrToStringAnsi(AsstGetVersion()), SemVersionStyles.AllowLowerV, out var curVersionObj) : + SemVersion.TryParse("4.11.7", SemVersionStyles.AllowLowerV, out curVersionObj); + bool curResourceVerParsed = SemVersion.TryParse( + tasksJsonClient?["ResourceVersion"]?.ToString() ?? tasksJson?["ResourceVersion"]?.ToString() ?? string.Empty, + SemVersionStyles.AllowLowerV, out var curResourceVersionObj); var resourceCollection = new StageActivityInfo() { @@ -88,40 +117,31 @@ namespace MaaWpfGui "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture).AddHours(-Convert.ToInt32(keyValuePairs?["TimeZone"].ToString() ?? "0")); - var clientType = ViewStatusStorage.Get("Start.ClientType", string.Empty); - - // 官服和B服使用同样的资源 - if (clientType == "Bilibili" || clientType == string.Empty) - { - clientType = "Official"; - } - if (activity?[clientType] != null) { try { // 资源全开放活动 - var resource = activity[clientType]["resourceCollection"]; - if (resource != null) + var resourceCollectionData = activity[clientType]["resourceCollection"]; + if (resourceCollectionData != null) { - resourceCollection.Tip = resource["Tip"]?.ToString(); - resourceCollection.UtcStartTime = GetDateTime(resource, "UtcStartTime"); - resourceCollection.UtcExpireTime = GetDateTime(resource, "UtcExpireTime"); + resourceCollection.Tip = resourceCollectionData["Tip"]?.ToString(); + resourceCollection.UtcStartTime = GetDateTime(resourceCollectionData, "UtcStartTime"); + resourceCollection.UtcExpireTime = GetDateTime(resourceCollectionData, "UtcExpireTime"); } // 活动关卡 foreach (var stageObj in activity[clientType]["sideStoryStage"] ?? Enumerable.Empty()) { - bool isDebugVersion = Marshal.PtrToStringAnsi(AsstGetVersion()) == "DEBUG VERSION"; - bool curParsed = !isDebugVersion ? - SemVersion.TryParse(Marshal.PtrToStringAnsi(AsstGetVersion()), SemVersionStyles.AllowLowerV, out var curVersionObj) : - SemVersion.TryParse("4.11.7", SemVersionStyles.AllowLowerV, out curVersionObj); - bool minimumRequiredPared = SemVersion.TryParse(stageObj?["MinimumRequired"]?.ToString() ?? string.Empty, SemVersionStyles.AllowLowerV, out var minimumRequiredObj); + // MinimumResourceRequired is not necessarily provided in json, in which case it is ok even if there are no cached resources + bool minResourceRequiredParsed = SemVersion.TryParse(stageObj?["MinimumResourceRequired"]?.ToString() ?? string.Empty, SemVersionStyles.AllowLowerV, out var minResourceRequiredObj); + bool minRequiredParsed = SemVersion.TryParse(stageObj?["MinimumRequired"]?.ToString() ?? string.Empty, SemVersionStyles.AllowLowerV, out var minRequiredObj); var stageInfo = new StageInfo(); - if (curParsed && minimumRequiredPared) + if (curVerParsed && minRequiredParsed && (!minResourceRequiredParsed || curResourceVerParsed)) { - if (curVersionObj.CompareSortOrderTo(minimumRequiredObj) < 0) + if (curVersionObj.CompareSortOrderTo(minRequiredObj) < 0 && + (!minResourceRequiredParsed || curResourceVersionObj.CompareSortOrderTo(minResourceRequiredObj) < 0)) { if (!tempStage.ContainsKey(Localization.GetString("UnsupportedStages"))) { diff --git a/src/MaaWpfGui/Helper/WebService.cs b/src/MaaWpfGui/Helper/WebService.cs index 32afaf5244..0793948a17 100644 --- a/src/MaaWpfGui/Helper/WebService.cs +++ b/src/MaaWpfGui/Helper/WebService.cs @@ -63,7 +63,7 @@ namespace MaaWpfGui.Helper } } - private const string CacheDir = "cache/gui/"; + private const string CacheDir = "cache/"; private const string MaaApi = "https://ota.maa.plus/MaaAssistantArknights/api/"; // 如果请求失败,则读取缓存。否则写入缓存 @@ -85,7 +85,8 @@ namespace MaaWpfGui.Helper try { var json = (JObject)JsonConvert.DeserializeObject(response); - var cache = CacheDir + api.Replace('/', '_'); + var cache = CacheDir + api; + Directory.CreateDirectory(Path.GetDirectoryName(cache)); File.WriteAllText(cache, response); return json; @@ -98,7 +99,7 @@ namespace MaaWpfGui.Helper public static JObject LoadApiCache(string api) { - var cache = CacheDir + api.Replace('/', '_'); + var cache = CacheDir + api; if (!File.Exists(cache)) { return null; diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index fdaff86592..f761a73dd2 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -213,12 +213,18 @@ namespace MaaWpfGui } loaded = AsstLoadResource(Directory.GetCurrentDirectory()); + + // Load the cached incremental resources + loaded = loaded && AsstLoadResource(Directory.GetCurrentDirectory() + "\\cache"); } else if (_curResource == "Official" || _curResource == "Bilibili") { // Load basic resources for CN client first // Then load global incremental resources loaded = AsstLoadResource(Directory.GetCurrentDirectory() + "\\resource\\global\\" + _settingsViewModel.ClientType); + + // Load the cached incremental resources + loaded = loaded && AsstLoadResource(Directory.GetCurrentDirectory() + "\\cache\\resource\\global\\" + _settingsViewModel.ClientType); } else { @@ -226,6 +232,10 @@ namespace MaaWpfGui // Then load global incremental resources loaded = AsstLoadResource(Directory.GetCurrentDirectory()) && AsstLoadResource(Directory.GetCurrentDirectory() + "\\resource\\global\\" + _settingsViewModel.ClientType); + + // Load the cached incremental resources + loaded = loaded && AsstLoadResource(Directory.GetCurrentDirectory() + "\\cache") + && AsstLoadResource(Directory.GetCurrentDirectory() + "\\cache\\resource\\global\\" + _settingsViewModel.ClientType); } if (!loaded)