Quick refactor of the config system to make it easier to refactor config.cpp/hpp later.

This commit is contained in:
Zed A. Shaw 2025-09-16 11:59:30 -04:00
parent 47f659ae8e
commit e523aa8b02
29 changed files with 138 additions and 140 deletions

View file

@ -60,7 +60,7 @@ clean:
meson compile --clean -C builddir meson compile --clean -C builddir
debug_test: build debug_test: build
gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests -e gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests -e "[lighting]"
win_installer: win_installer:
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp' powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'

2
ai.cpp
View file

@ -66,7 +66,7 @@ namespace ai {
void init(std::string config_path) { void init(std::string config_path) {
if(!initialized) { if(!initialized) {
Config config(config_path); auto config = settings::get(config_path);
// profile specifies what keys (bitset indexes) are allowed // profile specifies what keys (bitset indexes) are allowed
// and how they map to the bitset of State // and how they map to the bitset of State

View file

@ -97,8 +97,8 @@ namespace animation {
void init() { void init() {
if(!initialized) { if(!initialized) {
Config animations("assets/animations.json"); auto animations = settings::get("animations");
Config config("assets/config.json"); auto config = settings::get("config");
auto& sprites = config["sprites"]; auto& sprites = config["sprites"];
for(auto& [name, data] : animations.json().items()) { for(auto& [name, data] : animations.json().items()) {

View file

@ -265,5 +265,8 @@
"text_size": 20, "text_size": 20,
"label_size": 20, "label_size": 20,
"font_file_name": "assets/text.otf" "font_file_name": "assets/text.otf"
},
"player": {
"hands": "male_hand"
} }
} }

View file

@ -47,7 +47,7 @@ namespace sfml {
guecs::Theme Backend::theme() { guecs::Theme Backend::theme() {
palette::init(); palette::init();
auto config = Config("assets/config.json")["theme"]; auto config = settings::Config("assets/config.json")["theme"];
guecs::Theme theme { guecs::Theme theme {
.BLACK=palette::get("gui/theme:black"), .BLACK=palette::get("gui/theme:black"),
@ -71,7 +71,7 @@ namespace sfml {
theme.BG_COLOR = palette::get("gui/theme:bg_color"); theme.BG_COLOR = palette::get("gui/theme:bg_color");
theme.BORDER_COLOR = palette::get("gui/theme:border_color"); theme.BORDER_COLOR = palette::get("gui/theme:border_color");
theme.BG_COLOR_DARK = palette::get("gui/theme:bg_color_dark"); theme.BG_COLOR_DARK = palette::get("gui/theme:bg_color_dark");
theme.FONT_FILE_NAME = Config::path_to(config["font_file_name"]).string(); theme.FONT_FILE_NAME = settings::Config::path_to(config["font_file_name"]).string();
return theme; return theme;
} }

View file

@ -52,13 +52,13 @@ namespace components {
}; };
struct GameConfig { struct GameConfig {
Config game; settings::Config game;
Config enemies; settings::Config enemies;
Config items; settings::Config items;
Config tiles; settings::Config tiles;
Config devices; settings::Config devices;
Config bosses; settings::Config bosses;
Config rituals; settings::Config rituals;
}; };
struct Personality { struct Personality {

View file

@ -2,51 +2,66 @@
#include "dbc.hpp" #include "dbc.hpp"
#include <fmt/core.h> #include <fmt/core.h>
using nlohmann::json; namespace settings {
using fmt::format; using nlohmann::json;
using fmt::format;
std::filesystem::path Config::BASE_DIR{"."}; std::filesystem::path Config::BASE_DIR{"."};
Config::Config(const std::string src_path) : $src_path(src_path) { Config::Config(const std::string src_path) : $src_path(src_path) {
auto path_to = Config::path_to($src_path); auto path_to = Config::path_to($src_path);
dbc::check(std::filesystem::exists(path_to), dbc::check(std::filesystem::exists(path_to),
fmt::format("requested config file {} doesn't exist", path_to.string())); fmt::format("requested config file {} doesn't exist", path_to.string()));
std::ifstream infile(path_to); std::ifstream infile(path_to);
$config = json::parse(infile); $config = json::parse(infile);
}
nlohmann::json &Config::operator[](size_t key) {
return $config[key];
}
json &Config::operator[](const std::string &key) {
dbc::check($config.contains(key), fmt::format("ERROR in config, key {} doesn't exist.", key));
return $config[key];
}
std::wstring Config::wstring(const std::string main_key, const std::string sub_key) {
dbc::check($config.contains(main_key), fmt::format("ERROR wstring main/key in config, main_key {} doesn't exist.", main_key));
dbc::check($config[main_key].contains(sub_key), fmt::format("ERROR wstring in config, main_key/key {}/{} doesn't exist.", main_key, sub_key));
const std::string& str_val = $config[main_key][sub_key];
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
return $converter.from_bytes(str_val);
}
std::vector<std::string> Config::keys() {
std::vector<std::string> the_fucking_keys;
for(auto& [key, value] : $config.items()) {
the_fucking_keys.push_back(key);
} }
return the_fucking_keys; nlohmann::json &Config::operator[](size_t key) {
} return $config[key];
}
void Config::set_base_dir(const char *optarg) { json &Config::operator[](const std::string &key) {
Config::BASE_DIR.assign(optarg); dbc::check($config.contains(key), fmt::format("ERROR in config, key {} doesn't exist.", key));
} return $config[key];
}
std::filesystem::path Config::path_to(const std::string& path) { std::wstring Config::wstring(const std::string main_key, const std::string sub_key) {
return Config::BASE_DIR / path; dbc::check($config.contains(main_key), fmt::format("ERROR wstring main/key in config, main_key {} doesn't exist.", main_key));
dbc::check($config[main_key].contains(sub_key), fmt::format("ERROR wstring in config, main_key/key {}/{} doesn't exist.", main_key, sub_key));
const std::string& str_val = $config[main_key][sub_key];
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
return $converter.from_bytes(str_val);
}
std::vector<std::string> Config::keys() {
std::vector<std::string> the_fucking_keys;
for(auto& [key, value] : $config.items()) {
the_fucking_keys.push_back(key);
}
return the_fucking_keys;
}
void Config::set_base_dir(const char *optarg) {
Config::BASE_DIR.assign(optarg);
}
std::filesystem::path Config::path_to(const std::string& path) {
return Config::BASE_DIR / path;
}
Config get(const std::string& name) {
if(name.ends_with(".json")) {
return {name};
} else {
auto path = Config::BASE_DIR / fmt::format("assets/{}.json", name);
dbc::check(std::filesystem::exists(path), fmt::format(
"config file {} does not exist", path.string()));
return {path.string()};
}
}
} }

View file

@ -4,22 +4,26 @@
#include <codecvt> #include <codecvt>
#include <filesystem> #include <filesystem>
struct Config { namespace settings {
static std::filesystem::path BASE_DIR; struct Config {
nlohmann::json $config; static std::filesystem::path BASE_DIR;
std::string $src_path; nlohmann::json $config;
std::string $src_path;
Config(const std::string src_path); Config(const std::string src_path);
Config(nlohmann::json config, std::string src_path) Config(nlohmann::json config, std::string src_path)
: $config(config), $src_path(src_path) {} : $config(config), $src_path(src_path) {}
nlohmann::json &operator[](size_t); nlohmann::json &operator[](size_t);
nlohmann::json &operator[](const std::string &key); nlohmann::json &operator[](const std::string &key);
nlohmann::json &json() { return $config; }; nlohmann::json &json() { return $config; };
std::wstring wstring(const std::string main_key, const std::string sub_key); std::wstring wstring(const std::string main_key, const std::string sub_key);
std::vector<std::string> keys(); std::vector<std::string> keys();
static void set_base_dir(const char *optarg); static void set_base_dir(const char *optarg);
static std::filesystem::path path_to(const std::string& path); static std::filesystem::path path_to(const std::string& path);
}; };
Config get(const std::string &name);
}

View file

@ -2,7 +2,6 @@
#include "components.hpp" #include "components.hpp"
#include "worldbuilder.hpp" #include "worldbuilder.hpp"
#include "constants.hpp" #include "constants.hpp"
#include "save.hpp"
#include "systems.hpp" #include "systems.hpp"
#include "components.hpp" #include "components.hpp"
#include "rituals.hpp" #include "rituals.hpp"
@ -21,7 +20,7 @@ inline shared_ptr<DinkyECS::World> clone_load_world(shared_ptr<DinkyECS::World>
auto world = make_shared<DinkyECS::World>(); auto world = make_shared<DinkyECS::World>();
if(prev_world == nullptr) { if(prev_world == nullptr) {
save::load_configs(*world); GameDB::load_configs(*world);
} else { } else {
prev_world->clone_into(*world); prev_world->clone_into(*world);
} }
@ -134,4 +133,16 @@ namespace GameDB {
dbc::check(initialized, "Forgot to call GameDB::init()"); dbc::check(initialized, "Forgot to call GameDB::init()");
return current_level().player; return current_level().player;
} }
void load_configs(DinkyECS::World &world) {
world.set_the<GameConfig>({
settings::get("config"),
settings::get("enemies"),
settings::get("items"),
settings::get("tiles"),
settings::get("devices"),
settings::get("bosses"),
settings::get("rituals")
});
}
} }

View file

@ -12,7 +12,6 @@ namespace components {
struct Position; struct Position;
} }
namespace GameDB { namespace GameDB {
struct Level { struct Level {
size_t index; size_t index;
@ -31,4 +30,6 @@ namespace GameDB {
std::shared_ptr<DinkyECS::World> current_world(); std::shared_ptr<DinkyECS::World> current_world();
components::Position& player_position(); components::Position& player_position();
DinkyECS::Entity the_player(); DinkyECS::Entity the_player();
void load_configs(DinkyECS::World &world);
} }

View file

@ -11,12 +11,15 @@ namespace gui {
MainUI::MainUI(sf::RenderWindow& window) : MainUI::MainUI(sf::RenderWindow& window) :
$window(window), $window(window),
$rayview(std::make_shared<Raycaster>(RAY_VIEW_WIDTH, RAY_VIEW_HEIGHT)), $rayview(std::make_shared<Raycaster>(RAY_VIEW_WIDTH, RAY_VIEW_HEIGHT))
$hand(textures::get_sprite("female_hand")),
$hand_anim(animation::load("female_hand"))
{ {
$window.setVerticalSyncEnabled(VSYNC); $window.setVerticalSyncEnabled(VSYNC);
$window.setFramerateLimit(FRAME_LIMIT); $window.setFramerateLimit(FRAME_LIMIT);
auto config = settings::get("config");
$hand = textures::get_sprite(config["player"]["hands"]);
$hand_anim = animation::load(config["player"]["hands"]);
} }
void MainUI::dirty() { void MainUI::dirty() {
@ -34,7 +37,6 @@ namespace gui {
$overlay_ui.init(); $overlay_ui.init();
} }
void MainUI::render() { void MainUI::render() {
if($needs_render) $rayview->render(); if($needs_render) $rayview->render();
$rayview->draw($window); $rayview->draw($window);

View file

@ -14,7 +14,7 @@ int main(int argc, char* argv[]) {
components::init(); components::init();
sfml::Backend backend; sfml::Backend backend;
guecs::init(&backend); guecs::init(&backend);
ai::init("assets/ai.json"); ai::init("ai");
animation::init(); animation::init();
GameDB::init(); GameDB::init();

View file

@ -115,7 +115,6 @@ sources = [
'rand.cpp', 'rand.cpp',
'raycaster.cpp', 'raycaster.cpp',
'rituals.cpp', 'rituals.cpp',
'save.cpp',
'shaders.cpp', 'shaders.cpp',
'shiterator.hpp', 'shiterator.hpp',
'sound.cpp', 'sound.cpp',

View file

@ -21,7 +21,7 @@ namespace palette {
COLOR.initialized = true; COLOR.initialized = true;
COLOR.config = json_file; COLOR.config = json_file;
Config config(json_file); auto config = settings::get(json_file);
json& colors = config.json(); json& colors = config.json();
for(auto [key, value_specs] : colors.items()) { for(auto [key, value_specs] : colors.items()) {

View file

@ -4,7 +4,7 @@
namespace palette { namespace palette {
using std::string; using std::string;
void init(const std::string &config="assets/palette.json"); void init(const std::string &config="palette");
sf::Color get(const string &key); sf::Color get(const string &key);

View file

@ -52,7 +52,7 @@ namespace ritual {
}; };
struct Engine { struct Engine {
Config $config; settings::Config $config;
ai::AIProfile $profile; ai::AIProfile $profile;
std::unordered_map<std::string, ai::Action> $actions; std::unordered_map<std::string, ai::Action> $actions;
std::unordered_map<std::string, ai::State> $states; std::unordered_map<std::string, ai::State> $states;

View file

@ -1,23 +0,0 @@
#include "save.hpp"
#include <fstream>
#include "dbc.hpp"
#include <fmt/core.h>
#include "config.hpp"
#include <filesystem>
using namespace components;
using namespace fmt;
void save::load_configs(DinkyECS::World &world) {
Config game("./assets/config.json");
Config enemies("./assets/enemies.json");
Config items("./assets/items.json");
Config tiles("./assets/tiles.json");
Config devices("./assets/devices.json");
Config bosses("./assets/bosses.json");
Config rituals("./assets/rituals.json");
world.set_the<GameConfig>({
game, enemies, items, tiles, devices, bosses, rituals
});
}

View file

@ -1,14 +0,0 @@
#pragma once
#include "components.hpp"
#include "map.hpp"
#include "dinkyecs.hpp"
#include <filesystem>
#include <string>
#include <map>
namespace save {
namespace fs = std::filesystem;
void load_configs(DinkyECS::World &world);
}

View file

@ -33,7 +33,7 @@ namespace shaders {
if(!INITIALIZED) { if(!INITIALIZED) {
dbc::check(sf::Shader::isAvailable(), "no shaders?!"); dbc::check(sf::Shader::isAvailable(), "no shaders?!");
INITIALIZED = true; INITIALIZED = true;
Config config("assets/shaders.json"); auto config = settings::get("shaders");
bool good = load_shader("ERROR", config["ERROR"]); bool good = load_shader("ERROR", config["ERROR"]);
dbc::check(good, "Failed to load ERROR shader. Look in assets/shaders.json"); dbc::check(good, "Failed to load ERROR shader. Look in assets/shaders.json");

View file

@ -28,7 +28,7 @@ namespace sound {
void init() { void init() {
if(!initialized) { if(!initialized) {
Config assets("assets/config.json"); auto assets = settings::get("config");
for(auto& el : assets["sounds"].items()) { for(auto& el : assets["sounds"].items()) {
load(el.key(), el.value()); load(el.key(), el.value());

View file

@ -130,7 +130,7 @@ TEST_CASE("ai as a module like sound/sprites", "[ai]") {
TEST_CASE("ai autowalker ai test", "[ai]") { TEST_CASE("ai autowalker ai test", "[ai]") {
ai::reset(); ai::reset();
ai::init("assets/ai.json"); ai::init("ai");
auto start = ai::load_state("Host::initial_state"); auto start = ai::load_state("Host::initial_state");
auto goal = ai::load_state("Host::final_state"); auto goal = ai::load_state("Host::final_state");
int enemy_count = 5; int enemy_count = 5;
@ -170,7 +170,7 @@ TEST_CASE("ai autowalker ai test", "[ai]") {
TEST_CASE("Confirm EntityAI behaves as expected", "[ai]") { TEST_CASE("Confirm EntityAI behaves as expected", "[ai]") {
ai::reset(); ai::reset();
ai::init("assets/ai.json"); ai::init("ai");
auto ai_start = ai::load_state("Enemy::initial_state"); auto ai_start = ai::load_state("Enemy::initial_state");
auto ai_goal = ai::load_state("Enemy::final_state"); auto ai_goal = ai::load_state("Enemy::final_state");

View file

@ -9,7 +9,7 @@ using namespace combat;
TEST_CASE("battle operations fantasy", "[combat-battle]") { TEST_CASE("battle operations fantasy", "[combat-battle]") {
ai::reset(); ai::reset();
ai::init("assets/ai.json"); ai::init("ai");
auto ai_start = ai::load_state("Enemy::initial_state"); auto ai_start = ai::load_state("Enemy::initial_state");
auto ai_goal = ai::load_state("Enemy::final_state"); auto ai_goal = ai::load_state("Enemy::final_state");

View file

@ -16,7 +16,7 @@ TEST_CASE("confirm component loading works", "[components]") {
DinkyECS::World world; DinkyECS::World world;
for(auto test_data : test_list) { for(auto test_data : test_list) {
Config config(test_data); auto config = settings::get(test_data);
auto data_list = config.json(); auto data_list = config.json();
for(auto& [key, data] : data_list.items()) { for(auto& [key, data] : data_list.items()) {
@ -31,7 +31,7 @@ TEST_CASE("confirm component loading works", "[components]") {
} }
TEST_CASE("make sure json_mods works", "[components]") { TEST_CASE("make sure json_mods works", "[components]") {
Config config("assets/bosses.json"); auto config = settings::get("bosses");
// this confirms that loading something with an optional // this confirms that loading something with an optional
// field works with the json conversions in json_mods.hpp // field works with the json conversions in json_mods.hpp
for(auto& comp_data : config["RAT_KING"]["components"]) { for(auto& comp_data : config["RAT_KING"]["components"]) {

View file

@ -3,8 +3,8 @@
#include <iostream> #include <iostream>
TEST_CASE("confirm basic config loader ops", "[config]") { TEST_CASE("confirm basic config loader ops", "[config]") {
Config::set_base_dir("./"); settings::Config::set_base_dir("./");
Config config("assets/devices.json"); auto config = settings::get("devices");
auto data_list = config.json(); auto data_list = config.json();
auto the_keys = config.keys(); auto the_keys = config.keys();
@ -19,7 +19,7 @@ TEST_CASE("confirm basic config loader ops", "[config]") {
} }
} }
Config indexed("tests/config_test.json"); auto indexed = settings::get("tests/config_test.json");
auto& test_0 = indexed[0]; auto& test_0 = indexed[0];
REQUIRE(test_0["test"] == 0); REQUIRE(test_0["test"] == 0);

View file

@ -8,7 +8,7 @@ using namespace fmt;
using namespace components; using namespace components;
TEST_CASE("test the loot ui", "[loot]") { TEST_CASE("test the loot ui", "[loot]") {
Config items("assets/items.json"); auto items = settings::get("assets/items.json");
DinkyECS::World world; DinkyECS::World world;
auto torch = world.entity(); auto torch = world.entity();
auto& data = items["TORCH_BAD"]; auto& data = items["TORCH_BAD"];

View file

@ -39,12 +39,12 @@ namespace textures {
} }
void load_sprites() { void load_sprites() {
Config sprites("assets/config.json"); auto sprites = settings::get("config");
bool smooth = sprites["graphics"]["smooth_textures"]; bool smooth = sprites["graphics"]["smooth_textures"];
load_sprite_textures(TMGR.sprite_textures, sprites["sprites"], smooth); load_sprite_textures(TMGR.sprite_textures, sprites["sprites"], smooth);
Config icons("assets/icons.json"); auto icons = settings::get("assets/icons.json");
load_sprite_textures(TMGR.icon_textures, icons.json(), smooth); load_sprite_textures(TMGR.icon_textures, icons.json(), smooth);
} }
@ -56,7 +56,7 @@ namespace textures {
} }
void load_tiles() { void load_tiles() {
Config assets("assets/tiles.json"); auto assets = settings::get("tiles");
auto &tiles = assets.json(); auto &tiles = assets.json();
resize_shit(tiles.size()); resize_shit(tiles.size());
@ -93,7 +93,7 @@ namespace textures {
} }
void load_map_tiles() { void load_map_tiles() {
Config config("./assets/map_tiles.json"); auto config = settings::get("map_tiles");
json& tiles = config.json(); json& tiles = config.json();
for(auto tile : tiles) { for(auto tile : tiles) {

View file

@ -12,7 +12,7 @@ int main(int argc, char* argv[]) {
textures::init(); textures::init();
sound::init(); sound::init();
ai::init("assets/ai.json"); ai::init("ai");
animation::init(); animation::init();
sound::mute(false); sound::mute(false);

View file

@ -203,7 +203,7 @@ struct MapTileBuilder {
void load_config(MapConfig& config, bool is_centered, std::string path, std::function<json&(json&)> finder) void load_config(MapConfig& config, bool is_centered, std::string path, std::function<json&(json&)> finder)
{ {
Config tiles(path); auto tiles = settings::get(path);
for(auto [key, val] : tiles.json().items()) { for(auto [key, val] : tiles.json().items()) {
config.it.next(); config.it.next();
@ -248,13 +248,13 @@ int main() {
palette::init(); palette::init();
MapConfig config; MapConfig config;
load_config(config, false, "./assets/tiles.json", [](json& val) -> json& { load_config(config, false, "tiles", [](json& val) -> json& {
return val; return val;
}); });
load_config(config, true, "./assets/items.json", component_display); load_config(config, true, "items", component_display);
load_config(config, true, "./assets/devices.json", component_display); load_config(config, true, "devices", component_display);
load_config(config, true, "./assets/enemies.json", component_display); load_config(config, true, "enemies", component_display);
fmt::println("-----------------------------------------"); fmt::println("-----------------------------------------");
MapTileBuilder builder(ICONGEN_MAP_TILE_DIM, ICONGEN_MAP_TILE_DIM); MapTileBuilder builder(ICONGEN_MAP_TILE_DIM, ICONGEN_MAP_TILE_DIM);

View file

@ -15,7 +15,7 @@ using namespace components;
void WorldBuilder::stylize_rooms() { void WorldBuilder::stylize_rooms() {
auto& tiles = $map.tiles(); auto& tiles = $map.tiles();
Config style_config("assets/styles.json"); auto style_config = settings::get("styles");
json& styles = style_config.json(); json& styles = style_config.json();
for(auto& room : $map.rooms()) { for(auto& room : $map.rooms()) {