137 lines
3.9 KiB
C++
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
|