mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-18 18:20:39 +08:00
perf: 更快的加载!
This commit is contained in:
@@ -2,17 +2,33 @@
|
||||
|
||||
#include <meojson/json.hpp>
|
||||
|
||||
#include "Utils/Demangle.hpp"
|
||||
#include "Utils/Logger.hpp"
|
||||
|
||||
bool asst::AbstractConfig::load(const std::filesystem::path& path)
|
||||
{
|
||||
LogTraceFunction;
|
||||
Log.info("load", path);
|
||||
return _load(path);
|
||||
}
|
||||
|
||||
void asst::AbstractConfig::async_load(const std::filesystem::path& path)
|
||||
{
|
||||
m_load_future = std::async(std::launch::async, &AbstractConfig::_load, this, path);
|
||||
}
|
||||
|
||||
bool asst::AbstractConfig::_load(std::filesystem::path path)
|
||||
{
|
||||
if (!std::filesystem::exists(path) || !std::filesystem::is_regular_file(path)) {
|
||||
Log.error("file does not exist", path);
|
||||
std::string class_name = utils::demangle(typeid(*this).name());
|
||||
Log.error(class_name, "file does not exist", path);
|
||||
return false;
|
||||
}
|
||||
m_path = path;
|
||||
|
||||
std::unique_lock lock(m_load_mutex);
|
||||
|
||||
std::string class_name = utils::demangle(typeid(*this).name());
|
||||
LogTraceScope(class_name);
|
||||
Log.info(path.string());
|
||||
|
||||
auto ret = json::open(path, true);
|
||||
if (!ret) {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
#include "AbstractResource.h"
|
||||
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
|
||||
namespace json
|
||||
{
|
||||
class value;
|
||||
@@ -13,9 +16,16 @@ namespace asst
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractConfig() override = default;
|
||||
virtual bool load(const std::filesystem::path& path) override;
|
||||
virtual bool load(const std::filesystem::path& path);
|
||||
virtual void async_load(const std::filesystem::path& path);
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) = 0;
|
||||
|
||||
bool _load(std::filesystem::path path);
|
||||
|
||||
std::filesystem::path m_path;
|
||||
std::future<bool> m_load_future;
|
||||
std::mutex m_load_mutex;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ bool asst::AvatarCacheManager::load(const std::filesystem::path& path)
|
||||
waiting_to_load[role].emplace(name, filepath);
|
||||
}
|
||||
|
||||
m_load_future = std::async(std::launch::async, &AvatarCacheManager::_load, this, waiting_to_load);
|
||||
m_load_future = std::async(std::launch::async, &AvatarCacheManager::_load, this, std::move(waiting_to_load));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ void asst::AvatarCacheManager::set_avatar(const std::string& name, battle::Role
|
||||
asst::imwrite(path, avatar);
|
||||
}
|
||||
|
||||
void asst::AvatarCacheManager::_load(const LoadItem& waiting_to_load)
|
||||
void asst::AvatarCacheManager::_load(LoadItem waiting_to_load)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
@@ -77,7 +77,10 @@ void asst::AvatarCacheManager::_load(const LoadItem& waiting_to_load)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& [_1, _2, w, h] = Task.get("BattleOperAvatar")->rect_move;
|
||||
std::unique_lock<std::mutex> lock(m_load_mutex);
|
||||
// const auto [_1, _2, w, h] = Task.get("BattleOperAvatar")->rect_move;
|
||||
constexpr int w = 60;
|
||||
constexpr int h = 60;
|
||||
|
||||
for (const auto& [role, name_and_paths] : waiting_to_load) {
|
||||
for (const auto& [name, filepath] : name_and_paths) {
|
||||
|
||||
@@ -29,10 +29,11 @@ namespace asst
|
||||
|
||||
private:
|
||||
using LoadItem = std::unordered_map<battle::Role, std::unordered_map<std::string, std::filesystem::path>>;
|
||||
void _load(const LoadItem& waiting_to_load);
|
||||
void _load(LoadItem waiting_to_load);
|
||||
|
||||
std::filesystem::path m_save_path;
|
||||
std::future<void> m_load_future;
|
||||
std::mutex m_load_mutex;
|
||||
|
||||
std::unordered_map<battle::Role, std::unordered_map<std::string, cv::Mat>> m_avatars;
|
||||
};
|
||||
|
||||
@@ -21,43 +21,24 @@ ASST_SUPPRESS_CV_WARNINGS_END
|
||||
|
||||
#include "Utils/Logger.hpp"
|
||||
|
||||
bool asst::TilePack::load(const std::filesystem::path& path)
|
||||
bool asst::TilePack::parse(const json::value& json)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
auto overview_path = path / "overview.json";
|
||||
Log.info("load", overview_path);
|
||||
|
||||
if (!std::filesystem::exists(overview_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto overview_opt = json::open(overview_path);
|
||||
if (!overview_opt) {
|
||||
Log.error(overview_path, "failed to open");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& overview = overview_opt.value();
|
||||
for (const auto& [_, summary] : overview.as_object()) {
|
||||
for (const auto& [_, summary] : json.as_object()) {
|
||||
LevelKey level_key {
|
||||
.stageId = summary.at("stageId").as_string(),
|
||||
.code = summary.at("code").as_string(),
|
||||
.levelId = summary.at("levelId").as_string(),
|
||||
.name = summary.get("name", "UnknownLevelName"),
|
||||
};
|
||||
auto filepath = path / utils::path(summary.at("filename").as_string());
|
||||
auto filepath = m_path / utils::path(summary.at("filename").as_string());
|
||||
if (!std::filesystem::exists(filepath)) {
|
||||
Log.error("file not exists", filepath);
|
||||
return false;
|
||||
}
|
||||
m_summarize.emplace_back(std::move(level_key), std::move(filepath));
|
||||
}
|
||||
|
||||
if (!m_tile_calculator) {
|
||||
m_tile_calculator = std::make_shared<Map::TileCalc>(WindowWidthDefault, WindowHeightDefault);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -122,7 +103,9 @@ std::unordered_map<asst::Point, asst::TilePack::TileInfo> asst::TilePack::calc_(
|
||||
std::vector<std::vector<Map::Tile>> tiles;
|
||||
|
||||
Map::Level level(*json_opt);
|
||||
bool ret = m_tile_calculator->run(level, side, pos, tiles, shift_x, shift_y);
|
||||
Map::TileCalc calcer(WindowWidthDefault, WindowHeightDefault);
|
||||
|
||||
bool ret = calcer.run(level, side, pos, tiles, shift_x, shift_y);
|
||||
|
||||
if (!ret) {
|
||||
Log.info("Tiles calc error!");
|
||||
|
||||
@@ -2,20 +2,13 @@
|
||||
|
||||
#include "Common/AsstBattleDef.h"
|
||||
#include "Common/AsstTypes.h"
|
||||
#include "Config/AbstractResource.h"
|
||||
|
||||
#include <memory>
|
||||
#include "Config/AbstractConfig.h"
|
||||
|
||||
#include <Arknights-Tile-Pos/TileDef.hpp>
|
||||
|
||||
namespace Map
|
||||
{
|
||||
class TileCalc;
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class TilePack final : public SingletonHolder<TilePack>, public AbstractResource
|
||||
class TilePack final : public SingletonHolder<TilePack>, public AbstractConfig
|
||||
{
|
||||
public:
|
||||
using LevelKey = Map::LevelKey;
|
||||
@@ -61,8 +54,6 @@ namespace asst
|
||||
public:
|
||||
virtual ~TilePack() override = default;
|
||||
|
||||
virtual bool load(const std::filesystem::path& path) override;
|
||||
|
||||
template <typename KeyT>
|
||||
std::optional<LazyMap::value_type> find(const KeyT& key) const
|
||||
{
|
||||
@@ -85,11 +76,12 @@ namespace asst
|
||||
return calc_(file_opt->second, side, shift_x, shift_y);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
|
||||
private:
|
||||
std::unordered_map<Point, TileInfo> calc_(const std::filesystem::path& filepath, bool side, double shift_x,
|
||||
double shift_y) const;
|
||||
|
||||
std::shared_ptr<Map::TileCalc> m_tile_calculator = nullptr;
|
||||
LazyMap m_summarize;
|
||||
};
|
||||
|
||||
|
||||
@@ -30,20 +30,28 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path)
|
||||
return false;
|
||||
}
|
||||
|
||||
#define LoadResourceAndCheckRet(Config, Filename) \
|
||||
{ \
|
||||
LogTraceScope(std::string("LoadResourceAndCheckRet ") + #Config); \
|
||||
auto full_path = path / Filename; \
|
||||
bool ret = load_resource<Config>(full_path); \
|
||||
if (!ret) { \
|
||||
Log.error(#Config, " load failed, path:", full_path); \
|
||||
return false; \
|
||||
} \
|
||||
#define LoadResourceAndCheckRet(Config, Filename) \
|
||||
{ \
|
||||
auto full_path = path / Filename; \
|
||||
bool ret = load_resource<Config>(full_path); \
|
||||
if (!ret) { \
|
||||
Log.error(#Config, " load failed, path:", full_path); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define AsyncLoadConfig(Config, Filename) \
|
||||
{ \
|
||||
auto full_path = path / Filename; \
|
||||
bool ret = async_load_config<Config>(full_path); \
|
||||
if (!ret) { \
|
||||
Log.error(#Config, " load failed, path:", full_path); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LoadResourceWithTemplAndCheckRet(Config, Filename, TemplDir) \
|
||||
{ \
|
||||
LogTraceScope(std::string("LoadResourceWithTemplAndCheckRet ") + #Config); \
|
||||
auto full_path = path / Filename; \
|
||||
auto full_templ_dir = path / TemplDir; \
|
||||
bool ret = load_resource_with_templ<Config>(full_path, full_templ_dir); \
|
||||
@@ -65,17 +73,16 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path)
|
||||
|
||||
std::vector<std::future<bool>> futures;
|
||||
|
||||
// 这俩比较慢的单独拿出来,放最前面
|
||||
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;
|
||||
}));
|
||||
// 不太重要又加载的慢的资源,但不怎么占内存的,实时异步加载
|
||||
AsyncLoadConfig(StageDropsConfig, "stages.json"_p);
|
||||
AsyncLoadConfig(TilePack, "Arknights-Tile-Pos"_p);
|
||||
AsyncLoadConfig(RoguelikeCopilotConfig, "roguelike"_p / "copilot.json"_p);
|
||||
AsyncLoadConfig(RoguelikeRecruitConfig, "roguelike"_p / "recruitment.json"_p);
|
||||
AsyncLoadConfig(RoguelikeShoppingConfig, "roguelike"_p / "shopping.json"_p);
|
||||
AsyncLoadConfig(RoguelikeStageEncounterConfig, "roguelike"_p / "stage_encounter.json"_p);
|
||||
|
||||
futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool {
|
||||
// 太占内存的资源,都是惰性加载
|
||||
futures.emplace_back(std::async(std::launch::async, [&]() -> bool {
|
||||
// 战斗中技能识别,二分类模型
|
||||
LoadResourceAndCheckRet(OnnxSessions, "onnx"_p / "skill_ready_cls.onnx"_p);
|
||||
// 战斗中部署方向识别,四分类模型
|
||||
@@ -89,14 +96,11 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path)
|
||||
return true;
|
||||
}));
|
||||
|
||||
futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool {
|
||||
// 重要的资源,实时加载
|
||||
futures.emplace_back(std::async(std::launch::async, [&]() -> 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);
|
||||
|
||||
@@ -106,7 +110,8 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path)
|
||||
return true;
|
||||
}));
|
||||
|
||||
futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool {
|
||||
// 重要的资源,实时加载(图片还是惰性的)
|
||||
futures.emplace_back(std::async(std::launch::async, [&]() -> bool {
|
||||
/* load resource with json and template files*/
|
||||
LoadResourceWithTemplAndCheckRet(TaskData, "tasks.json"_p, "template"_p);
|
||||
LoadResourceWithTemplAndCheckRet(InfrastConfig, "infrast.json"_p, "template"_p / "infrast"_p);
|
||||
|
||||
@@ -29,6 +29,17 @@ namespace asst
|
||||
return SingletonHolder<T>::get_instance().load(path);
|
||||
}
|
||||
|
||||
template <Singleton T>
|
||||
requires std::is_base_of_v<AbstractConfig, T>
|
||||
bool async_load_config(const std::filesystem::path& path)
|
||||
{
|
||||
if (!std::filesystem::exists(path)) {
|
||||
return m_loaded;
|
||||
}
|
||||
SingletonHolder<T>::get_instance().async_load(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <Singleton T>
|
||||
requires std::is_base_of_v<AbstractConfigWithTempl, T>
|
||||
bool load_resource_with_templ(const std::filesystem::path& path, const std::filesystem::path& templ_dir)
|
||||
|
||||
Reference in New Issue
Block a user