Continues the ConfigLoader.cpp domain split. parseRotationString and parsePlacedModules are only used by loadShips, so they move along as domain-local anonymous-namespace helpers rather than into TomlHelpers. Pure move; no logic change. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
134 lines
5.2 KiB
C++
134 lines
5.2 KiB
C++
#include "ConfigLoader.h"
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <QPoint>
|
|
|
|
#include "toml.hpp"
|
|
|
|
#include "Rotation.h"
|
|
#include "ShipLayout.h"
|
|
#include "TomlHelpers.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
Rotation parseRotationString(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;
|
|
}
|
|
|
|
std::vector<PlacedModule> parsePlacedModules(const toml::array& arr,
|
|
const std::string& file,
|
|
const std::string& path)
|
|
{
|
|
std::vector<PlacedModule> result;
|
|
result.reserve(arr.size());
|
|
for (std::size_t i = 0; i < arr.size(); ++i)
|
|
{
|
|
const std::string elemPath = path + "[" + std::to_string(i) + "]";
|
|
const toml::table* t = arr[i].as_table();
|
|
if (t == nullptr) { continue; }
|
|
toml::table& mt = const_cast<toml::table&>(*t);
|
|
|
|
const std::optional<std::string> type = mt["type"].value<std::string>();
|
|
const std::optional<int64_t> x = mt["x"].value<int64_t>();
|
|
const std::optional<int64_t> y = mt["y"].value<int64_t>();
|
|
const std::optional<std::string> rot = mt["rotation"].value<std::string>();
|
|
if (!type || !x || !y || !rot) { continue; }
|
|
|
|
PlacedModule pm;
|
|
pm.moduleId = *type;
|
|
pm.position = QPoint(static_cast<int>(*x), static_cast<int>(*y));
|
|
pm.rotation = parseRotationString(*rot);
|
|
result.push_back(std::move(pm));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
ShipsConfig ConfigLoader::loadShips(const std::string& path)
|
|
{
|
|
const std::string file = "ships.toml";
|
|
toml::table tbl = parseFile(path, file);
|
|
|
|
ShipsConfig cfg;
|
|
const toml::array& arr = requireArray(tbl["ship"], file, "ship");
|
|
|
|
for (std::size_t i = 0; i < arr.size(); ++i)
|
|
{
|
|
const std::string elemPath = "ship[" + std::to_string(i) + "]";
|
|
const toml::table* st = arr[i].as_table();
|
|
if (st == nullptr)
|
|
{
|
|
throw makeError(file, elemPath, "not a table");
|
|
}
|
|
toml::table& mt = const_cast<toml::table&>(*st);
|
|
|
|
ShipDef def;
|
|
def.id = requireString(mt["id"], file, elemPath + ".id");
|
|
def.layout = requireStringArray(mt["layout"], file, elemPath + ".layout");
|
|
|
|
// Schematic
|
|
{
|
|
const std::string bpPath = elemPath + ".schematic";
|
|
const toml::table& bpTable = requireTable(mt["schematic"], file, bpPath);
|
|
toml::table& bpMt = const_cast<toml::table&>(bpTable);
|
|
|
|
const toml::array& materials = requireArray(bpMt["materials"], file, bpPath + ".materials");
|
|
def.schematic.materials = parseIngredients(materials, file, bpPath + ".materials");
|
|
def.schematic.productionTimeSeconds = requireDouble(
|
|
bpMt["production_time_seconds"], file, bpPath + ".production_time_seconds");
|
|
}
|
|
|
|
// Health
|
|
{
|
|
const std::string hPath = elemPath + ".health";
|
|
const toml::table& hTable = requireTable(mt["health"], file, hPath);
|
|
toml::table& hMt = const_cast<toml::table&>(hTable);
|
|
def.health.hp = static_cast<float>(requireDouble(hMt["hp"], file, hPath + ".hp"));
|
|
}
|
|
|
|
// Movement
|
|
{
|
|
const std::string mPath = elemPath + ".movement";
|
|
const toml::table& mTable = requireTable(mt["movement"], file, mPath);
|
|
toml::table& mMt = const_cast<toml::table&>(mTable);
|
|
def.movement.speed_mps = static_cast<float>(requireDouble(mMt["speed_mps"], file, mPath + ".speed_mps"));
|
|
def.movement.mainAcceleration_mpss = static_cast<float>(requireDouble(mMt["main_acceleration_mpss"], file, mPath + ".main_acceleration_mpss"));
|
|
def.movement.maneuveringAcceleration_mpss = static_cast<float>(requireDouble(mMt["maneuvering_acceleration_mpss"], file, mPath + ".maneuvering_acceleration_mpss"));
|
|
def.movement.angularAcceleration_radpss = static_cast<float>(requireDouble(mMt["angular_acceleration_radpss"], file, mPath + ".angular_acceleration_radpss"));
|
|
def.movement.maxRotationSpeed_radps = static_cast<float>(requireDouble(mMt["max_rotation_speed_radps"], file, mPath + ".max_rotation_speed_radps"));
|
|
}
|
|
|
|
// Sensor
|
|
{
|
|
const std::string snsPath = elemPath + ".sensor";
|
|
const toml::table& snsTable = requireTable(mt["sensor"], file, snsPath);
|
|
toml::table& snsMt = const_cast<toml::table&>(snsTable);
|
|
def.sensor.sensorRange_m = static_cast<float>(requireDouble(snsMt["sensor_range_m"], file, snsPath + ".sensor_range_m"));
|
|
}
|
|
|
|
// Optional: default_modules (REQ-WAV-DEFAULT-MODULES)
|
|
if (mt.contains("default_modules"))
|
|
{
|
|
const toml::array& modArr = requireArray(mt["default_modules"], file,
|
|
elemPath + ".default_modules");
|
|
def.defaultModules = parsePlacedModules(modArr, file,
|
|
elemPath + ".default_modules");
|
|
}
|
|
|
|
cfg.ships.push_back(std::move(def));
|
|
}
|
|
|
|
return cfg;
|
|
}
|