mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-18 18:20:39 +08:00
chore: 完成基建数据自动更新工具,并适配新数据的解析
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -8,37 +8,35 @@ bool asst::InfrastConfiger::parse(const json::value& json)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
for (const json::value& facility : json.at("facility").as_array()) {
|
||||
for (const json::value& facility : json.at("roomType").as_array()) {
|
||||
std::string facility_name = facility.as_string();
|
||||
const json::value& facility_json = json.at(facility_name);
|
||||
|
||||
/* 解析 products 字段 */
|
||||
std::vector<std::string> products;
|
||||
for (const json::value& product_json : facility_json.at("products").as_array()) {
|
||||
products.emplace_back(product_json.as_string());
|
||||
if (auto products_opt = facility_json.find<json::array>("products")) {
|
||||
for (const json::value& product_json : products_opt.value()) {
|
||||
products.emplace_back(product_json.as_string());
|
||||
}
|
||||
}
|
||||
|
||||
/* 解析skills字段 */
|
||||
std::unordered_map<std::string, infrast::Skill> facility_skills;
|
||||
for (const json::value& skill_json : facility_json.at("skills").as_array()) {
|
||||
for (const auto& [id, skill_json] : facility_json.at("skills").as_object()) {
|
||||
infrast::Skill skill;
|
||||
std::string templ_name = skill_json.at("template").as_string();
|
||||
skill.templ_name = templ_name;
|
||||
m_templ_required.emplace(skill.templ_name);
|
||||
// 默认id就是模板名(去掉格式)
|
||||
std::string default_id = templ_name.substr(0, templ_name.find_last_of('.'));
|
||||
std::string id = skill_json.get("id", default_id);
|
||||
skill.id = id;
|
||||
if (skill_json.contains("name")) {
|
||||
for (const json::value& skill_names : skill_json.at("name").as_array()) {
|
||||
skill.names.emplace_back(skill_names.as_string());
|
||||
}
|
||||
for (const json::value& skill_names : skill_json.at("name").as_array()) {
|
||||
skill.names.emplace_back(skill_names.as_string());
|
||||
}
|
||||
skill.desc = skill_json.get("desc", std::string());
|
||||
skill.desc = skill_json.at("desc").at(0).as_string();
|
||||
|
||||
/* 解析efficient的数字及正则值 */
|
||||
if (skill_json.contains("efficient")) {
|
||||
if (auto opt = skill_json.find("efficient")) {
|
||||
const json::value& efficient = *opt;
|
||||
const static std::string reg_suffix = "_reg";
|
||||
const json::value& efficient = skill_json.at("efficient");
|
||||
|
||||
if (std::string all_reg_key = "all" + reg_suffix;
|
||||
efficient.contains(all_reg_key)) {
|
||||
@@ -83,125 +81,127 @@ bool asst::InfrastConfiger::parse(const json::value& json)
|
||||
|
||||
/* 解析skillsGroup字段 */
|
||||
std::vector<infrast::SkillsGroup> group_vec;
|
||||
for (const json::value& group_json : facility_json.at("skillsGroup").as_array()) {
|
||||
infrast::SkillsGroup group;
|
||||
group.desc = group_json.get("desc", std::string());
|
||||
if (group_json.contains("conditions")) {
|
||||
for (const auto& [cond, value] : group_json.at("conditions").as_object()) {
|
||||
group.conditions.emplace(cond, value.as_integer());
|
||||
}
|
||||
}
|
||||
for (const json::value& necessary_json : group_json.at("necessary").as_array()) {
|
||||
infrast::SkillsComb comb;
|
||||
comb.desc = necessary_json.get("desc", std::string());
|
||||
for (const json::value& skill_json : necessary_json.at("skills").as_array()) {
|
||||
const auto& skill = m_skills.at(facility_name).at(skill_json.as_string());
|
||||
comb.skills.emplace(skill);
|
||||
}
|
||||
/* 解析efficient的数字及正则值 */
|
||||
if (necessary_json.contains("efficient")) {
|
||||
const static std::string reg_suffix = "_reg";
|
||||
const json::value& efficient = necessary_json.at("efficient");
|
||||
|
||||
if (std::string all_reg_key = "all" + reg_suffix;
|
||||
efficient.contains(all_reg_key)) {
|
||||
std::string all_reg_value = efficient.at(all_reg_key).as_string();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient_regex.emplace(pd, all_reg_value);
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
if (auto skills_group_opt = facility_json.find<json::array>("skillsGroup")) {
|
||||
for (const json::value& group_json : skills_group_opt.value()) {
|
||||
infrast::SkillsGroup group;
|
||||
group.desc = group_json.get("desc", std::string());
|
||||
if (group_json.contains("conditions")) {
|
||||
for (const auto& [cond, value] : group_json.at("conditions").as_object()) {
|
||||
group.conditions.emplace(cond, value.as_integer());
|
||||
}
|
||||
else if (efficient.contains("all")) {
|
||||
double all_value = efficient.at("all").as_double();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient.emplace(pd, all_value);
|
||||
}
|
||||
for (const json::value& necessary_json : group_json.at("necessary").as_array()) {
|
||||
infrast::SkillsComb comb;
|
||||
comb.desc = necessary_json.get("desc", std::string());
|
||||
for (const json::value& skill_json : necessary_json.at("skills").as_array()) {
|
||||
const auto& skill = m_skills.at(facility_name).at(skill_json.as_string());
|
||||
comb.skills.emplace(skill);
|
||||
}
|
||||
/* 解析efficient的数字及正则值 */
|
||||
if (necessary_json.contains("efficient")) {
|
||||
const static std::string reg_suffix = "_reg";
|
||||
const json::value& efficient = necessary_json.at("efficient");
|
||||
|
||||
if (std::string all_reg_key = "all" + reg_suffix;
|
||||
efficient.contains(all_reg_key)) {
|
||||
std::string all_reg_value = efficient.at(all_reg_key).as_string();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient_regex.emplace(pd, all_reg_value);
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
else if (efficient.contains("all")) {
|
||||
double all_value = efficient.at("all").as_double();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient.emplace(pd, all_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix;
|
||||
efficient.contains(pd_reg_key)) {
|
||||
comb.efficient_regex.emplace(pd, efficient.at(pd_reg_key).as_string());
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
else if (efficient.contains(pd)) {
|
||||
comb.efficient.emplace(pd, efficient.at(pd).as_double());
|
||||
}
|
||||
else {
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix;
|
||||
efficient.contains(pd_reg_key)) {
|
||||
comb.efficient_regex.emplace(pd, efficient.at(pd_reg_key).as_string());
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
else if (efficient.contains(pd)) {
|
||||
comb.efficient.emplace(pd, efficient.at(pd).as_double());
|
||||
}
|
||||
else {
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
if (auto filter_opt = necessary_json.find<json::array>("filter")) {
|
||||
for (const auto& filter : filter_opt.value()) {
|
||||
comb.name_filter.emplace_back(filter.as_string());
|
||||
}
|
||||
}
|
||||
group.necessary.emplace_back(std::move(comb));
|
||||
}
|
||||
for (const json::value& opt_json : group_json.at("optional").as_array()) {
|
||||
infrast::SkillsComb comb;
|
||||
comb.desc = opt_json.get("desc", std::string());
|
||||
for (const json::value& skill_json : opt_json.at("skills").as_array()) {
|
||||
const auto& skill = m_skills.at(facility_name).at(skill_json.as_string());
|
||||
comb.skills.emplace(skill);
|
||||
}
|
||||
/* 解析efficient的数字及正则值 */
|
||||
if (opt_json.contains("efficient")) {
|
||||
const static std::string reg_suffix = "_reg";
|
||||
const json::value& efficient = opt_json.at("efficient");
|
||||
|
||||
if (std::string all_reg_key = "all" + reg_suffix;
|
||||
efficient.contains(all_reg_key)) {
|
||||
std::string all_reg_value = efficient.at(all_reg_key).as_string();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient_regex.emplace(pd, all_reg_value);
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
else if (efficient.contains("all")) {
|
||||
double all_value = efficient.at("all").as_double();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient.emplace(pd, all_value);
|
||||
if (auto filter_opt = necessary_json.find<json::array>("filter")) {
|
||||
for (const auto& filter : filter_opt.value()) {
|
||||
comb.name_filter.emplace_back(filter.as_string());
|
||||
}
|
||||
}
|
||||
group.necessary.emplace_back(std::move(comb));
|
||||
}
|
||||
for (const json::value& opt_json : group_json.at("optional").as_array()) {
|
||||
infrast::SkillsComb comb;
|
||||
comb.desc = opt_json.get("desc", std::string());
|
||||
for (const json::value& skill_json : opt_json.at("skills").as_array()) {
|
||||
const auto& skill = m_skills.at(facility_name).at(skill_json.as_string());
|
||||
comb.skills.emplace(skill);
|
||||
}
|
||||
/* 解析efficient的数字及正则值 */
|
||||
if (opt_json.contains("efficient")) {
|
||||
const static std::string reg_suffix = "_reg";
|
||||
const json::value& efficient = opt_json.at("efficient");
|
||||
|
||||
if (std::string all_reg_key = "all" + reg_suffix;
|
||||
efficient.contains(all_reg_key)) {
|
||||
std::string all_reg_value = efficient.at(all_reg_key).as_string();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient_regex.emplace(pd, all_reg_value);
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
else if (efficient.contains("all")) {
|
||||
double all_value = efficient.at("all").as_double();
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient.emplace(pd, all_value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix;
|
||||
efficient.contains(pd_reg_key)) {
|
||||
comb.efficient_regex.emplace(pd, efficient.at(pd_reg_key).as_string());
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
else if (efficient.contains(pd)) {
|
||||
comb.efficient.emplace(pd, efficient.at(pd).as_double());
|
||||
}
|
||||
else {
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
if (std::string pd_reg_key = pd + reg_suffix;
|
||||
efficient.contains(pd_reg_key)) {
|
||||
comb.efficient_regex.emplace(pd, efficient.at(pd_reg_key).as_string());
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
else if (efficient.contains(pd)) {
|
||||
comb.efficient.emplace(pd, efficient.at(pd).as_double());
|
||||
}
|
||||
else {
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const std::string& pd : products) {
|
||||
comb.efficient.emplace(pd, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto filter_opt = opt_json.find<json::array>("filter")) {
|
||||
for (const auto& filter : filter_opt.value()) {
|
||||
comb.name_filter.emplace_back(filter.as_string());
|
||||
if (auto filter_opt = opt_json.find<json::array>("filter")) {
|
||||
for (const auto& filter : filter_opt.value()) {
|
||||
comb.name_filter.emplace_back(filter.as_string());
|
||||
}
|
||||
}
|
||||
group.optional.emplace_back(std::move(comb));
|
||||
}
|
||||
group.optional.emplace_back(std::move(comb));
|
||||
group.allow_external = group_json.get("allowExternal", false);
|
||||
group_vec.emplace_back(std::move(group));
|
||||
}
|
||||
group.allow_external = group_json.get("allowExternal", false);
|
||||
group_vec.emplace_back(std::move(group));
|
||||
}
|
||||
m_skills_groups.emplace(facility_name, std::move(group_vec));
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <meojson/json.hpp>
|
||||
@@ -7,11 +8,12 @@
|
||||
bool update_items_data(const std::filesystem::path& input_dir, const std::filesystem::path& output_dir);
|
||||
bool cvt_single_item_template(const std::filesystem::path& input, const std::filesystem::path& output);
|
||||
|
||||
bool update_infrast_data(const std::filesystem::path& input_dir, const std::filesystem::path& output_dir);
|
||||
bool update_stages_data(const std::filesystem::path& input_dir, const std::filesystem::path& output_dir);
|
||||
|
||||
bool update_infrast_templates(const std::filesystem::path& input_dir, const std::filesystem::path& output_dir);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int main([[maybe_unused]] int argc, char** argv)
|
||||
{
|
||||
const char* str_exec_path = argv[0];
|
||||
const auto cur_path = std::filesystem::path(str_exec_path).parent_path();
|
||||
@@ -51,6 +53,13 @@ int main(int argc, char** argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update infrast data from Arknights-Bot-Resource*/
|
||||
std::cout << "------------Update infrast data------------" << std::endl;
|
||||
if (!update_infrast_data(input_dir, resource_dir)) {
|
||||
std::cerr << "Update infrast data failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update infrast templates from Arknights-Bot-Resource*/
|
||||
std::cout << "------------Update infrast templates------------" << std::endl;
|
||||
if (!update_infrast_templates(input_dir / "building_skill", resource_dir / "template" / "infrast")) {
|
||||
@@ -197,6 +206,154 @@ bool cvt_single_item_template(const std::filesystem::path& input, const std::fil
|
||||
return true;
|
||||
}
|
||||
|
||||
void remove_xml(std::string& text)
|
||||
{
|
||||
if (text.empty() || text.size() < 2) {
|
||||
return;
|
||||
}
|
||||
// find the first of '<'
|
||||
auto first_iter = text.end();
|
||||
for (auto it = text.begin(); it != text.end(); ++it) {
|
||||
if (*it == '<') {
|
||||
first_iter = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first_iter == text.end()) {
|
||||
return;
|
||||
}
|
||||
bool in_xml = true;
|
||||
|
||||
// move forward all non-xml elements
|
||||
auto end_r1_iter = text.end() - 1;
|
||||
auto next_iter = first_iter;
|
||||
while (++first_iter != end_r1_iter) {
|
||||
auto move_it = [&]() {
|
||||
*next_iter = *first_iter;
|
||||
++next_iter;
|
||||
};
|
||||
|
||||
if (*first_iter != '>' && in_xml) {
|
||||
;
|
||||
}
|
||||
else if (*first_iter == '>' && in_xml) {
|
||||
in_xml = false;
|
||||
}
|
||||
else if (*first_iter == '<' && !in_xml) {
|
||||
in_xml = true;
|
||||
}
|
||||
else {
|
||||
move_it();
|
||||
}
|
||||
}
|
||||
*next_iter = *end_r1_iter;
|
||||
if (*next_iter != '>') {
|
||||
++next_iter;
|
||||
}
|
||||
text.erase(next_iter, text.end());
|
||||
}
|
||||
|
||||
bool update_infrast_data(const std::filesystem::path& input_dir, const std::filesystem::path& output_dir)
|
||||
{
|
||||
const auto input_file = input_dir / "gamedata" / "excel" / "building_data.json";
|
||||
const auto output_file = output_dir / "infrast.json";
|
||||
|
||||
json::value input_json;
|
||||
{
|
||||
std::ifstream ifs(input_file, std::ios::in);
|
||||
if (!ifs.is_open()) {
|
||||
std::cout << input_file << " not exist" << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::stringstream iss;
|
||||
iss << ifs.rdbuf();
|
||||
ifs.close();
|
||||
|
||||
auto opt = json::parse(iss.str());
|
||||
if (!opt) {
|
||||
std::cout << input_file << " parse error" << std::endl;
|
||||
return false;
|
||||
}
|
||||
input_json = std::move(opt.value());
|
||||
}
|
||||
|
||||
json::value old_json;
|
||||
{
|
||||
std::ifstream ifs(output_file, std::ios::in);
|
||||
if (!ifs.is_open()) {
|
||||
std::cout << output_file << " not exist" << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::stringstream iss;
|
||||
iss << ifs.rdbuf();
|
||||
ifs.close();
|
||||
|
||||
auto opt = json::parse(iss.str());
|
||||
if (!opt) {
|
||||
std::cout << output_file << " parse error" << std::endl;
|
||||
return false;
|
||||
}
|
||||
old_json = std::move(opt.value());
|
||||
}
|
||||
|
||||
auto buffs_opt = input_json.find<json::object>("buffs");
|
||||
if (!buffs_opt) {
|
||||
return false;
|
||||
}
|
||||
auto& buffs = buffs_opt.value();
|
||||
|
||||
// 这里面有些是手动修改的,要保留
|
||||
json::value& root = old_json;
|
||||
std::unordered_set<std::string> rooms;
|
||||
for (auto& [_, buff_obj] : buffs) {
|
||||
std::string raw_room_type = (std::string)buff_obj["roomType"];
|
||||
|
||||
// 为了兼容老版本的字段 orz
|
||||
static const std::unordered_map<std::string, std::string> RoomTypeMapping = {
|
||||
{ "POWER", "Power" },
|
||||
{ "CONTROL", "Control" },
|
||||
{ "DORMITORY", "Dorm" },
|
||||
{ "WORKSHOP", "" },
|
||||
{ "MANUFACTURE", "Mfg" },
|
||||
{ "TRADING", "Trade" },
|
||||
{ "MEETING", "Reception" },
|
||||
{ "HIRE", "Office" },
|
||||
{ "TRAINING", "" },
|
||||
};
|
||||
|
||||
std::string room_type = RoomTypeMapping.at(raw_room_type);
|
||||
if (room_type.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rooms.emplace(room_type);
|
||||
|
||||
std::string key = (std::string)buff_obj["skillIcon"];
|
||||
std::string name = (std::string)buff_obj["buffName"];
|
||||
// 这玩意里面有类似 xml 的东西,全删一下
|
||||
std::string desc = (std::string)buff_obj["description"];
|
||||
remove_xml(desc);
|
||||
|
||||
auto& skill = root[room_type]["skills"][key];
|
||||
skill["name"].array_emplace(name);
|
||||
skill["desc"].array_emplace(desc);
|
||||
|
||||
// 历史遗留问题,以前的图片是从wiki上爬的,都是大写开头
|
||||
// Windows下不区分大小写,现在新的小写文件名图片没法覆盖
|
||||
// 所以干脆全用大写开头算了
|
||||
std::string filename = key + ".png";
|
||||
filename[0] -= 32;
|
||||
skill["template"] = std::move(filename);
|
||||
}
|
||||
root["roomType"] = json::array(rooms);
|
||||
|
||||
std::ofstream ofs(output_file, std::ios::out);
|
||||
ofs << root.format();
|
||||
ofs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_stages_data(const std::filesystem::path& input_dir, const std::filesystem::path& output_dir)
|
||||
{
|
||||
// 国内访问可以改成 .cn 的域名
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int main([[maybe_unused]] int argc, char** argv)
|
||||
{
|
||||
// 这里默认读取的是可执行文件同目录下 resource 文件夹里的资源
|
||||
const char* str_exec_path = argv[0];
|
||||
|
||||
Reference in New Issue
Block a user