add balancing tool target
This commit is contained in:
166
src/balancing/BalancingConfig.cpp
Normal file
166
src/balancing/BalancingConfig.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "BalancingConfig.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "toml.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::runtime_error makeError(const std::string& path, const std::string& why)
|
||||
{
|
||||
return std::runtime_error("balancing.toml: '" + path + "' " + why);
|
||||
}
|
||||
|
||||
template <typename NodeView>
|
||||
int64_t requireInt(NodeView node, const std::string& path)
|
||||
{
|
||||
const std::optional<int64_t> value = node.template value<int64_t>();
|
||||
if (!value)
|
||||
{
|
||||
throw makeError(path, "missing or not an integer");
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
template <typename NodeView>
|
||||
std::string requireString(NodeView node, const std::string& path)
|
||||
{
|
||||
const std::optional<std::string> value = node.template value<std::string>();
|
||||
if (!value)
|
||||
{
|
||||
throw makeError(path, "missing or not a string");
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BalancingConfig loadBalancingConfig(const std::string& path)
|
||||
{
|
||||
toml::table root;
|
||||
try
|
||||
{
|
||||
root = toml::parse_file(path);
|
||||
}
|
||||
catch (const toml::parse_error& e)
|
||||
{
|
||||
throw std::runtime_error(std::string("balancing.toml: parse error: ") + e.what());
|
||||
}
|
||||
|
||||
const toml::array* arenaArray = root["arena"].as_array();
|
||||
if (!arenaArray)
|
||||
{
|
||||
throw makeError("arena", "missing or not an array of tables");
|
||||
}
|
||||
|
||||
BalancingConfig config;
|
||||
|
||||
for (std::size_t ai = 0; ai < arenaArray->size(); ++ai)
|
||||
{
|
||||
const toml::table* arenaTbl = (*arenaArray)[ai].as_table();
|
||||
if (!arenaTbl)
|
||||
{
|
||||
throw makeError("arena[" + std::to_string(ai) + "]", "not a table");
|
||||
}
|
||||
|
||||
const std::string prefix = "arena[" + std::to_string(ai) + "]";
|
||||
|
||||
ArenaConfig arena;
|
||||
arena.name = requireString((*arenaTbl)["name"], prefix + ".name");
|
||||
arena.heightTiles = static_cast<int>(
|
||||
requireInt((*arenaTbl)["height_tiles"], prefix + ".height_tiles"));
|
||||
arena.playerBufferWidth = static_cast<int>(
|
||||
requireInt((*arenaTbl)["player_buffer_width"], prefix + ".player_buffer_width"));
|
||||
arena.contestZoneWidth = static_cast<int>(
|
||||
requireInt((*arenaTbl)["contest_zone_width"], prefix + ".contest_zone_width"));
|
||||
arena.enemyBufferWidth = static_cast<int>(
|
||||
requireInt((*arenaTbl)["enemy_buffer_width"], prefix + ".enemy_buffer_width"));
|
||||
|
||||
const toml::array* teamArray = (*arenaTbl)["team"].as_array();
|
||||
if (!teamArray || teamArray->size() != 2)
|
||||
{
|
||||
throw makeError(prefix + ".team", "must contain exactly 2 teams");
|
||||
}
|
||||
|
||||
for (int ti = 0; ti < 2; ++ti)
|
||||
{
|
||||
const toml::table* teamTbl = (*teamArray)[static_cast<std::size_t>(ti)].as_table();
|
||||
if (!teamTbl)
|
||||
{
|
||||
throw makeError(prefix + ".team[" + std::to_string(ti) + "]", "not a table");
|
||||
}
|
||||
|
||||
const std::string tPrefix = prefix + ".team[" + std::to_string(ti) + "]";
|
||||
|
||||
ArenaTeamConfig& team = arena.teams[ti];
|
||||
team.name = requireString((*teamTbl)["name"], tPrefix + ".name");
|
||||
|
||||
const toml::array* shipArray = (*teamTbl)["ship"].as_array();
|
||||
if (shipArray)
|
||||
{
|
||||
for (std::size_t si = 0; si < shipArray->size(); ++si)
|
||||
{
|
||||
const toml::table* shipTbl = (*shipArray)[si].as_table();
|
||||
if (!shipTbl)
|
||||
{
|
||||
throw makeError(tPrefix + ".ship[" + std::to_string(si) + "]",
|
||||
"not a table");
|
||||
}
|
||||
|
||||
const std::string sPrefix =
|
||||
tPrefix + ".ship[" + std::to_string(si) + "]";
|
||||
|
||||
ArenaShipEntry entry;
|
||||
entry.schematicId = requireString((*shipTbl)["schematic"],
|
||||
sPrefix + ".schematic");
|
||||
entry.level = static_cast<int>(
|
||||
requireInt((*shipTbl)["level"], sPrefix + ".level"));
|
||||
entry.count = static_cast<int>(
|
||||
requireInt((*shipTbl)["count"], sPrefix + ".count"));
|
||||
team.ships.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
const toml::array* stationArray = (*teamTbl)["station"].as_array();
|
||||
if (stationArray)
|
||||
{
|
||||
for (std::size_t si = 0; si < stationArray->size(); ++si)
|
||||
{
|
||||
const toml::table* stationTbl = (*stationArray)[si].as_table();
|
||||
if (!stationTbl)
|
||||
{
|
||||
throw makeError(tPrefix + ".station[" + std::to_string(si) + "]",
|
||||
"not a table");
|
||||
}
|
||||
|
||||
const std::string sPrefix =
|
||||
tPrefix + ".station[" + std::to_string(si) + "]";
|
||||
|
||||
ArenaStationEntry entry;
|
||||
entry.stationType = requireString((*stationTbl)["type"],
|
||||
sPrefix + ".type");
|
||||
entry.level = static_cast<int>(
|
||||
requireInt((*stationTbl)["level"], sPrefix + ".level"));
|
||||
entry.position = QPoint(
|
||||
static_cast<int>(requireInt((*stationTbl)["x"], sPrefix + ".x")),
|
||||
static_cast<int>(requireInt((*stationTbl)["y"], sPrefix + ".y")));
|
||||
|
||||
if (entry.stationType != "player_station"
|
||||
&& entry.stationType != "enemy_station")
|
||||
{
|
||||
throw makeError(sPrefix + ".type",
|
||||
"must be 'player_station' or 'enemy_station'");
|
||||
}
|
||||
|
||||
team.stations.push_back(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config.arenas.push_back(arena);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
Reference in New Issue
Block a user