Files
dota_factory/src/lib/config/BlueprintSerializer.cpp

137 lines
3.9 KiB
C++

#include "BlueprintSerializer.h"
#include <sstream>
#include <stdexcept>
#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<Blueprint>& 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<int64_t>(b.offset.x()));
bldTbl.insert("offset_y", static_cast<int64_t>(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<Blueprint> 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<Blueprint> 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<BuildingType> 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<int>((*bldTbl)["offset_x"].value_or(int64_t{0})));
bb.offset.setY(static_cast<int>((*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