#include "area_data.h" #include "m2_tokvec.h" #include #include namespace fmt { namespace { // "yaw#pitch#roll" 或单个数(= roll)。原客户端 Area.cpp 用 atoi,这里用 atof 更宽容。 void parse_ypr(const std::string& s, float& yaw, float& pitch, float& roll) { yaw = pitch = roll = 0; auto h1 = s.find('#'); if (h1 == std::string::npos) { roll = (float)std::atof(s.c_str()); return; } auto h2 = s.find('#', h1 + 1); yaw = (float)std::atof(s.substr(0, h1).c_str()); if (h2 == std::string::npos) { pitch = (float)std::atof(s.substr(h1 + 1).c_str()); } else { pitch = (float)std::atof(s.substr(h1 + 1, h2 - h1 - 1).c_str()); roll = (float)std::atof(s.substr(h2 + 1).c_str()); } } } // namespace bool parse_area_data(const std::string& text, AreaData& out, std::string* err) { TokVecMap tv; std::string perr; parse_tokvec(text, tv, &perr); out = AreaData{}; if (!tv.has("areadatafile")) { if (err) *err = "areadata 缺首行 `AreaDataFile`"; return false; } if (!tv.has("objectcount")) { if (err) *err = "areadata 缺 ObjectCount"; return false; } out.declared_count = (int)tv.inum("objectcount"); for (int i = 0; i < out.declared_count; ++i) { char key[32]; std::snprintf(key, sizeof(key), "object%03d", i); const auto* v = tv.find(key); if (!v) continue; // 原客户端也是 `continue` if (v->size() < 4) { if (err) *err = std::string("areadata 块 ") + key + " token 不足 4 个"; return false; } AreaObject o; o.x = std::atof((*v)[0].c_str()); o.y = std::atof((*v)[1].c_str()); o.z = std::atof((*v)[2].c_str()); o.crc = (uint32_t)std::strtoul((*v)[3].c_str(), nullptr, 10); if (v->size() > 4) parse_ypr((*v)[4], o.yaw, o.pitch, o.roll); if (v->size() > 5) o.height_bias = (float)std::atof((*v)[5].c_str()); for (size_t k = 6; k < v->size(); ++k) o.portal_ids.push_back(std::atoi((*v)[k].c_str())); out.objects.push_back(std::move(o)); } return true; } bool parse_area_ambience(const std::string& text, AreaAmbienceData& out, std::string* err) { TokVecMap tv; std::string perr; parse_tokvec(text, tv, &perr); out = AreaAmbienceData{}; if (!tv.has("areaambiencedatafile")) { if (err) *err = "areaambiencedata 缺首行"; return false; } if (!tv.has("objectcount")) { if (err) *err = "areaambiencedata 缺 ObjectCount"; return false; } out.declared_count = (int)tv.inum("objectcount"); for (int i = 0; i < out.declared_count; ++i) { char key[32]; std::snprintf(key, sizeof(key), "object%03d", i); const auto* v = tv.find(key); if (!v || v->size() < 5) continue; AreaAmbienceObject o; o.x = std::atof((*v)[0].c_str()); o.y = std::atof((*v)[1].c_str()); o.z = std::atof((*v)[2].c_str()); o.crc = (uint32_t)std::strtoul((*v)[3].c_str(), nullptr, 10); o.range = (float)std::atof((*v)[4].c_str()); out.objects.push_back(std::move(o)); } return true; } bool parse_area_property(const std::string& text, AreaProperty& out, std::string* err) { TokVecMap tv; std::string perr; parse_tokvec(text, tv, &perr); out = AreaProperty{}; out.area_name = tv.str("areaname"); out.num_water = (int)tv.inum("numwater", 0); (void)err; return true; } // --- file wrappers --- static bool load(const std::string& path, std::string& text, std::string* err) { if (!read_file(path, text)) { if (err) *err = "打不开 " + path; return false; } return true; } bool parse_area_data_file(const std::string& p, AreaData& o, std::string* e) { std::string t; return load(p, t, e) && parse_area_data(t, o, e); } bool parse_area_ambience_file(const std::string& p, AreaAmbienceData& o, std::string* e) { std::string t; return load(p, t, e) && parse_area_ambience(t, o, e); } bool parse_area_property_file(const std::string& p, AreaProperty& o, std::string* e) { std::string t; return load(p, t, e) && parse_area_property(t, o, e); } } // namespace fmt