Files
MaaAssistantArknights/src/MaaCore/Config/Miscellaneous/TilePack.cpp
2026-02-12 16:01:30 +08:00

155 lines
5.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "TilePack.h"
#include "MaaUtils/Conf.h"
#include "meojson/json.hpp"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <filesystem>
#include <future>
#include <list>
#include <mutex>
#include <numeric>
#include <optional>
#include <queue>
MAA_SUPPRESS_CV_WARNINGS_BEGIN
#include <Arknights-Tile-Pos/TileCalc2.hpp>
MAA_SUPPRESS_CV_WARNINGS_END
#include "Utils/Logger.hpp"
bool asst::TilePack::parse(const json::value& json)
{
LogTraceFunction;
auto dir = m_path.parent_path();
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 = dir / 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));
}
return true;
}
bool proc_data(
std::unordered_map<asst::Point, asst::TilePack::TileInfo>& dst,
asst::Point loc,
cv::Point cv_p,
const Map::Tile& tile)
{
using namespace asst;
using TileKey = asst::TilePack::TileKey;
using TileInfo = asst::TilePack::TileInfo;
static const std::unordered_map<std::string, TileKey> TileKeyMapping = {
{ "tile_forbidden", TileKey::Forbidden },
{ "tile_wall", TileKey::Wall },
{ "tile_road", TileKey::Road },
{ "tile_end", TileKey::Home },
{ "tile_start", TileKey::EnemyHome },
{ "tile_green", TileKey::Green },
{ "tile_flystart", TileKey::Airport },
{ "tile_floor", TileKey::Floor },
{ "tile_hole", TileKey::Hole },
{ "tile_telin", TileKey::Telin },
{ "tile_telout", TileKey::Telout },
{ "tile_grass", TileKey::Grass },
{ "tile_deepsea", TileKey::DeepSea },
{ "tile_deepwater", TileKey::DeepSea },
{ "tile_volcano", TileKey::Volcano },
{ "tile_healing", TileKey::Healing },
{ "tile_fence", TileKey::Fence /* 疑似弃用, 改为 tile_fence_bound */ },
{ "tile_fence_bound", TileKey::Fence },
{ "tile_infection", TileKey::Infection },
};
auto key = TileKey::Invalid;
if (auto iter = TileKeyMapping.find(tile.tileKey); iter != TileKeyMapping.cend()) {
key = iter->second;
}
else {
key = TileKey::Invalid;
LogWarn << "Unknown tile type" << loc << ":" << tile.tileKey;
}
dst.emplace(
loc,
TileInfo { static_cast<battle::LocationType>(tile.buildableType),
static_cast<TilePack::HeightType>(tile.heightType),
key,
Point(cv_p.x, cv_p.y),
loc });
return true;
}
asst::TilePack::result_type asst::TilePack::calc_(const Map::Level& level, double shift_x, double shift_y)
{
LogTraceFunction;
std::vector<std::vector<cv::Point2d>> pos;
std::vector<std::vector<Map::Tile>> tiles;
result_type result;
const int w = level.get_width();
const int h = level.get_height();
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
const auto tile = level.get_item(y, x);
const cv::Point screen_pos =
Map::TileCalc2::get_tile_screen_pos(level, y, x, false, { -shift_x, shift_y, 0 });
const cv::Point screen_pos_side =
Map::TileCalc2::get_tile_screen_pos(level, y, x, true, { -shift_x, shift_y, 0 });
const asst::Point loc(x, y);
const bool ret = proc_data(result.normal_tile_info, loc, screen_pos, tile);
const bool ret_side = proc_data(result.side_tile_info, loc, screen_pos_side, tile);
if (tile.tileKey == "tile_start" || tile.tileKey == "tile_end") {
// 检查 screen_pos 是否在允许的范围内带5%容差)
constexpr double MIN_X = 0.0;
constexpr double MAX_X = WindowWidthDefault;
constexpr double MIN_Y = 0.0;
constexpr double MAX_Y = WindowHeightDefault;
constexpr double TOLERANCE = 0.05;
constexpr double x_tolerance = MAX_X * TOLERANCE;
constexpr double y_tolerance = MAX_Y * TOLERANCE;
constexpr double min_x_bound = MIN_X - x_tolerance;
constexpr double max_x_bound = MAX_X + x_tolerance;
constexpr double min_y_bound = MIN_Y - y_tolerance;
constexpr double max_y_bound = MAX_Y + y_tolerance;
if (screen_pos.x < min_x_bound || screen_pos.x > max_x_bound || screen_pos.y < min_y_bound ||
screen_pos.y > max_y_bound) {
LogInfo << "Tile" << tile.tileKey << "at" << loc << ", screen position:" << screen_pos
<< ", map has multi stages";
result.has_multi_stages = true;
}
}
if (!ret || !ret_side) {
Log.info("Tiles calc error!");
return {};
}
}
}
auto retreat = Map::TileCalc2::get_retreat_screen_pos(level, result.has_multi_stages);
auto skill = Map::TileCalc2::get_skill_screen_pos(level, result.has_multi_stages);
result.retreat_button = { retreat.x, retreat.y };
result.skill_button = { skill.x, skill.y };
return result;
}