From 3b299caf8c779cb35fc9a62dce9add67fcf2174e Mon Sep 17 00:00:00 2001 From: MistEO Date: Fri, 28 Apr 2023 18:35:11 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=9B=B4=E5=A4=9A=E7=9A=84=E6=83=B0?= =?UTF-8?q?=E6=80=A7=E5=8A=A0=E8=BD=BD=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Miscellaneous/AvatarCacheManager.cpp | 46 ++++---- .../Config/Miscellaneous/AvatarCacheManager.h | 3 +- src/MaaCore/Config/Miscellaneous/OcrPack.cpp | 1 - .../Config/Miscellaneous/StageDropsConfig.cpp | 1 + src/MaaCore/Config/ResourceLoader.cpp | 76 +++++++------ src/MaaWpfGui/Main/AsstProxy.cs | 100 ++++-------------- src/MaaWpfGui/Services/StageManager.cs | 3 - 7 files changed, 93 insertions(+), 137 deletions(-) diff --git a/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.cpp b/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.cpp index a38d26d7e2..fdf355c7c1 100644 --- a/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.cpp +++ b/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.cpp @@ -8,42 +8,30 @@ bool asst::AvatarCacheManager::load(const std::filesystem::path& path) { LogTraceFunction; - Log.info("load", path); - m_path = path; - - if (!std::filesystem::exists(path)) { + if (path == m_save_path) { + Log.info("already loaded", path); return true; } + Log.info("load", path); - const auto& [_1, _2, w, h] = Task.get("BattleOperAvatar")->rect_move; + m_waiting_to_load.clear(); + m_save_path = path; for (const auto& entry : std::filesystem::directory_iterator(path)) { if (!entry.is_regular_file()) { continue; } - const std::filesystem::path& filepath = entry.path(); std::string name = utils::path_to_utf8_string(filepath.stem()); + auto role = BattleData.get_role(name); if (role == battle::Role::Unknown) { Log.warn("unknown oper", name); continue; } - Log.trace(filepath); - cv::Mat avatar = asst::imread(filepath); - - if (avatar.empty()) { - Log.warn("failed to read", filepath); - continue; - } - if (avatar.cols > w || avatar.rows > h) { - Log.warn("avatar size too large", filepath); - continue; - } - - m_avatars[role].emplace(name, std::move(avatar)); + m_waiting_to_load.insert_or_assign(name, filepath); } return true; @@ -51,6 +39,24 @@ bool asst::AvatarCacheManager::load(const std::filesystem::path& path) const asst::AvatarCacheManager::AvatarsMap& asst::AvatarCacheManager::get_avatars(battle::Role role) { + if (!m_waiting_to_load.empty()) { + const auto& [_1, _2, w, h] = Task.get("BattleOperAvatar")->rect_move; + for (auto& [name, filepath] : m_waiting_to_load) { + Log.info("load", name, filepath); + auto avatar = asst::imread(filepath); + if (avatar.empty()) { + Log.error("load failed", filepath); + continue; + } + if (avatar.cols != w || avatar.rows != h) { + Log.error("size mismatch", filepath, avatar.cols, avatar.rows); + continue; + } + m_avatars[role].insert_or_assign(std::move(name), std::move(avatar)); + } + m_waiting_to_load.clear(); + } + return m_avatars[role]; } @@ -73,7 +79,7 @@ void asst::AvatarCacheManager::set_avatar(const std::string& name, battle::Role return; } - auto path = m_path / utils::path(name + CacheExtension); + auto path = m_save_path / utils::path(name + CacheExtension); Log.info(path); asst::imwrite(path, avatar); diff --git a/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.h b/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.h index d55bb8035f..773e27da22 100644 --- a/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.h +++ b/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.h @@ -27,8 +27,9 @@ namespace asst void set_avatar(const std::string& name, battle::Role role, const cv::Mat& avatar, bool overlay = true); private: + std::unordered_map m_waiting_to_load; std::unordered_map> m_avatars; - std::filesystem::path m_path; + std::filesystem::path m_save_path; }; inline static auto& AvatarCache = AvatarCacheManager::get_instance(); } diff --git a/src/MaaCore/Config/Miscellaneous/OcrPack.cpp b/src/MaaCore/Config/Miscellaneous/OcrPack.cpp index 2a363d6925..5ffeebcfd9 100644 --- a/src/MaaCore/Config/Miscellaneous/OcrPack.cpp +++ b/src/MaaCore/Config/Miscellaneous/OcrPack.cpp @@ -9,7 +9,6 @@ ASST_SUPPRESS_CV_WARNINGS_START #include "fastdeploy/vision/ocr/ppocr/recognizer.h" ASST_SUPPRESS_CV_WARNINGS_END -#include "Config/GeneralConfig.h" #include "Utils/Demangle.hpp" #include "Utils/File.hpp" #include "Utils/Logger.hpp" diff --git a/src/MaaCore/Config/Miscellaneous/StageDropsConfig.cpp b/src/MaaCore/Config/Miscellaneous/StageDropsConfig.cpp index a366ea63eb..6717f8f967 100644 --- a/src/MaaCore/Config/Miscellaneous/StageDropsConfig.cpp +++ b/src/MaaCore/Config/Miscellaneous/StageDropsConfig.cpp @@ -37,5 +37,6 @@ bool asst::StageDropsConfig::parse(const json::value& json) m_all_stage_code.emplace(code); m_stage_info.emplace(std::move(key), std::move(info)); } + return true; } diff --git a/src/MaaCore/Config/ResourceLoader.cpp b/src/MaaCore/Config/ResourceLoader.cpp index 3a70642f86..9370f762e2 100644 --- a/src/MaaCore/Config/ResourceLoader.cpp +++ b/src/MaaCore/Config/ResourceLoader.cpp @@ -63,46 +63,62 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path) LogTraceFunction; using namespace asst::utils::path_literals; - /* load resource with json files*/ - LoadResourceAndCheckRet(GeneralConfig, "config.json"_p); - LoadResourceAndCheckRet(RecruitConfig, "recruitment.json"_p); - LoadResourceAndCheckRet(StageDropsConfig, "stages.json"_p); - LoadResourceAndCheckRet(RoguelikeCopilotConfig, "roguelike"_p / "copilot.json"_p); - LoadResourceAndCheckRet(RoguelikeRecruitConfig, "roguelike"_p / "recruitment.json"_p); - LoadResourceAndCheckRet(RoguelikeShoppingConfig, "roguelike"_p / "shopping.json"_p); - LoadResourceAndCheckRet(RoguelikeStageEncounterConfig, "roguelike"_p / "stage_encounter.json"_p); - LoadResourceAndCheckRet(BattleDataConfig, "battle_data.json"_p); - LoadResourceAndCheckRet(OcrConfig, "ocr_config.json"_p); + std::vector> futures; - /* load resource with json and template files*/ - LoadResourceWithTemplAndCheckRet(TaskData, "tasks.json"_p, "template"_p); - LoadResourceWithTemplAndCheckRet(InfrastConfig, "infrast.json"_p, "template"_p / "infrast"_p); - LoadResourceWithTemplAndCheckRet(ItemConfig, "item_index.json"_p, "template"_p / "items"_p); + // 这俩比较慢的单独拿出来,放最前面 + futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { + LoadResourceAndCheckRet(StageDropsConfig, "stages.json"_p); + return true; + })); + futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { + LoadResourceAndCheckRet(TilePack, "Arknights-Tile-Pos"_p); + return true; + })); - /* load cache */ - LoadCacheWithoutRet(AvatarCacheManager, "avatars"_p); + futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { + // 战斗中技能识别,二分类模型 + LoadResourceAndCheckRet(OnnxSessions, "onnx"_p / "skill_ready_cls.onnx"_p); + // 战斗中部署方向识别,四分类模型 + LoadResourceAndCheckRet(OnnxSessions, "onnx"_p / "deploy_direction_cls.onnx"_p); + // 战斗中干员(血条)检测,yolov8 检测模型 + LoadResourceAndCheckRet(OnnxSessions, "onnx"_p / "operators_det.onnx"_p); - /*** lazy loading ***/ - // 战斗中技能识别,二分类模型 - LoadResourceAndCheckRet(OnnxSessions, "onnx"_p / "skill_ready_cls.onnx"_p); - // 战斗中部署方向识别,四分类模型 - LoadResourceAndCheckRet(OnnxSessions, "onnx"_p / "deploy_direction_cls.onnx"_p); - // 战斗中干员(血条)检测,yolov8 检测模型 - LoadResourceAndCheckRet(OnnxSessions, "onnx"_p / "operators_det.onnx"_p); + /* ocr */ + LoadResourceAndCheckRet(WordOcr, "PaddleOCR"_p); + LoadResourceAndCheckRet(CharOcr, "PaddleCharOCR"_p); + return true; + })); - /* tiles info */ - LoadResourceAndCheckRet(TilePack, "Arknights-Tile-Pos"_p); + futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { + /* load resource with json files*/ + LoadResourceAndCheckRet(GeneralConfig, "config.json"_p); + LoadResourceAndCheckRet(RecruitConfig, "recruitment.json"_p); + LoadResourceAndCheckRet(RoguelikeCopilotConfig, "roguelike"_p / "copilot.json"_p); + LoadResourceAndCheckRet(RoguelikeRecruitConfig, "roguelike"_p / "recruitment.json"_p); + LoadResourceAndCheckRet(RoguelikeShoppingConfig, "roguelike"_p / "shopping.json"_p); + LoadResourceAndCheckRet(RoguelikeStageEncounterConfig, "roguelike"_p / "stage_encounter.json"_p); + LoadResourceAndCheckRet(BattleDataConfig, "battle_data.json"_p); + LoadResourceAndCheckRet(OcrConfig, "ocr_config.json"_p); - /* ocr */ - LoadResourceAndCheckRet(WordOcr, "PaddleOCR"_p); - LoadResourceAndCheckRet(CharOcr, "PaddleCharOCR"_p); + /* load cache */ + // 这个任务依赖 BattleDataConfig + LoadCacheWithoutRet(AvatarCacheManager, "avatars"_p); + return true; + })); + + futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { + /* load resource with json and template files*/ + LoadResourceWithTemplAndCheckRet(TaskData, "tasks.json"_p, "template"_p); + LoadResourceWithTemplAndCheckRet(InfrastConfig, "infrast.json"_p, "template"_p / "infrast"_p); + LoadResourceWithTemplAndCheckRet(ItemConfig, "item_index.json"_p, "template"_p / "items"_p); + return true; + })); #undef LoadTemplByConfigAndCheckRet #undef LoadResourceAndCheckRet #undef LoadCacheWithoutRet - m_loaded = true; - + m_loaded = ranges::all_of(futures, [](auto& f) { return f.get(); }); return m_loaded; } diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index 626e2931ce..f153b0b3a9 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -175,30 +175,12 @@ namespace MaaWpfGui.Main } } - private string _curResource = "_Unloaded"; - - private static readonly bool ForcedReloadResource = File.Exists("DEBUG") || File.Exists("DEBUG.txt"); - /// - /// 加载全局资源。 + /// 加载全局资源。新版 core 全惰性加载资源,所以可以无脑调用 /// - /// 是否强制加载ota资源。 /// 是否成功。 - public bool LoadResource(bool onlyReloadOTA = false) + public bool LoadResource() { - if (!ForcedReloadResource && !onlyReloadOTA && Instances.SettingsViewModel.ClientType == _curResource) - { - return true; - } - - string mainRes = Directory.GetCurrentDirectory(); - string globalResource = mainRes + "\\resource\\global\\" + Instances.SettingsViewModel.ClientType; - string mainCache = Directory.GetCurrentDirectory() + "\\cache"; - string globalCache = mainCache + "\\resource\\global\\" + Instances.SettingsViewModel.ClientType; - - string officialClientType = "Official"; - string bilibiliClientType = "Bilibili"; - static bool LoadResIfExists(string path) { string resource = "\\resource"; @@ -210,73 +192,27 @@ namespace MaaWpfGui.Main return AsstLoadResource(path); } + string clientType = Instances.SettingsViewModel.ClientType; + string mainRes = Directory.GetCurrentDirectory(); + string globalResource = mainRes + "\\resource\\global\\" + clientType; + string mainCache = Directory.GetCurrentDirectory() + "\\cache"; + string globalCache = mainCache + "\\resource\\global\\" + clientType; + + string officialClientType = "Official"; + string bilibiliClientType = "Bilibili"; + bool loaded = false; - if (Instances.SettingsViewModel.ClientType == string.Empty - || Instances.SettingsViewModel.ClientType == officialClientType || Instances.SettingsViewModel.ClientType == bilibiliClientType) + if (clientType == string.Empty || clientType == officialClientType || clientType == bilibiliClientType) { - // The resources of Official and Bilibili are the same - if (!ForcedReloadResource && !onlyReloadOTA && (_curResource == officialClientType || _curResource == bilibiliClientType)) - { - return true; - } - - if (!onlyReloadOTA) - { - loaded = LoadResIfExists(mainRes); - } - - // Load the cached incremental resources - loaded = loaded && LoadResIfExists(mainCache); - } - else if (_curResource == officialClientType || _curResource == bilibiliClientType) - { - // Load basic resources for CN client first - // Then load global incremental resources - if (!onlyReloadOTA) - { - loaded = LoadResIfExists(globalResource); - } - - // Load the cached incremental resources - loaded = loaded && LoadResIfExists(mainCache) - && LoadResIfExists(globalCache); + // Read resources first, then read cache + loaded = LoadResIfExists(mainRes); + loaded &= LoadResIfExists(mainCache); } else { - // Load basic resources for CN client first - // Then load global incremental resources - if (!onlyReloadOTA) - { - loaded = LoadResIfExists(mainRes) - && LoadResIfExists(globalResource); - } - - // Load the cached incremental resources - loaded = loaded && LoadResIfExists(mainCache) - && LoadResIfExists(globalCache); - } - - if (!loaded) - { - return false; - } - - if (ForcedReloadResource) - { - Execute.OnUIThread(() => - { - using var toast = new ToastNotification("Auto Reload"); - toast.Show(); - }); - } - - if (Instances.SettingsViewModel.ClientType == string.Empty) - { - _curResource = officialClientType; - } - else - { - _curResource = Instances.SettingsViewModel.ClientType; + // Read resources first, then read cache + loaded = LoadResIfExists(mainRes) && LoadResIfExists(globalResource); + loaded &= LoadResIfExists(mainCache) && LoadResIfExists(globalCache); } return loaded; diff --git a/src/MaaWpfGui/Services/StageManager.cs b/src/MaaWpfGui/Services/StageManager.cs index 7ba63e4e72..9aa2cf7882 100644 --- a/src/MaaWpfGui/Services/StageManager.cs +++ b/src/MaaWpfGui/Services/StageManager.cs @@ -31,7 +31,6 @@ using Stylet; namespace MaaWpfGui.Services { - /// /// Stage manager /// @@ -159,8 +158,6 @@ namespace MaaWpfGui.Services await Instances.MaaApiService.RequestMaaApiWithCache(tasksPath); } - Instances.AsstProxy.LoadResource(true); - return activity; }