#include "BlueprintSerializer.h" #include #include #include "toml.hpp" #include "BuildingType.h" #include "Rotation.h" namespace { std::string rotationToString(Rotation r) { switch (r) { case Rotation::North: return "north"; case Rotation::East: return "east"; case Rotation::South: return "south"; case Rotation::West: return "west"; } return "north"; } Rotation parseRotation(const std::string& s) { if (s == "east") { return Rotation::East; } if (s == "south") { return Rotation::South; } if (s == "west") { return Rotation::West; } return Rotation::North; } } // namespace namespace BlueprintSerializer { std::string serialize(const std::vector& blueprints) { toml::array bpArr; for (const Blueprint& bp : blueprints) { toml::array bldArr; for (const BlueprintBuilding& b : bp.buildings) { toml::table bldTbl; bldTbl.insert("type", buildingTypeId(b.type)); bldTbl.insert("rotation", rotationToString(b.rotation)); bldTbl.insert("offset_x", static_cast(b.offset.x())); bldTbl.insert("offset_y", static_cast(b.offset.y())); bldTbl.insert("recipe_id", b.recipeId); bldArr.push_back(std::move(bldTbl)); } toml::table bpTbl; bpTbl.insert("name", bp.name.toStdString()); bpTbl.insert("buildings", std::move(bldArr)); bpArr.push_back(std::move(bpTbl)); } toml::table root; root.insert("blueprint", std::move(bpArr)); std::ostringstream oss; oss << root; return oss.str(); } std::vector deserialize(const std::string& tomlContent) { toml::table root; try { root = toml::parse(tomlContent); } catch (const toml::parse_error& e) { std::ostringstream msg; msg << "TOML parse error: " << e.description() << " at " << e.source().begin; throw std::runtime_error(msg.str()); } std::vector result; const toml::array* bpArr = root["blueprint"].as_array(); if (!bpArr) { return result; } for (std::size_t i = 0; i < bpArr->size(); ++i) { const toml::table* bpTbl = (*bpArr)[i].as_table(); if (!bpTbl) { throw std::runtime_error("blueprint[" + std::to_string(i) + "] is not a table"); } Blueprint bp; bp.name = QString::fromStdString((*bpTbl)["name"].value_or(std::string{})); const toml::array* bldArr = (*bpTbl)["buildings"].as_array(); if (bldArr) { for (std::size_t j = 0; j < bldArr->size(); ++j) { const toml::table* bldTbl = (*bldArr)[j].as_table(); if (!bldTbl) { throw std::runtime_error( "blueprint[" + std::to_string(i) + "].buildings[" + std::to_string(j) + "] is not a table"); } const std::string typeStr = (*bldTbl)["type"].value_or(std::string{}); const std::optional parsedType = parseBuildingType(typeStr); if (!parsedType) { throw std::runtime_error("unknown building type: '" + typeStr + "'"); } BlueprintBuilding bb; bb.type = *parsedType; bb.rotation = parseRotation((*bldTbl)["rotation"].value_or(std::string{})); bb.offset.setX(static_cast((*bldTbl)["offset_x"].value_or(int64_t{0}))); bb.offset.setY(static_cast((*bldTbl)["offset_y"].value_or(int64_t{0}))); bb.recipeId = (*bldTbl)["recipe_id"].value_or(std::string{}); bp.buildings.push_back(std::move(bb)); } } result.push_back(std::move(bp)); } return result; } } // namespace BlueprintSerializer