diff --git a/3rdparty/include/Arknights-Tile-Pos/TileCalc.hpp b/3rdparty/include/Arknights-Tile-Pos/TileCalc.hpp index 83e2c3de1f..550953c09a 100644 --- a/3rdparty/include/Arknights-Tile-Pos/TileCalc.hpp +++ b/3rdparty/include/Arknights-Tile-Pos/TileCalc.hpp @@ -38,7 +38,7 @@ namespace Map class TileCalc { public: - TileCalc(int width, int height, const std::string& dir); + TileCalc(int width, int height, const std::filesystem::path& dir); bool run(const std::string& code_or_name, bool side, std::vector>& out_pos, std::vector>& out_tiles) const; private: int width = 0; @@ -87,7 +87,7 @@ namespace Map } } - inline TileCalc::TileCalc(int width, int height, const std::string& dir) + inline TileCalc::TileCalc(int width, int height, const std::filesystem::path& dir) { TileCalc::width = width; TileCalc::height = height; diff --git a/src/MeoAssistant/AbstractImageAnalyzer.cpp b/src/MeoAssistant/AbstractImageAnalyzer.cpp index d25f5e3b9f..1964928731 100644 --- a/src/MeoAssistant/AbstractImageAnalyzer.cpp +++ b/src/MeoAssistant/AbstractImageAnalyzer.cpp @@ -5,6 +5,7 @@ #include "AsstUtils.hpp" #include "Controller.h" #include "Logger.hpp" +#include "AsstImageIo.hpp" asst::AbstractImageAnalyzer::AbstractImageAnalyzer(const cv::Mat& image) : m_image(image), m_roi(empty_rect_to_full(Rect(), image)) @@ -70,10 +71,10 @@ bool asst::AbstractImageAnalyzer::save_img() std::string stem = utils::get_format_time(); stem = utils::string_replace_all(stem, { { ":", "-" }, { " ", "_" } }); std::filesystem::create_directory("debug"); - bool ret = cv::imwrite("debug/" + stem + "_raw.png", m_image); + bool ret = asst::imwrite("debug/" + stem + "_raw.png", m_image); #ifdef ASST_DEBUG - cv::imwrite("debug/" + stem + "_draw.png", m_image_draw); + asst::imwrite("debug/" + stem + "_draw.png", m_image_draw); #endif return ret; diff --git a/src/MeoAssistant/AbstractTask.cpp b/src/MeoAssistant/AbstractTask.cpp index 8a3c1abad0..73e1612efc 100644 --- a/src/MeoAssistant/AbstractTask.cpp +++ b/src/MeoAssistant/AbstractTask.cpp @@ -14,6 +14,7 @@ #include "GeneralConfiger.h" #include "Logger.hpp" #include "ProcessTask.h" +#include "AsstImageIo.hpp" using namespace asst; @@ -193,5 +194,5 @@ void asst::AbstractTask::save_image() std::string stem = utils::get_format_time(); stem = utils::string_replace_all(stem, { { ":", "-" }, { " ", "_" } }); std::filesystem::create_directory("debug"); - cv::imwrite("debug/" + stem + "_raw.png", m_ctrler->get_image()); + asst::imwrite("debug/" + stem + "_raw.png", m_ctrler->get_image()); } diff --git a/src/MeoAssistant/AsstCaller.cpp b/src/MeoAssistant/AsstCaller.cpp index 576956afff..ed9102b13d 100644 --- a/src/MeoAssistant/AsstCaller.cpp +++ b/src/MeoAssistant/AsstCaller.cpp @@ -42,15 +42,11 @@ static bool inited = false; bool AsstLoadResource(const char* path) { -#ifdef _WIN32 - std::filesystem::path working_path = asst::utils::utf8_to_ansi(path); -#else - std::filesystem::path working_path = path; -#endif + auto working_path = asst::utils::path(path); if (!inited) { asst::Logger::set_directory(working_path); } - inited = asst::ResourceLoader::get_instance().load(working_path / "resource"); + inited = asst::ResourceLoader::get_instance().load(working_path / asst::utils::path("resource")); return inited; } @@ -86,11 +82,7 @@ bool AsstConnect(AsstHandle handle, const char* adb_path, const char* address, c return false; } -#ifdef _WIN32 - return handle->connect(asst::utils::utf8_to_ansi(adb_path), address, config ? config : std::string()); -#else return handle->connect(adb_path, address, config ? config : std::string()); -#endif } bool AsstStart(AsstHandle handle) diff --git a/src/MeoAssistant/AsstImageIo.hpp b/src/MeoAssistant/AsstImageIo.hpp new file mode 100644 index 0000000000..3e298af8bc --- /dev/null +++ b/src/MeoAssistant/AsstImageIo.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include + +#include "NoWarningCVMat.h" +#include "NoWarningCV.h" + +#include "AsstUtils.hpp" + +namespace asst { + + inline cv::Mat imread(const std::filesystem::path& path, int flags = cv::IMREAD_COLOR) + { + std::ifstream file(path, std::ios::binary | std::ios::ate); + auto fileSize = file.tellg(); + file.seekg(0, std::ios::beg); + std::vector content(fileSize); + file.read((char*)&content[0], fileSize); + return cv::imdecode(content, flags); + } + + inline cv::Mat imread(const std::string& utf8_path, int flags = cv::IMREAD_COLOR) { + return imread(asst::utils::path(utf8_path), flags); + } + + inline bool imwrite(const std::filesystem::path& path, cv::InputArray img, const std::vector& params = std::vector()) { + std::ofstream of(path, std::ios::out | std::ios::binary); + std::vector encoded; + auto ext = asst::utils::path_to_utf8_string(path.extension()); + if (cv::imencode(ext.c_str(), img, encoded, params)) { + of.write((char*)&encoded[0], encoded.size()); + return true; + } + return false; + } + + inline bool imwrite(const std::string& utf8_path, cv::InputArray img, const std::vector& params = std::vector()) { + return imwrite(asst::utils::path(utf8_path), img, params); + } + +} diff --git a/src/MeoAssistant/AsstUtils.cpp b/src/MeoAssistant/AsstUtils.cpp new file mode 100644 index 0000000000..e7139d480a --- /dev/null +++ b/src/MeoAssistant/AsstUtils.cpp @@ -0,0 +1,77 @@ +#include "AsstUtils.hpp" + +#ifdef _WIN32 + +#include + +std::string asst::utils::path_to_crt_string(const std::filesystem::path& path) +{ + // UCRT may use UTF-8 encoding while ANSI code page is still some other MBCS encoding + // so we use CRT wcstombs instead of WideCharToMultiByte + size_t mbsize; + auto osstr = path.native(); + auto err = wcstombs_s(&mbsize, nullptr, 0, osstr.c_str(), osstr.size()); + if (err == 0) { + std::string result(mbsize, 0); + err = wcstombs_s(&mbsize, &result[0], mbsize, osstr.c_str(), osstr.size()); + if (err != 0) return {}; + return result.substr(0, mbsize - 1); + } + else { + // cannot convert (CRT is not using UTF-8), fallback to short path name in ACP + wchar_t short_path[MAX_PATH]; + auto shortlen = GetShortPathNameW(osstr.c_str(), short_path, MAX_PATH); + if (shortlen == 0) return {}; + BOOL failed = FALSE; + auto ansilen = WideCharToMultiByte(CP_ACP, 0, short_path, shortlen, nullptr, 0, nullptr, &failed); + if (failed) return {}; + std::string result(ansilen, 0); + WideCharToMultiByte(CP_ACP, 0, short_path, shortlen, &result[0], ansilen, nullptr, nullptr); + return result; + } +} + +std::string asst::utils::path_to_ansi_string(const std::filesystem::path& path) +{ + // UCRT may use UTF-8 encoding while ANSI code page is still some other MBCS encoding + // so we use CRT wcstombs instead of WideCharToMultiByte + BOOL failed = FALSE; + auto osstr = path.native(); + auto ansilen = WideCharToMultiByte(CP_ACP, 0, osstr.c_str(), (int)osstr.size(), nullptr, 0, nullptr, &failed); + if (!failed) { + std::string result(ansilen, 0); + WideCharToMultiByte(CP_ACP, 0, osstr.c_str(), (int)osstr.size(), &result[0], ansilen, nullptr, &failed); + return result; + } + else { + // contains character that cannot be converted, fallback to short path name in ACP + wchar_t short_path[MAX_PATH]; + auto shortlen = GetShortPathNameW(osstr.c_str(), short_path, MAX_PATH); + if (shortlen == 0) return {}; + ansilen = WideCharToMultiByte(CP_ACP, 0, short_path, shortlen, nullptr, 0, nullptr, &failed); + if (failed) return {}; + std::string result(ansilen, 0); + WideCharToMultiByte(CP_ACP, 0, short_path, shortlen, &result[0], ansilen, nullptr, nullptr); + return result; + } +} + +asst::utils::os_string asst::utils::to_osstring(const std::string& utf8_str) +{ + int len = MultiByteToWideChar(CP_UTF8, 0, utf8_str.c_str(), (int)utf8_str.size(), nullptr, 0); + asst::utils::os_string result(len, 0); + MultiByteToWideChar(CP_UTF8, 0, utf8_str.c_str(), (int)utf8_str.size(), &result[0], len); + return result; +} + +std::string asst::utils::from_osstring(const asst::utils::os_string& os_str) +{ + int len = WideCharToMultiByte(CP_UTF8, 0, os_str.c_str(), (int)os_str.size(), nullptr, 0, nullptr, nullptr); + std::string result(len, 0); + WideCharToMultiByte(CP_UTF8, 0, os_str.c_str(), (int)os_str.size(), &result[0], len, nullptr, nullptr); + return result; +} + + + +#endif diff --git a/src/MeoAssistant/AsstUtils.hpp b/src/MeoAssistant/AsstUtils.hpp index 6c3ab5afef..c553e587c8 100644 --- a/src/MeoAssistant/AsstUtils.hpp +++ b/src/MeoAssistant/AsstUtils.hpp @@ -27,6 +27,8 @@ namespace asst::utils { + + using os_string = std::filesystem::path::string_type; template constexpr bool always_false = false; template @@ -297,6 +299,59 @@ namespace asst::utils return buff; } +#ifdef _WIN32 + static_assert(std::is_same_v); + os_string to_osstring(const std::string& utf8_str); + std::string from_osstring(const os_string& os_str); +#else + static_assert(std::is_same_v); + inline os_string to_osstring(const std::string& utf8_str) { return utf8_str; } + inline std::string from_osstring(const os_string& os_str) { return os_str; } +#endif + + inline std::filesystem::path path(const os_string& os_str) { + return std::filesystem::path(os_str); + } + + template >> + inline std::filesystem::path path(const std::string& utf8_str) { + return std::filesystem::path(to_osstring(utf8_str)); + } + +#ifdef _WIN32 + + std::string path_to_crt_string(const std::filesystem::path& path); + + std::string path_to_ansi_string(const std::filesystem::path& path); + + inline std::string path_to_utf8_string(const std::filesystem::path& path) { + return from_osstring(path.native()); + } + + inline std::string path_to_crt_string(const std::string& utf8_path) { + return path_to_crt_string(path(utf8_path)); + } + + inline std::string path_to_ansi_string(const std::string& utf8_path) { + return path_to_crt_string(path(utf8_path)); + } + +#else + + inline std::string path_to_utf8_string(const std::filesystem::path& path) { + return path.native(); + } + + inline std::string path_to_ansi_string(const std::filesystem::path& path) { + return path.native(); + } + + inline std::string path_to_crt_string(const std::filesystem::path& path) { + return path.native(); + } + +#endif + template inline std::string ansi_to_utf8(const std::string& ansi_str) { @@ -551,4 +606,12 @@ namespace asst::utils return std::string(temp); #endif } + + namespace path_literals { + inline std::filesystem::path operator "" _p(const char* utf8_str, size_t len) { + // 日后再优化( + return asst::utils::path(std::string(std::string_view(utf8_str, len))); + } + } + } // namespace asst::utils diff --git a/src/MeoAssistant/BattleProcessTask.cpp b/src/MeoAssistant/BattleProcessTask.cpp index da6075ef19..4ed55b3bc5 100644 --- a/src/MeoAssistant/BattleProcessTask.cpp +++ b/src/MeoAssistant/BattleProcessTask.cpp @@ -18,6 +18,8 @@ #include "TaskData.h" #include "TilePack.h" +#include "AsstImageIo.hpp" + void asst::BattleProcessTask::set_stage_name(std::string name) { m_stage_name = std::move(name); @@ -143,11 +145,7 @@ bool asst::BattleProcessTask::analyze_opers_preview() std::string text = "( " + std::to_string(loc.x) + ", " + std::to_string(loc.y) + " )"; cv::putText(draw, text, cv::Point(info.pos.x - 30, info.pos.y), 1, 1.2, cv::Scalar(0, 0, 255), 2); } -#ifdef WIN32 - cv::imwrite("map/" + utils::utf8_to_ansi(m_stage_name) + ".png", draw); -#else - cv::imwrite("map/" + m_stage_name + ".png", draw); -#endif + asst::imwrite("map/" + m_stage_name + ".png", draw); }); auto opers = oper_analyzer.get_opers(); diff --git a/src/MeoAssistant/DebugTask.cpp b/src/MeoAssistant/DebugTask.cpp index 077e6587b1..d095831b34 100644 --- a/src/MeoAssistant/DebugTask.cpp +++ b/src/MeoAssistant/DebugTask.cpp @@ -8,6 +8,7 @@ #include "Logger.hpp" #include "StageDropsImageAnalyzer.h" +#include "AsstImageIo.hpp" asst::DebugTask::DebugTask(const AsstCallback& callback, void* callback_arg) : PackageTask(callback, callback_arg, TaskType) @@ -22,7 +23,7 @@ bool asst::DebugTask::run() size_t total = 0; size_t success = 0; for (const auto& entry : std::filesystem::directory_iterator("../../test/drops/screenshots")) { - cv::Mat image = cv::imread(entry.path().string()); + cv::Mat image = asst::imread(entry.path()); if (image.empty()) { continue; } diff --git a/src/MeoAssistant/Logger.hpp b/src/MeoAssistant/Logger.hpp index 9a5b6eae83..42a1f7a8bf 100644 --- a/src/MeoAssistant/Logger.hpp +++ b/src/MeoAssistant/Logger.hpp @@ -154,6 +154,12 @@ namespace asst : std::true_type {}; + template + static Stream& stream_put(Stream& s, std::filesystem::path&& v) + { + return stream_put(s, asst::utils::path_to_utf8_string(v)); + } + template static Stream& stream_put(Stream& s, T&& v) { diff --git a/src/MeoAssistant/MeoAssistant.vcxproj b/src/MeoAssistant/MeoAssistant.vcxproj index 7fb9598131..6899d9bb61 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj +++ b/src/MeoAssistant/MeoAssistant.vcxproj @@ -21,6 +21,7 @@ + @@ -121,6 +122,7 @@ + diff --git a/src/MeoAssistant/MeoAssistant.vcxproj.filters b/src/MeoAssistant/MeoAssistant.vcxproj.filters index 01dff0d45f..4753619b2f 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj.filters +++ b/src/MeoAssistant/MeoAssistant.vcxproj.filters @@ -396,6 +396,9 @@ 头文件\Resource + + 头文件\Utils + @@ -668,6 +671,9 @@ 源文件\Task\Sub + + 源文件 + diff --git a/src/MeoAssistant/OcrPack.cpp b/src/MeoAssistant/OcrPack.cpp index bc812bab9f..0d239f7bc7 100644 --- a/src/MeoAssistant/OcrPack.cpp +++ b/src/MeoAssistant/OcrPack.cpp @@ -8,6 +8,18 @@ #include "AsstUtils.hpp" #include "Logger.hpp" +#ifdef _WIN32 +#include +#include +static std::filesystem::path prepare_paddle_dir(const std::filesystem::path& dir, bool* is_temp); +#else +static std::filesystem::path prepare_paddle_dir(const std::filesystem::path& dir, bool* is_temp) +{ + *is_temp = false; + return dir; +} +#endif + asst::OcrPack::OcrPack() { Log.info("hardware_concurrency:", std::thread::hardware_concurrency()); @@ -25,22 +37,51 @@ asst::OcrPack::~OcrPack() } PaddleOcrDestroy(m_ocr); + } bool asst::OcrPack::load(const std::filesystem::path& path) { - if (!std::filesystem::exists(path)) { + bool use_temp_dir; + auto paddle_dir = prepare_paddle_dir(path, &use_temp_dir); + + if (paddle_dir.empty() || !std::filesystem::exists(paddle_dir)) { return false; } - const auto& dst_path = path / "det"; - const auto& rec_path = path / "rec"; - const auto& key_path = path / "ppocr_keys_v1.txt"; + constexpr static auto DetName = "det"; + // constexpr static const char* ClsName = "cls"; + constexpr static auto RecName = "rec"; + constexpr static auto KeysName = "ppocr_keys_v1.txt"; + + const auto dst_filename = paddle_dir / asst::utils::path(DetName); + // const std::string cls_filename = dir + ClsName; + const auto rec_filename = paddle_dir / asst::utils::path(RecName); + const auto keys_filename = paddle_dir / asst::utils::path(KeysName); if (m_ocr != nullptr) { PaddleOcrDestroy(m_ocr); } - m_ocr = PaddleOcrCreate(dst_path.string().c_str(), rec_path.string().c_str(), key_path.string().c_str(), nullptr); + + const auto det4paddle = asst::utils::path_to_crt_string(dst_filename); + const auto rec4paddle = asst::utils::path_to_crt_string(rec_filename); + const auto keys4paddle = asst::utils::path_to_crt_string(keys_filename); + + if (det4paddle.empty() || rec4paddle.empty() || keys4paddle.empty()) { + return false; + } + + m_ocr = PaddleOcrCreate(det4paddle.c_str(), rec4paddle.c_str(), keys4paddle.c_str(), nullptr); + + if (use_temp_dir) { + // files can be removed after load + std::thread([paddle_dir]() { + for (int i = 0; i < 50; i++) { + if (std::filesystem::remove(paddle_dir)) break; + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } + }).detach(); + } return m_ocr != nullptr; } @@ -125,3 +166,143 @@ std::vector asst::OcrPack::recognize(const cv::Mat& image, const cv::Mat roi_img = image(utils::make_rect(roi)); return recognize(roi_img, rect_cor, without_det); } + + +#ifdef _WIN32 + +#define REPARSE_MOUNTPOINT_HEADER_SIZE 8 + +struct REPARSE_MOUNTPOINT_DATA_BUFFER +{ + DWORD ReparseTag; + DWORD ReparseDataLength; + WORD Reserved; + WORD ReparseTargetLength; + WORD ReparseTargetMaximumLength; + WORD Reserved1; + WCHAR ReparseTarget[1]; +}; + +struct REPARSE_DATA_BUFFER +{ + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; + union + { + struct + { + WORD SubstituteNameOffset; + WORD SubstituteNameLength; + WORD PrintNameOffset; + WORD PrintNameLength; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + WORD SubstituteNameOffset; + WORD SubstituteNameLength; + WORD PrintNameOffset; + WORD PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + BYTE DataBuffer[1]; + } GenericReparseBuffer; + }; +}; + +#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) + +static HANDLE OpenDirectory(LPCWSTR pszPath, BOOL bReadWrite) +{ + // Obtain backup/restore privilege in case we don't have it + HANDLE hToken; + TOKEN_PRIVILEGES tp; + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken); + LookupPrivilegeValueW(NULL, (bReadWrite ? SE_RESTORE_NAME : SE_BACKUP_NAME), &tp.Privileges[0].Luid); + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL); + CloseHandle(hToken); + + // Open the directory + DWORD dwAccess = bReadWrite ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ; + HANDLE hDir = CreateFileW(pszPath, dwAccess, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); + + return hDir; +} + +static std::filesystem::path prepare_paddle_dir(const std::filesystem::path& dir, bool* is_temp) +{ + static std::atomic id{}; + + *is_temp = false; + auto path = asst::utils::path(asst::utils::string_replace_all(asst::utils::path_to_utf8_string(dir), "/", "\\")); + if (!asst::utils::path_to_ansi_string(path).empty()) { + // can be passed to paddle via path_to_ansi_string + return path; + } + // fallback: create junction (reparse point) in user temp directory + wchar_t tempbuf[MAX_PATH + 1]; + auto templen = GetTempPathW(MAX_PATH + 1, tempbuf); + std::filesystem::path tempdir(std::wstring_view(tempbuf, templen)); + if (asst::utils::path_to_ansi_string(tempdir).empty()) { + asst::Log.error("failed to escape unicode path: temp dir cannot be escaped"); + // cannot escape temp dir, no luck + return {}; + } + auto pid = GetCurrentProcessId(); + while (1) { + auto dirname = std::format(L"MaaLink-{}-{}", pid, id++); + auto linkdir = tempdir / dirname; + if (CreateDirectoryW(linkdir.c_str(), nullptr)) { + // prepare link target (NT path) + + auto normtarget = L"\\??\\" + std::filesystem::absolute(path).native(); + if (normtarget.back() != L'\\') normtarget.push_back(L'\\'); + + // set reparse point + auto hReparsePoint = OpenDirectory(linkdir.c_str(), TRUE); + + BYTE buf[sizeof(REPARSE_MOUNTPOINT_DATA_BUFFER) + MAX_PATH * sizeof(WCHAR)]; + REPARSE_MOUNTPOINT_DATA_BUFFER& ReparseBuffer = (REPARSE_MOUNTPOINT_DATA_BUFFER&)buf; + + // Prepare reparse point data + memset(buf, 0, sizeof(buf)); + ReparseBuffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + wcsncpy_s(ReparseBuffer.ReparseTarget, MAX_PATH + 1, normtarget.c_str(), MAX_PATH); + ReparseBuffer.ReparseTargetMaximumLength = (WORD)((normtarget.size() + 1) * sizeof(WCHAR)); + ReparseBuffer.ReparseTargetLength = (WORD)(normtarget.size() * sizeof(WCHAR)); + ReparseBuffer.ReparseDataLength = ReparseBuffer.ReparseTargetLength + 12; + + // Attach reparse point + auto success = DeviceIoControl(hReparsePoint, FSCTL_SET_REPARSE_POINT, &ReparseBuffer, + ReparseBuffer.ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE, nullptr, 0, + nullptr, nullptr); + + CloseHandle(hReparsePoint); + + if (success) { + *is_temp = true; + return linkdir; + } + else { + asst::Log.error("failed to escape unicode path: failed to create junction"); + return {}; + } + + } else { + auto err = GetLastError(); + if (err != ERROR_ALREADY_EXISTS) { + // cannot create link, no luck + asst::Log.error("failed to escape unicode path: failed to create junction"); + return {}; + } + } + } +} + +#endif diff --git a/src/MeoAssistant/ResourceLoader.cpp b/src/MeoAssistant/ResourceLoader.cpp index 829b93fd0e..3edb29d876 100644 --- a/src/MeoAssistant/ResourceLoader.cpp +++ b/src/MeoAssistant/ResourceLoader.cpp @@ -21,6 +21,8 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path) { + using namespace asst::utils::path_literals; + #define LoadResourceAndCheckRet(Configer, Filename) \ { \ LogTraceScope(std::string("LoadResourceAndCheckRet ") + #Configer); \ @@ -47,22 +49,22 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path) LogTraceFunction; /* load resource with json files*/ - LoadResourceAndCheckRet(GeneralConfiger, "config.json"); - LoadResourceAndCheckRet(RecruitConfiger, "recruit.json"); - LoadResourceAndCheckRet(StageDropsConfiger, "stages.json"); - LoadResourceAndCheckRet(RoguelikeCopilotConfiger, "roguelike_copilot.json"); - LoadResourceAndCheckRet(RoguelikeRecruitConfiger, "roguelike_recruit.json"); - LoadResourceAndCheckRet(RoguelikeShoppingConfiger, "roguelike_shopping.json"); - LoadResourceAndCheckRet(BattleDataConfiger, "battle_data.json"); + LoadResourceAndCheckRet(GeneralConfiger, "config.json"_p); + LoadResourceAndCheckRet(RecruitConfiger, "recruit.json"_p); + LoadResourceAndCheckRet(StageDropsConfiger, "stages.json"_p); + LoadResourceAndCheckRet(RoguelikeCopilotConfiger, "roguelike_copilot.json"_p); + LoadResourceAndCheckRet(RoguelikeRecruitConfiger, "roguelike_recruit.json"_p); + LoadResourceAndCheckRet(RoguelikeShoppingConfiger, "roguelike_shopping.json"_p); + LoadResourceAndCheckRet(BattleDataConfiger, "battle_data.json"_p); /* load resource with json and template files*/ - LoadResourceWithTemplAndCheckRet(TaskData, "tasks.json", "template"); - LoadResourceWithTemplAndCheckRet(InfrastConfiger, "infrast.json", "template" / "infrast"); - LoadResourceWithTemplAndCheckRet(ItemConfiger, "item_index.json", "template" / "items"); + LoadResourceWithTemplAndCheckRet(TaskData, "tasks.json"_p, "template"_p); + LoadResourceWithTemplAndCheckRet(InfrastConfiger, "infrast.json"_p, "template"_p / "infrast"_p); + LoadResourceWithTemplAndCheckRet(ItemConfiger, "item_index.json"_p, "template"_p / "items"_p); /* load 3rd parties resource */ - LoadResourceAndCheckRet(TilePack, "Arknights-Tile-Pos" / "levels.json"); - LoadResourceAndCheckRet(OcrPack, "PaddleOCR"); + LoadResourceAndCheckRet(TilePack, "Arknights-Tile-Pos"_p / "levels.json"_p); + LoadResourceAndCheckRet(OcrPack, "PaddleOCR"_p); m_loaded = true; diff --git a/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp b/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp index 2f415bc2c9..6d7aef09ab 100644 --- a/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp @@ -17,6 +17,7 @@ #include "RuntimeStatus.h" #include "TaskData.h" #include "TilePack.h" +#include "AsstImageIo.hpp" bool asst::RoguelikeBattleTaskPlugin::verify(AsstMsg msg, const json::value& details) const { @@ -515,12 +516,7 @@ bool asst::RoguelikeBattleTaskPlugin::wait_start() m_total_kills = kills_analyzer.get_total_kills(); } -#ifdef WIN32 - cv::imwrite("map/" + utils::utf8_to_ansi(m_stage_name) + ".png", image); -#else - cv::imwrite("map/" + m_stage_name + ".png", image); -#endif - + asst::imwrite("map/" + m_stage_name + ".png", image); return true; } diff --git a/src/MeoAssistant/StageDropsImageAnalyzer.cpp b/src/MeoAssistant/StageDropsImageAnalyzer.cpp index 14d4347030..092caad9d1 100644 --- a/src/MeoAssistant/StageDropsImageAnalyzer.cpp +++ b/src/MeoAssistant/StageDropsImageAnalyzer.cpp @@ -11,6 +11,7 @@ #include "OcrWithPreprocessImageAnalyzer.h" #include "StageDropsConfiger.h" #include "TaskData.h" +#include "AsstImageIo.hpp" #include @@ -22,7 +23,7 @@ bool asst::StageDropsImageAnalyzer::analyze() std::string stem = utils::get_format_time(); stem = utils::string_replace_all(stem, { { ":", "-" }, { " ", "_" } }); std::filesystem::create_directory("debug"); - cv::imwrite("debug/" + stem + "_raw.png", m_image); + asst::imwrite("debug/" + stem + "_raw.png", m_image); #endif analyze_stage_code(); @@ -35,7 +36,7 @@ bool asst::StageDropsImageAnalyzer::analyze() } #ifdef ASST_DEBUG - cv::imwrite("debug/" + stem + "_draw.png", m_image_draw); + asst::imwrite("debug/" + stem + "_draw.png", m_image_draw); #endif return ret; diff --git a/src/MeoAssistant/TemplResource.cpp b/src/MeoAssistant/TemplResource.cpp index 6a4b05e77c..488bc18faf 100644 --- a/src/MeoAssistant/TemplResource.cpp +++ b/src/MeoAssistant/TemplResource.cpp @@ -7,6 +7,7 @@ #include "NoWarningCV.h" #include "Logger.hpp" +#include "AsstImageIo.hpp" void asst::TemplResource::set_load_required(std::unordered_set required) noexcept { @@ -19,12 +20,12 @@ bool asst::TemplResource::load(const std::filesystem::path& path) Log.info("load", path); for (const std::string& filename : m_templs_filename) { - std::filesystem::path filepath(path / filename); + std::filesystem::path filepath(path / asst::utils::path(filename)); if (!filepath.has_extension()) { - filepath.replace_extension(".png"); + filepath.replace_extension(asst::utils::path(".png")); } if (std::filesystem::exists(filepath)) { - cv::Mat templ = cv::imread(filepath.string()); + cv::Mat templ = asst::imread(filepath); insert_or_assign_templ(filename, std::move(templ)); } else if (m_loaded) { diff --git a/src/MeoAssistant/TilePack.cpp b/src/MeoAssistant/TilePack.cpp index 8f7765e19f..a00bf53804 100644 --- a/src/MeoAssistant/TilePack.cpp +++ b/src/MeoAssistant/TilePack.cpp @@ -16,7 +16,7 @@ bool asst::TilePack::load(const std::filesystem::path& path) } try { - m_tile_calculator = std::make_unique(WindowWidthDefault, WindowHeightDefault, path.string()); + m_tile_calculator = std::make_unique(WindowWidthDefault, WindowHeightDefault, path); } catch (std::exception& e) { Log.error("Tile create failed", e.what());